Auto save game on application close (synchronous)

Share custom commands, script functions, actor implementations and other Naninovel plug-ins you've created.
Post Reply
User avatar
Elringus
Admin
Posts: 385
Joined: 11 May 2020 18:03

Auto save game on application close (synchronous)

Post by Elringus »

While our built-in state manager doesn't provide synchronous (blocking) APIs to serialize state, there are cases when you may need the blocking versions, eg to automatically save the game when player forcefully closes the application (for example, closing application window instead of clicking "EXIT" button in the title menu).

Below is an example of a custom state manager (see the guide for more info on overriding engine services), which exposes sync versions to save both game and global state.

Code: Select all

using System;
using Naninovel;
using Naninovel.Commands;

[InitializeAtRuntime(int.MinValue, typeof(StateManager)), Goto.DontResetAttribute]
public class SyncSaveStateManager : StateManager
{
    public SyncSaveStateManager (StateConfiguration config, EngineConfiguration engineConfig)
        : base(config, engineConfig) { }

    public void QuickSaveGame ()
    {
        var slotId = string.Format(Configuration.QuickSaveSlotMask, 1);
        SaveGame(slotId);
    }

    public void SaveGame (string slotId)
    {
        var state = new GameStateMap();
        state.SaveDateTime = DateTime.Now;
        state.Thumbnail = Engine.GetService<ICameraManager>().CaptureThumbnail();
        SaveAllServicesToState<IStatefulService<GameStateMap>, GameStateMap>(state);
        PerformOnGameSerializeTasks(state);
        state.RollbackStackJson = SerializeRollbackStack();
        (GameSlotManager as PlayerPrefsGameStateSlotManager)?.Save(slotId, state);
        SaveGlobal();
    }

    public void SaveGlobal ()
    {
        var state = new GlobalStateMap();
        var slotId = Configuration.DefaultGlobalSlotId;
        SaveAllServicesToState<IStatefulService<GlobalStateMap>, GlobalStateMap>(state);
        (GlobalSlotManager as PlayerPrefsGlobalStateSlotManager)?.SaveAsync(slotId, state);
    }
}

Notice, that the implementation assumes you've selected PlayerPrefs game and global serialization handlers.

Image

Below is an example script, which will automatically save the game to the first quick save slot when the application is closed.

Code: Select all

using System.Collections;
using Naninovel;
using UnityEngine;

public class AutoSaveGame : MonoBehaviour
{
    private SyncSaveStateManager stateManager;
    private ITitleUI titleUI;

    [RuntimeInitializeOnLoadMethod]
    private static void Initialize ()
    {
        var gameObject = new GameObject(nameof(AutoSaveGame));
        gameObject.AddComponent<AutoSaveGame>();
        DontDestroyOnLoad(gameObject);
    }

    private IEnumerator Start ()
    {
        while (!Engine.Initialized)
            yield return null;
        stateManager = Engine.GetService<SyncSaveStateManager>();
        titleUI = Engine.GetService<IUIManager>().GetUI<ITitleUI>();
    }

    private void OnApplicationQuit ()
    {
        if (!titleUI?.Visible ?? true) // Don't save when on the title screen.
            stateManager?.QuickSaveGame();
    }
}

You can now load last auto-saved (quick) slot as follows:

Code: Select all

Engine.GetService<IStateManager>().QuickLoadAsync()

Below is an example of a custom component, which can be used to handle uGUI's button "OnClick" event to load the last auto save:

Code: Select all

using Naninovel;
using UnityEngine;

public class LoadLastQuickSave : MonoBehaviour
{
    public void Load () => Engine.GetService<IStateManager>().QuickLoadAsync();
}

Attach that component to uGUI button and set the "OnClick" handler to LoadLastQuickSave.Load:

Image

jgo
Posts: 1
Joined: 03 Mar 2021 17:49

Re: Auto save game on application close (synchronous)

Post by jgo »

This is very useful - thank you for creating this example! If I were to create a custom state manager to use IOGameStateSlotManager/IOGlobalStateSlotManager instead, would that work as well? Or is there a specific reason you chose PlayerPrefs for this?

User avatar
Elringus
Admin
Posts: 385
Joined: 11 May 2020 18:03

Re: Auto save game on application close (synchronous)

Post by Elringus »

IO serialization handler doesn't have a sync version of save method; you can add your own, though: https://naninovel.com/guide/state-management.html#custom-serialization-handlers.

Post Reply