Search Unity

PlayerData cannot be serialized because it does not have a parameterless constructor.

Discussion in 'Scripting' started by MrSirDolphin, Jan 17, 2022.

  1. MrSirDolphin

    MrSirDolphin

    Joined:
    Mar 30, 2020
    Posts:
    12
    Hello, so I was following Brackey's Save System tutorial and wanted to use the XmlSerializer instead of the binary one because Microsoft deemed it unsafe. But when trying to test the save feature I got this error. I'm not that smart when it comes to this kind of stuff so could anybody please help me?
    Code (CSharp):
    1. InvalidOperationException: PlayerData cannot be serialized because it does not have a parameterless constructor.
    2. System.Xml.Serialization.TypeDesc.CheckSupported () (at <0f9699188f0c414ea6fb5557f5c16d15>:0)
    3. System.Xml.Serialization.TypeScope.GetTypeDesc (System.Type type, System.Reflection.MemberInfo source, System.Boolean directReference, System.Boolean throwOnError) (at <0f9699188f0c414ea6fb5557f5c16d15>:0)
    4. System.Xml.Serialization.TypeScope.GetTypeDesc (System.Type type, System.Reflection.MemberInfo source, System.Boolean directReference) (at <0f9699188f0c414ea6fb5557f5c16d15>:0)
    5. System.Xml.Serialization.ModelScope.GetTypeModel (System.Type type, System.Boolean directReference) (at <0f9699188f0c414ea6fb5557f5c16d15>:0)
    6. System.Xml.Serialization.ModelScope.GetTypeModel (System.Type type) (at <0f9699188f0c414ea6fb5557f5c16d15>:0)
    7. System.Xml.Serialization.XmlReflectionImporter.ImportTypeMapping (System.Type type, System.Xml.Serialization.XmlRootAttribute root, System.String defaultNamespace) (at <0f9699188f0c414ea6fb5557f5c16d15>:0)
    8. System.Xml.Serialization.XmlSerializer..ctor (System.Type type, System.String defaultNamespace) (at <0f9699188f0c414ea6fb5557f5c16d15>:0)
    9. System.Xml.Serialization.XmlSerializer..ctor (System.Type type) (at <0f9699188f0c414ea6fb5557f5c16d15>:0)
    10. SaveSystem.SavePlayer (CoinManager coinManager) (at Assets/Scripts/SaveSystem.cs:10)
    11. CoinManager.SavePlayer () (at Assets/Scripts/CoinManager.cs:55)
    12. UnityEngine.Events.InvokableCall.Invoke () (at <0ee480759f3d481d82ada245dc74f9fd>:0)
    13. UnityEngine.Events.UnityEvent.Invoke () (at <0ee480759f3d481d82ada245dc74f9fd>:0)
    14. UnityEngine.UI.Button.Press () (at Library/PackageCache/com.unity.ugui@1.0.0/Runtime/UI/Core/Button.cs:68)
    15. UnityEngine.UI.Button.OnPointerClick (UnityEngine.EventSystems.PointerEventData eventData) (at Library/PackageCache/com.unity.ugui@1.0.0/Runtime/UI/Core/Button.cs:110)
    16. UnityEngine.EventSystems.ExecuteEvents.Execute (UnityEngine.EventSystems.IPointerClickHandler handler, UnityEngine.EventSystems.BaseEventData eventData) (at Library/PackageCache/com.unity.ugui@1.0.0/Runtime/EventSystem/ExecuteEvents.cs:50)
    17. UnityEngine.EventSystems.ExecuteEvents.Execute[T] (UnityEngine.GameObject target, UnityEngine.EventSystems.BaseEventData eventData, UnityEngine.EventSystems.ExecuteEvents+EventFunction`1[T1] functor) (at Library/PackageCache/com.unity.ugui@1.0.0/Runtime/EventSystem/ExecuteEvents.cs:262)
    18. UnityEngine.EventSystems.EventSystem:Update() (at Library/PackageCache/com.unity.ugui@1.0.0/Runtime/EventSystem/EventSystem.cs:385)
     
  2. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    38,742
    Since you must already have a constructor for this class that takes arguments, you must ALSO provide a parameter-less way to make one of these, such as a constructor like:

    public PlayerData() {}
     
  3. MrSirDolphin

    MrSirDolphin

    Joined:
    Mar 30, 2020
    Posts:
    12
    So I should just make a public PlayerData() and copy n paste the code from the public static PlayerData
     
  4. MrSirDolphin

    MrSirDolphin

    Joined:
    Mar 30, 2020
    Posts:
    12
    If you need more context here is the save system code

    Code (CSharp):
    1. using UnityEngine;
    2. using System.IO;
    3. using System.Xml.Serialization;
    4.  
    5. public static class SaveSystem
    6. {
    7.     public static void SavePlayer(CoinManager coinManager)
    8.     {
    9.         //create a XmlSerializer Formatter
    10.         XmlSerializer formatter = new XmlSerializer(typeof(PlayerData));
    11.  
    12.         string path = Application.persistentDataPath + "/player.sav";
    13.         FileStream stream = new FileStream(path, FileMode.Create);
    14.  
    15.         PlayerData data = new PlayerData(coinManager);
    16.  
    17.         formatter.Serialize(stream, data);
    18.         stream.Close();
    19.        
    20.     }
    21.  
    22.     public static PlayerData LoadPlayer()
    23.     {
    24.         string path = Application.persistentDataPath + "/player.sav";
    25.         if (File.Exists(path))
    26.         {
    27.             XmlSerializer serializer = new XmlSerializer(typeof(PlayerData));
    28.             FileStream stream = new FileStream(path, FileMode.Open);
    29.  
    30.             PlayerData data = serializer.Deserialize(stream) as PlayerData;
    31.  
    32.             stream.Close();
    33.  
    34.             return data;
    35.         }else
    36.         {
    37.             Debug.LogError("Save file not found in " + path);
    38.             return null;
    39.         }
    40.            
    41.     }
    42. }
    43.  
     
  5. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    38,742
    You can't serialize static classes in C#.

    https://stackoverflow.com/questions/1293496/serialize-a-static-class

    Here's some more notes on Load/Save steps:

    https://forum.unity.com/threads/save-system-questions.930366/#post-6087384

    When loading, you can never re-create a MonoBehaviour or ScriptableObject instance directly from JSON. The reason is they are hybrid C# and native engine objects, and when the JSON package calls
    new
    to make one, it cannot make the native engine portion of the object.

    Instead you must first create the MonoBehaviour using AddComponent<T>() on a GameObject instance, or use ScriptableObject.CreateInstance<T>() to make your SO, then use the appropriate JSON "populate object" call to fill in its public fields.

    If you want to use PlayerPrefs to save your game, it's always better to use a JSON-based wrapper such as this one I forked from a fellow named Brett M Johnson on github:

    https://gist.github.com/kurtdekker/7db0500da01c3eb2a7ac8040198ce7f6
     
  6. MrSirDolphin

    MrSirDolphin

    Joined:
    Mar 30, 2020
    Posts:
    12
    So sorry but I don't really understand what you are saying.
     
  7. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    38,742
    I'll assume you're following this tutorial:



    Note how he does NOT have the PlayerData class marked static.

    Screen Shot 2022-01-17 at 11.42.54 AM.png
     
  8. MrSirDolphin

    MrSirDolphin

    Joined:
    Mar 30, 2020
    Posts:
    12
    Ok I now see the issue, but im not sure about how to solve it
     
  9. MrSirDolphin

    MrSirDolphin

    Joined:
    Mar 30, 2020
    Posts:
    12
    How can I solve the issue then?
     
  10. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    38,742
    These steps (same as what I linked above) will help you begin to reason about how to engineer a load/save solution:

    https://forum.unity.com/threads/save-system-questions.930366/#post-6087384

    Alternately I am told there are save products on the asset store. I have not used them.

    Obviously they still need to be integrated with your actual game data no matter what ultimate solution you choose.
     
  11. MrSirDolphin

    MrSirDolphin

    Joined:
    Mar 30, 2020
    Posts:
    12
    I dont understand?