A Persistent State Manager is any class that implements the IPersistentStateManager interface. They serve as a replacement for the previously used Persistent Data Controllers and are used to save and load the persistent data necessary to maintain game state related to the Streamable Assets Manager between gaming sessions.
The IPersistentStateManager interface defines a contract that the Component Manager can utilize to save and load persistent data. Once you define a class that implements this interface, you can pass an instance of your class to the Component Manager when Saving and Loading data, which is accomplished by calling the Save and Load methods of the Component Manager class. More information on Saving/Loading via the Component Manager can be found in the Saving And Loading Data Section within the Component Managers Chapter.
Saving & Loading With The Component Manager
--Special Note--
You will need to add a using DeepSpaceLabs.SAM; statement in order to use the IPersistentStateManager interface! An easy way to start with your custom class is to hover over the interface name and choose the option Show potential fixes -> Implement interface. This will provide default implementations for all interface members.
In addition, we recommend adding the following attribute above your class, which will ensure the custom persistent state manager is shown with other secondary components in menus:
[AddComponentMenu(GlobalValues.COMPONENT_ROOT_PATH + "Secondary Components/Custom Persistent State Manager Name")]
A full breakdown of what members need to be implemented from the IPersistentStateManager interface can be found in the Custom Persistent State Managers Section within this Chapter.
You also have the option to use a basic binary serialization based persistent state manager which is included with the Streamable Assets Manager for free. More information can be found in the Binary Serializer Manager Section within this Chapter.
For any Persistent State Mangager, however, the basic idea is for the Component Manager to be able to save/load specific data types in sequential order. These data types are int, bool, float, double, and string, however more types may be added in the future as needed.
When the Component Manager's Save method is called, data from the Component Manager and any persistent Worlds and Active Grids in the scene are saved in a pre-set order. When the Load method is called, this data is then loaded in the same pre-set order. This system removes the need to store keys for each piece of data, reducing the save game file size.
Versioning info is also saved with the data, which allows for future additions, removals, and/or changes to the pre-set data that is saved/loaded.
The interface also requires implementations for pre/post save/load methods, which can be used to setup and cleanup anything necessary to perform the saving/loading.
This is just an example of how the Component Manager interacts with the IPersistentStateManager implementation. The data described may or may not be actual saved data (note, psm would be an instance of a Persistent State Manager).
Save Called on ComponentManager:
psm.OnBeforeDataSaved();
psm.SaveInt(componentManagerID);
psm.SaveFloat(playerXPosition);
psm.SaveFloat(playerYPosition);
psm.SaveFloat(playerZPosition);
psm.SaveString(newGroupName);
psm.OnAfterDataSaved();
Load Called on ComponentManager:
psm.OnBeforeDataLoaded();
int componentManagerID = psm.LoadInt();
float playerXPosition = psm.LoadFloat();
float playerYPosition = psm.LoadFloat();;
float playerZPosition = psm.LoadFloat();
string newGroupName = psm.LoadString();
psm.OnAfterDataLoaded();
By default, when the Component Manager's Save method is called, the OnBeforeDataSaved and OnAfterDataSaved methods are called automatically before and after it saves the data it needs to save. This allows for setup and cleanup; for example, within the OnBeforeDataSaved method, the Binary Serializer Persistent State Manager opens a File Stream and sets up the Binary Writer necessary to save data. The File Stream and binary writer are both closed within the OnAfterDataSaved method.
Similarily, when the Component Manager's Load method is called, the OnBeforeDataLoaded and OnAfterDataLoaded methods are called automatically before and after it loads the data it needs to load.
This strategy can be problematic when using the Persistent State Manager to save/load data not related to SAM, as you may want to save/load this other data before/after the Component Manager's Save/Load methods are called.
In these cases, you can disable the auto invocation of the methods by returning true for the DisableAutoInvocationOfBeforeAndAfterSaveMethods and/or DisableAutoInvocationOfBeforeAndAfterLoadMethods properties.
When doing so, you will need to manually call the methods yourself! Here's an example of how that might look when Saving Data:
psm.OnBeforeDataSave();
SaveUnrelatedData();
componentManager.Save(psm);
SaveMoreUnrelatedData();
psm.OnAfterDataSaved();
When Loading Data:
psm.OnBeforeDataLoaded();
LoadUnrelatedData();
componentManager.Load(psm);
LoadMoreUnrelatedData();
psm.OnAfterDataLoaded();
Note, when saving/loading data unrelated to the Streamable Assets Manager using a Persistent State Manager, that data also must be loaded in the same order that it is saved!