Lots of references

Discussion and help for Easy Save 3
aloxuhik
Posts: 8
Joined: Wed Jul 12, 2023 6:54 am

Lots of references

Post by aloxuhik »

Hello,
I have city builder game and I am trying to save it. But I have lots of references between buildings and roads. I have non-monobehaviour class roadblock, which holds references to all connected roads and buildings. And each road and buildings holds reference to roadblock on which its placed.
Also road hold reference to their neighbours.

Problems:
1) When I tried to load problem is assigning references before they are instantiated. So for example first road have roadblock which have list of 19 roads. But only first element has reference(to itself), others are empty. Second road have two elemets assigned(First road and itself) and so on. Until last one have correctly signed all roads. With neighbours its same problem. It have assigned only neighbour spawned before not that which was spawned after.
Its "easily" solved with double loading. I reckon its because at first all things are spawned and on second they can be assigned with references. But that doesn't seems as correct solution, can it cause any problems other then being slow?

2) For some reason when I build roads and then building(they are saved in same order) building failed to load, ES3 won't load it properly from prefab. ScriptableObject Data is missing even it is correctly set in prefab and int Types set not to save it. When it is build without roads(no references on it), no problem occure.

3)Also when I check save file building sometimes reference is saved corectly as Type and ES3Ref number, but sometimes it is saved with all data. So same data is saved twice. I think problem will be that it is referenced before it is saved on its own.

Is my design flawed for ES3 saving I a need to find some workaround or is there some solution to this?
My idea for workaround was that I will instantiate all the buildings myself and then load data or use LoadInto, but that would break references as my instantiate wouldn't have correct ES3 Ref?
User avatar
Joel
Moodkie Staff
Posts: 4849
Joined: Wed Nov 07, 2012 10:32 pm

Re: Lots of references

Post by Joel »

Hi there,
Its "easily" solved with double loading. I reckon its because at first all things are spawned and on second they can be assigned with references. But that doesn't seems as correct solution, can it cause any problems other then being slow?
Double-loading is a suitable solution and usually the one I recommend. There are other ways but these require you to make a database of all of your references, load these, and then manually assign references which can be quite complex, so not recommended unless absolutely necessary.
For some reason when I build roads and then building(they are saved in same order) building failed to load, ES3 won't load it properly from prefab. ScriptableObject Data is missing even it is correctly set in prefab and int Types set not to save it. When it is build without roads(no references on it), no problem occure.
I don't quite understand what you're saying here. Please could you create a new project with a very simple scene which replicates your issue and private message it to me with step-by-step instructions.
Also when I check save file building sometimes reference is saved corectly as Type and ES3Ref number, but sometimes it is saved with all data. So same data is saved twice. I think problem will be that it is referenced before it is saved on its own.
If it is saved with all data that would indicate that you're saving it directly (i.e. ES3.Save("key", building) ). If it just has the _ref, that indicates that you're saving an object which has the building in a field. Saving directly always saves by value, whereas saving a field of a UnityEngine.Object type will always save by reference.

All the best,
Joel
Joel @ Moodkie Interactive
Purchase Easy Save | Contact | Guides | Docs | Getting started
aloxuhik
Posts: 8
Joined: Wed Jul 12, 2023 6:54 am

Re: Lots of references

Post by aloxuhik »

I am not sure if I can replicate it in simple scene as that problem occur when scene is complicated. Can I somehow investigate why it didn't load from prefab even when prefabID is correct?

To be precise problem is that my building is trying access Data(which is ScriptableObject saved in prefab) in Awake method, but those data is null.
But it only happens when there are other buildings with reference to this building. When I save only that building without references, it is loaded correctly.
If it is saved with all data that would indicate that you're saving it directly (i.e. ES3.Save("key", building) ). If it just has the _ref, that indicates that you're saving an object which has the building in a field. Saving directly always saves by value, whereas saving a field of a UnityEngine.Object type will always save by reference.
Yes, thats what it should work like. But I have those data saved twice. Once at reference and once when I save it directly.
I attached my save file.

If you check ES3Ref "2769080340868088064" type "RoguelikeStrategy.Core.PowerSystem.PowerGenerator" it is firstly saved at "deliveryBuildings"(line 27) which is reference at ProductionBuilding. Other is at line 3563, which is correct this is direct save (because PowerGenerator was last in list of buildings).
I am saving all buildings(prefabs) in list with one call to ES3.Save.
Is that problem and I should save them one by one?
Attachments
SaveFile.zip
(9.6 KiB) Downloaded 86 times
aloxuhik
Posts: 8
Joined: Wed Jul 12, 2023 6:54 am

Re: Lots of references

Post by aloxuhik »

With double saving. It seems problem is that I am saving "deliveryBuildings" as Interface not as class. Where PowerGenerator is saved as abstract base class it is working correctly(saved with __ES3Ref), but when when saved as interface it is saved with all data. So when I have two production buildings both with PowerGenerator saved in "deliveryBuildings", data is saved for each one plus for direct save. So I have data saved three times.

Can be this solved?

EDIT: This also cause that other problem with loading. When in Types I set not to save "deliveryBuildings"(interfaces). It is working correctly and prefab is loaded as it should.
User avatar
Joel
Moodkie Staff
Posts: 4849
Joined: Wed Nov 07, 2012 10:32 pm

Re: Lots of references

Post by Joel »

I'm afraid it's very hard for me to comment without being able to see a project which replicates it, so I can't guarantee that I can provide assistance without one. I haven't seen your project or been involved in the development of it, so describing classes verbally or showing me the save file doesn't allow me to understand them or how they link together.

Have you changed any settings or are you providing any settings objects to your ES3 calls? Please could you show me a screenshot of Tools > Easy Save 3 > Settings with the Advanced Settings fold out open.

All the best,
Joel
Joel @ Moodkie Interactive
Purchase Easy Save | Contact | Guides | Docs | Getting started
aloxuhik
Posts: 8
Joined: Wed Jul 12, 2023 6:54 am

Re: Lots of references

Post by aloxuhik »

Yes, I understand that. But you can clearly see data saved twice no?

Here is first occurance, where it should be saved as ref :

Code: Select all

"deliveryBuildings" : [
							{
								"Item1" : {
									"__type" : "RoguelikeStrategy.Core.PowerSystem.PowerGenerator,Assembly-CSharp",
									"_ES3Ref" : "9084041327799021389",
									"goID" : "8137564140609201100",
									"providerOfWare" : true,
									"InputPriority" : 1,
									"WareInput" : [
										11
									],
									"CurrentPower" : 60,
									"Morale" : -10,
									"MaterialsBuild" : [
										{
											"_ES3Ref" : "7937693740101634068"
										},{
											"_ES3Ref" : "8586237444173196192"
										}
									],
									"DurabilityIndex" : 100,
									"GridPosition" : {
										"x" : 26,
										"y" : 5
									},
									"ConnectedRoadBlocks" : [
										{
											"Roads" : [
												{
													"_ES3Ref" : "3159485378651097364"
												},{
													"_ES3Ref" : "5455424948848225192"
												},{
													"_ES3Ref" : "3992804227504422998"
												},{
													"_ES3Ref" : "3158719623345131827"
												},{
													"_ES3Ref" : "7829794538974794690"
												},{
													"_ES3Ref" : "6948230470524624126"
												},{
													"_ES3Ref" : "9154948274596858685"
												},{
													"_ES3Ref" : "1441632772320614073"
												},{
													"_ES3Ref" : "4675262424503105038"
												},{
													"_ES3Ref" : "3650407545379767586"
												},{
													"_ES3Ref" : "2935416555117599581"
												},{
													"_ES3Ref" : "3000745683555732653"
												},{
													"_ES3Ref" : "7096808522044838124"
												},{
													"_ES3Ref" : "8644250855644413766"
												},{
													"_ES3Ref" : "2442560767722006"
												},{
													"_ES3Ref" : "2646118068067915051"
												},{
													"_ES3Ref" : "1087966665475538975"
												},{
													"_ES3Ref" : "3256903714378529725"
												},{
													"_ES3Ref" : "7449510221937552945"
												},{
													"_ES3Ref" : "6465790378345680786"
												},{
													"_ES3Ref" : "3243614229869448199"
												},{
													"_ES3Ref" : "7497307873312962573"
												},{
													"_ES3Ref" : "9139946662739117109"
												}
											],
											"Buildings" : [
												{
													"__type" : "RoguelikeStrategy.Core.ProductionSystem.ProductionBuilding,Assembly-CSharp",
													"_ES3Ref" : "4292409545337279039"
												},{
													"__type" : "RoguelikeStrategy.Core.ProductionSystem.ProductionBuilding,Assembly-CSharp",
													"_ES3Ref" : "4206791853916573370"
												},{
													"__type" : "RoguelikeStrategy.Core.PowerSystem.PowerGenerator,Assembly-CSharp",
													"_ES3Ref" : "9084041327799021389"
												}
											]
										}
									]
Here is second one, direct save which is correct:

Code: Select all

{
				"_ES3Ref" : "8137564140609201100",
				"es3Prefab" : {
					"prefabId" : "2008545434710025288",
					"refs" : {"866545837241176349":"6837828330485267671","2499135595610179568":"5186889177017585247","6703758744450389517":"30274313322010812","4112243554148292846":"7812375001243246182","3175220101503419002":"3186731318781931677","3451651663860416791":"2068207270127623508","7873937360344898815":"3859176139431945260","7877768471409126732":"2624342752203705383","9170729581379324796":"4236711254919414122","4798864372301905763":"6700575994318849796","7622754883857745079":"8921236106829665773","5316747501995359814":"9004703249906500515","6541194425826498235":"9084041327799021389","7195115386045231959":"6546560222022397362","3376595058230182731":"7078707155591721619","1698387891814668186":"8137564140609201100","3355697808516570183":"3251080275113679090","5898401463344520174":"1146909984801161695","1732580728538838577":"6003041907730280566","3712854014775997676":"4062679407134179285","6691453780896321305":"5785482916882713730","6793417886035406298":"4271832940356647406"
					}
				},
				"transformID" : 6700575994318849796,
				"components" : [
					{
						"__type" : "RoguelikeStrategy.Core.PowerSystem.PowerGenerator,Assembly-CSharp",
						"_ES3Ref" : "9084041327799021389",
						"goID" : "8137564140609201100",
						"providerOfWare" : true,
						"InputPriority" : 1,
						"WareInput" : [
							11
						],
						"CurrentPower" : 60,
						"Morale" : -10,
						"MaterialsBuild" : [
							{
								"_ES3Ref" : "7937693740101634068"
							},{
								"_ES3Ref" : "8586237444173196192"
							}
						],
						"DurabilityIndex" : 100,
						"GridPosition" : {
							"x" : 26,
							"y" : 5
						},
						"ConnectedRoadBlocks" : [
							{
								"Roads" : [
									{
										"_ES3Ref" : "3159485378651097364"
									},{
										"_ES3Ref" : "5455424948848225192"
									},{
										"_ES3Ref" : "3992804227504422998"
									},{
										"_ES3Ref" : "3158719623345131827"
									},{
										"_ES3Ref" : "7829794538974794690"
									},{
										"_ES3Ref" : "6948230470524624126"
									},{
										"_ES3Ref" : "9154948274596858685"
									},{
										"_ES3Ref" : "1441632772320614073"
									},{
										"_ES3Ref" : "4675262424503105038"
									},{
										"_ES3Ref" : "3650407545379767586"
									},{
										"_ES3Ref" : "2935416555117599581"
									},{
										"_ES3Ref" : "3000745683555732653"
									},{
										"_ES3Ref" : "7096808522044838124"
									},{
										"_ES3Ref" : "8644250855644413766"
									},{
										"_ES3Ref" : "2442560767722006"
									},{
										"_ES3Ref" : "2646118068067915051"
									},{
										"_ES3Ref" : "1087966665475538975"
									},{
										"_ES3Ref" : "3256903714378529725"
									},{
										"_ES3Ref" : "7449510221937552945"
									},{
										"_ES3Ref" : "6465790378345680786"
									},{
										"_ES3Ref" : "3243614229869448199"
									},{
										"_ES3Ref" : "7497307873312962573"
									},{
										"_ES3Ref" : "9139946662739117109"
									}
								],
								"Buildings" : [
									{
										"__type" : "RoguelikeStrategy.Core.ProductionSystem.ProductionBuilding,Assembly-CSharp",
										"_ES3Ref" : "4292409545337279039"
									},{
										"__type" : "RoguelikeStrategy.Core.ProductionSystem.ProductionBuilding,Assembly-CSharp",
										"_ES3Ref" : "4206791853916573370"
									},{
										"__type" : "RoguelikeStrategy.Core.PowerSystem.PowerGenerator,Assembly-CSharp",
										"_ES3Ref" : "9084041327799021389"
									}
								]
							}
						]
Code for production building:

Code: Select all

public class ProductionBuilding : WareBuilding<ProductionDataSO>, IProductionBuilding
    {
        public short WareAmountToSend;

        public short[] WareOutput;

        [SerializeField]
        private bool running = false;

	//HERE it isn't saved as reference but as whole object.
        [SerializeField]
        List<(IWareBuilding, List<Road>)> deliveryBuildings = new List<(IWareBuilding, List<Road>)>();

        Coroutine coroutine;
        ...
        }
        
When I change it from Interface to base class, save file work as it should and delivery buildings are saved like this:

Code: Select all

"deliveryBuildings" : [
							{
								"Item1" : {
									"__type" : "RoguelikeStrategy.Core.PowerSystem.PowerGenerator,Assembly-CSharp",
									"_ES3Ref" : "987942091185721837"
								}						
						
Should Interfaces be saved by Ref too and I have somewhere problem or it is normal behaviour and I should find workaround?

For clarification when I use "IWareBuilding"(Interface implemented by PowerGenerator) its saved without reference with all data.
When I use BuildingBase(base class of PowerGenerator) its saved as reference as it should be.
User avatar
Joel
Moodkie Staff
Posts: 4849
Joined: Wed Nov 07, 2012 10:32 pm

Re: Lots of references

Post by Joel »

Hi there,

I could see your issue, but the problem is this doesn't provide me with any information on why it's happening, and I'm unable to replicate it at my end.

The reason I asked about your settings is the only cases I've seen this happen is if "Serialise Unity Object Fields" is set to ToRefAndValue in Tools > Easy Save 3 > Settings > Advanced Settings, or you're providing an ES3Settings object to your ES3 methods with the referenceMode or memberReferenceMode set to ToRefAndValue.

Please could you also check that you are using the latest version of Easy Save.

Please could you also share with me your interface and base class that you mention.

All the best,
Joel
Joel @ Moodkie Interactive
Purchase Easy Save | Contact | Guides | Docs | Getting started
aloxuhik
Posts: 8
Joined: Wed Jul 12, 2023 6:54 am

Re: Lots of references

Post by aloxuhik »

Oh yes! I am sorry I forget to atttache screenshot. By it is as Ref. And I am not using settings.

But after some testing I managed to recreate problem in small project.

I am sending it as package. If you run it and hit "S" it will save.

ClassOne have dictionary with interface, where is Derived(monobehaviour object) saved. Save manager will save both objects. And data from derived are saved twice, once at dictionary once at direct save.

However if you change dictionary type from TestInterface to BaseAbstract(base abstract class) it is working correctly and it is saved as reference in dictionary.
Attachments
Settings.PNG
Settings.PNG (82.19 KiB) Viewed 772 times
User avatar
Joel
Moodkie Staff
Posts: 4849
Joined: Wed Nov 07, 2012 10:32 pm

Re: Lots of references

Post by Joel »

Hi there,

Thanks for sending that over If you could private message projects as requested in the future rather than sharing them publicly here that would be appreciated as publicly sharing the Easy Save package is against the EULA.

The SampleScene you've sent over appears to be empty, and the project doesn't contain any prefabs.
Capture.PNG
Capture.PNG (66.4 KiB) Viewed 767 times
All the best,
Joel
Joel @ Moodkie Interactive
Purchase Easy Save | Contact | Guides | Docs | Getting started
aloxuhik
Posts: 8
Joined: Wed Jul 12, 2023 6:54 am

Re: Lots of references

Post by aloxuhik »

I am sorry, it won't happen again.

I am sending it again. There are no prefabs. The problem is replicable without them. I think the problem will lay somewhere with my class inheritance, because interfaces without it works fine.
Post Reply