Scriptable object reference not saved

Discussion and help for Easy Save 3
funtomata
Posts: 26
Joined: Tue Feb 23, 2021 4:25 pm

Re: Scriptable object reference not saved

Post by funtomata »

@Berg

if you want to autosave scriptable object references that may change at runtime on the scene, then you can drag and drop the SO asset into the Reference Manager

if you want to save a scriptable object that was modified at runtime (an inventory for example), then you have to code it manually.

The way I handle this is to have an SoSaver object on my scene.

I implement a Save() method inside my SO's that need to save data (I only save relevant data, like state enum, counters or in the case of my Inventory, a list of Item references)

This allows me to specify on a per-scene basis which SO's are saved, when etc...

Code: Select all

public class SavableSOManager : MonoBehaviour
    {
        public List<Inventory> inventories;
        public List<Quest> quests;

        public bool saveOnApplicationPause;
        public bool saveOnApplicationQuit;

        public void LoadSaveData(string saveId)
        {
            saveData.Load(saveId);
        }
        
        public void Save()
        {
            inventories.ForEach(i => i.Save());
            quests.ForEach(q => q.Save());
        }

        public void Load()
        {
            inventories.ForEach(i => i.Save());
            quests.ForEach(q => q.Save());
        }

        private void OnApplicationPause(bool pauseStatus)
        {
            if (saveOnApplicationPause)
                Save();
        }

        private void OnApplicationQuit()
        {
            if (saveOnApplicationQuit)
                Save();
        }
    }
Berg02
Posts: 1
Joined: Thu Feb 25, 2021 3:07 pm

Re: Scriptable object reference not saved

Post by Berg02 »

Thanks for reply!

To be more clear:
I have a class Monster and in this class I have my SO MonsterBase. This scriptable never change his values, only the Monster class. The scriptable is used only to keep data that is used in runtime to change Monster. So, my problem is that this MonsterBase SO always disappear from Monster class after close/open game. (and it's the same with my itens)

I have a PlayerData SO that has every class that need to be saved (List<Monster>, List<Item>, etc). Can I save only this PlayerData and solve everything? Didn't find a way yet!

And, about the code that you send, it's all corect? in Load() um use Save method again?

P.S.: I'm using another user because I just forgot my passwd and didn't receive the recovery e-mail.
RemDust
Posts: 4
Joined: Wed Mar 24, 2021 7:13 pm

Re: Scriptable object reference not saved

Post by RemDust »

Just wanna add to the need of a real scriptable objects best practice guide !

I (and many others) are using scriptable objects in a lot of creative ways (there is a new "school" of SO users lead by really nice Unite talks these last years).

It is REALLY hard to got it to work. I'm in try n error mode for 2 weeks -and I'm by no mean a senior developper- but most of ES3 buyers who actually need that kind of tool are probably not !

Also documentation pretty much say that ES3 can save/load scriptable objects but not really say that it will deal only with direct public properties when SO's are pretty much often used referencing other assets (and references lost are THE real pain).

I wouldn't say that I'm disappointed because the support is A+ and quick and Joel is a very helpful person but still it's very frustrating not being able to load an inventory properly after long hours of intense reading and trials :'(
User avatar
Joel
Moodkie Staff
Posts: 4846
Joined: Wed Nov 07, 2012 10:32 pm

Re: Scriptable object reference not saved

Post by Joel »

Hi there,
Also documentation pretty much say that ES3 can save/load scriptable objects but not really say that it will deal only with direct public properties when SO's are pretty much often used referencing other assets (and references lost are THE real pain).
This isn't a ScriptableObject thing, this applies to any class by default and applies to Unity's Editor serialisation also.

If you want a non-public field to be serialised, you should add the SerialiseField attribute. This is covered in the Supported Types guide, which is linked in the Getting Started guide:

https://docs.moodkie.com/easy-save-3/es ... ted-types/

It's also covered in Unity's documentation here:

https://docs.unity3d.com/ScriptReferenc ... Field.html

All the best,
Joel
Joel @ Moodkie Interactive
Purchase Easy Save | Contact | Guides | Docs | Getting started
RemDust
Posts: 4
Joined: Wed Mar 24, 2021 7:13 pm

Re: Scriptable object reference not saved

Post by RemDust »

Joel wrote: Wed Mar 24, 2021 7:43 pm Hi there,
Also documentation pretty much say that ES3 can save/load scriptable objects but not really say that it will deal only with direct public properties when SO's are pretty much often used referencing other assets (and references lost are THE real pain).
This isn't a ScriptableObject thing, this applies to any class by default and applies to Unity's Editor serialisation also.

If you want a non-public field to be serialised, you should add the SerialiseField attribute. This is covered in the Supported Types guide, which is linked in the Getting Started guide:

https://docs.moodkie.com/easy-save-3/es ... ted-types/

It's also covered in Unity's documentation here:

https://docs.unity3d.com/ScriptReferenc ... Field.html

All the best,
Joel
Sorry, I wasn't clear. I'm not talking about private fields or not serializable stuff.
I was talking about public fields referencing other assets (scriptable objects, prefabs, sprites and so on)
User avatar
Joel
Moodkie Staff
Posts: 4846
Joined: Wed Nov 07, 2012 10:32 pm

Re: Scriptable object reference not saved

Post by Joel »

RemDust wrote: Wed Mar 24, 2021 8:17 pm
Joel wrote: Wed Mar 24, 2021 7:43 pm Hi there,
Also documentation pretty much say that ES3 can save/load scriptable objects but not really say that it will deal only with direct public properties when SO's are pretty much often used referencing other assets (and references lost are THE real pain).
This isn't a ScriptableObject thing, this applies to any class by default and applies to Unity's Editor serialisation also.

If you want a non-public field to be serialised, you should add the SerialiseField attribute. This is covered in the Supported Types guide, which is linked in the Getting Started guide:

https://docs.moodkie.com/easy-save-3/es ... ted-types/

It's also covered in Unity's documentation here:

https://docs.unity3d.com/ScriptReferenc ... Field.html

All the best,
Joel
Sorry, I wasn't clear. I'm not talking about private fields or not serializable stuff.
I was talking about public fields referencing other assets (scriptable objects, prefabs, sprites and so on)
Hi there,

If you're having issues regarding this, please could you create a new thread describing your issue. This thread is about ScriptableObjects specifically, whereas your issue regards public fields in general.

All the best,
Joel
Joel @ Moodkie Interactive
Purchase Easy Save | Contact | Guides | Docs | Getting started
Alej
Posts: 2
Joined: Thu Mar 25, 2021 4:24 am

Re: Scriptable object reference not saved

Post by Alej »

UPDATE #1: I'll be d*mned. I just had to add the scriptable objects to the ES3GlobalReferences, there are many references in there, including other scriptable objects like Post processing volumes and others, just not these one. Does it mean that for every new scriptable object that I create I'll have to add it there manually?

UPDATE #2: I'll just continue working and testing to see what's up, suddenly it's now working, after tinkering with the setting's use Global References file back and forth, even if it currently shows no references, it is still working. So I'll need to come up with better repro steps and see if it is actually an issue. The error was that the 'key' of the scriptable object to use for the dictionary was null.

-------------------------------

Hello! Just wanted to add to the discussion as this seem to be the exact issue I'm having.
I'm by no means a persistence expert and this is the first-time/first-day ever trying this actually, enter Easy Save 3, which already gives me a 'save file' ready to use in just under an hour of playing around.
But on the scriptable objects front, it is not quite clear how to go about static nested references on them, let me explain the use case as best as I can:

0. It's a sort of flappy bird, each run the player accumulates kills, tricks, dodges, etc. When the player dies it's all reset (by hand because SOs between plays).
1. There's a PlayerRuntimeData scriptable object that contains a set of config values and the current session's running stats (how many jumps, tricks, objects evaded, etc have happened in the currently running session) -> done like this so that other objects (like UI elements) can reference the same SO, effectively having a middle man link between them and the data.
2. The problematic part: every time the player collects/kills/jumps something and want to calculate the score, I don't add it to a running score directly, instead I add an scriptable object that represents the object collected (that SO has extra data that how much each item scores, colors and others) and how many have been collected so far of that scriptable object in a dictionary, i.e. Dictionary<ColletableDataSo, int>.

Sumary explanation: there's a PlayerRuntimeData ScriptableObject (which I Save and LoadInto<> manually) and inside there's a Dictionary at some point Dict<CollectableSoAsKey, howManyOfThatCollected_Int>. Could think of it as a glorified enum with a lot of data and flexible values (to create a new 'enum' just create new SOs of the same type and name it differently).

A few images might help:
The PlayerRuntimeData scriptable object (notice the dictionary I'm referring to)
PlayerRuntimeData.png
PlayerRuntimeData.png (270.32 KiB) Viewed 2310 times

And how Easy Save is serializing it (don't mind for now the actual value, these different run timestamps and couldn't catch it at the exact same time so the 'amount' doesn't match but the type does)
PlayerRuntimeData_json.png
PlayerRuntimeData_json.png (102.23 KiB) Viewed 2310 times

Reading through the forums it has come to my understanding that actually Unity creates a new instance of that SO every single time we hit play (and effectively ES3 shows this because every time I hit save it has a different _ES3Ref number assigned to it) and somehow makes sure that everybody that's referencing it gets the same one (please correct me if I'm wrong, that's what I understand by, paraphrasing, 'a new instance is created always').

Also read that dropping the reference on the reference manager will achieve that consistency but I couldn't find where this is exactly, the only reference link I have found so far was by adding an ES 3 Save Manager but it has 4K+ elements array in it and it recommends not expanding that list, I drop SOs there?

The other thing I tried was using ES3Settings member References by Ref and Value -> this at least allows it to load but it creates a truly freshly new instance of the scriptable object and not the reference used by the unity scenes drag'n'dropped on the inspectors, can continue developing like that, however the idea is to be able to adapt in the future the scores of players in the assets themselves and not bake it into the save file, at least for now.

This is how a collectable scriptable object looks like
There's bad guys, coin, rare coin, missiles, etc with their own scores and color values (and allows to expanded later on)
CollectableDataScriptableObjectExample.png
CollectableDataScriptableObjectExample.png (116.31 KiB) Viewed 2310 times
So, ways to get around this:
- Maybe with a custom ES3 Type Reader?
- or if I could somehow get all scriptable object in a single list and store the index on that list instead?
- Also have to experiment with prefab references, I'm assuming prefabs are serializing fine, so could somehow use prefabs as SO holders? far from ideal but I'll take whatever works and expand later on.

I'm afraid I'm doing something horribly wrong though.
Thanks a lot in advance.
User avatar
Joel
Moodkie Staff
Posts: 4846
Joined: Wed Nov 07, 2012 10:32 pm

Re: Scriptable object reference not saved

Post by Joel »

Alej wrote: Thu Mar 25, 2021 5:48 am UPDATE #1: I'll be d*mned. I just had to add the scriptable objects to the ES3GlobalReferences, there are many references in there, including other scriptable objects like Post processing volumes and others, just not these one. Does it mean that for every new scriptable object that I create I'll have to add it there manually?

UPDATE #2: I'll just continue working and testing to see what's up, suddenly it's now working, after tinkering with the setting's use Global References file back and forth, even if it currently shows no references, it is still working. So I'll need to come up with better repro steps and see if it is actually an issue. The error was that the 'key' of the scriptable object to use for the dictionary was null.

-------------------------------

Hello! Just wanted to add to the discussion as this seem to be the exact issue I'm having.
I'm by no means a persistence expert and this is the first-time/first-day ever trying this actually, enter Easy Save 3, which already gives me a 'save file' ready to use in just under an hour of playing around.
But on the scriptable objects front, it is not quite clear how to go about static nested references on them, let me explain the use case as best as I can:

0. It's a sort of flappy bird, each run the player accumulates kills, tricks, dodges, etc. When the player dies it's all reset (by hand because SOs between plays).
1. There's a PlayerRuntimeData scriptable object that contains a set of config values and the current session's running stats (how many jumps, tricks, objects evaded, etc have happened in the currently running session) -> done like this so that other objects (like UI elements) can reference the same SO, effectively having a middle man link between them and the data.
2. The problematic part: every time the player collects/kills/jumps something and want to calculate the score, I don't add it to a running score directly, instead I add an scriptable object that represents the object collected (that SO has extra data that how much each item scores, colors and others) and how many have been collected so far of that scriptable object in a dictionary, i.e. Dictionary<ColletableDataSo, int>.

Sumary explanation: there's a PlayerRuntimeData ScriptableObject (which I Save and LoadInto<> manually) and inside there's a Dictionary at some point Dict<CollectableSoAsKey, howManyOfThatCollected_Int>. Could think of it as a glorified enum with a lot of data and flexible values (to create a new 'enum' just create new SOs of the same type and name it differently).

A few images might help:
The PlayerRuntimeData scriptable object (notice the dictionary I'm referring to)
PlayerRuntimeData.png


And how Easy Save is serializing it (don't mind for now the actual value, these different run timestamps and couldn't catch it at the exact same time so the 'amount' doesn't match but the type does)
PlayerRuntimeData_json.png


Reading through the forums it has come to my understanding that actually Unity creates a new instance of that SO every single time we hit play (and effectively ES3 shows this because every time I hit save it has a different _ES3Ref number assigned to it) and somehow makes sure that everybody that's referencing it gets the same one (please correct me if I'm wrong, that's what I understand by, paraphrasing, 'a new instance is created always').

Also read that dropping the reference on the reference manager will achieve that consistency but I couldn't find where this is exactly, the only reference link I have found so far was by adding an ES 3 Save Manager but it has 4K+ elements array in it and it recommends not expanding that list, I drop SOs there?

The other thing I tried was using ES3Settings member References by Ref and Value -> this at least allows it to load but it creates a truly freshly new instance of the scriptable object and not the reference used by the unity scenes drag'n'dropped on the inspectors, can continue developing like that, however the idea is to be able to adapt in the future the scores of players in the assets themselves and not bake it into the save file, at least for now.

This is how a collectable scriptable object looks like
There's bad guys, coin, rare coin, missiles, etc with their own scores and color values (and allows to expanded later on)
CollectableDataScriptableObjectExample.png

So, ways to get around this:
- Maybe with a custom ES3 Type Reader?
- or if I could somehow get all scriptable object in a single list and store the index on that list instead?
- Also have to experiment with prefab references, I'm assuming prefabs are serializing fine, so could somehow use prefabs as SO holders? far from ideal but I'll take whatever works and expand later on.

I'm afraid I'm doing something horribly wrong though.
Thanks a lot in advance.
Hi there,

Only references directly referenced by your scene in a serialisable field prior to runtime will be visible to the reference manager. If this is the case for your project, but it didn't work until you added it to the manager, please could you private message me a new, basic project with a simple scene which replicates this?

All the best,
Joel
Joel @ Moodkie Interactive
Purchase Easy Save | Contact | Guides | Docs | Getting started
Alej
Posts: 2
Joined: Thu Mar 25, 2021 4:24 am

Re: Scriptable object reference not saved

Post by Alej »

Joel wrote: Thu Mar 25, 2021 7:33 am Hi there,

Only references directly referenced by your scene in a serialisable field prior to runtime will be visible to the reference manager. If this is the case for your project, but it didn't work until you added it to the manager, please could you private message me a new, basic project with a simple scene which replicates this?

All the best,
Joel
Hi! Thanks a lot for the prompt reply.
That makes it clear actually. I'll be moving forward keeping this in mind.
Currently I can't trigger the bug anymore even if I take out an object I manually placed with references to those SOs. Could even be related to Enter Play Mode options and other variables... not quite sure.

As a clarification and for further testing, is it expected to work with deeply nested references? i.e, a factory that's placed on the scene that spawns some prefabs (directly referenced in the factory's field) and in those prefabs somewhere a couple of levels below a component with the actual reference to the Scriptable Object will exist. I.e., the scriptable object might not be at a first level depth on a scene's object field.

Thanks once again for the quick reply, greatly appreciated.
User avatar
Joel
Moodkie Staff
Posts: 4846
Joined: Wed Nov 07, 2012 10:32 pm

Re: Scriptable object reference not saved

Post by Joel »

Alej wrote: Thu Mar 25, 2021 4:31 pm
Joel wrote: Thu Mar 25, 2021 7:33 am Hi there,

Only references directly referenced by your scene in a serialisable field prior to runtime will be visible to the reference manager. If this is the case for your project, but it didn't work until you added it to the manager, please could you private message me a new, basic project with a simple scene which replicates this?

All the best,
Joel
Hi! Thanks a lot for the prompt reply.
That makes it clear actually. I'll be moving forward keeping this in mind.
Currently I can't trigger the bug anymore even if I take out an object I manually placed with references to those SOs. Could even be related to Enter Play Mode options and other variables... not quite sure.

As a clarification and for further testing, is it expected to work with deeply nested references? i.e, a factory that's placed on the scene that spawns some prefabs (directly referenced in the factory's field) and in those prefabs somewhere a couple of levels below a component with the actual reference to the Scriptable Object will exist. I.e., the scriptable object might not be at a first level depth on a scene's object field.

Thanks once again for the quick reply, greatly appreciated.
Hi there,

The serializer will go through 5 levels of depth, so in your case it should be able to pick these up.

All the best,
Joel
Joel @ Moodkie Interactive
Purchase Easy Save | Contact | Guides | Docs | Getting started
Post Reply