Either SaveSystem.Serialize or SaveSystem.Deserialize are no longer working.

Announcements, support questions, and discussion for the Dialogue System.
Post Reply
MartinLFO
Posts: 3
Joined: Mon Feb 15, 2021 10:38 pm

Either SaveSystem.Serialize or SaveSystem.Deserialize are no longer working.

Post by MartinLFO »

Hello,

So I wrote a custom saver, seen below. It's very basic since I'm new to serialization in general.

Code: Select all

public class CustomSaver : Saver
    {
        bool enemyActive;
        string serializedEnemyActive;
        int testmessage;

        public override string RecordData()
        {
            /// This method should return a string that represents the data you want to save.
            /// You can use SaveSystem.Serialize() to serialize a serializable object to a 
            /// string. This will use the serializer component on the Save System GameObject,
            /// which defaults to JSON serialization.
            enemyActive = GetComponent<EnemyAI>().Active;
            serializedEnemyActive = SaveSystem.Serialize(enemyActive);
            return serializedEnemyActive;
            //testmessage = GetComponent<EnemyAI>().testLoad;
            //serializedEnemyActive = SaveSystem.Serialize(testmessage);
            //return serializedEnemyActive;
        }

        public override void ApplyData(string data)
        {
            /// This method should process the string representation of saved data and apply
            /// it to the current state of the game. You can use SaveSystem.Deserialize()
            /// to deserialize the string to an object that specifies the state to apply to
            /// the game.
            GetComponent<EnemyAI>().Active = SaveSystem.Deserialize<bool>(serializedEnemyActive);
            //GetComponent<EnemyAI>().testLoad = SaveSystem.Deserialize<int>(serializedEnemyActive);
        }
    }
Now, I tested this with the "testmessage" variable, working basically the same as the enemyActive variable. When I did, it worked. But that was a week ago, and during this week an unrelated incident happened where the master branch of our project got some serious issues. As a result, we found it best to create a new repository using an older version of the project one of our members had. Because my scripts had nothing to do with the issue, I exported them as a unity package (including the custom saver) and reimported them when the new project was on my system. However, after briefly recreating/replacing other things that had been lost and running the game to make sure the save system was running, this error message appeared whenever I loaded a saved slot:

"NullReferenceException: Object reference not set to an instance of an object
UnityEngine.JsonUtility.FromJson[T] (System.String json) (at <1386288601af43018501cce2912f52f4>:0)
PixelCrushers.JsonDataSerializer.Deserialize[T] (System.String s, T data) (at <810d2e6289844e9fbf86de0ff4e5efbb>:0)
PixelCrushers.SaveSystem.Deserialize[T] (System.String s, T data) (at <810d2e6289844e9fbf86de0ff4e5efbb>:0)
PixelCrushers.CustomSaver.ApplyData (System.String data) (at Assets/Scripts/CustomSaver.cs:35)
PixelCrushers.SaveSystem.ApplySavedGameData (PixelCrushers.SavedGameData savedGameData) (at <810d2e6289844e9fbf86de0ff4e5efbb>:0)
UnityEngine.Debug:LogException(Exception)"

Line 35 of the custom saver is the line where it deserializes the data. So at first I thought that was the issue. But after some sleuthing and testing, I ended up writing a debug message that prints the variable "serializedEnemyActive" after the data's been serialized. The string I got was only "{}". I tested this with the testvariable as well and got the same result. I know little to nothing about serialization, but if it's saved as a unique string, I feel as though it shouldn't be printed as a pair of empty brackets.

Regardless, I've also tested the serialization with the gameobject's position and a completely different gameobject's position, and I still get the error. I have no idea where this error is coming from; to my knowledge the above code is exactly the same as it was previously. I also followed the documentation again to make sure all the needed components were in the scene. So... what's going on here?
User avatar
Tony Li
Posts: 22166
Joined: Thu Jul 18, 2013 1:27 pm

Re: Either SaveSystem.Serialize or SaveSystem.Deserialize are no longer working.

Post by Tony Li »

Hi,

Use SaveSystem.Serialize (and thus JsonUtility) for structs and classes. For individual primitive types, you can just return the type as a string. Examples:

Code: Select all

public override string RecordData()
{
    enemyActive = GetComponent<EnemyAI>().Active;
    return enemyActive.ToString();
}

public override void ApplyData(string data)
{
    if (!string.IsNullOrEmpty(data))
    {
        GetComponent<EnemyAI>().Active = (data == "True");
    }
}
(For numbers, the Dialogue System provides number helper methods in the SafeConvert class.)
MartinLFO
Posts: 3
Joined: Mon Feb 15, 2021 10:38 pm

Re: Either SaveSystem.Serialize or SaveSystem.Deserialize are no longer working.

Post by MartinLFO »

Thank you, this does appear to solve my issue. However, say in the future of this project I need to save a struct or class, and I run into the same issue. Would there be another way of converting those to a string and back again?
User avatar
Tony Li
Posts: 22166
Joined: Thu Jul 18, 2013 1:27 pm

Re: Either SaveSystem.Serialize or SaveSystem.Deserialize are no longer working.

Post by Tony Li »

Hi,

Yes. Take a look at some of the built-in savers, such as PositionSaver, for examples. Add the [Serializable] attribute to your class or struct. Example:

Code: Select all

public class EnemySaver : Saver
{
    [System.Serializable]
    public class EnemyData
    {
        public bool isEnemyActive;
        public int enemyHealth;
    }
    
    public override string RecordData()
    {
        var enemy = GetComponent<Enemy>();
        var data = new EnemyData();        
        data.isEnemyActive = enemy.isActive;
        data.enemyHealth = enemy.health;
        return SaveSystem.Serialize(data);
    }
    
    public override void ApplyData(string s)
    {
        if (string.IsNullOrEmpty(s)) return;
        var data = SaveSystem.Deserialize<EnemyData>(s);
        var enemy = GetComponent<Enemy>();
        enemy.isActive = data.isEnemyActive;
        enemy.health = data.enemyHealth;
    }
}
MartinLFO
Posts: 3
Joined: Mon Feb 15, 2021 10:38 pm

Re: Either SaveSystem.Serialize or SaveSystem.Deserialize are no longer working.

Post by MartinLFO »

Thank you, I will get back to you if I run into any more problems :)
User avatar
Tony Li
Posts: 22166
Joined: Thu Jul 18, 2013 1:27 pm

Re: Either SaveSystem.Serialize or SaveSystem.Deserialize are no longer working.

Post by Tony Li »

Sounds good! Glad to help.
Post Reply