Archive

Archive for October, 2017

Unity C# hotswapping with saved games

October 14th, 2017 No comments

One of the main things I missed moving to Unity from XNA was Visual C#’s edit and continue, allowing for quick code changes without having to recompile. Decreasing the time to iterate and adjust is incredibly important for quick development.
Unity has built in support for hotswapping – but its basically unusable. There are a few guides on how to structure code to allow for it – but that adds a lot of complexity, and easily breaks once you use any 3rd party code that isn’t designed for (basically all 3rd party Unity code). In my previous projects I just included a editor script to stop play mode once a recompile happens.

So instead of letting Unity try to serialize the scene (and then break horribly) I decided to just use Modbox’s save/load game system.
Once the ‘ModboxHotswap’ editor script detects a recompile, it saves the game and deletes all game objects from the scene. Once the recompile is finished it reloads the saved state.

[InitializeOnLoad]
public class ModboxHotSwap
{
    // Static initialiser called by Unity Editor whenever scripts are loaded
    static ModboxHotSwap()
    {
        Unused(_instance);
        _instance = new ModboxHotSwap();
    }

    private ModboxHotSwap()
    {
        EditorApplication.update += OnEditorUpdate;
    }

    ~ModboxHotSwap()
    {
        EditorApplication.update -= OnEditorUpdate;
        _instance = null;
    }

    private static void OnEditorUpdate()
    {
        if (EditorApplication.isPlaying)
        {
            if (EditorApplication.isCompiling)
            {
                if (!EditorPrefs.GetBool("HotSwapNeeded"))
                {
                    EditorPrefs.SetBool("HotSwapNeeded", true);

                    Debug.Log("Saving state before script compilation");
                    string SavedGameJSON = SaveSystem.Instance.SaveGame();
                    EditorPrefs.SetString("SavedGame", SavedGameJSON);

                    foreach (ModMetaData Mod in ModSystem.ModsMetaData)
                    {
                        // unload all modbox asset bundles
                        if (Mod.assetBundle != null)
                            Mod.assetBundle.Unload(false);
                    }

                    // destroy all game objects
                    foreach (GameObject o in Object.FindObjectsOfType())
                    {
                        UnityEngine.Object.Destroy(o);
                    }
                }
            }
            else if (EditorPrefs.GetBool("HotSwapNeeded"))
            {
                EditorPrefs.SetBool("HotSwapNeeded", false);

                // reload current Unity scene
                Scene scene = SceneManager.GetActiveScene();
                SceneManager.LoadScene(scene.name);

                // load saved game
                SaveSystem.Instance.LoadJSON(EditorPrefs.GetString("SavedGame"));
            }
        }
    }

    private static void Unused(T unusedVariable) { }
    private static ModboxHotSwap _instance = null;
}

Modbox was designed from the start to always be able to serialize any game state, mostly for networking synchronization, but this approach should also work well for any game project with a save game system.

Categories: Modbox