Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add a base JsonFile implementation for extension, as well as a SaveDataCache extension of JsonFile for working with per-mod-per-saveslot cached data #233

Merged
merged 12 commits into from
Jul 12, 2021

Conversation

toebeann
Copy link
Contributor

@toebeann toebeann commented Jul 9, 2021

Changes made in this pull request

  • Adds a basic JsonFile abstract implementation of IJsonFile, to alow easy extension in a similar manner to how ConfigFile operates.
  • Adds a base SaveDataCache abstract extension of JsonFile, which is intended to be used as a per-mod-per-saveslot data cache. Multiple can be used per mod. It automatically generates the file path based on the game's SaveLoadManager.GetTemporaryStoragePath() and the SaveDataCache's defining QMod, i.e.:
    Subnautica\TempSave\tmp964151\SMLHelperExampleMod\player_position.json.
    This data will be moved into/out of deep storage as per normal, whenever the game is saved and loaded.
  • Adds a SaveDataHandler, which allows an API consumer to easily register a SaveDataCache to be automatically loaded and saved when appropriate.
  • To facilitate SaveDataHandler auto-loading the SaveDataCache files, adds public methods to the InGameMenuHandler: RegisterOnLoadEvent, UnregisterOnLoadEvent and RegisterOneTimeUseOnLoadEvent as companions to the methods already provided, which trigger when the game loads into the "Main" scene.
  • Updated ExampleMod to show a basic usage of SaveDataCache.

Examples

JsonFile

public class MyJsonFile : JsonFile
{
    private static IQMod qMod;
    private static IQMod QMod => qMod ??= QModServices.Main.GetMyMod();

    public override string JsonFilePath => Path.Combine(Path.GetDirectoryName(QMod.LoadedAssembly.Location),
                                                        "my_json_file.json");

    public string MyString { get; set; }
}

[QModCore]
public static class Main
{
    [QModPatch]
    public static void Patch()
    {
        MyJsonFile json = new MyJsonFile();
        json.Load();
        json.MyString = "foo";
        json.Save();
    }
}

SaveDataCache

/// <summary>
/// A simple SaveDataCache implementation, intended to save the players current position to disk.
/// </summary>
[FileName("player_position")]
internal class SaveData : SaveDataCache
{
    public Vector3 PlayerPosition { get; set; }
}

[QModCore]
public static class Main
{
    [QModPatch]
    public static void Patch()
    {
        /// Works like ConfigFile - it will be automatically saved/loaded to/from disk appropriately,
        /// with its members updated whenever the user switches between save slots.
        SaveData saveData = SaveDataHandler.Main.RegisterSaveDataCache<SaveData>();

        // Simply display the recorded player position whenever the save data is loaded
        saveData.OnFinishedLoading += (object sender, JsonFileEventArgs e) =>
        {
            SaveData data = e.Instance as SaveData; // e.Instance is the instance of your SaveData stored as a JsonFile.
                                                    // We can use polymorphism to convert it back into a SaveData
                                                    // instance, and access its members, such as PlayerPosition.

            Logger.Log(Logger.Level.Info, 
                       $"loaded player position from save slot: {data.PlayerPosition}", 
                       showOnScreen: true);
        };

        // Update the player position before saving it
        saveData.OnStartedSaving += (object sender, JsonFileEventArgs e) =>
        {
            SaveData data = e.Instance as SaveData;
            data.PlayerPosition = Player.main.transform.position;
        };

        // Simply display the position we recorded to the save file whenever the save data it is saved
        saveData.OnFinishedSaving += (object sender, JsonFileEventArgs e) =>
        {
            SaveData data = e.Instance as SaveData;
            Logger.Log(Logger.Level.Info, 
                       $"saved player position to save slot: {data.PlayerPosition}", 
                       showOnScreen: true);
        };
    }
}

JsonFile implementations, similar to ConfigFile, have public OnStartedLoading/OnFinishedLoading & OnStartedSaving/OnFinishedSaving events, and since SaveDataCache extends JsonFile, you can easily hook up to these events if you need to react to the save/loads and do a bunch of processing, for example spawning in items in the correct locations.

Like with ConfigFile, it is entirely possible to use SaveDataCache without using the SaveDataHandler, but you will be responsible for handling when to save and load the data yourself.

If no FileNameAttribute is provided, the default filename is the QMod's id.

Builds a3634f5

Subnautica

Stable

SMLHelper
Example Mod

Experimental

SMLHelper
Example Mod

Below Zero

Stable

SMLHelper Zero
Example Mod

Experimental

SMLHelper Zero
Example Mod

…aHandler` that can be used to automatically read/write to from a json file that is per-mod-per-save.
@toebeann
Copy link
Contributor Author

Builds b2479a6

Subnautica

Stable

SMLHelper
Example Mod

Experimental

SMLHelper
Example Mod

Below Zero

Stable

SMLHelper Zero
Example Mod

Experimental

SMLHelper Zero
Example Mod

…er than deep storage, and reverted the change to createFileIfNotExist.
…taCache, and changed the way it handles updating the player position to utilise the OnStartedSaving etc. events of SaveDataCache, inherited from JsonFile.
@toebeann
Copy link
Contributor Author

Builds a3634f5

Subnautica

Stable

SMLHelper
Example Mod

Experimental

SMLHelper
Example Mod

Below Zero

Stable

SMLHelper Zero
Example Mod

Experimental

SMLHelper Zero
Example Mod

…since for this mod they will work just fine as variables within the `Patch` method.
Copy link
Member

@MrPurple6411 MrPurple6411 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks useful, Builds on all branches, Example mod loads and saved player position on save, Doesnt seem to break my 136 mod loadout. I think it works 👍🏻

@toebeann toebeann mentioned this pull request Jul 10, 2021
…sIncludedConverters` of `JsonFile`, and subsequently removing the override from `SaveDataCache` that adds these converters.
@toebeann toebeann merged commit 3b57c10 into dev Jul 12, 2021
@toebeann toebeann deleted the jsonfile-and-savedatacache branch July 12, 2021 16:12
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants