How to catch Unity deserialising (file loading) blowing up?
Hi guys
I know what the problem is but I can't figure out how to catch the exception in the code...
I'm using this code to save/load data:
It's been working fine until I recently started adding/removing arrays to the GameData type. Now, adding other variables over time seemed to be fine, but somehow arrays break it. I understand why it's breaking - it breaks because it tries to load the old file, and when it tries to deserialise the data into the GameData class, there are mismatches, and so it breaks.
While I can manually tell the game to reset the save file no problem, If I do that outside of unity when I deploy, I can only either ALWAYS reset the save file, rendering saving useless, or never reset the file, which throws the error always.
How do I ask the script to catch the exception when the deserialisation fails, so I can tell it to start a new file?
Thanks guys!
I know what the problem is but I can't figure out how to catch the exception in the code...
I'm using this code to save/load data:
if (File.Exists(Application.persistentDataPath + "/gamesave.save")) { BinaryFormatter bf = new BinaryFormatter(); FileStream file = File.Open(Application.persistentDataPath + "/gamesave.save", FileMode.Open); GameData save = (GameData)bf.Deserialize(file); file.Close(); gameData = save; }
It's been working fine until I recently started adding/removing arrays to the GameData type. Now, adding other variables over time seemed to be fine, but somehow arrays break it. I understand why it's breaking - it breaks because it tries to load the old file, and when it tries to deserialise the data into the GameData class, there are mismatches, and so it breaks.
While I can manually tell the game to reset the save file no problem, If I do that outside of unity when I deploy, I can only either ALWAYS reset the save file, rendering saving useless, or never reset the file, which throws the error always.
How do I ask the script to catch the exception when the deserialisation fails, so I can tell it to start a new file?
Thanks guys!
Comments
I use XML Serialization + compression instead of a binary format, the advantage is that you can save to plaintext if you want to inspect it manually, and you can mark deprecated fields with ignore tags so they at least don't get written to disk. It doesn't scale as well for larger save files though.
Personally I'm a fan of json for the ease of readability and direct mapping to objects and have used json.net for ages. You can optionally run a second pass by zipping and password protecting your savedata towards the end of development.
On data versioning, it's worth having a migration plan in place for old data rather than just starting with fresh data for failed loads. Consider having a save metadata format that will not change, something like just the file version and a datetime, and possibly some kind of checksum. This goes in a separate file to your actual save data. You load it first, compare it to your current save version (ie the version of the save/load code that is running) and act accordingly:
-if it's the current version, great. Load up the save file and carry on
-if it's a newer version, request the user update their app/game/whatever
-if it's an older version, load it and upgrade it, then save it out again and carry on as normal
How that "load it and upgrade it" works can vary.
-If you've just added some new fields since that version, populate them with reasonable default data.
-If you've renamed a field keep it around with an [obsolete] attribute (so you don't accidentally use it in code) and copy that data over to the new version. Depending on your serialization library, it may have support for alternate serialized names as well.
-If you have deleted or changed the types of fields, it may be worth keeping that old version of your savedata class around (class SaveData_v1_2_3), loading the data using that class (json.net generic deserialization for example) and then doing a migration (saveData = new SaveData(oldSaveData)).