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 62bf7a8..1fb6acf 100644
--- a/StarMap.Core/ModRepository/RuntimeMod.cs
+++ b/StarMap.Core/ModRepository/RuntimeMod.cs
@@ -159,17 +159,17 @@ 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))!,
- args =>
+ var allModsLoadedPatch = patchManager.RegisterStaticVoidPatch(IPatchService.PatchType.Postfix, this, typeof(KSA.ModLibrary).GetMethod(nameof(ModLibrary.LoadAll)),
+ _ =>
{
- classMethod.Invoke(modObject, args);
+ 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/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
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. |