Actually, you should be ok if you added Traits, because the SaveableEntity won’t find a dictionary entry in the save file in RestoreState and it will simply be ignored.
The structural changes that will blow up the saving system are things where you change the types of data being saved within the individual component (like Inventory, for example).
A great example of this is if you decided in Mover that in addition to the location, you also wanted to save the current rotation…
This would mean that you’d be changing:
public object CaptureState()
{
return new SerializeableVector3(transform.position);
}
public void RestoreState(object state)
{
SerializableVector3 position = (SerializableVector3)state;
transform.position = position.ToVector();
}
to
[System.Serializable]
public struct PositionData
{
public SerializableVector3 position;
public SerializableVector3 rotation;
public PositionData(Vector3 pos, Vector3 rot)
{
position = new SerializableVector3(pos);
rotation = new SerializableVector3(rot);
}
}
public object CaptureState()
{
return new PositionData(transform.position, transform.eulerAngles);
}
public void RestoreState(object state)
{
PositionData data = (PositionData)state;
transform.position = data.position.ToVector();
transform.eulerAngles = data.rotation.ToVector();
}
This will crash with an old save file because you can’t convert a SerializableVector3 to a PositionData.
The first, and most obvious fix is to be mindful of data that may need to be saved in a component and avoid making changes once the game is out in the wild, but that’s not always a practical option.
Here’s how I would handle such a change:
public void RestoreState(object state)
{
if(state is PositionData data)
{
transform.position = data.position.ToVector();
transform.eulerAngles = data.position.ToVector();
}
else if(state is SerializableVector3 vector)
{
transform.position = vector.ToVector();
}
}
The if(variable is SomeClass newVariable) construction is a C# feature that tries to cast one class ot another class. If the cast fails, the if fails, and the program moved on. In my example, I continued using the error checking if() statement because it’s a good programming habit.