How to create persistable Objects
This section covers the standard workflow for making any script or actor in your scene persistable. Whether it's the players position, health, a door's open state or an npcs inventory. The process always follows the same pattern.
Core Concepts
Subscription Model
Instead of the SaveManager searching thru a scene (which is slow), your scripts and actors opt-in to the save process.
- Use
OnEnableto subscribe toSaveManagerevents - Use
OnDisableto unsubscribe (crucial to prevent issues)
Identity (ID)
Every script and actor in Flax has a unique Guid (the ID property). Best practice is to use this as the "key" in the save dictionary.
This ensures that when the game loads, the data finds its way back to the exact same object, even if you have multiple instances of the same prefab.
Prefab Safety
Flax instantiates every prefab with a unique ID. Using this property is the most robust way to identify save data and avoids prefabs overwriting each other.
Step-By-Step
To get the most flexibility out of FlaxSave, use scripts to handle saving and loading an actor state in a self-contained fashion. But the following steps can be directly applied to custom actors.
-
Prepare your Moduls
Make sure to add the FlaxSave dependency to the
*.Build.csfile in any module, where you want to use FlaxSave -
Create a script
Like you would with any. Make sure to name it something you can easy identify.
-
Loading Data
The
OnEnablemethod in your script is a good place to recreate the previously saved state of the attached actor.To retieve the data from the loaded savegame, you can simply call the
GetSaveDatamethod. -
Saving Data
Saving data can be handled in two distinct ways, depending on whether you want to react to a global save request or manally update the state of an object.
Via the
OnSavingeventThis is the standard way. Your scripts listen to the global save command and pushes its data into the shared dictionary.
C#public override void OnEnable() { // Subscribe to the saving event SaveManager.Instance.OnSaving += OnSaving; } private void OnSaving(Dictionary<Guid, string> savegame) { // Write the actor's current rotation to the save dictionary string data = JsonSerializer.Serialize(Actor.Orientation) savegame[ID] = data; } public override void OnDisable() { // Unsubscribe to avoid memory leaks and other issues SaveManager.Instance.OnSaving -= OnSaving; }Via
SetSaveData(Manual updates)Sometimes you want to update the save data immediatly when something happens (i.e. a player picking up an item or an actor being disabled) rather than waiting for a global save request.
Common Setups
FlaxSave is designed to handle anything from simple floats to complex custom classes. Here are the most common patterns.
Example Scripts
FlaxSave contains example scripts with common setups and pattern. You'll find them in the plugin folder
FlaxSave > Source > FlaxSaveExamples > Scripts
Complex Classes or Structs
If you have multiple variables (i.e. health, stamina, mana) don't save them one by one. Create a small struct or class and save the whole object. The system will handle the JSON nesting for you.
public struct PlayerStats
{
public float Health;
public int SkillLevel;
}
// During OnSaving event
private void OnSaving(Dictionary<Guid, string> savegame)
{
PlayerStats stats = new PlayerStats
{
Health = 89;
SkillLevel = 5;
};
savegame[ID] = JsonSerializer.Serialize(stats);
}
// Loading during actor initalization
public override void OnEnable()
{
string data = SaveManager.Instance.GetSaveData(ID);
PlayerStats stats = JsonSerializer.Deserialize<PlayerStats>(data);
...
}