From 047220e8e4d46bc4dad41875ce3b5cedef79438d Mon Sep 17 00:00:00 2001 From: KlaasWhite Date: Sat, 15 Nov 2025 19:33:31 +0100 Subject: [PATCH 1/3] Refactor + IStarMapOnUi --- .github/workflows/release-zip.yml | 11 +- StarMap.API/IStarMapInterface.cs | 6 + StarMap.API/IStarMapMod.cs | 4 +- StarMap.API/IStarMapOnUi.cs | 8 ++ StarMap.Core/{ => Legacy}/ModManagerScreen.cs | 0 StarMap.Core/ModLoaderPatcher.cs | 42 ------ StarMap.Core/ModManager.cs | 134 ------------------ .../ModRepository/LoadedModRepository.cs | 93 ++++++++++++ StarMap.Core/ModRepository/ModRegistry.cs | 58 ++++++++ StarMap.Core/Patches/ModLibraryPatches.cs | 16 +++ StarMap.Core/Patches/ModPatches.cs | 16 +++ StarMap.Core/Patches/ProgramPatcher.cs | 36 +++++ StarMap.Core/StarMapCore.cs | 94 ++++++++++++ StarMap.Types/LoaderConfig.cs | 2 +- .../Mods/{IModManager.cs => IStarMapCore.cs} | 2 +- StarMap/GameSurveyer.cs | 32 +++-- StarMap/Program.cs | 17 ++- .../{DumbGameFacade.cs => SoloGameFacade.cs} | 2 +- 18 files changed, 368 insertions(+), 205 deletions(-) create mode 100644 StarMap.API/IStarMapInterface.cs create mode 100644 StarMap.API/IStarMapOnUi.cs rename StarMap.Core/{ => Legacy}/ModManagerScreen.cs (100%) delete mode 100644 StarMap.Core/ModLoaderPatcher.cs delete mode 100644 StarMap.Core/ModManager.cs create mode 100644 StarMap.Core/ModRepository/LoadedModRepository.cs create mode 100644 StarMap.Core/ModRepository/ModRegistry.cs create mode 100644 StarMap.Core/Patches/ModLibraryPatches.cs create mode 100644 StarMap.Core/Patches/ModPatches.cs create mode 100644 StarMap.Core/Patches/ProgramPatcher.cs create mode 100644 StarMap.Core/StarMapCore.cs rename StarMap.Types/Mods/{IModManager.cs => IStarMapCore.cs} (78%) rename StarMap/{DumbGameFacade.cs => SoloGameFacade.cs} (88%) diff --git a/.github/workflows/release-zip.yml b/.github/workflows/release-zip.yml index 414803e..46b6c20 100644 --- a/.github/workflows/release-zip.yml +++ b/.github/workflows/release-zip.yml @@ -118,6 +118,9 @@ jobs: exit 0 fi + echo "DEBUG: Previous tag: $prev" + echo "DEBUG: Current commit: $current" + diff=$(git diff --name-only "$prev" "$current") echo "diff_files=$diff" >> $GITHUB_OUTPUT @@ -131,6 +134,12 @@ jobs: if: steps.api_check.outputs.changed == 'true' run: | dotnet restore StarMap.API/StarMap.API.csproj - dotnet pack StarMap.API/StarMap.API.csproj -c Release -o ./nupkg /p:PackageVersion=${{ steps.version.outputs.new }} + dotnet pack \ + -c Release \ + -o ./nupkg \ + /p:PackageVersion=${{ steps.version.outputs.new }} \ + /p:Version=${{ steps.version.outputs.new }} \ + /p:AssemblyVersion=${{ steps.version.outputs.new }} \ + /p:FileVersion=${{ steps.version.outputs.new }} dotnet nuget add source --username "${{ github.actor }}" --password "${{ secrets.GITHUB_TOKEN }}" --store-password-in-clear-text --name github "${{ env.NUGET_SOURCE }}" dotnet nuget push ./nupkg/*.nupkg --source github --api-key "${{ secrets.GITHUB_TOKEN }}" --skip-duplicate diff --git a/StarMap.API/IStarMapInterface.cs b/StarMap.API/IStarMapInterface.cs new file mode 100644 index 0000000..0d1d329 --- /dev/null +++ b/StarMap.API/IStarMapInterface.cs @@ -0,0 +1,6 @@ +namespace StarMap.API +{ + public interface IStarMapInterface + { + } +} diff --git a/StarMap.API/IStarMapMod.cs b/StarMap.API/IStarMapMod.cs index c6411bf..7bfe317 100644 --- a/StarMap.API/IStarMapMod.cs +++ b/StarMap.API/IStarMapMod.cs @@ -1,6 +1,6 @@ -namespace StarMap.Types +namespace StarMap.API { - public interface IStarMapMod + public interface IStarMapMod : IStarMapInterface { bool ImmediateUnload { get; } void OnImmediatLoad(); diff --git a/StarMap.API/IStarMapOnUi.cs b/StarMap.API/IStarMapOnUi.cs new file mode 100644 index 0000000..1b590ca --- /dev/null +++ b/StarMap.API/IStarMapOnUi.cs @@ -0,0 +1,8 @@ +namespace StarMap.API +{ + public interface IStarMapOnUi : IStarMapInterface + { + void OnBeforeUi(double dt); + void OnAfterUi(double dt); + } +} diff --git a/StarMap.Core/ModManagerScreen.cs b/StarMap.Core/Legacy/ModManagerScreen.cs similarity index 100% rename from StarMap.Core/ModManagerScreen.cs rename to StarMap.Core/Legacy/ModManagerScreen.cs diff --git a/StarMap.Core/ModLoaderPatcher.cs b/StarMap.Core/ModLoaderPatcher.cs deleted file mode 100644 index 77f48f9..0000000 --- a/StarMap.Core/ModLoaderPatcher.cs +++ /dev/null @@ -1,42 +0,0 @@ -using KSA; -using HarmonyLib; - -namespace StarMap.Core -{ - [HarmonyPatch] - internal static class ModLoaderPatcher - { - private static ModManager? _modManager; - private readonly static Harmony? _harmony = new Harmony("StarMap.Core.ModLoaderPatcher"); - - public static void Patch(ModManager modManager) - { - _modManager = modManager; - _harmony?.PatchAll(); - - // Currently needed to force patch in release mode - Harmony.GetAllPatchedMethods(); - } - - public static void Unload() - { - _modManager = null; - _harmony?.UnpatchAll(); - } - - [HarmonyPatch(typeof(Mod), nameof(Mod.PrepareSystems))] - [HarmonyPrefix] - public static void OnLoadMod(this Mod __instance) - { - _modManager?.LoadMod(__instance); - } - - [HarmonyPatch(typeof(ModLibrary), nameof(ModLibrary.LoadAll))] - [HarmonyPostfix] - public static void AfterLoad() - { - _modManager?.OnAllModsLoaded(); - _harmony?.UnpatchAll(_harmony.Id); - } - } -} diff --git a/StarMap.Core/ModManager.cs b/StarMap.Core/ModManager.cs deleted file mode 100644 index 2f7ab31..0000000 --- a/StarMap.Core/ModManager.cs +++ /dev/null @@ -1,134 +0,0 @@ - -using KSA; -using HarmonyLib; -using StarMap.Types; -using StarMap.Types.Mods; -using StarMap.Types.Proto.IPC; -using System.Reflection; -using System.Runtime.Loader; - -namespace StarMap.Core -{ - internal class ModManager : IModManager - { - private readonly AssemblyLoadContext _coreAssemblyLoadContext; - private readonly IGameFacade _gameFacade; - - private readonly TaskCompletionSource _managedMods = new(); - private readonly Dictionary _loadedMods = []; - - public ModManager(AssemblyLoadContext coreAssemblyLoadContext, IGameFacade gameFacade) - { - _coreAssemblyLoadContext = coreAssemblyLoadContext; - _gameFacade = gameFacade; - } - - public void Init() - { - _ = RetrieveManagedMods(); - - ModLoaderPatcher.Patch(this); - } - - public void DeInit() { - ModLoaderPatcher.Unload(); - - foreach (var mod in _loadedMods.Values) - { - mod.mod.Unload(); - } - - _loadedMods.Clear(); - } - - public void LoadMod(Mod mod) - { - var fullPath = Path.GetFullPath(mod.DirectoryPath); - var filePath = Path.Combine(fullPath, $"{mod.Name}.dll"); - var folderExists = Directory.Exists(fullPath); - var fileExists = File.Exists(filePath); - - if (!folderExists || !fileExists) return; - - var modLoadContext = new ModAssemblyLoadContext(mod, _coreAssemblyLoadContext); - var modAssembly = modLoadContext.LoadFromAssemblyName(new AssemblyName() { Name = mod.Name }); - - var loadedMod = modAssembly.GetTypes().FirstOrDefault((type) => typeof(IStarMapMod).IsAssignableFrom(type) && !type.IsInterface).CreateInstance(); - if (loadedMod is not IStarMapMod starMapMod) return; - - starMapMod.OnImmediatLoad(); - - if (starMapMod.ImmediateUnload) - { - modLoadContext.Unload(); - return; - } - - Console.WriteLine($"Loaded mod: {mod.Name}"); - - _loadedMods[mod] = (starMapMod, modLoadContext); - return; - } - - public void OnAllModsLoaded() - { - foreach (var (mod, _) in _loadedMods.Values) - { - mod.OnFullyLoaded(); - } - } - - public async Task RetrieveManagedMods() - { - var message = new IPCGetCurrentManagedModsRequest(); - - var response = await _gameFacade.RequestData(message); - - if (!response.Is(IPCGetCurrentManagedModsResponse.Descriptor)) return; - - _managedMods.SetResult(response.Unpack()); - } - - public IPCGetCurrentManagedModsResponse GetManagedMods() - { - return _managedMods.Task.GetAwaiter().GetResult(); - } - - public async Task GetAvailableModsAsync() - { - var message = new IPCGetModsRequest(); - - var response = await _gameFacade.RequestData(message); - - if (!response.Is(IPCGetModsResponse.Descriptor)) return[]; - - return [.. response.Unpack().Mods]; - } - - public async Task GetModInformationAsync(string id) - { - var message = new IPCGetModDetailsRequest() - { - Id = id - }; - - var response = await _gameFacade.RequestData(message); - - if (!response.Is(IPCGetModDetailsResponse.Descriptor)) return null; - - return response.Unpack().Mod; - } - - public string[] GetLoadedMods() - { - if (_loadedMods is null) return []; - - return _loadedMods.Select(loadedMod => loadedMod.Key.Name).ToArray(); - } - - public async Task SetModUpdates(IPCSetManagedMods update) - { - await _gameFacade.RequestData(update); - } - } -} diff --git a/StarMap.Core/ModRepository/LoadedModRepository.cs b/StarMap.Core/ModRepository/LoadedModRepository.cs new file mode 100644 index 0000000..4d13ce9 --- /dev/null +++ b/StarMap.Core/ModRepository/LoadedModRepository.cs @@ -0,0 +1,93 @@ +using HarmonyLib; +using KSA; +using StarMap.API; +using System.Reflection; +using System.Runtime.Loader; + +namespace StarMap.Core.ModRepository +{ + internal class LoadedModRepository : IDisposable + { + private readonly AssemblyLoadContext _coreAssemblyLoadContext; + private readonly IEnumerable _registeredInterfaces = []; + + private readonly ModRegistry _mods = new(); + public ModRegistry Mods => _mods; + + public LoadedModRepository(AssemblyLoadContext coreAssemblyLoadContext) + { + _coreAssemblyLoadContext = coreAssemblyLoadContext; + + var baseInterface = typeof(IStarMapInterface); + Assembly starMapTypes = baseInterface.Assembly; + + _registeredInterfaces = starMapTypes + .GetTypes() + .Where( + t => t.IsInterface && + baseInterface.IsAssignableFrom(t) && + t != baseInterface); + } + + private bool IsStarMapMod(Type type) + { + return typeof(IStarMapMod).IsAssignableFrom(type) && !type.IsInterface; + } + + public void LoadMod(Mod mod) + { + var fullPath = Path.GetFullPath(mod.DirectoryPath); + var filePath = Path.Combine(fullPath, $"{mod.Name}.dll"); + var folderExists = Directory.Exists(fullPath); + var fileExists = File.Exists(filePath); + + if (!folderExists || !fileExists) return; + + var modLoadContext = new ModAssemblyLoadContext(mod, _coreAssemblyLoadContext); + var modAssembly = modLoadContext.LoadFromAssemblyName(new AssemblyName() { Name = mod.Name }); + + var modClass = modAssembly.GetTypes().FirstOrDefault(IsStarMapMod); + if (modClass is null) return; + + if (modClass.CreateInstance() is not IStarMapInterface modObject) return; + + foreach (var interfaceType in _registeredInterfaces) + { + if (interfaceType.IsAssignableFrom(modClass)) + { + _mods.Add(interfaceType, modObject); + } + } + + if (modObject is not IStarMapMod starMapMod) return; + + starMapMod.OnImmediatLoad(); + + if (starMapMod.ImmediateUnload) + { + modLoadContext.Unload(); + return; + } + + Console.WriteLine($"Loaded mod: {mod.Name}"); + } + + public void OnAllModsLoaded() + { + foreach (var mod in _mods.Get()) + { + mod.OnFullyLoaded(); + } + } + + public void Dispose() + { + foreach (var mod in _mods.Get()) + { + mod.Unload(); + } + + _mods.Dispose(); + } + } +} diff --git a/StarMap.Core/ModRepository/ModRegistry.cs b/StarMap.Core/ModRepository/ModRegistry.cs new file mode 100644 index 0000000..1a7cabd --- /dev/null +++ b/StarMap.Core/ModRepository/ModRegistry.cs @@ -0,0 +1,58 @@ +using StarMap.API; + +namespace StarMap.Core.ModRepository +{ + internal sealed class ModRegistry : IDisposable + { + private readonly Dictionary> _map = new(); + + public void Add(Type iface, IStarMapInterface instance) + { + // --- type-safety checks --- + if (!typeof(IStarMapInterface).IsAssignableFrom(iface) || !iface.IsInterface) + throw new ArgumentException($"{iface} is not an interface inheriting {typeof(IStarMapInterface).Name}"); + + if (instance is null) + throw new ArgumentNullException(nameof(instance)); + + Type implType = instance.GetType(); + + if (!iface.IsAssignableFrom(implType)) + throw new ArgumentException( + $"{implType.Name} does not implement {iface.Name}" + ); + + // --- add instance --- + if (!_map.TryGetValue(iface, out var list)) + { + list = []; + _map[iface] = list; + } + + list.Add(instance); + } + + public IReadOnlyList Get() + where TInterface : IStarMapInterface + { + if (_map.TryGetValue(typeof(TInterface), out var list)) + { + return list.Cast().ToList(); + } + + return Array.Empty(); + } + + public IReadOnlyList Get(Type iface) + { + return _map.TryGetValue(iface, out var list) + ? list + : Array.Empty(); + } + + public void Dispose() + { + _map.Clear(); + } + } +} diff --git a/StarMap.Core/Patches/ModLibraryPatches.cs b/StarMap.Core/Patches/ModLibraryPatches.cs new file mode 100644 index 0000000..cb87311 --- /dev/null +++ b/StarMap.Core/Patches/ModLibraryPatches.cs @@ -0,0 +1,16 @@ +using HarmonyLib; +using KSA; + +namespace StarMap.Core.Patches +{ + [HarmonyPatch(typeof(ModLibrary))] + internal class ModLibraryPatches + { + [HarmonyPatch(nameof(ModLibrary.LoadAll))] + [HarmonyPostfix] + public static void AfterLoad() + { + StarMapCore.Instance?.LoadedMods.OnAllModsLoaded(); + } + } +} diff --git a/StarMap.Core/Patches/ModPatches.cs b/StarMap.Core/Patches/ModPatches.cs new file mode 100644 index 0000000..7934da2 --- /dev/null +++ b/StarMap.Core/Patches/ModPatches.cs @@ -0,0 +1,16 @@ +using HarmonyLib; +using KSA; + +namespace StarMap.Core.Patches +{ + [HarmonyPatch(typeof(Mod))] + internal static class ModPatches + { + [HarmonyPatch(nameof(Mod.PrepareSystems))] + [HarmonyPrefix] + public static void OnLoadMod(this Mod __instance) + { + StarMapCore.Instance?.LoadedMods.LoadMod(__instance); + } + } +} diff --git a/StarMap.Core/Patches/ProgramPatcher.cs b/StarMap.Core/Patches/ProgramPatcher.cs new file mode 100644 index 0000000..260fc94 --- /dev/null +++ b/StarMap.Core/Patches/ProgramPatcher.cs @@ -0,0 +1,36 @@ +using HarmonyLib; +using KSA; +using StarMap.API; + +namespace StarMap.Core.Patches +{ + [HarmonyPatch(typeof(Program))] + internal static class ProgramPatcher + { + private const string OnDrawUiMethodName = "OnDrawUi"; + + [HarmonyPatch(OnDrawUiMethodName)] + [HarmonyPrefix] + public static void BeforeOnDrawUi(double dt) + { + var mods = StarMapCore.Instance?.LoadedMods.Mods.Get() ?? []; + + foreach (var mod in mods) + { + mod.OnBeforeUi(dt); + } + } + + [HarmonyPatch(OnDrawUiMethodName)] + [HarmonyPostfix] + public static void AfterOnDrawUi(double dt) + { + var mods = StarMapCore.Instance?.LoadedMods.Mods.Get() ?? []; + + foreach (var mod in mods) + { + mod.OnAfterUi(dt); + } + } + } +} diff --git a/StarMap.Core/StarMapCore.cs b/StarMap.Core/StarMapCore.cs new file mode 100644 index 0000000..f625fd4 --- /dev/null +++ b/StarMap.Core/StarMapCore.cs @@ -0,0 +1,94 @@ +using HarmonyLib; +using StarMap.Core.ModRepository; +using StarMap.Types.Mods; +using System.Runtime.Loader; + +namespace StarMap.Core +{ + internal class StarMapCore : IStarMapCore + { + public static StarMapCore? Instance; + + private readonly Harmony _harmony = new("StarMap.Core"); + private readonly AssemblyLoadContext _coreAssemblyLoadContext; + + private readonly LoadedModRepository _loadedMods; + public LoadedModRepository LoadedMods => _loadedMods; + + public StarMapCore(AssemblyLoadContext coreAssemblyLoadContext) + { + Instance = this; + _coreAssemblyLoadContext = coreAssemblyLoadContext; + _loadedMods = new(_coreAssemblyLoadContext); + } + + public void Init() + { + _harmony.PatchAll(); + } + + public void DeInit() + { + _harmony.UnpatchAll(); + _loadedMods.Dispose(); + } + } +} + +/*public async Task RetrieveManagedMods() +{ + var message = new IPCGetCurrentManagedModsRequest(); + + var response = await _gameFacade.RequestData(message); + + if (!response.Is(IPCGetCurrentManagedModsResponse.Descriptor)) return; + + _managedMods.SetResult(response.Unpack()); +} + +public IPCGetCurrentManagedModsResponse GetManagedMods() +{ + return _managedMods.Task.GetAwaiter().GetResult(); +} + +public async Task GetAvailableModsAsync() +{ + var message = new IPCGetModsRequest(); + + var response = await _gameFacade.RequestData(message); + + if (!response.Is(IPCGetModsResponse.Descriptor)) return []; + + return [.. response.Unpack().Mods]; +} + +public async Task GetModInformationAsync(string id) +{ + var message = new IPCGetModDetailsRequest() + { + Id = id + }; + + var response = await _gameFacade.RequestData(message); + + if (!response.Is(IPCGetModDetailsResponse.Descriptor)) return null; + + return response.Unpack().Mod; +} + +public string[] GetLoadedMods() +{ + if (_loadedMods is null) return []; + + return _loadedMods.Select(loadedMod => loadedMod.Key.Name).ToArray(); +} + +public async Task SetModUpdates(IPCSetManagedMods update) +{ + await _gameFacade.RequestData(update); +} + + //private readonly IGameFacade _gameFacade; + + //private readonly TaskCompletionSource _managedMods = new(); +*/ \ No newline at end of file diff --git a/StarMap.Types/LoaderConfig.cs b/StarMap.Types/LoaderConfig.cs index 4ed0594..370b273 100644 --- a/StarMap.Types/LoaderConfig.cs +++ b/StarMap.Types/LoaderConfig.cs @@ -22,7 +22,7 @@ public bool TryLoadConfig() } var jsonString = File.ReadAllText("./StarMapConfig.json"); - var config = System.Text.Json.JsonSerializer.Deserialize(jsonString); + var config = JsonSerializer.Deserialize(jsonString); if (config is null) return false; diff --git a/StarMap.Types/Mods/IModManager.cs b/StarMap.Types/Mods/IStarMapCore.cs similarity index 78% rename from StarMap.Types/Mods/IModManager.cs rename to StarMap.Types/Mods/IStarMapCore.cs index fd38178..8eac83e 100644 --- a/StarMap.Types/Mods/IModManager.cs +++ b/StarMap.Types/Mods/IStarMapCore.cs @@ -2,7 +2,7 @@ namespace StarMap.Types.Mods { - public interface IModManager + public interface IStarMapCore { void Init(); void DeInit(); diff --git a/StarMap/GameSurveyer.cs b/StarMap/GameSurveyer.cs index 07eaa6f..08e531a 100644 --- a/StarMap/GameSurveyer.cs +++ b/StarMap/GameSurveyer.cs @@ -1,6 +1,5 @@ using StarMap.Types.Mods; using System.Diagnostics; -using System.Diagnostics.CodeAnalysis; using System.Reflection; using System.Runtime.Loader; @@ -13,7 +12,7 @@ internal class GameSurveyer : IDisposable private readonly string _gameLocation; private Assembly? _game; - private IModManager? _modManager; + private IStarMapCore? _core; public GameSurveyer(IGameFacade facade, AssemblyLoadContext alc, string location) { @@ -22,22 +21,19 @@ public GameSurveyer(IGameFacade facade, AssemblyLoadContext alc, string location _gameLocation = location; } - public bool TryLoadModManagerAndGame([NotNullWhen(true)] out IModManager? modManager) + public bool TryLoadCoreAndGame() { - modManager = null; - var modManagerAssembly = _gameAssemblyContext.LoadFromAssemblyPath(Path.GetFullPath("./StarMap.Core.dll")); - var modManagerType = modManagerAssembly.GetTypes().FirstOrDefault((type) => typeof(IModManager).IsAssignableFrom(type) && !type.IsInterface); - if (modManagerType is null) return false; - var createdModManager = Activator.CreateInstance(modManagerType, [_gameAssemblyContext, _facade]); - if (createdModManager is not IModManager manager) return false; + var starMapCore = modManagerAssembly.GetTypes().FirstOrDefault((type) => typeof(IStarMapCore).IsAssignableFrom(type) && !type.IsInterface); + if (starMapCore is null) return false; + var createdCore = Activator.CreateInstance(starMapCore, [_gameAssemblyContext]); + if (createdCore is not IStarMapCore core) return false; _game = _gameAssemblyContext.LoadFromAssemblyPath(_gameLocation); - _modManager = manager; - manager.Init(); - modManager = manager; + _core = core; + core.Init(); return true; } @@ -46,14 +42,22 @@ public void RunGame() Debug.Assert(_game is not null, "Load needs to be called before running game"); string[] args = []; - Directory.SetCurrentDirectory(Path.GetDirectoryName(_gameLocation)); + + var gameDirectory = Path.GetDirectoryName(_gameLocation); + if (string.IsNullOrWhiteSpace(gameDirectory) || !Directory.Exists(gameDirectory)) + { + Console.WriteLine("StarMap - Game directory not found"); + return; + } + + Directory.SetCurrentDirectory(gameDirectory); _game.EntryPoint!.Invoke(null, [args]); } public void Dispose() { _gameAssemblyContext.Unload(); - _modManager?.DeInit(); + _core?.DeInit(); } } } diff --git a/StarMap/Program.cs b/StarMap/Program.cs index 088b933..de2ac49 100644 --- a/StarMap/Program.cs +++ b/StarMap/Program.cs @@ -1,6 +1,5 @@ using StarMap.Types; using StarMap.Types.Pipes; -using StarMap.Types.Proto.IPC; using System.Runtime.Loader; namespace StarMap @@ -11,12 +10,12 @@ static void Main(string[] args) { if (args.Length < 1) { - Console.WriteLine("Running Starmap in dumb mode!"); - DumbModeInner(); + Console.WriteLine("StarMapLoader - Running Starmap in solo mode!"); + SoleModeInner(); return; } - Console.WriteLine("Running Starmap normally."); + Console.WriteLine("Running Starmap in loader mode."); var pipeName = args[0]; Console.WriteLine($"Connection to pipe: {pipeName}"); @@ -24,7 +23,7 @@ static void Main(string[] args) MainInner(pipeName).GetAwaiter().GetResult(); } - static void DumbModeInner() + static void SoleModeInner() { var gameConfig = new LoaderConfig(); @@ -36,11 +35,11 @@ static void DumbModeInner() AssemblyLoadContext.Default.LoadFromAssemblyPath(Path.GetFullPath("./0Harmony.dll")); var gameAssemblyContext = new GameAssemblyLoadContext(gameConfig.GameLocation); - var dumbFacade = new DumbGameFacade(); + var dumbFacade = new SoloGameFacade(); var gameSurveyer = new GameSurveyer(dumbFacade, gameAssemblyContext, gameConfig.GameLocation); - if (!gameSurveyer.TryLoadModManagerAndGame(out _)) + if (!gameSurveyer.TryLoadCoreAndGame()) { - Console.WriteLine("Unable to load mod manager and game in dumb mode."); + Console.WriteLine("Unable to load mod manager and game in solo mode."); return; } @@ -57,7 +56,7 @@ static async Task MainInner(string pipeName) var gameLocation = await facade.Connect(); var gameAssemblyContext = new GameAssemblyLoadContext(Path.GetFullPath(gameLocation)); var gameSurveyer = new GameSurveyer(facade, gameAssemblyContext, gameLocation); - if (!gameSurveyer.TryLoadModManagerAndGame(out _)) return; + if (!gameSurveyer.TryLoadCoreAndGame()) return; gameSurveyer.RunGame(); diff --git a/StarMap/DumbGameFacade.cs b/StarMap/SoloGameFacade.cs similarity index 88% rename from StarMap/DumbGameFacade.cs rename to StarMap/SoloGameFacade.cs index 229cb58..eb3438a 100644 --- a/StarMap/DumbGameFacade.cs +++ b/StarMap/SoloGameFacade.cs @@ -9,7 +9,7 @@ namespace StarMap { - internal class DumbGameFacade : IGameFacade + internal class SoloGameFacade : IGameFacade { public Task RequestData(IMessage request) { From 6b59476604972c9613fc9b9e47d7f6498adb6aa9 Mon Sep 17 00:00:00 2001 From: KlaasWhite Date: Sat, 15 Nov 2025 19:38:44 +0100 Subject: [PATCH 2/3] Fixed readme + Bumped dummy version --- README.md | 4 ++-- StarMap.Core/StarMap.Core.csproj | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 06a2880..04de225 100644 --- a/README.md +++ b/README.md @@ -8,8 +8,8 @@ It makes use of Assembly Load Contexts to ensure mod dependencies are managed se ## Installation - Download and unzip release from [Releases](https://github.com/StarMapLoader/StarMap/releases/latest). -- Run StarMapLoader.exe, this will fail and create a StarMapLoader.json. -- Open StarMapLoader.json and set the location of your KSA installation. +- Run StarMapLoader.exe, this will fail and create a StarMapConfig.json. +- Open StarMapConfig.json and set the location of your KSA installation. - Run StarMapLoader.exe again, this should launch KSA and load your mods. ## Running as dumb loader diff --git a/StarMap.Core/StarMap.Core.csproj b/StarMap.Core/StarMap.Core.csproj index 6b5194d..dd1cfba 100644 --- a/StarMap.Core/StarMap.Core.csproj +++ b/StarMap.Core/StarMap.Core.csproj @@ -22,7 +22,7 @@ - + runtime From 844b14cb24160aa416d8ed34fae6629b014d857c Mon Sep 17 00:00:00 2001 From: KlaasWhite Date: Sat, 15 Nov 2025 19:40:58 +0100 Subject: [PATCH 3/3] Another fix for readme --- README.md | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index 04de225..76885dc 100644 --- a/README.md +++ b/README.md @@ -1,20 +1,17 @@ # StarMap A POC/Prototype arbitrary code modloader for Kitten Space Agency. -The idea is to get to a Factorio like experience where mods can be managed in game and mods can be synced by restarting the game. Currently this loader can be ran with this functionality in the background, or as a dumb loader just loading mods. It makes use of Assembly Load Contexts to ensure mod dependencies are managed seperatly, reducing conflicts ## Installation - Download and unzip release from [Releases](https://github.com/StarMapLoader/StarMap/releases/latest). -- Run StarMapLoader.exe, this will fail and create a StarMapConfig.json. +- Run StarMap.exe, this will fail and create a StarMapConfig.json. - Open StarMapConfig.json and set the location of your KSA installation. -- Run StarMapLoader.exe again, this should launch KSA and load your mods. - -## Running as dumb loader - -If you do not want the seperate process and mod manager functionality, StarMap.exe can also be ran seperatly, this will just load the installed mods + - `GameLocation` should be set to the location of your KSA.dll, pointing directly to that file (e.g. `C:\\games\\Kitten Space Agency\\KSA.dll`) + - `RepositoryLocation` can be kept empty +- Run StarMap.exe again, this should launch KSA and load your mods. ## Mod location @@ -24,6 +21,12 @@ Mods should be installed in the mods folder in the KSA installation, any KSA mod For more information on mod creation, check out the example mods: [StarMap-ExampleMods](https://github.com/StarMapLoader/StarMap-ExampleMods). +## Future plans + +The goal is to create a modloader similar to the mod functionality in Factorio, where users can select mods in game taken from a remote repository, and that those mods than get installed after an automatic restart of the game +It currently does this by using two processes to host the game itself seperately so it can restart +The idea would be to have the repository just be an index of mods, versions and download locations, and that the download locations themselves are seperate (for example github releases) + ## Credits - Lexi - [KSALoader](https://github.com/cheese3660/KsaLoader)