Use the JSON serilization for ScriptableObject with asset fields in Editor and Build

in this post this was described…

You only have a way of doing it in the editor, not at run time. So you’ve spent days on this and still haven’t solved the crux of the problem. It’s useless to anyone reading this in the future as a save system that only works in the editor is pretty useless.

To be clear, the method of serialisation is secondary to the true issue here. In fact it’s almost completely ancillary. You should be putting your focus into a basic database system in which you can look up some sort of ID and use that to get an asset reference, regardless of the serialisation method.

I’m not sure if there’s a language issue at play, but you’ve basically ignored all the advice given so far. It’s kind of infuriating.

I didn’t understand your reaction. I had a question, you and other gave to me answers and proposals to workaround of existent issue.
There is an Odin Serializer, the documentation of which describes (not very detail) the possibilities of use it for the same issue. I tested it and described the result of using it. It can be used to save complex Unity objects, but only in the editor (this solution will not help in the Build). It’s a standard solution proposed by Odin (for Editor)

I didn’t talk what this a “final” solution for initial issue.

P.s>
As I told initially, I had two aims - store complex objects in Unity (it’s not a big problem, and can be decided by 5 min through use the intermediate surrogate class, it I known initially) and how it did “elegant using the OOP and other possibilities of c#”, if you studied the possibilities of Binary serialization (IFormatter, real “Surrogate class” and so on),which give a elegant possibilities to change the “standard serialization protocols”, you can understand it.
If I was a participating in Game Jam, i didn’t ask here about possible solutions.
I hope I more clear described my aims and motivations.

Thank you for your time and information … and take it easy.:slight_smile:

The way I ended up doing to identify my serialized ScriptableObject in my game is not with a uuid, or a supposed unique file name string,
but with the ScriptableObject’s index in another “Database”/Container ScriptableObject that holds them

The ScriptableObject

public class WeaponSO: ScriptableObject {
    [field: SerializeField] public string Name { get; private set; } = "Nameless weapon";
}

The database holding these SO

public class WeaponDB : ScriptableSingleton<WeaponDB> {

    public static WeaponDB GetById(int id) => instance.data[id];
    public static int GetId(WeaponDB obj) => instance.data.IndexOf(obj);

// Drop all your game's WeaponSO from the Inspector here
    [SerializeField] private List<WeaponSO> data;
}

The object being serialized

public class GameData : ISerializationCallbackReceiver {

    public int healthPoints;
    [NonSerialized] public WeaponSO weaponSO; // ignored by json
    [SerializeField] private int weaponId;

// Extends the ISerializationCallbackReceiver interface to receive the OnBefore/AfterSerialize calls of your JsonSerializer
    public void OnBeforeSerialize() {
        weaponId = WeaponDB.GetId(weaponSO); // SO => int
    }

    public void OnAfterDeserialize() {
        weaponSO = WeaponDB.GetById(weaponId); // int => SO
    }

}

hope it might help

That assumes the index of the item in the database never changes. It just takes one index change for a ton of save data to be messed up.

If you’re using editor scripting to automate filling that database, you will need to ensure it maintains the same order always.

Remember that Unity uses a GUID system to manage Unity object references. This is what makes them stable across asset renames or file moves. While implementing your own takes more work that other solutions, it will ultimately be the most stable.

Though I suppose I will say “the most stable” in my opinion. Other people have different opinions on the matter, but I’ve used a GUID/UUID system for ages now and it’s not let me down.

I agree the GUID way is the most stable way 100%, but I am not fond of creating your own over Unity’s .meta GUID.
I wish Unity had an interface to convert from/to that already existing .meta’s GUID in the first place

Yeah I don’t disagree there. I’ve even had direct conversations about Unity staff about exposing the existing asset GUID myself, so, there’s maybe a small hope it happens in the future sometime.

I personally didn’t want something that could screw up save data simply by doing day-to-day editing. Especially in a larger project.

Though once you have something worked out, you can make it portable between projects and don’t have to reimplement it every time.

Yes, this has been brought up countless times over the years. We have that information and we even have methods in the editor to query the asset database and convert GUIDs to object references. I’m not asking Unity to implement a save system because depending on the project, the requirements can be very different. Though the engine could just provide some low level methods to access the already available information so we can build several specialized save systems on top.

Unity often times tries to come up with fully fletched features that they can ship and promote, but it’s usually the small tools and APIs that are the most useful. I remember the time before they added the CreateAssetMenu attribute. Almost nobody was using ScriptableObjects because you always needed to write editor code to actually create them. When they added this one attribute, the usage of ScriptableObjects literally exploded. The smallest things can have the largest impact.

So hopefully they consider some of those things. Having access to the GUIDs of assets would be one thing, but it would also be useful to assign / query a GUID for instances in the same way. This would really help creating any kind of save system. Currently at runtime an instance does not know that it came from a prefab and also does not know from which prefab. That information is only there in the editor. That would also be a nice addition to have some kind of “source” reference GUID which of course could be null. But when Instantiate is used it should be filled automatically.