Save Load

What can I do with Save/Load addon?

  • Save/load the state of the database to/from byte array during runtime on players devices
  • Define which table and which fields you want to be saved/loaded using merge settings (it won't work if you skip this step)
  • Create C# class for fine-grained row-level control.
  • You can save the whole database without Save/Load addon (click)

Should I use additional save/load solutions besides this addon?

If you do not have any additional data to save and you do not want to use cloud saves, then no, there is no need for additional asset(s). Use folder-based approach for better flexibility (each save in separate folder).

Restrictions

Data inside horizontal partitions, created with partitioning addon can not be saved/loaded properly

How can I enable it?

Choose Addons->Save Load, click "Enable", mark tables/fields for saving/loading and save the database.

Examples

The following projects use SaveLoad addon to save/load runtime data:

  1. Basic 3D example
  2. Basic 2D example
  3. Inventory example
  4. Localization example (localization addon is required)

How it works?

SaveLoad addon can create multiple, configurable snapshots of database data, and it can restore database state from these snapshots. Snapshots are constructed from the data, you marked as changeable, using Merge settings, described below. (Why it works like this?) Please, make sure you marked all data you want to be saved.

[Important] Loading with SaveLoad addon results in whole database to be reloaded, so if you use SaveLoad addon do not store references to tables/fields/entities, because they will be obsolete after loading.

Why it works like this?

Here is the quick explanation and main reasons why it works the way it works and why it's much better than simply saving the whole database.

  1. we want to be able to change database between public game releases
  2. we want to make sure the old saves, which are made with old version of database will remain compatible with new database
  3. As a result of loading old save, we want to keep all saved data, and we want to keep the changes we made to default database (shipped with a game)

Here is the detailed illustration about what we want to achieve:

Another diagram:

Read more about:
  1. How to change your database and keep it compatible with old save files - read the section below
  2. How to implement row-level control over merging - read Row-level controller section below.

How to use it?

//to save
byte[] bytes = BGRepo.I.Addons.Get<BGAddonSaveLoad>().Save();

//to load
BGRepo.I.Addons.Get<BGAddonSaveLoad>().Load(bytes);

Once you obtained bytes array using Save method, you need to write it to some persistent storage (file or cloud drive) See this minimalistic example for more details. There are also custom units/actions for Visual Scripting tools are available (see the full list at the bottom of this page)

When you load the saved data by using the code above, the whole database is reloaded, meaning all current database objects (tables, fields, rows) become obsolete. You can prevent database reloading by using the following code instead

//alternative loading without database reloading
BGRepo.I.Addons.Get<BGAddonSaveLoad>().Load(
    new BGSaveLoadAddonLoadContext(new BGSaveLoadAddonLoadContext.LoadRequest(BGAddonSaveLoad.DefaultSettingsName, bytes))
    {ReloadDatabase = false}
);

Is it possible to save/load the whole database?

// !!!! This is not recommended !!!!
//to save
byte[] bytes = BGRepo.I.Save();

//to load
BGRepo.I.Load(bytes);

The above call does not support Partition and localization addons currently

Using Merge settings

With Merge settings you can choose which data to save/load. You want as fewer data to be saved as possible. You do not need to include data, which is "static" and can not be changed during play session.

Try to stick to the following 3 rules:

  1. Rule #1 - If table's data is not changing in runtime, do not include this table to SaveLoad addon merge settings
  2. Rule #2 - If you want to save table data but at the same time you do not add or remove rows from this table in runtime, do not toggle on "Add missing" and "Remove orphaned". If you toggle on these parameters, the rows from default database are replaced with the saved rows after loading, and you need to use a builtin row controller or custom C# row controller to prevent new rows from removal.
  3. Rule #3 - Include only those fields, that are changing in runtime. If field values are not changing in runtime, do not include these fields. Toggle on "Choose fields to update" and select the fields, which values are changing in runtime

How to change your database and keep it compatible with old save files?

  1. Do not include static data (the data, which can not be changed during game session) to save/load merge settings
  2. While developing new, public version of your game - you can change anything in your static data with one simple exception: you can not delete rows which may be referenced from saved data. Well, actually you can, but in this case you need to make sure your code should handle null relation values properly.(and they will be null if you remove the rows)
  3. As for the data, which is saved within database snapshot (save file),
    • if you mark the field for saving using merge settings ("Update Matching") it will be loaded if the target row still exists in the default database
    • if you mark the rows for saving ("Add missing" and "Remove Orphaned") the whole table will be updated with values from the saved file during loading, if this table (meta) still exists in the default database. If you want to add new rows for such table, use our builtin row controller
    • if you want fine-grained, row-level control over loading - you can do it with C# controller class (read the next section for more details).

Here is an example from our basic 3D example project:

Row-level control over loading

Merge settings give you control over which tables/fields you want to save. But what about particular rows? What if you want to update/add/delete only those rows which comply to some condition?

This can be done with C# row controller class, which can cancel update operation before it actually takes place. Currently, there is no any merging on saving data, only on loading (but we reserved "merging on saving" option for future releases)

Our basic 3D example project uses row controller class. The main objective of this controller is to prevent deleting Collectable rows for new scenes (the scenes, which was added between public game releases). See the link below for detailed guide with C# source code.

Read more about:
  1. Starting with version 1.8.12, there is a builtin controller for adding rows to the tables with "Remove orphaned" setting
  2. basic example project has a page with detailed guide about row-level controller implementation.
  3. row-level controller on export/import page

Row-level control on saving

To filter out rows while saving the data, your C# controller should implement ISaveLoadAddonSavedEntityFilter interface. Method bool OnSaveEntity(BGEntity entity); will be called for every row, and it should return true if you want to skip provided row.

BeforeSave event

You can declare you MonoBehavior script to be a receiver of BeforeSave event, so it could update the database before saving (code from the example project)
//this class implement BGAddonSaveLoad.BeforeSaveReciever interface,
//so OnBeforeSave method will be called before saving
public class BGPlayer : BGM_Player, BGAddonSaveLoad.BeforeSaveReciever
{
    ...
    //this method is called before saving
    void BGAddonSaveLoad.BeforeSaveReciever.OnBeforeSave()
    {
        //save current position , rotation and scene to the database
        m_position = transform.position;
        m_rotation = transform.rotation;
        m_scene = BGE_Scene.FindEntity(scene => string.Equals(scene.Name, SceneManager.GetActiveScene().name));
    }
}
Note, callback method is called on all loaded objects, including inactive game objects and prefabs. Use the following code (at the beginning of your callback function) to filter out inactive game objects and prefabs.
        // use the following line to filter out components, attached to inactive GameObjects
        if (!gameObject.activeInHierarchy) return;

        // use the following line to filter out prefabs
        if (!gameObject.scene.IsValid()) return;

Additional configs

Starting with BGDatabase version 1.8.0, additional optional configs can be created for SaveLoad addon to save/load different data, for example game settings. Here is how to use it:

  1. Create an additional config with name Settings and include game settings to this config
  2. To save current settings data use this code
        byte[] settingsSave = BGRepo.I.Addons.Get<BGAddonSaveLoad>().Save(new BGSaveLoadAddonSaveContext("Settings"));
  3. To load game settings on your application startup, use this code
        // ReloadDatabase parameter, set to false, prevents database reloading
        BGRepo.I.Addons.Get<BGAddonSaveLoad>().Load(new BGSaveLoadAddonLoadContext(new BGSaveLoadAddonLoadContext.LoadRequest("Settings", settingsData)){ReloadDatabase = false});
  4. To load saved game using default config, use the following code. Preserve request is required to not lost settings data during main database reloading.
                BGRepo.I.Addons.Get<BGAddonSaveLoad>().Load(
                new BGSaveLoadAddonLoadContext(new BGSaveLoadAddonLoadContext.LoadRequest(BGAddonSaveLoad.DefaultSettingsName, gameSessionData))
                {
                    //the data for "Settings" config will be saved before database is reloaded and loaded after database reloading
                    PreserveRequests = new List<BGSaveLoadAddonLoadContext.PreserveRequest> { new BGSaveLoadAddonLoadContext.PreserveRequest("Settings") }
                }
            );

Example project can be downloaded here (ignore the errors on startup and import BGDatabase asset after opening the project). Run Assets\Scenes\SampleScene.unity scene and keep in mind that Settings config saves Settings.value field only.

Additional downloads

  1. Minimalistic C# script to make use of SaveLoad addon's Save/Load methods
  2. Custom actions for Playmaker to support SaveLoad addon
  3. Custom units for Bolt to support SaveLoad addon
  4. Custom nodes for Flow Canvas
  5. Node Canvas integration package has custom actions to use with SaveLoad addon
  6. Behavior Designer integration package has custom actions to use with SaveLoad addon
  7. UNode integration package has custom nodes to use with SaveLoad addon
  8. Game Creator integration package has custom actions to use with SaveLoad addon