Page 1 of 1

Help with save migration

Posted: Tue Dec 10, 2024 10:11 pm
by Strook
Hello, I'm stumbling on a bit of logic for my game

I have a preload scene at the very beginning of my game. In there I check if there is a save in slot 0, and then proceed to continue with the new user flow, or load the save.
What I'm trying to do is have a specific migration flow, when the save version are different.

Here is a and example case, I'd love if you could tell me how you would approach this:
(using an imaginary example of updating the player's profile name)
  • During application startup in my Preload I check that the slot 0 has a save.
  • I detect that this save is of version 1. I trigger my save migration process
  • Player has Save with version 1. The custom Saver 'PlayerProfile' (Key "profile") has a variable PlayerName="Alex" in its data (PlayerProfileData)
  • I want to change "Alex" to for example, "Migrated_Alex"
  • I want to update the save file, and reapply all savers
The last two points are really messing with me, I feel like I am missing something obvious! Regardless of what I try, the old save data is always applied. Note that I'm using the DiskSaver, and I am running this migration process in a coroutine, I can wait for the save to be loaded/applied/etc before continuing in the code.

To give more detail as to why I need to this: In some of my savers, some data format has changed. A List<int> is now a List<string>. Since the game is already out (Squeakross DEMO), I need to migrate that save to a new format. For now simple making sure that list is initialized to a default state is good enough.

Thanks, hope it makes sense!

Re: Help with save migration

Posted: Wed Dec 11, 2024 7:56 pm
by Tony Li
Hi,

What if you make your saver compatible with saved game version 1 and version 2?

For example, say the DEMO has an InventorySaver like this:

Code: Select all

public class InventorySaver : Saver // (save system version 1)
{
    [Serializable] public class Data
    {
        public List<int> itemIDs;
    }
    public override string RecordData()
    {
        var data = new Data() { itemIDs = new List<int>(PlayerInventory.ItemIDs) };
        return SaveSystem.Serialize(data);
    }
    public override void ApplyData(string s)
    {
        var data = SaveSystem.Deserialize<Data>(s);
        PlayerInventory.ItemIDs = new List<int>(data.itemIDs);
    }
}
But now your PlayerInventory class has List<string> ItemNames instead of ItemIDs. Change the InventorySaver script to:

Code: Select all

public class InventorySaver : Saver // (save system version 2)
{
    [Serializable] public class DataV1
    {
        public List<int> itemIDs;
    }
    [Serializable] public class DataV2
    {
        public List<string> itemNames;
    }
    public override string RecordData()
    {
        var data = new DataV2() { itemNames = new List<string>(PlayerInventory.ItemNames) };
        return SaveSystem.Serialize(data);
    }
    public override void ApplyData(string s)
    {
        if (SaveSystem.currentSavedGameData.version == 1)
        {
            // This is version 1 save data, so we get the List<int> and handle it:
            var dataV1 = SaveSystem.Deserialize<DataV1>(s);
            PlayerInventory.HandleOldItemIDs(data.itemIDs);
        }
        else
        {        
            // Version 2, so handle normally for version 2:
            var dataV2 = SaveSystem.Deserialize<DataV2>(s);
            PlayerInventory.ItemNames = new List<string>(data.itemNames);
        }
    }
}

Re: Help with save migration

Posted: Thu Dec 12, 2024 1:03 am
by Strook
Thats not a bad way to do it, i like it!
I’ll try this, thanks a lot 😁

Re: Help with save migration

Posted: Thu Dec 12, 2024 7:14 am
by Tony Li
Glad to help!