Persistent Data Components

To prepare a GameObject for saving and loading, you should add one or more PersistentData components. These components respond to messages to record the GameObjects' data to the Lua environment when saving, and to retrieve the GameObjects' data from the Lua environment when loading.

When saving a game, the PersistentDataManager sends an "OnRecordPersistentData" message to all GameObjects to give them an opportunity to record their state in the Lua environment. You can use the components described below or write your own scripts that respond to "OnRecordPersistentData".

Likewise, when loading a game, the PersistentDataManager sends an "OnApplyPersistentData" message to all GameObjects to let them retrieve their state from the Lua environment and apply it.

NOTE: Call PersistentDataManager.LevelWillBeUnloaded() before loading a new level! Some persistent data components, such as Persistent Destructible, record data in the Lua environment when a game object is destroyed during play. GameObjects are also destroyed when you load a new level. In this case, you don't want to record it in the Lua environment. The LevelWillBeUnloaded() method tells these components to ignore the "OnDestroy" message.


Level Manager

If your player can move between levels, add the Level Manager component to your Dialogue Manager object.

While the name doesn't start with PersistentData, this component acts like a persistent data component. It records the player's current level in Variable["SavedLevelName"] so it can reload the player's current level when reloading a game using the Game Saver component or the LevelManager.LoadGame() method. Add it to the Dialogue Manager so it's not destroyed between level loads.

LevelManager calls PersistentDataManager.LevelWillBeUnloaded() for you.

The scene in the Examples/Save Load Example folder demonstrates the use of LevelManager.

The LoadLevel() sequencer command also uses LevelManager's LoadLevel() method.

Level Manager Details

This section describes the internal details of LevelManager.

The method LevelManager.LoadLevel("foo") loads the level named "foo". It then waits two frames before applying the persistent data saved in the Lua environment. The first frame allows scripts' Start() methods to finish. The second frame allows other third-party plugins to finish their initialization; UFPS, for example, takes two frames to start up. Finally, on the third frame, LevelManager applies the persistent data.

However, the player is handled slightly differently from NPCs. If your player is tagged "Player", then LevelManager.LoadLevel() will not apply the saved position. The rationale is that you'll be handling the player's position yourself when moving between levels. For example, if you look at the Dialogue System's Save and Load Example, when changing between the Airlock and Server Room scenes, the player always starts at the door between the levels, which is where I placed the player in the scene at design time.

If you want to prevent another GameObject from restoring its position, too, set its PersistentPositionData.restoreCurrentLevelPosition value to false.

When loading a saved game, on the other hand, LevelManager does restore the player's saved position.


Persistent Position Data

This component saves the game object's position and rotation.

In the example above, Private Hart will save his position data into the Lua environment. When the player loads a saved game, Private Hart will be moved to the correct position instead of the start position.

If the Record Current Level checkbox is ticked, the object also records its current level. If ticked, then when asked to apply this saved-game data later, the object will only apply the data if the level matches.

See Setting Spawnpoints to make use of different entry locations when changing scenes.


Persistent Active Data

This component sets a GameObject active or inactive based on a Lua condition.

In the example above, the Force Field Controller object will activate or deactivate the Force Field object based on a quest condition. It will activate the Force Field object when the player loads a saved game in which the quest "Raise Force Field" has been completed successfully.


Persistent Destructible

This component records when a game object has been destroyed. When the saved game data is applied, if the game object has been previously destroyed, it will be destroyed again. You can add this to destructible crates and barrels, enemies, and gathered crafting resources.

It works by recording true in a unique Lua variable. You don't have to define this variable ahead of time in your dialogue database, but you should assign a variable name to the component. If you don't assign a variable name, it will use the name of the game object as the variable name.


How to Save Multiple Destructibles

To save the state of multiple destructible objects, you can:

Using Persistent Destructible to Save Multiple Destructibles

To use Persistent Destructible, simply assign a unique variable name to each one. Optionally, you can leave the variable name blank and assign unique game object names.

The example above shows an enemy with three components:

  • Die On Take Damage: Destroys the game object when it receives a TakeDamage message.
  • Increment On Destroy: Increments a kill counter for a quest.
  • Persistent Destructible: Records when "Enemy001" has been destroyed. The next time the level is loaded, this component will automatically destroy the game object.

Using Persistent Active Data to Save Multiple Destructibles

To use Persistent Active Data components:

  1. Give each object a unique variable (for example, "Crate001", "Crate002", etc.). You don't have to define the variable in the dialogue database. The Increment On Destroy script (next step) will create the variable if it doesn't already exist.
  2. Add an Increment On Destroy component to each destructible object. Assign the variable name. When the object is destroyed, it will increment the value of this variable from 0 to 1.
  3. Add a Persistent Active Data component to each destructible object.
    • Set the target to the object.
    • Add a Lua condition that compares the value of the variable to 0. When the saved data is applied, if the value is 0 the object will be active. If the value is 1 the object will be inactive.

Writing Your Own Persistent Data Components

Any component that implements OnRecordPersistentData() and OnApplyPersistentData() can save and load persistent data. As a convenience, a template script is available in Scripts/Templates/PersistentDataTemplate.cs. Just make a copy of this script and customize it according to the instructions in the script's comments.


<< Saved Game Data | Game Saver >>