Good day, I am working on a project in Unity and I want to anticipate potential future problems with the way I save data. Currently, I am saving a JSON file in the Application.persistentDataPath folder that contains all the variables storing the player’s progress. The problem with this approach is that if I want to add or remove variables in the future, it could become difficult to retrieve the player’s data since I cannot use JsonUtility.FromJson. I have been thinking about using JObject to compare keys with the existing variables in the new version, but it seems not to be available in Unity by default. Is there a way to perform this comparison to load values? or do you suggest any advice to solve my issue?
Usually one uses versioning within the save system for this purpose.
Minor changes do not cause a version bump, eg, just adding more fields.
Major and breaking changes cause a version bump, eg, changing the nature or shape of some critical data.
Depending on the nature of your installed userbase, you can leave “reading” code in that can handle more than one prior version of save data, but always migrates it and saves it as the current version.
You can also use Newtonsoft JSON .NET from the Unity Package Manager (Window → Package Manager).
If you want to avoid the Package Mangler’s UI, just add this to your Packages/manifest.json
file:
"com.unity.nuget.newtonsoft-json": "3.0.2",
The former asset store package is now deprecated, as you can see here:
Also, when working with JSON, always be sure to leverage sites like:
Why exactly do you think you can’t use FromJson? FromJson is very forgiving and can be used to load partial objects just fine. Variables that don’t exist anymore would not be populated and simply be ignored. Of course new variables would be initialized with the default value since the old json data would not have any data for them.
If you actually think about breaking changes so you have to migrate data over from one format to the next, you need to be able to load different versions anyways and you need the loading code for all those versions in order to do the migration.
Note that I’ve written a simple json library some time ago (it’s just a single C# file) that just represents the json structure as JSONObjects, JSONArrays, JSONStrings, etc… all kinda abstracted away through the base JSONNode class. It’s lightweight and quite fast as it’s a straight forward parser. It has many automatic conversion operators which makes it easy to use. Since all classes are declared as “partial”, it’s also easy to extend the classes with some additional operators or conversion properties. I have some extension files in that repository which you just have to drop next to the main file. It just adds convenient conversions for some of the common types. It’s not an object mapper. So the loading and saving has to be done by yourself. However you can write some extensions for your project to make it much easier to serialize / deserialize sub objects. Since you have full control over the actual data it’s up to you how to organise it. I would recommend to include some kind of version string or number so the loading code can actually go to the right branch.
I didn’t know that, I always thought I had to adapt to the class format that uses JSON serialization. Thank you for the information, this gives me more flexibility in case I modify or add variables.
Well, you kinda have, but missing values or additional values do not cause any errors. Unity specifically has the JsonUtility.FromJsonOverwrite method which can be used to partially “patch” an object. This method does not create a new instance of your target class but simply applies the data from the json object to an existing target object and replaces only those fields which have matching names. So if your class has the variables a, b, c and d and you apply a json like this:
{
"b" : "Hello World",
"e" : 42
}
FromJsonOverwrite would only set the field “b” in that class instance. None of the other fields are changed or altered and the additional “e” would be ignored since it does not exist in the class.
Now I understand, Thank you for helping me understand the handling of JsonUtility
Definitely not necroposting.
Think of it from a data standpoint.
This means understand what the FromJsonOverwrite() will (and will not) change in your data under different circumstances, such as a field being added or removed, either in subsequent or antecedent versions of your data.
Then plan your code appropriately to either tolerate missing fields or complain and reset the data.
And as I noted above, use versioning to engineer more confidently-testable solutions.
Code doesn’t matter… it’s data that matters.