From 02b3a59718bc883492a1b0929ebd2b64868bbe47 Mon Sep 17 00:00:00 2001 From: Laurens Date: Sun, 8 Nov 2026 14:51:53 +0100 Subject: [PATCH 1/3] Run on KSA 2026.11.10.5801, and skip a hook whose target is gone (#114) --- StarMap.Core/ModRepository/RuntimeMod.cs | 7 ++-- StarMap.Core/Patches/PatchManager.cs | 33 ++++++++++++++----- .../UI/ConfirmRestart/ConfirmRestart.cs | 3 +- docs/modding/lifecycle.md | 2 +- 4 files changed, 32 insertions(+), 13 deletions(-) diff --git a/StarMap.Core/ModRepository/RuntimeMod.cs b/StarMap.Core/ModRepository/RuntimeMod.cs index 62bf7a8..59b8a2f 100644 --- a/StarMap.Core/ModRepository/RuntimeMod.cs +++ b/StarMap.Core/ModRepository/RuntimeMod.cs @@ -159,17 +159,18 @@ public bool InitializeMod(ModRegistry modRegistry, IPatchManager patchManager, I modRegistry.AddModMethod(ModId, attr, modObject, classMethod); break; case StarMapAllModsLoadedAttribute: - var allModsLoadedPatch = patchManager.RegisterStaticVoidPatch(IPatchService.PatchType.Postfix, this, typeof(KSA.ModLibrary).GetMethod(nameof(ModLibrary.LoadAll))!, + var allModsLoadedPatch = patchManager.RegisterStaticVoidPatch(IPatchService.PatchType.Postfix, this, typeof(KSA.ModLibrary).GetMethod(nameof(ModLibrary.LoadAll)), args => { - classMethod.Invoke(modObject, args); + // The callback takes no parameters, whatever LoadAll takes. + classMethod.Invoke(modObject, []); return true; }); Patches.Add(allModsLoadedPatch); break; case StarMapImmediateLoadAttribute: - var immediateLoadPatch = patchManager.RegisterInstanceVoidPatch(IPatchService.PatchType.Prefix, this, typeof(KSA.Mod).GetMethod(nameof(Mod.PrepareSystems))!, + var immediateLoadPatch = patchManager.RegisterInstanceVoidPatch(IPatchService.PatchType.Prefix, this, typeof(KSA.Mod).GetMethod(nameof(Mod.LoadSettings)), (args, mod) => { if (mod.Id.Equals(ModId)) diff --git a/StarMap.Core/Patches/PatchManager.cs b/StarMap.Core/Patches/PatchManager.cs index 9d91f2f..c6ee34e 100644 --- a/StarMap.Core/Patches/PatchManager.cs +++ b/StarMap.Core/Patches/PatchManager.cs @@ -9,10 +9,10 @@ namespace StarMap.Core.Patches { internal interface IPatchManager : IDisposable { - IDisposable RegisterInstancePatch(PatchType patchType, RuntimeMod? mod, MethodBase method, IPatchService.InstanceCallback callback); - IDisposable RegisterInstanceVoidPatch(PatchType patchType, RuntimeMod? mod, MethodBase method, IPatchService.InstanceVoidCallback callback); - IDisposable RegisterStaticPatch(PatchType patchType, RuntimeMod? mod, MethodBase method, IPatchService.StaticCallback callback); - IDisposable RegisterStaticVoidPatch(PatchType patchType, RuntimeMod? mod, MethodBase method, IPatchService.StaticVoidCallback callback); + IDisposable RegisterInstancePatch(PatchType patchType, RuntimeMod? mod, MethodBase? method, IPatchService.InstanceCallback callback); + IDisposable RegisterInstanceVoidPatch(PatchType patchType, RuntimeMod? mod, MethodBase? method, IPatchService.InstanceVoidCallback callback); + IDisposable RegisterStaticPatch(PatchType patchType, RuntimeMod? mod, MethodBase? method, IPatchService.StaticCallback callback); + IDisposable RegisterStaticVoidPatch(PatchType patchType, RuntimeMod? mod, MethodBase? method, IPatchService.StaticVoidCallback callback); } internal class PatchManager : IPatchManager @@ -34,25 +34,42 @@ public PatchManager(ILogger logger) _instance = this; } - public IDisposable RegisterInstancePatch(PatchType patchType, RuntimeMod? mod, MethodBase method, IPatchService.InstanceCallback callback) + public IDisposable RegisterInstancePatch(PatchType patchType, RuntimeMod? mod, MethodBase? method, IPatchService.InstanceCallback callback) { + if (method is null) return MissingTarget(mod); return GetOrCreateMethodPatch(method).RegisterPatch(patchType, mod, new InstanceCallback(callback), _logger); } - public IDisposable RegisterInstanceVoidPatch(PatchType patchType, RuntimeMod? mod, MethodBase method, IPatchService.InstanceVoidCallback callback) + public IDisposable RegisterInstanceVoidPatch(PatchType patchType, RuntimeMod? mod, MethodBase? method, IPatchService.InstanceVoidCallback callback) { + if (method is null) return MissingTarget(mod); return GetOrCreateMethodPatch(method).RegisterPatch(patchType, mod, new InstanceVoidCallback(callback), _logger); } - public IDisposable RegisterStaticPatch(PatchType patchType, RuntimeMod? mod, MethodBase method, IPatchService.StaticCallback callback) + public IDisposable RegisterStaticPatch(PatchType patchType, RuntimeMod? mod, MethodBase? method, IPatchService.StaticCallback callback) { + if (method is null) return MissingTarget(mod); return GetOrCreateMethodPatch(method).RegisterPatch(patchType, mod, new StaticCallback(callback), _logger); } - public IDisposable RegisterStaticVoidPatch(PatchType patchType, RuntimeMod? mod, MethodBase method, IPatchService.StaticVoidCallback callback) + public IDisposable RegisterStaticVoidPatch(PatchType patchType, RuntimeMod? mod, MethodBase? method, IPatchService.StaticVoidCallback callback) { + if (method is null) return MissingTarget(mod); return GetOrCreateMethodPatch(method).RegisterPatch(patchType, mod, new StaticVoidCallback(callback), _logger); } + // A KSA update can remove a method StarMap hooks. Skipping the one callback keeps the loader + // and every other mod running. + private IDisposable MissingTarget(RuntimeMod? mod) + { + _logger.Warning($"StarMap - A hook target is missing from this KSA build; a callback of {mod?.ModId ?? "StarMap"} will not run"); + return new NoPatch(); + } + + private sealed class NoPatch : IDisposable + { + public void Dispose() { } + } + private MethodPatch GetOrCreateMethodPatch(MethodBase method) { if (!_patches.TryGetValue(method, out var methodPatch)) diff --git a/StarMap.Core/UI/ConfirmRestart/ConfirmRestart.cs b/StarMap.Core/UI/ConfirmRestart/ConfirmRestart.cs index 59d904b..4258d86 100644 --- a/StarMap.Core/UI/ConfirmRestart/ConfirmRestart.cs +++ b/StarMap.Core/UI/ConfirmRestart/ConfirmRestart.cs @@ -1,4 +1,5 @@ -using Brutal.GlfwApi; +using Brutal.Collections; +using Brutal.GlfwApi; using Brutal.ImGuiApi; using Brutal.VulkanApi; using Brutal.VulkanApi.Abstractions; diff --git a/docs/modding/lifecycle.md b/docs/modding/lifecycle.md index 70c9dcd..f1b930b 100644 --- a/docs/modding/lifecycle.md +++ b/docs/modding/lifecycle.md @@ -7,7 +7,7 @@ Mark the entry class with `[StarMapMod]`. StarMap creates one instance for the m | Attribute | Required method signature | Called | | --- | --- | --- | | `[StarMapBeforeMain]` | `void Method()` | After the mod is initialized and before KSA starts. | -| `[StarMapImmediateLoad]` | `void Method(KSA.Mod definingMod)` | Immediately before KSA prepares that mod's systems. | +| `[StarMapImmediateLoad]` | `void Method(KSA.Mod definingMod)` | When KSA registers that mod, before its settings and any content load. | | `[StarMapAllModsLoaded]` | `void Method()` | After KSA's `ModLibrary.LoadAll` completes. | | `[StarMapUnload]` | `void Method()` | When KSA unloads. Dispose mod-owned subscriptions and menu items here. | | `[StarMapBeforeGui]` | `void Method(double dt)` | Before KSA's GUI frame callback. | From 3263b6e42d949383f3894ef7c66b80b104ab54cc Mon Sep 17 00:00:00 2001 From: KlaasWhite Date: Sun, 8 Nov 2026 13:59:09 +0100 Subject: [PATCH 2/3] Update packages and made some changes --- Directory.Packages.props | 4 ++-- StarMap.Core/ModRepository/RuntimeMod.cs | 3 +-- StarMap.Core/UI/ConfirmRestart/ConfirmRestart.cs | 3 +-- 3 files changed, 4 insertions(+), 6 deletions(-) diff --git a/Directory.Packages.props b/Directory.Packages.props index 358addf..9d2fb00 100644 --- a/Directory.Packages.props +++ b/Directory.Packages.props @@ -19,7 +19,7 @@ - - + + \ No newline at end of file diff --git a/StarMap.Core/ModRepository/RuntimeMod.cs b/StarMap.Core/ModRepository/RuntimeMod.cs index 59b8a2f..1fb6acf 100644 --- a/StarMap.Core/ModRepository/RuntimeMod.cs +++ b/StarMap.Core/ModRepository/RuntimeMod.cs @@ -160,9 +160,8 @@ public bool InitializeMod(ModRegistry modRegistry, IPatchManager patchManager, I break; case StarMapAllModsLoadedAttribute: var allModsLoadedPatch = patchManager.RegisterStaticVoidPatch(IPatchService.PatchType.Postfix, this, typeof(KSA.ModLibrary).GetMethod(nameof(ModLibrary.LoadAll)), - args => + _ => { - // The callback takes no parameters, whatever LoadAll takes. classMethod.Invoke(modObject, []); return true; }); diff --git a/StarMap.Core/UI/ConfirmRestart/ConfirmRestart.cs b/StarMap.Core/UI/ConfirmRestart/ConfirmRestart.cs index 4258d86..59d904b 100644 --- a/StarMap.Core/UI/ConfirmRestart/ConfirmRestart.cs +++ b/StarMap.Core/UI/ConfirmRestart/ConfirmRestart.cs @@ -1,5 +1,4 @@ -using Brutal.Collections; -using Brutal.GlfwApi; +using Brutal.GlfwApi; using Brutal.ImGuiApi; using Brutal.VulkanApi; using Brutal.VulkanApi.Abstractions; From fbf87784fc6225dfdc88a479258ebff4d1e00501 Mon Sep 17 00:00:00 2001 From: KlaasWhite Date: Sun, 8 Nov 2026 14:04:56 +0100 Subject: [PATCH 3/3] Update changelog --- docs/changelog.md | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/docs/changelog.md b/docs/changelog.md index 5f0aeac..f399649 100644 --- a/docs/changelog.md +++ b/docs/changelog.md @@ -1,6 +1,16 @@ # Changelog -## 0.5 +## 0.5.3 + +- Ensure StarMap is compatible with KSA 2025.11.10.5801 + +## 0.5.1 and 0.5.2 + +### Fixed + +- Ensure API nuget is released correctly + +## 0.5.0 ### Added