Two copies of variables declarations, necessary to serialize?

Was working thru the excellent beginner tutorial “Persistence - Saving and Loading Data” by Mike Geig at https://unity3d.com/learn/tutorials/modules/beginner/live-training-archive/persistence-data-saving-loading

Question: is it necessary to duplicate all the variable declarations I want to serialize?

At the top he declares:

   public float health;
   public float experience;

And down at the bottom he declares:

[SERIALIZABLE]
class PlayerData {
   public float health;
   public float experience;
}

Easy enough for two variables, but my data model is growing enormous as I develop a project, and the variables evolve under constant remodeling, and it’s increasingly difficult to keep the whole set of declarations identical in two different places. Am I missing an easier way? Not doing anything fancy, just storing basic strings and ints and floats, but it’s gonna be so-o-o many … there must be a clever solution. Help please!

1 Answer

1

No, it is not necessary, however it is necessary to keep your saved data in a writable class; you can’t serialize monobehaviours properly with the binary formatter.

If you are careful to keep it organized and encapsulated, and you remember that the individual references will change upon a save / load, then when you load (deserialize) data back into its class form you can send that to your actors and have them dip into it instead of their own fields.

However, it may become questionable practice if the majority of a scripts fields are all held in containers instead of the script itself.

Keeping scripts from getting too long, and keeping data (including save data) encapsulated to specific purposes, as well as only saving critical things and avoiding unnecessary detail, may help alleviate copypasta and bloated load methods.

Edit:
Here’s an example of some sci-fi game save management script that might utilize values through the class containers instead of explicit declarations:

using UnityEngine;
using System.Collections;
using System.Collections.Generic;

public class GameDataManager : MonoBehaviour 
{
	public PlayerData PlayerData;
	public PlayerData AIEnemyData;
	public MapData MapData;

	public void Load()
	{
		object loadedPlayerData = null;
		object loadedEnemyData = null;
		object loadedMapData = null;

		//
		// <---- load logic ----- >
		//
		 
		this.PlayerData = (PlayerData) loadedPlayerData;
		this.AIEnemyData = (PlayerData) loadedEnemyData;
		this.MapData = (MapData) loadedMapData;
	}
		

}

[System.Serializable]
public class PlayerData
{
	public int Health;
	public int Experience;
	public int TimeSaved;
	public long LastSaveDateTimeTicks;
	public string PlayerName;
	public string CharacterName;
	public List<int> UnitTypesRecruited;
	public List<int> UnitTypesActive;
	public int SpaceCredits;
	public List<int> AchievementProgress;
}

[System.Serializable]
public class MapData
{
	public List<int> LocationIndicesExplored;
	public long CurrentStellarDate;
	public int StarCount;
	public int EnemiesRemaining;
	public int SystemType; 		
	public string NameOfSystem;
	public long SizeOfSystem;
}

Now you can store and load lots of MapData and even store them in List fields in the manager, and the same with multiple PlayerData objects for multiplayer or multiple AI opponents in a 4x game, for example. In this manner you can just access the loaded values by accessing the playerdata itself, etc.

Right now this uses a lot of public values, but I advise keeping as much private as possible for encapsulation. Also I would recommend having the data be separate scripts so they can expand without bloating the management script.

OK sounds good, but ... I have to declare a variable in the serializable class, so that I can save/load that variable, yes? But that declaration inside a serializable class (even if the variable and serializable class are both public) does not seem to count towards making that variable available as a public variable within the project or even within the same script in which I declare the serializable class ... so I have to declare it again outside the serializable class ... so, there's the duplicate declarations that I don't know how to avoid. What am I missing here? :\

Geig has a public class GameControl { } with some variables declared. Then he has a [SERIALIZABLE] class PlayerData { } with the same variables declared again. Maybe I am supposed to be combining the two? Could we e.g. serialize the public class GameControl? and do away with the PlayerData class? ... I'm gonna have to try it, aren't I ... at least it's an idea to try ... brb ...

(in my best Sam Lowry voice) ... My God, it works!