diff --git a/StarMap.API/README.md b/StarMap.API/README.md index 0a90ade..41880b9 100644 --- a/StarMap.API/README.md +++ b/StarMap.API/README.md @@ -220,3 +220,31 @@ Methods marked with this attribute will be called after `KSA.Program.OnFrame` is [StarMapAfterOnFrame] public void ModMethod(double currentPlayerTime, double dtPlayer); ``` + +#### StarMapAfterSave + +Namespace: `StarMap.API` +Assembly: `StarMap.API` +Target: Method + +Methods marked with this attribute will be called after KSA has written a save, with the directory +it was written to. A mod that keeps per-save state can write its own file beside `universe.xml`. + +```csharp +[StarMapAfterSave] +public void ModMethod(System.IO.DirectoryInfo saveDirectory); +``` + +#### StarMapAfterLoad + +Namespace: `StarMap.API` +Assembly: `StarMap.API` +Target: Method + +Methods marked with this attribute will be called after KSA has loaded a save, with the directory +it was read from. + +```csharp +[StarMapAfterLoad] +public void ModMethod(System.IO.DirectoryInfo saveDirectory); +``` diff --git a/StarMap.API/SaveAttributes.cs b/StarMap.API/SaveAttributes.cs new file mode 100644 index 0000000..6f8bb70 --- /dev/null +++ b/StarMap.API/SaveAttributes.cs @@ -0,0 +1,75 @@ +using System.IO; +using System.Reflection; + +namespace StarMap.API +{ + /// + /// Methods marked with this attribute will be called after KSA has written a save. + /// + /// + /// Methods using this attribute must match the following signature: + /// + /// + /// public void MethodName(System.IO.DirectoryInfo saveDirectory); + /// + /// + /// Parameter requirements: + /// + /// + /// + /// is the folder the save was written to. + /// + /// + /// + /// + /// Requirements: + /// + /// Return type must be . + /// Method must be an instance method (non-static). + /// + /// + public sealed class StarMapAfterSaveAttribute : StarMapMethodAttribute + { + public override bool IsValidSignature(MethodInfo method) + { + return method.ReturnType == typeof(void) && + method.GetParameters().Length == 1 && + method.GetParameters()[0].ParameterType == typeof(DirectoryInfo); + } + } + + /// + /// Methods marked with this attribute will be called after KSA has loaded a save. + /// + /// + /// Methods using this attribute must match the following signature: + /// + /// + /// public void MethodName(System.IO.DirectoryInfo saveDirectory); + /// + /// + /// Parameter requirements: + /// + /// + /// + /// is the folder the save was read from. + /// + /// + /// + /// + /// Requirements: + /// + /// Return type must be . + /// Method must be an instance method (non-static). + /// + /// + public sealed class StarMapAfterLoadAttribute : StarMapMethodAttribute + { + public override bool IsValidSignature(MethodInfo method) + { + return method.ReturnType == typeof(void) && + method.GetParameters().Length == 1 && + method.GetParameters()[0].ParameterType == typeof(DirectoryInfo); + } + } +} diff --git a/StarMap.Core/Patches/UniverseDataPatcher.cs b/StarMap.Core/Patches/UniverseDataPatcher.cs new file mode 100644 index 0000000..4bae1ee --- /dev/null +++ b/StarMap.Core/Patches/UniverseDataPatcher.cs @@ -0,0 +1,42 @@ +using System.IO; +using HarmonyLib; +using KSA; +using StarMap.API; + +namespace StarMap.Core.Patches +{ + /// + /// Tells mods when a save is written or read, and which directory it is in. + /// + [HarmonyPatch(typeof(UniverseData))] + internal static class UniverseDataPatcher + { + private const string WriteToMethodName = "WriteTo"; + private const string LoadFromMethodName = "LoadFrom"; + + // WriteTo is overloaded; the DirectoryInfo one is the save on disk. + [HarmonyPatch(WriteToMethodName, [typeof(DirectoryInfo)])] + [HarmonyPostfix] + public static void AfterWriteTo(DirectoryInfo directory) + { + var methods = StarMapCore.Instance?.Loader.ModRegistry.Get() ?? []; + + foreach (var (_, @object, method) in methods) + { + method.Invoke(@object, [directory]); + } + } + + [HarmonyPatch(LoadFromMethodName)] + [HarmonyPostfix] + public static void AfterLoadFrom(UncompressedSave uncompressedSave) + { + var methods = StarMapCore.Instance?.Loader.ModRegistry.Get() ?? []; + + foreach (var (_, @object, method) in methods) + { + method.Invoke(@object, [uncompressedSave.Directory]); + } + } + } +}