Search Unity

Bug Save and Load System error

Discussion in 'Scripting' started by y0da00, May 20, 2023.

  1. y0da00

    y0da00

    Joined:
    Apr 25, 2023
    Posts:
    2
    I'm attempting to implement a save and load system in my project but I keep on running into the following error whenever I press the save button:

    NullReferenceException: Object reference not set to an instance of an object
    System.Collections.Generic.Dictionary`2[TKey,TValue].get_Keys () (at <9aad1b3a47484d63ba2b3985692d80e9>:0)
    System.Reflection.RuntimePropertyInfo.GetterAdapterFrame[T,R] (System.Reflection.RuntimePropertyInfo+Getter`2[T,R] getter, System.Object obj) (at <9aad1b3a47484d63ba2b3985692d80e9>:0)
    System.Reflection.RuntimePropertyInfo.GetValue (System.Object obj, System.Object[] index) (at <9aad1b3a47484d63ba2b3985692d80e9>:0)
    Rethrow as TargetInvocationException: Exception has been thrown by the target of an invocation.
    System.Reflection.RuntimePropertyInfo.GetValue (System.Object obj, System.Object[] index) (at <9aad1b3a47484d63ba2b3985692d80e9>:0)
    SaveLoadUtility.WriteToDictionary (System.Type fieldType, System.String fieldName, System.Object fieldValue, System.Collections.Generic.Dictionary`2[System.String,System.Object]& baseDict, System.Boolean isField) (at Assets/Dead Earth/Scripts/Unity Save Load Utility/SaveLoadUtility.cs:924)
    SaveLoadUtility.GetValues (System.Object baseInstance, System.Collections.Generic.Dictionary`2[System.String,System.Object]& baseDict, System.Boolean checkForPropertySelector) (at Assets/Dead Earth/Scripts/Unity Save Load Utility/SaveLoadUtility.cs:676)
    SaveLoadUtility.GetValues (System.Object baseInstance, System.Collections.Generic.Dictionary`2[System.String,System.Object]& baseDict) (at Assets/Dead Earth/Scripts/Unity Save Load Utility/SaveLoadUtility.cs:570)
    SaveLoadUtility.WriteToDictionary (System.Type fieldType, System.String fieldName, System.Object fieldValue, System.Collections.Generic.Dictionary`2[System.String,System.Object]& baseDict, System.Boolean isField) (at Assets/Dead Earth/Scripts/Unity Save Load Utility/SaveLoadUtility.cs:966)
    SaveLoadUtility.GetValues (System.Object baseInstance, System.Collections.Generic.Dictionary`2[System.String,System.Object]& baseDict, System.Boolean checkForPropertySelector) (at Assets/Dead Earth/Scripts/Unity Save Load Utility/SaveLoadUtility.cs:676)
    SaveLoadUtility.PackComponent (System.Object component) (at Assets/Dead Earth/Scripts/Unity Save Load Utility/SaveLoadUtility.cs:564)
    SaveLoadUtility.PackGameObject (UnityEngine.GameObject go, ObjectIdentifier oi) (at Assets/Dead Earth/Scripts/Unity Save Load Utility/SaveLoadUtility.cs:522)
    SaveLoadUtility.SaveGame (System.String saveGameName) (at Assets/Dead Earth/Scripts/Unity Save Load Utility/SaveLoadUtility.cs:207)
    SaveLoadMenu.OnGUI () (at Assets/Dead Earth/Scripts/Unity Save Load Utility/SaveLoadMenu.cs:197)

    When I double click on the error in the editor I'm redirected to the following lines of code in the "SaveLoadUtility.cs" script:

    Code (CSharp):
    1. //Go through the OIsToSerialize array again to pack the GameObjects into serializable form, and add the packed data to the sceneObjects list of the new SaveGame instance.
    2. if(true) {
    3. foreach (ObjectIdentifier oi in OIsToSerialize) {
    4. //Convert the GameObject's data into a form that can be serialized (an instance of SceneObject),
    5. //and add it to the SaveGame instance's list of SceneObjects.
    6. newSaveGame.sceneObjects.Add(PackGameObject(oi.gameObject, oi));
    7. }
    8. }

    I'm using this asset I discovered called "USLU" (linked below) which is meant to be straightforward yet I still can't wrap my head around this error.
    https://forum.unity.com/threads/dis...d-utility-free-save-and-load-your-data.435506

    I'm going to attach some files that relate to this error in particular. There are a few requirements for the save system to work (which I've fulfilled), first is that the "ObjectIdentifier.cs" script must be attached to the prefabs that I wish to save and second is that those prefabs must be placed in the "Assets/Resouces/prefabs" folder created after importing the asset.
    Lastly, I have written "GameSaveManager.cs" script which fetches the player's data, like health and inventory, and encrypts/decrypts it on save/load. I will also attach this file, tho I don't think this script is causing any issues.
     

    Attached Files:

    Last edited: May 20, 2023
  2. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    38,689
    y0da00 likes this.
  3. Brathnann

    Brathnann

    Joined:
    Aug 12, 2014
    Posts:
    7,187
    Also, if you look at the thread, the developer for that asset says they no longer support it. I'm not sure when they stopped supporting it, but they made a lot of good comments on why they stopped supporting it. I suggest you look into other options for saving. It may be better to find a solution that still has support if you are unable to write your own solution.
     
    y0da00 likes this.
  4. AngryProgrammer

    AngryProgrammer

    Joined:
    Jun 4, 2019
    Posts:
    490
  5. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    38,689
    ^ ^ ^ ^ ^ This. Everybody wants to "save all the state" of a running scene, as if it was a thing you can just rip out and do. Unity doesn't even do that when they save the scene.

    Save the absolute MINIMUM amount of data you can get away with. Any more save data instantly becomes a source of bugs.

    As much as we groused with early console memory cards and even before that with on-cart flash ram, it kept you really honest and encouraged parsimony.

    Load/Save steps:

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

    An excellent discussion of loading/saving in Unity3D by Xarbrough:

    https://forum.unity.com/threads/save-system.1232301/#post-7872586

    Loading/Saving ScriptableObjects by a proxy identifier such as name:

    https://forum.unity.com/threads/use...lds-in-editor-and-build.1327059/#post-8394573

    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

    Do not use the binary formatter/serializer: it is insecure, it cannot be made secure, and it makes debugging very difficult, plus it actually will NOT prevent people from modifying your save data on their computers.

    https://docs.microsoft.com/en-us/dotnet/standard/serialization/binaryformatter-security-guide