How to save nested instances?

Discussion and help for Easy Save 3
Post Reply
Rdbk
Posts: 35
Joined: Sun Jun 09, 2019 3:58 pm

How to save nested instances?

Post by Rdbk »

In my game I have a ScriptableObject called "Skill" and then I also have another SO called "Character" that can store references to skills. When I run the game, I instantiate random characters and then instantiate random skills to be stored within those recently created characters. But the issue is that if I save an array of Characters, the Characters can be loaded just fine, but the skills within them will be loaded as null. In log I get the "Reference for Skill with ID could not be found in Easy Save's reference manager" error for BOTH the Character and the Skill. But as said, Character is loaded fine while Skill is not. How could I resolve this issue?

I tested that separately saving the instantiated Skill works, but that would become too cumbersome. Based on another topic here I also tried adjusting the collectDependenciesDepth (up to 20), but that didn't resolve the issue. Also in case it's relevant, within the scene and before loading I have populated lists of all the available original Character & Skill options. Before entering run mode, I have also tried to refresh the references and separately press the "Add Reference(s) to Manager" on the gameobject that holds the lists of SO's.


Here are the relevant parts of the code simplified:

Code: Select all

public class Character : ScriptableObject
{
    public Skill CharacterAbility;
}

Code: Select all

public class Skill : ScriptableObject
{
    public int ID;
}

Code: Select all

public List<Character> CharacterTemplates;
public List<Skill> AllSkills;
public Character[] PlayerTeam = new Character[4];

Character NewRandomCharacter = Instantiate(CharacterTemplates[Random.Range(0,CharacterTemplates.Count)];
Skill NewRandomSkill = Instantiate(AllSkills[Random.Range(0,AllSkills.Count)];
NewCharacter.CharacterAbility =NewRandomSkill;
PlayerTeam[0] = NewRandomCharacter;
ES3.Save("PlayerTeam",PlayerTeam);

<RESTART GAME>

PlayerTeam = ES3.Load<Character[]>("PlayerTeam")
---> Character is loaded, but CharacterAbility is not loaded
User avatar
Joel
Moodkie Staff
Posts: 4846
Joined: Wed Nov 07, 2012 10:32 pm

Re: How to save nested instances?

Post by Joel »

Hi there,

Fields of reference types will be saved and loaded by reference by default (see Supported Types), which is why your fields of ScriptableObjects are loading as null and you're receiving that warning.

However, if you want to load fields by value and ref you can change the MemberReferenceMode to ValueAndRef. I.e.

Code: Select all

var settings = new ES3Settings { memberReferenceMode = ES3.ReferenceMode.ByRefAndValue };
ES3.Save("PlayerTeam",PlayerTeam, settings);
All the best,
Joel
Joel @ Moodkie Interactive
Purchase Easy Save | Contact | Guides | Docs | Getting started
Rdbk
Posts: 35
Joined: Sun Jun 09, 2019 3:58 pm

Re: How to save nested instances?

Post by Rdbk »

Joel wrote: Mon Mar 06, 2023 9:50 am Hi there,

Fields of reference types will be saved and loaded by reference by default (see Supported Types), which is why your fields of ScriptableObjects are loading as null and you're receiving that warning.

However, if you want to load fields by value and ref you can change the MemberReferenceMode to ValueAndRef. I.e.

Code: Select all

var settings = new ES3Settings { memberReferenceMode = ES3.ReferenceMode.ByRefAndValue };
ES3.Save("PlayerTeam",PlayerTeam, settings);
All the best,
Joel
That worked great, thank you! I got 2 related questions to this if you don't mind:
  • Is there any downside to using the ValueAndRef mode? I noticed the save file is a bit bigger, but not enough to matter in my case.
  • I also store Sprite references within the SO's (f.ex. skill icons) and now when I save, I get warnings: "Easy Save cannot save the pixels or properties of this Texture because it is not read/write enabled...". with these Sprites I actually only want to save the reference and not the value so is it safe to just ignore this warning or would there be a proper way to avoid the warning? I tried creating ES3 types for my SO classes, which removes the warning on saving (I assume because by default it includes "writer.WritePropertyByRef" for the Sprite) but on loading I actually get an error: "System.NotSupportedException: Type of is not currently supported, and could not be loaded using reflection", which I assume is because my SO's reference other SO's and at least with the default reader field values it is having troubles loading them. If I only create a type for one SO type, I don't get the error on loading (then I just get the warning on saving for SO's I haven't created a type for).
User avatar
Joel
Moodkie Staff
Posts: 4846
Joined: Wed Nov 07, 2012 10:32 pm

Re: How to save nested instances?

Post by Joel »

Hi there,
Is there any downside to using the ValueAndRef mode? I noticed the save file is a bit bigger, but not enough to matter in my case.
It would make more of a different if your class has fields of something like Texture2D or Mesh, as saving this by value can be quite expensive. In your case you're saving Sprites, which themselves have a Texture, so it will be saving every pixel of that Texture. However, as you've marked it as non-readable, it will only be saving it by reference.

Another situation where it might matter: lets say that a reference to your ScriptableObject was held by multiple objects you are saving. For each of these objects the ScriptableObject would be loaded in it's entirety.
I also store Sprite references within the SO's (f.ex. skill icons) and now when I save, I get warnings: "Easy Save cannot save the pixels or properties of this Texture because it is not read/write enabled...". with these Sprites I actually only want to save the reference and not the value so is it safe to just ignore this warning or would there be a proper way to avoid the warning?
It should be safe to ignore the warning in this case.
I tried creating ES3 types for my SO classes, which removes the warning on saving (I assume because by default it includes "writer.WritePropertyByRef" for the Sprite) but on loading I actually get an error: "System.NotSupportedException: Type of is not currently supported, and could not be loaded using reflection", which I assume is because my SO's reference other SO's and at least with the default reader field values it is having troubles loading them. If I only create a type for one SO type, I don't get the error on loading (then I just get the warning on saving for SO's I haven't created a type for).
I wouldn't be able to understand what is happening here without being able to see the ES3Type you created, and the full error with stacktrace. If you send those over I'm happy to look into it further if you want more info. However, if you were pursuing this then you might just find it easier to save a List of your ScriptableObjects and load them before loading anything which references them, which will achieve what you require without having to save by value.

All the best,
Joel
Joel @ Moodkie Interactive
Purchase Easy Save | Contact | Guides | Docs | Getting started
Rdbk
Posts: 35
Joined: Sun Jun 09, 2019 3:58 pm

Re: How to save nested instances?

Post by Rdbk »

Joel wrote: Mon Mar 06, 2023 3:23 pmI wouldn't be able to understand what is happening here without being able to see the ES3Type you created, and the full error with stacktrace. If you send those over I'm happy to look into it further if you want more info. However, if you were pursuing this then you might just find it easier to save a List of your ScriptableObjects and load them before loading anything which references them, which will achieve what you require without having to save by value.
Thanks! I PM'd you two ES3 types & the stacktrace if you can take a quick look. But no need to dig in too deeply if the issue is not immediately obvious. So by just having the type script for Skill won't cause an error but then if I add the type script for Character also, the game will run into an error as soon as within the Character script it gets to loading a Skill.
User avatar
Joel
Moodkie Staff
Posts: 4846
Joined: Wed Nov 07, 2012 10:32 pm

Re: How to save nested instances?

Post by Joel »

Hi there,

The error looks to me like the file contains a type of data for which a Type no longer exists in your project. If deleting your save data (Tools > Easy Save 3 > Clear Persistent Data Path) doesn't resolve the issue, please could you replicate this in a new project with a simple scene so I can try to debug it at my end.

I'd also check that you're on the latest version of Easy Save by updating from the Asset Store.

All the best,
Joel
Joel @ Moodkie Interactive
Purchase Easy Save | Contact | Guides | Docs | Getting started
Rdbk
Posts: 35
Joined: Sun Jun 09, 2019 3:58 pm

Re: How to save nested instances?

Post by Rdbk »

Joel wrote: Tue Mar 07, 2023 4:21 pm Hi there,

The error looks to me like the file contains a type of data for which a Type no longer exists in your project. If deleting your save data (Tools > Easy Save 3 > Clear Persistent Data Path) doesn't resolve the issue, please could you replicate this in a new project with a simple scene so I can try to debug it at my end.

I'd also check that you're on the latest version of Easy Save by updating from the Asset Store.

All the best,
Joel
Clearing persistent data path didn't help and the file shouldn't contain any type that doesn't exist anymore in the project. I do believe I created ES3types (for other SO's) that I later deleted during testing. Those SO types are referenced in the Skill/Character SO's - I wonder if that might have left some remnants that are causing the issue. I tried creating a simple scene to mimic the situation but I couldn't reproduce the issue. Anyway, I think I'll just go ahead with ignoring the warning messages since functionality-wise everything is ok.
User avatar
Joel
Moodkie Staff
Posts: 4846
Joined: Wed Nov 07, 2012 10:32 pm

Re: How to save nested instances?

Post by Joel »

Hi again,

I had another user with a very similar issue which related to fields of enums in classes for which there is an ES3Type. I'm quite sure this is the same issue you're encountering.

If you private message me your invoice number I can send over the update. Alternatively you can manually modify your ES3Types by removing the ES3Type_enum.Instance parameter for any writer.WriteProperty lines which are writing enums. I.e.

Code: Select all

// Old
writer.WriteProperty("myEnum", instance.classWithEnum, ES3Type_enum.Instance);
// New
writer.WriteProperty("nyEnum", instance.classWithEnum);
All the best,
Joel
Joel @ Moodkie Interactive
Purchase Easy Save | Contact | Guides | Docs | Getting started
Rdbk
Posts: 35
Joined: Sun Jun 09, 2019 3:58 pm

Re: How to save nested instances?

Post by Rdbk »

Joel wrote: Wed Mar 08, 2023 8:01 am Hi again,

I had another user with a very similar issue which related to fields of enums in classes for which there is an ES3Type. I'm quite sure this is the same issue you're encountering.

If you private message me your invoice number I can send over the update. Alternatively you can manually modify your ES3Types by removing the ES3Type_enum.Instance parameter for any writer.WriteProperty lines which are writing enums. I.e.

Code: Select all

// Old
writer.WriteProperty("myEnum", instance.classWithEnum, ES3Type_enum.Instance);
// New
writer.WriteProperty("nyEnum", instance.classWithEnum);
All the best,
Joel
Bingo! I tried the manual adjustments and the error is now gone. I sent you my invoice number now too for the update - I bet at some point I would forget to do the manual adjustments.
Post Reply