Persistence

Persistence (aka game saving) is what we call the ability for the server to write the current state of the running game to the disk, so that the server can exit, and then resume at a later time.

Where does the save go?

The saved data will all be stored starting in the install's root, to the path ./save/<name of save>/*

How Often does it save?

This is a setting in the config file (save-frequency), and defaults to 1 minute. Each part of the game manages its own data, and some areas save more frequently than others (eg, worlds often will write to disk more frequently).

Plugin Persistence

There are a few different ways plugins can persist data. I try to make them as common as possible. Most of the persistence uses the PersistAttribute tag on fields and properties within a class that marks it as wanting to save-to-disk. This is not true for all classes, so I will talk about each area in-detail.

Entities (NPCs, structures, etc; non-players)

With entities, by default, all items marked with the SyncableAttribute or PersistAttribute are saved and restored to the disk. No extra work needs to be done.

Players

Players persist their data in the same exact way that Entities do, but with one major difference: it doesn't happen automatically. Players can be easily saved and loaded in the implementation of UserControllerBase as part of your Plugin Context.

NOTE: This is subject to change in the future.

Here's an example:

snippet.csharp
public class UserController : UserControllerBase
{
    public UserController(IEntityManager em, IUserManager userManager)
        :base(em, userManager)
    {
    }
 
    public override IPlayableEntity CreateEntityFor (IUser user)
    {
        var player = EntityManager.Load(user.Username) as Player;
 
        if (player == null)
        {
            player = new Player();
            player.SetPosition(0, 0, 10);
        }
 
        player.SetName(user.Username);
 
        return player;
    }
 
    public override void UnloadEntityFor(IUser user, IPlayableEntity entity)
    {
        EntityManager.Persist(user.Username, entity);
    }
}

Subsystems

By default, all fields or properties marked with the PersistAttribute are syncd to disk.

Plugin Extensions

Plugin extensions are not persisted by default. You can set the Persist=true on a server-side plugin extension, and all fields and properties marked with PersistAttribute in the implementation will be persisted.

Other Classes (Misc)

There are some cases where you may have a class that was not created in such a way that it falls under one of these categories. For this category, simply inject the ISavedGame dependency into your class, and call this.SavedGame.RegisterObjectForPersistence(this).

This will do three things 1. All persistable data in the class will be loaded from file, if possible 2. Every duration (set in config), properties and fields marked with PersistAttribute will be saved to disk 3. The class will be saved if the server is stopped

What if my data is more complex than json?

If you don't want to use the PersistAttribute, and would prefer to save and load data yourself, simply implement the IPersistable interface to use streams instead. This is good when you have large amounts of data, or data that can not be serialized correctly.