From 6976053d81383ea4791c2c1dc70d340d555e45db Mon Sep 17 00:00:00 2001 From: KlaasWhite Date: Sun, 18 Oct 2026 15:33:20 +0200 Subject: [PATCH 1/6] Add ModMenu service --- StarMap.API/Interfaces/IModMenuService.cs | 11 ++ .../{IPatchHelper.cs => IPatchService.cs} | 2 +- StarMap.Core/API/ModMenuService.cs | 23 ++++ .../API/{PatchHelper.cs => PatchService.cs} | 12 +- StarMap.Core/Patches/PatchManager.cs | 36 +++--- StarMap.Core/Patches/StarMapPatches.cs | 4 +- StarMap.Core/StarMapCore.cs | 3 + StarMap.Core/UI/ModMenu.cs | 109 ++++++++++++++++++ 8 files changed, 173 insertions(+), 27 deletions(-) create mode 100644 StarMap.API/Interfaces/IModMenuService.cs rename StarMap.API/Interfaces/{IPatchHelper.cs => IPatchService.cs} (97%) create mode 100644 StarMap.Core/API/ModMenuService.cs rename StarMap.Core/API/{PatchHelper.cs => PatchService.cs} (51%) create mode 100644 StarMap.Core/UI/ModMenu.cs diff --git a/StarMap.API/Interfaces/IModMenuService.cs b/StarMap.API/Interfaces/IModMenuService.cs new file mode 100644 index 0000000..6563bf4 --- /dev/null +++ b/StarMap.API/Interfaces/IModMenuService.cs @@ -0,0 +1,11 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace StarMap.API.Interfaces +{ + public interface IModMenuService + { + IDisposable AddModMenuItem(string label, Action OnClick); + } +} diff --git a/StarMap.API/Interfaces/IPatchHelper.cs b/StarMap.API/Interfaces/IPatchService.cs similarity index 97% rename from StarMap.API/Interfaces/IPatchHelper.cs rename to StarMap.API/Interfaces/IPatchService.cs index ba1c667..fc7e634 100644 --- a/StarMap.API/Interfaces/IPatchHelper.cs +++ b/StarMap.API/Interfaces/IPatchService.cs @@ -8,7 +8,7 @@ namespace StarMap.API.Interfaces { - public interface IPatchHelper + public interface IPatchService { enum PatchType { diff --git a/StarMap.Core/API/ModMenuService.cs b/StarMap.Core/API/ModMenuService.cs new file mode 100644 index 0000000..b62c4ef --- /dev/null +++ b/StarMap.Core/API/ModMenuService.cs @@ -0,0 +1,23 @@ +using StarMap.API.Interfaces; +using StarMap.Core.UI; +using System; +using System.Collections.Generic; +using System.Text; + +namespace StarMap.Core.API +{ + internal class ModMenuService : IModMenuService + { + private readonly IModMenu _modMenu; + + public ModMenuService(IModMenu modMenu) + { + _modMenu = modMenu; + } + + public IDisposable AddModMenuItem(string label, Action OnClick) + { + return _modMenu.AddModMenuButton(label, OnClick); + } + } +} diff --git a/StarMap.Core/API/PatchHelper.cs b/StarMap.Core/API/PatchService.cs similarity index 51% rename from StarMap.Core/API/PatchHelper.cs rename to StarMap.Core/API/PatchService.cs index bb612cc..8dba8b8 100644 --- a/StarMap.Core/API/PatchHelper.cs +++ b/StarMap.Core/API/PatchService.cs @@ -5,34 +5,34 @@ namespace StarMap.Core.API { - internal class PatchHelper : IPatchHelper + internal class PatchService : IPatchService { private IPatchManager _patchManager; private IModContext _modContext; - public PatchHelper(IPatchManager patchManager, IModContext mod) + public PatchService(IPatchManager patchManager, IModContext mod) { _patchManager = patchManager; _modContext = mod; } - void IPatchHelper.RegisterInstancePatch(IPatchHelper.PatchType type, MethodBase method, IPatchHelper.InstanceCallback callback) + void IPatchService.RegisterInstancePatch(IPatchService.PatchType type, MethodBase method, IPatchService.InstanceCallback callback) { _patchManager.RegisterInstancePatch(type, _modContext.Mod, method, callback); } - void IPatchHelper.RegisterInstanceVoidPatch(IPatchHelper.PatchType type, MethodBase method, IPatchHelper.InstanceVoidCallback callback) + void IPatchService.RegisterInstanceVoidPatch(IPatchService.PatchType type, MethodBase method, IPatchService.InstanceVoidCallback callback) { _patchManager.RegisterInstanceVoidPatch(type, _modContext.Mod, method, callback); } - void IPatchHelper.RegisterStaticPatch(IPatchHelper.PatchType type, MethodBase method, IPatchHelper.StaticCallback callback) + void IPatchService.RegisterStaticPatch(IPatchService.PatchType type, MethodBase method, IPatchService.StaticCallback callback) { _patchManager.RegisterStaticPatch(type, _modContext.Mod, method, callback); } - void IPatchHelper.RegisterStaticVoidPatch(IPatchHelper.PatchType type, MethodBase method, IPatchHelper.StaticVoidCallback callback) + void IPatchService.RegisterStaticVoidPatch(IPatchService.PatchType type, MethodBase method, IPatchService.StaticVoidCallback callback) { _patchManager.RegisterStaticVoidPatch(type, _modContext.Mod, method, callback); } diff --git a/StarMap.Core/Patches/PatchManager.cs b/StarMap.Core/Patches/PatchManager.cs index 71e5115..b66263d 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 { - void RegisterInstancePatch(IPatchHelper.PatchType patchType, RuntimeMod? mod, MethodBase method, IPatchHelper.InstanceCallback callback); - void RegisterInstanceVoidPatch(IPatchHelper.PatchType patchType, RuntimeMod? mod, MethodBase method, IPatchHelper.InstanceVoidCallback callback); - void RegisterStaticPatch(IPatchHelper.PatchType patchType, RuntimeMod? mod, MethodBase method, IPatchHelper.StaticCallback callback); - void RegisterStaticVoidPatch(IPatchHelper.PatchType patchType, RuntimeMod? mod, MethodBase method, IPatchHelper.StaticVoidCallback callback); + void RegisterInstancePatch(IPatchService.PatchType patchType, RuntimeMod? mod, MethodBase method, IPatchService.InstanceCallback callback); + void RegisterInstanceVoidPatch(IPatchService.PatchType patchType, RuntimeMod? mod, MethodBase method, IPatchService.InstanceVoidCallback callback); + void RegisterStaticPatch(IPatchService.PatchType patchType, RuntimeMod? mod, MethodBase method, IPatchService.StaticCallback callback); + void RegisterStaticVoidPatch(IPatchService.PatchType patchType, RuntimeMod? mod, MethodBase method, IPatchService.StaticVoidCallback callback); } internal class PatchManager : IPatchManager @@ -33,21 +33,21 @@ public PatchManager() _instance = this; } - public void RegisterInstancePatch(IPatchHelper.PatchType patchType, RuntimeMod? mod, MethodBase method, IPatchHelper.InstanceCallback callback) + public void RegisterInstancePatch(IPatchService.PatchType patchType, RuntimeMod? mod, MethodBase method, IPatchService.InstanceCallback callback) { GetOrCreateMethodPatch(method).RegisterPatch(patchType, mod, new InstanceCallback(callback)); } - public void RegisterInstanceVoidPatch(IPatchHelper.PatchType patchType, RuntimeMod? mod, MethodBase method, IPatchHelper.InstanceVoidCallback callback) + public void RegisterInstanceVoidPatch(IPatchService.PatchType patchType, RuntimeMod? mod, MethodBase method, IPatchService.InstanceVoidCallback callback) { GetOrCreateMethodPatch(method).RegisterPatch(patchType, mod, new InstanceVoidCallback(callback)); } - public void RegisterStaticPatch(IPatchHelper.PatchType patchType, RuntimeMod? mod, MethodBase method, IPatchHelper.StaticCallback callback) + public void RegisterStaticPatch(IPatchService.PatchType patchType, RuntimeMod? mod, MethodBase method, IPatchService.StaticCallback callback) { GetOrCreateMethodPatch(method).RegisterPatch(patchType, mod, new StaticCallback(callback)); } - public void RegisterStaticVoidPatch(IPatchHelper.PatchType patchType, RuntimeMod? mod, MethodBase method, IPatchHelper.StaticVoidCallback callback) + public void RegisterStaticVoidPatch(IPatchService.PatchType patchType, RuntimeMod? mod, MethodBase method, IPatchService.StaticVoidCallback callback) { GetOrCreateMethodPatch(method).RegisterPatch(patchType, mod, new StaticVoidCallback(callback)); } @@ -176,7 +176,7 @@ internal interface IResultCallback : IPatchCallback Type ResultType { get; } } - internal class InstanceCallback(IPatchHelper.InstanceCallback callback) : IResultCallback + internal class InstanceCallback(IPatchService.InstanceCallback callback) : IResultCallback { public Type ResultType => typeof(U); @@ -191,7 +191,7 @@ public bool Invoke(object[] args, object? instance, ref object? result) } } - internal class InstanceVoidCallback(IPatchHelper.InstanceVoidCallback callback) : IVoidCallback + internal class InstanceVoidCallback(IPatchService.InstanceVoidCallback callback) : IVoidCallback { public bool Invoke(object[] args, object? instance, ref object? result) { @@ -201,7 +201,7 @@ public bool Invoke(object[] args, object? instance, ref object? result) } } - internal class StaticCallback(IPatchHelper.StaticCallback callback) : IResultCallback + internal class StaticCallback(IPatchService.StaticCallback callback) : IResultCallback { public Type ResultType => typeof(U); @@ -215,7 +215,7 @@ public bool Invoke(object[] args, object? instance, ref object? result) } } - internal class StaticVoidCallback(IPatchHelper.StaticVoidCallback callback) : IVoidCallback + internal class StaticVoidCallback(IPatchService.StaticVoidCallback callback) : IVoidCallback { public bool Invoke(object[] args, object? instance, ref object? result) { @@ -240,7 +240,7 @@ public MethodPatch(Harmony harmony, MethodBase method) _method = method; } - public void RegisterPatch(IPatchHelper.PatchType type, RuntimeMod? mod, IPatchCallback patchCallback) + public void RegisterPatch(IPatchService.PatchType type, RuntimeMod? mod, IPatchCallback patchCallback) { if (patchCallback is IResultCallback resultCallback && GetReturnType() != resultCallback.ResultType) { @@ -251,11 +251,11 @@ public void RegisterPatch(IPatchHelper.PatchType type, RuntimeMod? mod, IPatchCa switch (type) { - case IPatchHelper.PatchType.Prefix: + case IPatchService.PatchType.Prefix: AddPrefix(mod, patchCallback); break; - case IPatchHelper.PatchType.Postfix: + case IPatchService.PatchType.Postfix: AddPostfix(mod, patchCallback); break; @@ -264,15 +264,15 @@ public void RegisterPatch(IPatchHelper.PatchType type, RuntimeMod? mod, IPatchCa }; } - public void UnregisterPatch(IPatchHelper.PatchType type, RuntimeMod? mod) + public void UnregisterPatch(IPatchService.PatchType type, RuntimeMod? mod) { switch (type) { - case IPatchHelper.PatchType.Prefix: + case IPatchService.PatchType.Prefix: RemovePrefix(mod); break; - case IPatchHelper.PatchType.Postfix: + case IPatchService.PatchType.Postfix: RemovePostfix(mod); break; diff --git a/StarMap.Core/Patches/StarMapPatches.cs b/StarMap.Core/Patches/StarMapPatches.cs index afcd9a1..29b4fd9 100644 --- a/StarMap.Core/Patches/StarMapPatches.cs +++ b/StarMap.Core/Patches/StarMapPatches.cs @@ -22,10 +22,10 @@ public StarMapPatches(IPatchManager patchManager) public void Init() { - _patchManager.RegisterStaticVoidPatch(IPatchHelper.PatchType.Prefix, null, typeof(ModLibrary).GetMethod(nameof(ModLibrary.PrepareAll))!, BeforePrepareAll); + _patchManager.RegisterStaticVoidPatch(IPatchService.PatchType.Prefix, null, typeof(ModLibrary).GetMethod(nameof(ModLibrary.PrepareAll))!, BeforePrepareAll); if (DocumentsPathOverride.ShouldApplyOverride()) - _patchManager.RegisterStaticPatch(IPatchHelper.PatchType.Prefix, null, AccessTools.PropertyGetter(typeof(Constants), nameof(Constants.DocumentsFolderPath)), DocumentsPathOverride.BeforeDocumentsFolderPath); + _patchManager.RegisterStaticPatch(IPatchService.PatchType.Prefix, null, AccessTools.PropertyGetter(typeof(Constants), nameof(Constants.DocumentsFolderPath)), DocumentsPathOverride.BeforeDocumentsFolderPath); } private bool BeforePrepareAll(object[] _) diff --git a/StarMap.Core/StarMapCore.cs b/StarMap.Core/StarMapCore.cs index 0ab6b0e..35fa129 100644 --- a/StarMap.Core/StarMapCore.cs +++ b/StarMap.Core/StarMapCore.cs @@ -3,6 +3,7 @@ using StarMap.Core.API; using StarMap.Core.ModRepository; using StarMap.Core.Patches; +using StarMap.Core.UI; using StarMap.Types; using System.Runtime.Loader; @@ -33,9 +34,11 @@ public StarMapCore(AssemblyLoadContext coreAssemblyLoadContext) serviceCollection.AddSingleton(); serviceCollection.AddSingleton(); serviceCollection.AddSingleton(); + serviceCollection.AddSingleton(); serviceCollection.AddScoped(); serviceCollection.AddScoped(); + serviceCollection.AddScoped(); _serviceProvider = serviceCollection.BuildServiceProvider(); } diff --git a/StarMap.Core/UI/ModMenu.cs b/StarMap.Core/UI/ModMenu.cs new file mode 100644 index 0000000..89733b6 --- /dev/null +++ b/StarMap.Core/UI/ModMenu.cs @@ -0,0 +1,109 @@ +using Brutal.ImGuiApi; +using KSA; +using StarMap.API.Interfaces; +using StarMap.Core.ModRepository; +using StarMap.Core.Patches; +using System; +using System.Collections; +using System.Collections.Concurrent; +using System.Collections.Generic; +using System.Reflection; +using System.Reflection.Emit; +using System.Runtime.InteropServices; +using System.Text; + +namespace StarMap.Core.UI +{ + internal interface IModMenu + { + IDisposable AddModMenuButton(string label, Action action); + } + + internal class ModMenu : IModMenu + { + private enum ModMenuAction + { + ADD, + REMOVE, + } + + private readonly IPatchManager _patchManager; + private readonly ConcurrentDictionary _buttons = []; + private readonly string _title; + + public ModMenu(IPatchManager patchManager) + { + _patchManager = patchManager; + + _patchManager.RegisterInstanceVoidPatch( + IPatchHelper.PatchType.Prefix, + null, + typeof(Program).GetMethod("DrawProgramMenusHook")!, + CreateMenu); + + _title = new ImString("Mods"); + } + + private bool CreateMenu(object[] args, T program) where T : Program + { + if (_buttons.Count < 1) + return true; + + + if (ImGui.BeginMenu(_title)) + { + foreach (var (_, button) in _buttons) + { + button.DrawItem(); + } + + ImGui.EndMenu(); + } + + return true; + } + + public IDisposable AddModMenuButton(string label, Action action) + { + if (_buttons.ContainsKey(label)) + throw new Exception($"Modmenu button with label {label} already exists"); + + var newButton = new ModMenuButton(this, label, action); + _buttons.TryAdd(label, newButton); + + + + return newButton; + } + + public void RemoveModMenuButton(string label) + { + _buttons.TryRemove(label, out _); + } + } + + internal class ModMenuButton : IDisposable + { + private readonly ModMenu _menu; + private readonly string _label; + private readonly Action _action; + + public ModMenuButton(ModMenu menu, string label, Action action) + { + _menu = menu; + _label = label; + _action = action; + } + + public void DrawItem() + { + if (ImGui.MenuItem(_label)) + _action(); + } + + public void Dispose() + { + _menu.RemoveModMenuButton(_label); + } + } +} From 786635378079ecb097af2bdb04fdaf60226941fd Mon Sep 17 00:00:00 2001 From: KlaasWhite Date: Sun, 18 Oct 2026 15:43:27 +0200 Subject: [PATCH 2/6] Fix issues --- StarMap.Core/ModRepository/RuntimeMod.cs | 10 +++++----- StarMap.Core/StarMapCore.cs | 4 ++-- StarMap.Core/UI/ModMenu.cs | 2 +- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/StarMap.Core/ModRepository/RuntimeMod.cs b/StarMap.Core/ModRepository/RuntimeMod.cs index 66a00f4..18466e3 100644 --- a/StarMap.Core/ModRepository/RuntimeMod.cs +++ b/StarMap.Core/ModRepository/RuntimeMod.cs @@ -160,7 +160,7 @@ public bool InitializeMod(ModRegistry modRegistry, ICoreService core, IPatchMana modRegistry.AddModMethod(ModId, attr, modObject, classMethod); break; case StarMapAllModsLoadedAttribute: - patchManager.RegisterStaticVoidPatch(IPatchHelper.PatchType.Postfix, this, typeof(KSA.ModLibrary).GetMethod(nameof(ModLibrary.LoadAll))!, + patchManager.RegisterStaticVoidPatch(IPatchService.PatchType.Postfix, this, typeof(KSA.ModLibrary).GetMethod(nameof(ModLibrary.LoadAll))!, args => { classMethod.Invoke(modObject, args); @@ -169,7 +169,7 @@ public bool InitializeMod(ModRegistry modRegistry, ICoreService core, IPatchMana break; case StarMapImmediateLoadAttribute: - patchManager.RegisterInstanceVoidPatch(IPatchHelper.PatchType.Prefix, this, typeof(KSA.Mod).GetMethod(nameof(Mod.PrepareSystems))!, + patchManager.RegisterInstanceVoidPatch(IPatchService.PatchType.Prefix, this, typeof(KSA.Mod).GetMethod(nameof(Mod.PrepareSystems))!, (args, mod) => { if (mod.Id.Equals(ModId)) @@ -179,7 +179,7 @@ public bool InitializeMod(ModRegistry modRegistry, ICoreService core, IPatchMana }); break; case StarMapAfterOnFrameAttribute: - patchManager.RegisterInstanceVoidPatch(IPatchHelper.PatchType.Postfix, this, typeof(Program).GetMethod("OnFrame")!, + patchManager.RegisterInstanceVoidPatch(IPatchService.PatchType.Postfix, this, typeof(Program).GetMethod("OnFrame")!, (args, mod) => { classMethod.Invoke(modObject, [args[0], args[1]]); @@ -188,7 +188,7 @@ public bool InitializeMod(ModRegistry modRegistry, ICoreService core, IPatchMana }); break; case StarMapBeforeGuiAttribute: - patchManager.RegisterInstanceVoidPatch(IPatchHelper.PatchType.Prefix, this, typeof(Program).GetMethod("OnDrawUiFrame", BindingFlags.NonPublic | BindingFlags.Instance)!, + patchManager.RegisterInstanceVoidPatch(IPatchService.PatchType.Prefix, this, typeof(Program).GetMethod("OnDrawUiFrame", BindingFlags.NonPublic | BindingFlags.Instance)!, (args, mod) => { classMethod.Invoke(modObject, [args[0]]); @@ -197,7 +197,7 @@ public bool InitializeMod(ModRegistry modRegistry, ICoreService core, IPatchMana }); break; case StarMapAfterGuiAttribute: - patchManager.RegisterInstanceVoidPatch(IPatchHelper.PatchType.Postfix, this, typeof(Program).GetMethod("OnDrawUiViewports", BindingFlags.NonPublic | BindingFlags.Instance)!, + patchManager.RegisterInstanceVoidPatch(IPatchService.PatchType.Postfix, this, typeof(Program).GetMethod("OnDrawUiViewports", BindingFlags.NonPublic | BindingFlags.Instance)!, (args, mod) => { classMethod.Invoke(modObject, [args[0]]); diff --git a/StarMap.Core/StarMapCore.cs b/StarMap.Core/StarMapCore.cs index 35fa129..332063e 100644 --- a/StarMap.Core/StarMapCore.cs +++ b/StarMap.Core/StarMapCore.cs @@ -37,8 +37,8 @@ public StarMapCore(AssemblyLoadContext coreAssemblyLoadContext) serviceCollection.AddSingleton(); serviceCollection.AddScoped(); - serviceCollection.AddScoped(); - serviceCollection.AddScoped(); + serviceCollection.AddScoped(); + serviceCollection.AddScoped(); _serviceProvider = serviceCollection.BuildServiceProvider(); } diff --git a/StarMap.Core/UI/ModMenu.cs b/StarMap.Core/UI/ModMenu.cs index 89733b6..d437ec7 100644 --- a/StarMap.Core/UI/ModMenu.cs +++ b/StarMap.Core/UI/ModMenu.cs @@ -36,7 +36,7 @@ public ModMenu(IPatchManager patchManager) _patchManager = patchManager; _patchManager.RegisterInstanceVoidPatch( - IPatchHelper.PatchType.Prefix, + IPatchService.PatchType.Prefix, null, typeof(Program).GetMethod("DrawProgramMenusHook")!, CreateMenu); From abeab18108b132eb355788e1ef41f2ccf3042398 Mon Sep 17 00:00:00 2001 From: KlaasWhite Date: Sun, 18 Oct 2026 16:32:04 +0200 Subject: [PATCH 3/6] Make item adding atomic and fix warnings --- NuGet.Config | 15 +++++++++++++++ StarMap.API/StarMap.API.csproj | 1 + StarMap.Core/StarMap.Core.csproj | 1 + StarMap.Core/UI/ConfirmRestart/ConfirmRestart.cs | 5 ++++- StarMap.Core/UI/ModMenu.cs | 9 +++------ StarMap/StarMap.csproj | 1 + 6 files changed, 25 insertions(+), 7 deletions(-) create mode 100644 NuGet.Config diff --git a/NuGet.Config b/NuGet.Config new file mode 100644 index 0000000..136b071 --- /dev/null +++ b/NuGet.Config @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + + diff --git a/StarMap.API/StarMap.API.csproj b/StarMap.API/StarMap.API.csproj index 2ea71cd..3c59070 100644 --- a/StarMap.API/StarMap.API.csproj +++ b/StarMap.API/StarMap.API.csproj @@ -2,6 +2,7 @@ net10.0 + x64 enable enable true diff --git a/StarMap.Core/StarMap.Core.csproj b/StarMap.Core/StarMap.Core.csproj index d7005e2..b83fbe3 100644 --- a/StarMap.Core/StarMap.Core.csproj +++ b/StarMap.Core/StarMap.Core.csproj @@ -1,6 +1,7 @@  net10.0 + x64 enable enable Debug;Release;SourceNuget diff --git a/StarMap.Core/UI/ConfirmRestart/ConfirmRestart.cs b/StarMap.Core/UI/ConfirmRestart/ConfirmRestart.cs index 17cadde..f6de530 100644 --- a/StarMap.Core/UI/ConfirmRestart/ConfirmRestart.cs +++ b/StarMap.Core/UI/ConfirmRestart/ConfirmRestart.cs @@ -57,6 +57,9 @@ public unsafe void OnFrame() ImGui.UpdatePlatformWindows(); ImGui.RenderPlatformWindowsDefault(); } + var clearValues = Program.MainPass.ClearValues; + if (clearValues is null) + return; (FrameResult result, AcquiredFrame acquiredFrame1) = _renderer.TryAcquireNextFrame(); AcquiredFrame acquiredFrame2 = acquiredFrame1; if (result != 0) @@ -73,7 +76,7 @@ public unsafe void OnFrame() RenderPass = Program.MainPass.Pass, Framebuffer = resources.Framebuffer, RenderArea = new VkRect2D(this._renderer.Extent), - ClearValues = (VkClearValue*)Program.MainPass.ClearValues.Ptr, + ClearValues = (VkClearValue*)clearValues.Ptr, ClearValueCount = 2 }; commandBuffer.Reset(); diff --git a/StarMap.Core/UI/ModMenu.cs b/StarMap.Core/UI/ModMenu.cs index d437ec7..516dfd2 100644 --- a/StarMap.Core/UI/ModMenu.cs +++ b/StarMap.Core/UI/ModMenu.cs @@ -65,13 +65,10 @@ private bool CreateMenu(object[] args, T program) where T : Program public IDisposable AddModMenuButton(string label, Action action) { - if (_buttons.ContainsKey(label)) - throw new Exception($"Modmenu button with label {label} already exists"); - - var newButton = new ModMenuButton(this, label, action); - _buttons.TryAdd(label, newButton); + var newButton = new ModMenuButton(this, label, action); - + if (!_buttons.TryAdd(label, newButton)) + throw new Exception($"Modmenu button with label {label} already exists"); return newButton; } diff --git a/StarMap/StarMap.csproj b/StarMap/StarMap.csproj index 8758fd0..e7ed6d5 100644 --- a/StarMap/StarMap.csproj +++ b/StarMap/StarMap.csproj @@ -2,6 +2,7 @@ Exe net10.0 + x64 enable enable Debug;Release;SourceNuget From 4f7a7372214bce2e99d5b8c1b66854b50be99d3b Mon Sep 17 00:00:00 2001 From: KlaasWhite Date: Sun, 18 Oct 2026 16:43:36 +0200 Subject: [PATCH 4/6] Fix workflows --- .github/workflows/pr-build.yml | 4 ++-- .github/workflows/rc-build.yml | 6 +++--- .github/workflows/release.yml | 4 ++-- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/.github/workflows/pr-build.yml b/.github/workflows/pr-build.yml index 36ee228..81d898b 100644 --- a/.github/workflows/pr-build.yml +++ b/.github/workflows/pr-build.yml @@ -17,7 +17,7 @@ jobs: if: github.event.pull_request.head.repo.full_name == github.repository runs-on: ubuntu-latest env: - DOTNET_VERSION: 9.0 + DOTNET_VERSION: 10.0 PROJECT: StarMap/StarMap.csproj NUGET_SOURCE: "https://nuget.pkg.github.com/${{ github.repository_owner }}/index.json" @@ -32,7 +32,7 @@ jobs: - name: Restore dependencies run: | - dotnet nuget add source --username "${{ secrets.ORG_PACKAGE_USERNAME }}" --password "${{ secrets.ORG_PACKAGE_TOKEN }}" --store-password-in-clear-text --name github "${{ env.NUGET_SOURCE }}" + dotnet nuget add source --username "${{ secrets.ORG_PACKAGE_USERNAME }}" --password "${{ secrets.ORG_PACKAGE_TOKEN }}" --store-password-in-clear-text --name StarMapGitHubNugetSource "${{ env.NUGET_SOURCE }}" dotnet restore ${{ env.PROJECT }} - name: Build diff --git a/.github/workflows/rc-build.yml b/.github/workflows/rc-build.yml index 42ce53e..8b0ec6c 100644 --- a/.github/workflows/rc-build.yml +++ b/.github/workflows/rc-build.yml @@ -70,7 +70,7 @@ jobs: --username ${{ secrets.ORG_PACKAGE_USERNAME }} \ --password ${{ secrets.ORG_PACKAGE_TOKEN }} \ --store-password-in-clear-text \ - --name github "${{ env.NUGET_SOURCE }}" + --name StarMapGitHubNugetSource "${{ env.NUGET_SOURCE }}" - name: Build run: | @@ -120,7 +120,7 @@ jobs: --username ${{ secrets.ORG_PACKAGE_USERNAME }} \ --password ${{ secrets.ORG_PACKAGE_TOKEN }} \ --store-password-in-clear-text \ - --name github "${{ env.NUGET_SOURCE }}" + --name StarMapGitHubNugetSource "${{ env.NUGET_SOURCE }}" - name: Pack and push RC NuGet package run: | @@ -132,7 +132,7 @@ jobs: /p:Version=${{ needs.build.outputs.new_version }} \ /p:InformationalVersion=${{ needs.build.outputs.hash_version }} dotnet nuget push ./nupkg/*.nupkg \ - --source github \ + --source StarMapGitHubNugetSource \ --api-key "${{ secrets.GITHUB_TOKEN }}" \ --skip-duplicate diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 5841bea..87e73fe 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -81,7 +81,7 @@ jobs: --username ${{ secrets.ORG_PACKAGE_USERNAME }} \ --password ${{ secrets.ORG_PACKAGE_TOKEN }} \ --store-password-in-clear-text \ - --name github "${{ env.NUGET_SOURCE }}" + --name StarMapGitHubNugetSource "${{ env.NUGET_SOURCE }}" - name: Build standalone run: | @@ -159,7 +159,7 @@ jobs: --username ${{ secrets.ORG_PACKAGE_USERNAME }} \ --password ${{ secrets.ORG_PACKAGE_TOKEN }} \ --store-password-in-clear-text \ - --name github "${{ env.NUGET_SOURCE }}" + --name StarMapGitHubNugetSource "${{ env.NUGET_SOURCE }}" - name: Pack and push StarMap.API (if changed) run: | From 615a0b21c63f65a04626eee8d01dd34e8f2a22c3 Mon Sep 17 00:00:00 2001 From: KlaasWhite Date: Sun, 18 Oct 2026 16:45:50 +0200 Subject: [PATCH 5/6] Change --- StarMap.Core/UI/ConfirmRestart/ConfirmRestart.cs | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/StarMap.Core/UI/ConfirmRestart/ConfirmRestart.cs b/StarMap.Core/UI/ConfirmRestart/ConfirmRestart.cs index f6de530..59d904b 100644 --- a/StarMap.Core/UI/ConfirmRestart/ConfirmRestart.cs +++ b/StarMap.Core/UI/ConfirmRestart/ConfirmRestart.cs @@ -57,9 +57,6 @@ public unsafe void OnFrame() ImGui.UpdatePlatformWindows(); ImGui.RenderPlatformWindowsDefault(); } - var clearValues = Program.MainPass.ClearValues; - if (clearValues is null) - return; (FrameResult result, AcquiredFrame acquiredFrame1) = _renderer.TryAcquireNextFrame(); AcquiredFrame acquiredFrame2 = acquiredFrame1; if (result != 0) @@ -76,7 +73,7 @@ public unsafe void OnFrame() RenderPass = Program.MainPass.Pass, Framebuffer = resources.Framebuffer, RenderArea = new VkRect2D(this._renderer.Extent), - ClearValues = (VkClearValue*)clearValues.Ptr, + ClearValues = (VkClearValue*)Program.MainPass.ClearValues!.Ptr, ClearValueCount = 2 }; commandBuffer.Reset(); From 006c81a449c0400c565a0dd072566dce7c1c012e Mon Sep 17 00:00:00 2001 From: KlaasWhite Date: Sun, 18 Oct 2026 16:51:16 +0200 Subject: [PATCH 6/6] Make dispose idempotent --- StarMap.Core/UI/ModMenu.cs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/StarMap.Core/UI/ModMenu.cs b/StarMap.Core/UI/ModMenu.cs index 516dfd2..f09d18d 100644 --- a/StarMap.Core/UI/ModMenu.cs +++ b/StarMap.Core/UI/ModMenu.cs @@ -85,6 +85,8 @@ internal class ModMenuButton : IDisposable private readonly string _label; private readonly Action _action; + private bool _disposed; + public ModMenuButton(ModMenu menu, string label, Action action) { _menu = menu; @@ -100,6 +102,11 @@ public void DrawItem() public void Dispose() { + var disposed = Interlocked.Exchange(ref _disposed, true); + + if (disposed) + return; + _menu.RemoveModMenuButton(_label); } }