From ba3ad083824be559f8d076418e894c90106cd23d Mon Sep 17 00:00:00 2001 From: KlaasWhite Date: Thu, 13 Nov 2025 23:09:05 +0100 Subject: [PATCH 1/5] Prepare for KSA public release --- .github/workflows/release-zip.yml | 2 +- DummyProgram/DummyProgram.csproj | 1 + DummyProgram/Mod.cs | 16 +-- DummyProgram/ModLibrary.cs | 9 +- DummyProgram/Program.cs | 9 +- DummyProgram/Screens/IScreen.cs | 2 +- DummyProgram/Screens/Screens.cs | 4 +- LICENSE.txt | 21 ++++ README.md | 38 +++++-- StarMap.Core/ModAssemblyLoadContext.cs | 15 +-- StarMap.Core/ModLoaderPatcher.cs | 9 +- StarMap.Core/ModManager.cs | 44 ++++----- StarMap.Core/ModManagerScreen.cs | 132 ++++++++++++++----------- StarMap.Core/StarMap.Core.csproj | 4 +- StarMap.Types/LoaderConfig.cs | 43 ++++++++ StarMap.Types/Proto/IPC.proto | 59 ++++++----- StarMap.Types/StarMap.Types.csproj | 2 +- StarMap/DumbGameFacade.cs | 19 ++++ StarMap/GameAssemblyLoadContext.cs | 8 +- StarMap/GameFacade.cs | 8 +- StarMap/GameSurveyer.cs | 6 +- StarMap/Program.cs | 33 ++++++- StarMap/Properties/launchSettings.json | 3 +- StarMap/StarMap.csproj | 1 - StarMapLoader/LoaderConfig.cs | 15 --- StarMapLoader/LoaderFacade.cs | 64 +++++++++--- StarMapLoader/ModDownloader.cs | 33 +------ StarMapLoader/ModRepository.cs | 69 ++++++------- StarMapLoader/Program.cs | 11 ++- StarMapLoader/StarMapLoader.csproj | 3 +- 30 files changed, 416 insertions(+), 267 deletions(-) create mode 100644 LICENSE.txt create mode 100644 StarMap.Types/LoaderConfig.cs create mode 100644 StarMap/DumbGameFacade.cs delete mode 100644 StarMapLoader/LoaderConfig.cs diff --git a/.github/workflows/release-zip.yml b/.github/workflows/release-zip.yml index b87734a..2dc0991 100644 --- a/.github/workflows/release-zip.yml +++ b/.github/workflows/release-zip.yml @@ -17,7 +17,7 @@ jobs: PROJECT: StarMapLoader/StarMapLoader.csproj OUTPUT_PATH: ./publish NUGET_SOURCE: "https://nuget.pkg.github.com/${{ github.repository_owner }}/index.json" - EXCLUDE: "*.pdb *.xml DummyProgram.deps.json DummyProgram.runtimeconfig.json DummyProgram.pdb DummyProgram.exe Tomlyn.dll" + EXCLUDE: "*.pdb *.xml" steps: - uses: actions/checkout@v4 diff --git a/DummyProgram/DummyProgram.csproj b/DummyProgram/DummyProgram.csproj index 109581c..d2b3efd 100644 --- a/DummyProgram/DummyProgram.csproj +++ b/DummyProgram/DummyProgram.csproj @@ -5,6 +5,7 @@ net9.0 enable enable + KSA diff --git a/DummyProgram/Mod.cs b/DummyProgram/Mod.cs index 2c8b746..1723feb 100644 --- a/DummyProgram/Mod.cs +++ b/DummyProgram/Mod.cs @@ -1,21 +1,21 @@ -using DummyProgram.Screens; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Reflection; -using System.Text; -using System.Threading.Tasks; +using System.Reflection; -namespace DummyProgram +namespace KSA { public class Mod { public required string DirectoryPath { get; init; } public required AssemblyName Assembly { get; init; } + public required string Name { get; init; } public Mod() { } public void PrepareSystems() { } + + public void DoSomething() + { + Console.WriteLine($"Mod {Name} is doing something!"); + } } } diff --git a/DummyProgram/ModLibrary.cs b/DummyProgram/ModLibrary.cs index 567e79a..1b8d6d8 100644 --- a/DummyProgram/ModLibrary.cs +++ b/DummyProgram/ModLibrary.cs @@ -7,11 +7,11 @@ using Tomlyn.Model; using Tomlyn; -namespace DummyProgram +namespace KSA { public class ModLibrary { - private List _mods = []; + public List Mods = []; public ModLibrary() { } public void LoadAll() @@ -60,11 +60,12 @@ public void FetchMods() var mod = new Mod { DirectoryPath = folder, - Assembly = assemblyName + Assembly = assemblyName, + Name = assemblyName.Name }; mod.PrepareSystems(); - _mods.Add(mod); + Mods.Add(mod); } } diff --git a/DummyProgram/Program.cs b/DummyProgram/Program.cs index 7a0692b..2c72879 100644 --- a/DummyProgram/Program.cs +++ b/DummyProgram/Program.cs @@ -1,15 +1,14 @@ -using DummyProgram.Screens; - -namespace DummyProgram +namespace KSA { public class Program { + public static ModLibrary ModLibrary = new ModLibrary(); + private static IScreen _currentScreen = new MainScreen(); static void Main(string[] args) { - var library = new ModLibrary(); - library.LoadAll(); + ModLibrary.LoadAll(); while (true) { diff --git a/DummyProgram/Screens/IScreen.cs b/DummyProgram/Screens/IScreen.cs index b64fd77..16e0c5e 100644 --- a/DummyProgram/Screens/IScreen.cs +++ b/DummyProgram/Screens/IScreen.cs @@ -4,7 +4,7 @@ using System.Text; using System.Threading.Tasks; -namespace DummyProgram.Screens +namespace KSA { public interface IScreen { diff --git a/DummyProgram/Screens/Screens.cs b/DummyProgram/Screens/Screens.cs index 73db6d5..6d44e1c 100644 --- a/DummyProgram/Screens/Screens.cs +++ b/DummyProgram/Screens/Screens.cs @@ -4,11 +4,10 @@ using System.Text; using System.Threading.Tasks; -namespace DummyProgram.Screens +namespace KSA { public class MainScreen : IScreen { - public static IScreen[] Screens { get; set; } = [new GameScreen(), new ExitScreen()]; public string ScreenName => "Main"; @@ -59,6 +58,7 @@ public IScreen HandleInput(int input) public void DoSomething() { + Program.ModLibrary.Mods.ForEach((mod) => mod.DoSomething()); Console.WriteLine("GameScreen.DoSomething"); Console.ReadLine(); } diff --git a/LICENSE.txt b/LICENSE.txt new file mode 100644 index 0000000..95d86e9 --- /dev/null +++ b/LICENSE.txt @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2025 StarMap + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/README.md b/README.md index 8c3b624..06a2880 100644 --- a/README.md +++ b/README.md @@ -1,11 +1,29 @@ # StarMap -A POC/test modloader primarly for Kitten Space Agency -This was inspired by https://github.com/cheese3660/KsaLoader for me to learn about assemblyloading. -It very heavily relies on AssemblyLoadContexts to load both the game and then the mods in the game. -The advantage of this is that different mods can use different versions of the same dependencies. - -The main goal was to be able to unload the whole game and the modding, change the mods/dlls around and then load it again. -This could result in a simular system to how Factory feels where the mod manager lives within the game. -Sadly it did not work out in the current way it is implemented because Harmony does not play well ALC's and it keeps references to objects within the Assemblies. -This results in the assemblies not unloading which means I can not swap the dll's (it locks them). -A probable way forward is using a seperate process for the game itself so the whole process can shut down, however communication between processes forms a barrier to doing it this way. + +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 StarMapLoader.json. +- Open StarMapLoader.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 + +## Mod location + +Mods should be installed in the mods folder in the KSA installation, any KSA mod that has a dll with the same name as the mod that impelements the IStarMapMod interface will be loaded. + +## Mod creation + +For more information on mod creation, check out the example mods: [StarMap-ExampleMods](https://github.com/StarMapLoader/StarMap-ExampleMods). + +## Credits + +- Lexi - [KSALoader](https://github.com/cheese3660/KsaLoader) diff --git a/StarMap.Core/ModAssemblyLoadContext.cs b/StarMap.Core/ModAssemblyLoadContext.cs index 16ee0f7..9217a8b 100644 --- a/StarMap.Core/ModAssemblyLoadContext.cs +++ b/StarMap.Core/ModAssemblyLoadContext.cs @@ -1,11 +1,6 @@ -using DummyProgram; -using System; -using System.Collections.Generic; -using System.Linq; +using KSA; using System.Reflection; using System.Runtime.Loader; -using System.Text; -using System.Threading.Tasks; namespace StarMap.Core { @@ -20,29 +15,27 @@ public ModAssemblyLoadContext(Mod mod, AssemblyLoadContext coreAssemblyContext) _coreAssemblyLoadContext = coreAssemblyContext; _modDependencyResolver = new AssemblyDependencyResolver( - Path.GetFullPath(Path.Combine(mod.DirectoryPath, mod.Assembly.Name + ".dll")) + Path.GetFullPath(Path.Combine(mod.DirectoryPath, mod.Name + ".dll")) ); } protected override Assembly? Load(AssemblyName assemblyName) { var existingInDefault = Default.Assemblies - .FirstOrDefault(a => a.FullName == assemblyName.FullName); + .FirstOrDefault(a => string.Equals(a.GetName().Name, assemblyName.Name, StringComparison.OrdinalIgnoreCase)); if (existingInDefault != null) return existingInDefault; var existingInGameContext = _coreAssemblyLoadContext?.Assemblies - .FirstOrDefault(a => a.FullName == assemblyName.FullName); + .FirstOrDefault(a => string.Equals(a.GetName().Name, assemblyName.Name, StringComparison.OrdinalIgnoreCase)); if (existingInGameContext != null) return existingInGameContext; var foundPath = _modDependencyResolver.ResolveAssemblyToPath(assemblyName); - if (foundPath is null) return null; var path = Path.GetFullPath(foundPath); - return path != null ? LoadFromAssemblyPath(path) : null; } } diff --git a/StarMap.Core/ModLoaderPatcher.cs b/StarMap.Core/ModLoaderPatcher.cs index ffc1425..ed20131 100644 --- a/StarMap.Core/ModLoaderPatcher.cs +++ b/StarMap.Core/ModLoaderPatcher.cs @@ -1,5 +1,4 @@ -using DummyProgram; -using DummyProgram.Screens; +using KSA; using HarmonyLib; namespace StarMap.Core @@ -19,7 +18,7 @@ public static void Patch(ModManager modManager) public static void Unload() { _modManager = null; - MainScreen.Screens = []; + //MainScreen.Screens = []; _harmony?.UnpatchAll(); } @@ -35,10 +34,10 @@ public static void OnLoadMod(this Mod __instance) public static void AfterLoad() { _modManager?.OnAllModsLoaded(); - var screens = MainScreen.Screens.ToList(); + /*var screens = MainScreen.Screens.ToList(); screens.Insert(MainScreen.Screens.Length - 1, new ModManagerScreen(_modManager)); - MainScreen.Screens = screens.ToArray(); + MainScreen.Screens = screens.ToArray();*/ _harmony?.UnpatchAll(_harmony.Id); } } diff --git a/StarMap.Core/ModManager.cs b/StarMap.Core/ModManager.cs index 77d4f57..cddeb65 100644 --- a/StarMap.Core/ModManager.cs +++ b/StarMap.Core/ModManager.cs @@ -1,7 +1,5 @@  - -using DummyProgram; -using Google.Protobuf.WellKnownTypes; +using KSA; using HarmonyLib; using StarMap.Types; using StarMap.Types.Mods; @@ -16,7 +14,7 @@ internal class ModManager : IModManager private readonly AssemblyLoadContext _coreAssemblyLoadContext; private readonly IGameFacade _gameFacade; - private readonly TaskCompletionSource _managedMods = new(); + private readonly TaskCompletionSource _managedMods = new(); private readonly Dictionary _loadedMods = []; public ModManager(AssemblyLoadContext coreAssemblyLoadContext, IGameFacade gameFacade) @@ -28,6 +26,7 @@ public ModManager(AssemblyLoadContext coreAssemblyLoadContext, IGameFacade gameF public void Init() { _ = RetrieveManagedMods(); + ModLoaderPatcher.Patch(this); } @@ -47,7 +46,7 @@ public void LoadMod(Mod mod) if (!Directory.Exists(mod.DirectoryPath)) return; var modLoadContext = new ModAssemblyLoadContext(mod, _coreAssemblyLoadContext); - var modAssembly = modLoadContext.LoadFromAssemblyName(mod.Assembly); + 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; @@ -60,6 +59,8 @@ public void LoadMod(Mod mod) return; } + Console.WriteLine($"Loaded mod: {mod.Name}"); + _loadedMods[mod] = (starMapMod, modLoadContext); return; } @@ -74,54 +75,53 @@ public void OnAllModsLoaded() public async Task RetrieveManagedMods() { - var message = new ManagedModsRequest(); + var message = new IPCGetCurrentManagedModsRequest(); var response = await _gameFacade.RequestData(message); - if (!response.Is(ManagedModsResponse.Descriptor)) return; + if (!response.Is(IPCGetCurrentManagedModsResponse.Descriptor)) return; - _managedMods.SetResult(response.Unpack()); + _managedMods.SetResult(response.Unpack()); } - public ManagedModsResponse GetManagedMods() + public IPCGetCurrentManagedModsResponse GetManagedMods() { - Console.WriteLine("GetManagedMods"); return _managedMods.Task.GetAwaiter().GetResult(); } - public async Task GetManagedModsAsync() + public async Task GetAvailableModsAsync() { - var message = new AvailableModsRequest(); + var message = new IPCGetModsRequest(); var response = await _gameFacade.RequestData(message); - if (!response.Is(AvailableModsResponse.Descriptor)) return[]; + if (!response.Is(IPCGetModsResponse.Descriptor)) return[]; - return [.. response.Unpack().Mods]; + return [.. response.Unpack().Mods]; } - public async Task GetModInformationAsync(string modName) + public async Task GetModInformationAsync(string id) { - var message = new ModInformationRequest() + var message = new IPCGetModDetailsRequest() { - Mod = modName + Id = id }; var response = await _gameFacade.RequestData(message); - if (!response.Is(ModInformationResponse.Descriptor)) return null; + if (!response.Is(IPCGetModDetailsResponse.Descriptor)) return null; - return response.Unpack().Mod; + return response.Unpack().Mod; } - public AssemblyName[] GetLoadedMods() + public string[] GetLoadedMods() { if (_loadedMods is null) return []; - return _loadedMods.Select(loadedMod => loadedMod.Key.Assembly).ToArray(); + return _loadedMods.Select(loadedMod => loadedMod.Key.Name).ToArray(); } - public async Task SetModUpdates(SetModUpdates update) + public async Task SetModUpdates(IPCSetManagedMods update) { await _gameFacade.RequestData(update); } diff --git a/StarMap.Core/ModManagerScreen.cs b/StarMap.Core/ModManagerScreen.cs index 8105da4..d23490a 100644 --- a/StarMap.Core/ModManagerScreen.cs +++ b/StarMap.Core/ModManagerScreen.cs @@ -1,4 +1,4 @@ -using DummyProgram; +/*using DummyProgram; using DummyProgram.Screens; using StarMap.Types.Mods; using StarMap.Types.Proto.IPC; @@ -15,12 +15,12 @@ internal sealed class ModManagerScreen : IScreen { private readonly ModManager _modManager; - private List _managedMods = []; - private List _unmanagedMods = []; + private List _managedMods = []; + private List _unmanagedMods = []; - private List<(string modName, Version? before, Version after)> _changes = []; + private List _changes = []; - private (string name, Version? version, bool unmanaged)? _currentMod; + private (IPCMod mod, bool unmanaged, bool fromStore)? _currentMod; enum ManagerState { @@ -45,7 +45,8 @@ public ModManagerScreen(ModManager? modManager) private void RetrieveModInfo() { _managedMods = [.. _modManager.GetManagedMods().Mods]; - _unmanagedMods = _modManager.GetLoadedMods().Where(loadedMod => !_managedMods.Any(managedMod => managedMod.Name == loadedMod.Name)).ToList(); + _unmanagedMods = _modManager.GetLoadedMods().Where(loadedMod => !_managedMods.Any(managedMod => managedMod.Name == loadedMod.Name)).Select((loadedMod) => new IPCMod() { Name = loadedMod.Name}).ToList(); + } public string ScreenName => "Mod manager"; @@ -71,6 +72,11 @@ public void Render() RenderModInfo(); break; } + case ManagerState.MOD_STORE: + { + RenderModStore(); + break; + } } } @@ -96,10 +102,10 @@ private ModManagerScreen GoToStore() return this; } - private ModManagerScreen GoToSpecificMod(string modName, Version? modVersion, bool unmanaged) + private ModManagerScreen GoToSpecificMod(IPCMod mod, bool unmanaged, bool fromStore) { _managerState = ManagerState.MOD_INFO; - _currentMod = (modName, modVersion, unmanaged); + _currentMod = (mod, unmanaged, fromStore); return this; } @@ -115,7 +121,7 @@ private void RenderMain() { var localMod = mod; Console.WriteLine($"{index++}: {localMod.Name}:{localMod.Version}"); - _actions.Add(() => GoToSpecificMod(localMod.Name, Version.Parse(localMod.Version), false)); + _actions.Add(() => GoToSpecificMod(localMod, false, false)); } Console.WriteLine("Unmanaged mods: "); @@ -123,7 +129,7 @@ private void RenderMain() { var localMod = mod; Console.WriteLine($"{index++}: {localMod.Name}:{localMod.Version}"); - _actions.Add(() => GoToSpecificMod(localMod.Name ?? "", localMod.Version, true)); + _actions.Add(() => GoToSpecificMod(mod, true, false)); } Console.WriteLine($""); @@ -131,12 +137,12 @@ private void RenderMain() if (_changes.Count > 0) { Console.WriteLine($"Current changes"); - foreach (var (name, before, after) in _changes) + foreach (var modUpdate in _changes) { - if (before is not null) - Console.WriteLine($"{name}: {before} => {after}"); + if (modUpdate.BeforeVersion is IPCModVersion beforeVersion && !string.IsNullOrEmpty(beforeVersion.Version)) + Console.WriteLine($"{modUpdate.Mod.Name}: {beforeVersion.Version} => {modUpdate.AfterVersion.Version}"); else - Console.WriteLine($"{name}: {after}"); + Console.WriteLine($"{modUpdate.Mod.Name}: {modUpdate.AfterVersion.Version}"); } Console.WriteLine($""); @@ -162,81 +168,102 @@ private void RenderMain() private void RenderModInfo() { if (_currentMod is null) return; - var modInformation = _modManager.GetModInformationAsync(_currentMod.Value.name).GetAwaiter().GetResult(); + var modInformation = _modManager.GetModInformationAsync(_currentMod.Value.mod.Id).GetAwaiter().GetResult(); if (modInformation is null) { - Console.WriteLine($"Unable to retrieve information for mod: {_currentMod.Value.name}"); + Console.WriteLine($"Unable to retrieve information for mod: {_currentMod.Value.mod.Name}"); Console.WriteLine($"Return"); _actions.Add(GoToModManager); return; } - var modName = _currentMod.Value.name; - var version = _currentMod.Value.version; + var mod = _currentMod.Value.mod; var unmanaged = _currentMod.Value.unmanaged; - Console.WriteLine($"Alter version for mod: {modName}"); + Console.WriteLine($"Alter version for mod: {mod.Name}"); if (unmanaged) Console.WriteLine($"Will remove the unmanaged mod and make it managed"); var index = 0; - foreach (var possibleVersion in modInformation.AvailableVersions) + foreach (var possibleVersion in modInformation.Versions) { - if (!unmanaged && possibleVersion.Equals(version)) + if (!unmanaged && possibleVersion.Equals(mod.Version)) { - Console.WriteLine($"* {version}"); + Console.WriteLine($"* {mod.Version}"); continue; } - var localName = modName; - var localVersion = possibleVersion; + var localMod = mod; + var localversion = possibleVersion; var localUnmanaged = unmanaged; - Console.WriteLine($"{index++}: {possibleVersion}"); - _actions.Add(() => SetModVersion(localName, Version.Parse(localVersion), localUnmanaged)); + Console.WriteLine($"{index++}: {possibleVersion.Version}"); + _actions.Add(() => SetModVersion(localMod, localversion, localUnmanaged)); } Console.WriteLine($"{index}: Return"); _actions.Add(GoToModManager); } - private ModManagerScreen SetModVersion(string modName, Version modVersion, bool unmanaged) + private void RenderModStore() + { + var availableMods = _modManager.GetAvailableModsAsync().GetAwaiter().GetResult(); + + var index = 0; + + foreach (var availableMod in availableMods) + { + var localMod = availableMod; + + Console.WriteLine($"{index++}: {availableMod.Name} by {availableMod.Author}"); + _actions.Add(() => GoToSpecificMod(localMod, false, true)); + } + + Console.WriteLine($"{index}: Return"); + _actions.Add(GoToModManager); + } + + private ModManagerScreen SetModVersion(IPCMod mod, IPCModVersion version, bool unmanaged) { _managerState = ManagerState.MAIN; - Version? previousVersion = null; + IPCModVersion? previousVersion = null; if (unmanaged) { - var assembly = _unmanagedMods.FirstOrDefault((assembly) => string.Equals(assembly.Name, modName)); - if (assembly is not null) + var removedMod = _unmanagedMods.FirstOrDefault((unmanagedMod) => string.Equals(unmanagedMod.Name, mod.Name)); + if (removedMod is not null) { - previousVersion = assembly.Version; - _unmanagedMods.Remove(assembly); + previousVersion = new IPCModVersion() { Version = removedMod.Version }; + _unmanagedMods.Remove(removedMod); + } + } + else + { + var oldModIndex = _managedMods.FindIndex(0, (modInfo) => modInfo.Id == mod.Id); + if (oldModIndex >= 0) + { + previousVersion = new IPCModVersion() { Version = _managedMods[oldModIndex].Version }; } } - var newModInformation = new ManagedModInformation() + var newModInformation = new IPCMod() { - Name = modName, - Version = modVersion.ToString(), + Id = mod.Id, + Name = mod.Name, + Author = mod.Author, }; - var index = _managedMods.FindIndex(0, (modInfo) => modInfo.Name == modName); - - if (index >= 0) + var changesIndex = _changes.FindIndex(0, (change) => change.Mod.Id == mod.Id); + var change = new IPCUpdateModInformation() { - previousVersion = Version.Parse(_managedMods[index].Version); - _managedMods[index] = newModInformation; - } - - else - _managedMods.Add(newModInformation); + Mod = newModInformation, + BeforeVersion = new IPCModVersion() { Version = previousVersion?.ToString() ?? "" }, + AfterVersion = version, + }; - var change = (modName, previousVersion, modVersion); - var changesIndex = _changes.FindIndex(0, (change) => change.modName == modName); - if (changesIndex > 0) + if (changesIndex >= 0) _changes[changesIndex] = change; else _changes.Add(change); @@ -246,15 +273,9 @@ private ModManagerScreen SetModVersion(string modName, Version modVersion, bool private IScreen ApplyMods() { - var modUpdates = _changes.Select(change => new ManagedModUpdate() - { - Name = change.modName, - BeforeVersion = change.before?.ToString() ?? "", - AfterVersion = change.after.ToString(), - }); - var message = new SetModUpdates(); - message.Updates.AddRange(modUpdates); + var message = new IPCSetManagedMods(); + message.Updates.AddRange(_changes); _modManager.SetModUpdates(message).GetAwaiter().GetResult(); @@ -262,3 +283,4 @@ private IScreen ApplyMods() } } } +*/ \ No newline at end of file diff --git a/StarMap.Core/StarMap.Core.csproj b/StarMap.Core/StarMap.Core.csproj index 1285696..1488325 100644 --- a/StarMap.Core/StarMap.Core.csproj +++ b/StarMap.Core/StarMap.Core.csproj @@ -8,10 +8,12 @@ + + runtime + - diff --git a/StarMap.Types/LoaderConfig.cs b/StarMap.Types/LoaderConfig.cs new file mode 100644 index 0000000..4ed0594 --- /dev/null +++ b/StarMap.Types/LoaderConfig.cs @@ -0,0 +1,43 @@ +using StarMap.Types.Proto.IPC; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Text.Json; +using System.Threading.Tasks; + +namespace StarMap.Types +{ + public class LoaderConfig + { + + public bool TryLoadConfig() + { + if (!File.Exists("./StarMapConfig.json")) { + Console.WriteLine("Please fill the StarMapConfig.json and restart the program"); + File.Create("./StarMapConfig.json").Dispose(); + File.WriteAllText("./StarMapConfig.json", JsonSerializer.Serialize(new LoaderConfig())); + Console.ReadLine(); + return false; + } + + var jsonString = File.ReadAllText("./StarMapConfig.json"); + var config = System.Text.Json.JsonSerializer.Deserialize(jsonString); + + if (config is null) return false; + + if (string.IsNullOrEmpty(config.GameLocation) || !File.Exists(config.GameLocation)) + { + Console.WriteLine("The 'GameLocation' property in StarMapConfig.json is either empty or points to a non-existing file."); + Console.ReadLine(); + return false; + } + + GameLocation = config.GameLocation; + return true; + } + + public string GameLocation { get; set; } = ""; + public string RepositoryLocation { get; set; } = ""; + } +} diff --git a/StarMap.Types/Proto/IPC.proto b/StarMap.Types/Proto/IPC.proto index 45c8bb5..e29db6f 100644 --- a/StarMap.Types/Proto/IPC.proto +++ b/StarMap.Types/Proto/IPC.proto @@ -9,56 +9,65 @@ message PipeMessage { google.protobuf.Any Payload = 2; } -message ConnectRequest{ +message IPCConnectRequest { } -message ConnectResponse{ +message IPCConnectResponse { string game_location = 1; } -message ManagedModsRequest{ +message IPCGetCurrentManagedModsRequest { } -message ManagedModsResponse{ - repeated ManagedModInformation mods = 1; +message IPCGetCurrentManagedModsResponse { + repeated IPCMod mods = 1; } -message ManagedModInformation{ - string name = 1; - string version = 2; +message IPCGetModsRequest{ + } -message AvailableModsRequest{ +message IPCGetModsResponse{ + repeated IPCMod mods = 1; +} +message IPCGetModDetailsRequest{ + string id = 1; } -message AvailableModsResponse{ - repeated string mods = 1; +message IPCGetModDetailsResponse{ + IPCModDetails mod = 1; } -message ModInformationRequest{ - string mod = 1; +message IPCMod { + string id = 1; + string name = 2; + string version = 3; + string author = 4; } -message ModInformationResponse{ - ModInformation mod = 1; +message IPCModDetails{ + IPCMod mod = 1; + repeated IPCModVersion versions = 2; + string description = 3; } -message ModInformation{ - string name = 1; - repeated string available_versions = 2; +message IPCModVersion{ + string id = 1; + string version = 2; + string download_location = 3; } -message ManagedModUpdate{ - string name = 1; - string before_version = 2; - string after_version = 3; +message IPCUpdateModInformation{ + IPCMod mod = 1; + IPCModVersion before_version = 2; + IPCModVersion after_version = 3; } -message SetModUpdates{ - repeated ManagedModUpdate updates = 1; +message IPCSetManagedMods{ + repeated IPCUpdateModInformation updates = 1; } -message ClosePipeMessage{} \ No newline at end of file +message IPCClosePipeMessage{} \ No newline at end of file diff --git a/StarMap.Types/StarMap.Types.csproj b/StarMap.Types/StarMap.Types.csproj index 9357b8d..290fcc2 100644 --- a/StarMap.Types/StarMap.Types.csproj +++ b/StarMap.Types/StarMap.Types.csproj @@ -6,7 +6,7 @@ - + all runtime; build; native; contentfiles; analyzers; buildtransitive diff --git a/StarMap/DumbGameFacade.cs b/StarMap/DumbGameFacade.cs new file mode 100644 index 0000000..229cb58 --- /dev/null +++ b/StarMap/DumbGameFacade.cs @@ -0,0 +1,19 @@ +using Google.Protobuf; +using Google.Protobuf.WellKnownTypes; +using StarMap.Types.Mods; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace StarMap +{ + internal class DumbGameFacade : IGameFacade + { + public Task RequestData(IMessage request) + { + return Task.FromResult(new Any()); + } + } +} diff --git a/StarMap/GameAssemblyLoadContext.cs b/StarMap/GameAssemblyLoadContext.cs index 9b7bb34..1786894 100644 --- a/StarMap/GameAssemblyLoadContext.cs +++ b/StarMap/GameAssemblyLoadContext.cs @@ -25,10 +25,10 @@ public GameAssemblyLoadContext(string gamePath) protected override Assembly? Load(AssemblyName assemblyName) { - var existing = Default.Assemblies - .FirstOrDefault(a => a.FullName == assemblyName.FullName); - if (existing != null) - return existing; + var existingInDefault = Default.Assemblies + .FirstOrDefault(a => string.Equals(a.GetName().Name, assemblyName.Name, StringComparison.OrdinalIgnoreCase)); + if (existingInDefault != null) + return existingInDefault; var path = _gameDependencyResolver.ResolveAssemblyToPath(assemblyName); diff --git a/StarMap/GameFacade.cs b/StarMap/GameFacade.cs index b2298fc..5953d92 100644 --- a/StarMap/GameFacade.cs +++ b/StarMap/GameFacade.cs @@ -22,16 +22,16 @@ public async Task Connect() await _pipe.ConnectAsync(default); _connected = true; - var connectResponse = await RequestData(new ConnectRequest()); + var connectResponse = await RequestData(new IPCConnectRequest()); - if (!connectResponse.Is(ConnectResponse.Descriptor)) return ""; + if (!connectResponse.Is(IPCConnectResponse.Descriptor)) return ""; - return connectResponse.Unpack().GameLocation; + return connectResponse.Unpack().GameLocation; } public async ValueTask DisposeAsync() { - await RequestData(new ClosePipeMessage()); + //await RequestData(new IPCClosePipeMessage()); _pipe.Dispose(); } diff --git a/StarMap/GameSurveyer.cs b/StarMap/GameSurveyer.cs index 6d92023..2e94dd8 100644 --- a/StarMap/GameSurveyer.cs +++ b/StarMap/GameSurveyer.cs @@ -8,14 +8,14 @@ namespace StarMap { internal class GameSurveyer : IDisposable { - private readonly GameFacade _facade; + private readonly IGameFacade _facade; private readonly AssemblyLoadContext _gameAssemblyContext; private readonly string _gameLocation; private Assembly? _game; private IModManager? _modManager; - public GameSurveyer(GameFacade facade, AssemblyLoadContext alc, string location) + public GameSurveyer(IGameFacade facade, AssemblyLoadContext alc, string location) { _facade = facade; _gameAssemblyContext = alc; @@ -33,7 +33,7 @@ public bool TryLoadModManagerAndGame([NotNullWhen(true)] out IModManager? modMan var createdModManager = Activator.CreateInstance(modManagerType, [_gameAssemblyContext, _facade]); if (createdModManager is not IModManager manager) return false; - _game = _gameAssemblyContext.LoadFromAssemblyPath(Path.Combine(_gameLocation, "DummyProgram.dll")); + _game = _gameAssemblyContext.LoadFromAssemblyPath(_gameLocation); _modManager = manager; manager.Init(); diff --git a/StarMap/Program.cs b/StarMap/Program.cs index 5c6ff71..088b933 100644 --- a/StarMap/Program.cs +++ b/StarMap/Program.cs @@ -1,4 +1,6 @@ -using StarMap.Types.Pipes; +using StarMap.Types; +using StarMap.Types.Pipes; +using StarMap.Types.Proto.IPC; using System.Runtime.Loader; namespace StarMap @@ -9,15 +11,42 @@ static void Main(string[] args) { if (args.Length < 1) { - Console.WriteLine("Usage: StarMap "); + Console.WriteLine("Running Starmap in dumb mode!"); + DumbModeInner(); return; } + Console.WriteLine("Running Starmap normally."); + var pipeName = args[0]; + Console.WriteLine($"Connection to pipe: {pipeName}"); MainInner(pipeName).GetAwaiter().GetResult(); } + static void DumbModeInner() + { + var gameConfig = new LoaderConfig(); + + if (!gameConfig.TryLoadConfig()) + { + return; + } + + AssemblyLoadContext.Default.LoadFromAssemblyPath(Path.GetFullPath("./0Harmony.dll")); + + var gameAssemblyContext = new GameAssemblyLoadContext(gameConfig.GameLocation); + var dumbFacade = new DumbGameFacade(); + var gameSurveyer = new GameSurveyer(dumbFacade, gameAssemblyContext, gameConfig.GameLocation); + if (!gameSurveyer.TryLoadModManagerAndGame(out _)) + { + Console.WriteLine("Unable to load mod manager and game in dumb mode."); + return; + } + + gameSurveyer.RunGame(); + } + static async Task MainInner(string pipeName) { AssemblyLoadContext.Default.LoadFromAssemblyPath(Path.GetFullPath("./0Harmony.dll")); diff --git a/StarMap/Properties/launchSettings.json b/StarMap/Properties/launchSettings.json index 8a543f9..19a1027 100644 --- a/StarMap/Properties/launchSettings.json +++ b/StarMap/Properties/launchSettings.json @@ -1,8 +1,7 @@ { "profiles": { "StarMap": { - "commandName": "Project", - "commandLineArgs": "starmap_pipe" + "commandName": "Project" } } } \ No newline at end of file diff --git a/StarMap/StarMap.csproj b/StarMap/StarMap.csproj index 70dbfb6..fb71fb5 100644 --- a/StarMap/StarMap.csproj +++ b/StarMap/StarMap.csproj @@ -12,7 +12,6 @@ - diff --git a/StarMapLoader/LoaderConfig.cs b/StarMapLoader/LoaderConfig.cs deleted file mode 100644 index 5c246f2..0000000 --- a/StarMapLoader/LoaderConfig.cs +++ /dev/null @@ -1,15 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace StarMapLoader -{ - internal class LoaderConfig - { - public string GameFolder { get; set; } = "C:\\data\\programming\\game-modding\\KSA\\StarMap\\StarMapLoader\\bin\\Debug\\net9.0"; - public string GamePath => Path.Combine(GameFolder, "StarMap.exe"); - public string ModPath => Path.Combine(GameFolder, "mods"); - } -} diff --git a/StarMapLoader/LoaderFacade.cs b/StarMapLoader/LoaderFacade.cs index fdc5e27..2f9838d 100644 --- a/StarMapLoader/LoaderFacade.cs +++ b/StarMapLoader/LoaderFacade.cs @@ -1,5 +1,6 @@ using Google.Protobuf; using Google.Protobuf.WellKnownTypes; +using StarMap.Types; using StarMap.Types.Pipes; using StarMap.Types.Proto.IPC; @@ -31,43 +32,74 @@ private void PipeServer_OnRequest(object? sender, Any pipeMessage) IMessage? response = null; - if (message.Is(ConnectRequest.Descriptor)) + if (message.Is(IPCConnectRequest.Descriptor)) { - response = new ConnectResponse() + response = new IPCConnectResponse() { - GameLocation = _config.GameFolder, + GameLocation = _config.GameLocation, }; OnProcessStarted?.Invoke(this, EventArgs.Empty); } - if (message.Is(ManagedModsRequest.Descriptor)) + if (message.Is(IPCGetCurrentManagedModsRequest.Descriptor)) { - var modsRepsonse = new ManagedModsResponse(); + var modsRepsonse = new IPCGetCurrentManagedModsResponse(); modsRepsonse.Mods.AddRange(_repository.LoadedModInformation); response = modsRepsonse; } - if (message.Is(AvailableModsRequest.Descriptor)) + if (message.Is(IPCGetModsRequest.Descriptor)) { - var availableModsResponse = new AvailableModsResponse(); - availableModsResponse.Mods.AddRange(_repository.GetPossibleMods()); + var availableModsResponse = new IPCGetModsResponse(); + var availableMods = _repository.GetPossibleMods().GetAwaiter().GetResult().Select(repositoryMod => new IPCMod() + { + Id = repositoryMod.Id, + Name = repositoryMod.Name, + Author = repositoryMod.Author, + }); + + availableModsResponse.Mods.AddRange(availableMods); response = availableModsResponse; } - if (message.Is(ModInformationRequest.Descriptor)) + if (message.Is(IPCGetModDetailsRequest.Descriptor)) { - var modInformationRequest = message.Unpack(); + var modDetailsRequest = message.Unpack(); - var modInformationResponse = new ModInformationResponse() + var modDetails = _repository.GetModInformation(modDetailsRequest.Id).GetAwaiter().GetResult(); + if (modDetails is null) { - Mod = _repository.GetModInformation(modInformationRequest.Mod) - }; - response = modInformationResponse; + response = new IPCGetModDetailsResponse(); + } + else + { + var mod = new IPCModDetails() + { + Mod = new IPCMod() + { + Id = modDetails.Mod.Id, + Name = modDetails.Mod.Name, + Author = modDetails.Mod.Author, + }, + Description = modDetails.Description, + }; + mod.Versions.AddRange(modDetails.Versions.Select((version) => new IPCModVersion() + { + Id = version.Id, + Version = version.Version, + DownloadLocation = version.DownloadLocation, + })); + + response = new IPCGetModDetailsResponse() + { + Mod = mod + }; + } } - if (message.Is(SetModUpdates.Descriptor)) + if (message.Is(IPCSetManagedMods.Descriptor)) { - var setModUpdates = message.Unpack(); + var setModUpdates = message.Unpack(); _repository.SetModUpdates([.. setModUpdates.Updates]); diff --git a/StarMapLoader/ModDownloader.cs b/StarMapLoader/ModDownloader.cs index 56cf46e..160b3b2 100644 --- a/StarMapLoader/ModDownloader.cs +++ b/StarMapLoader/ModDownloader.cs @@ -10,44 +10,13 @@ namespace StarMapLoader { internal class ModDownloader { - private const string ModLocation = "C:\\data\\programming\\game-modding\\KSA\\Mods"; - - public bool DownloadMod(string modName, string modVersion, string location) + public bool DownloadMod(IPCMod mod, IPCModVersion version, string location) { try { - var sourceFile = Path.Combine(ModLocation, $"{modName}-{modVersion}.zip"); - var destinationFile = Path.Combine(location, $"{modName}-{modVersion}.zip"); - - if (!File.Exists(sourceFile)) return false; - - File.Copy(sourceFile, destinationFile, true); - - ZipFile.ExtractToDirectory(destinationFile, location); - File.Delete(destinationFile); - return true; } catch { return false; } } - - public Dictionary GetModsFromStore() - { - var mods = new Dictionary(); - - mods["TestMod1"] = new ModInformation() - { - Name = "TestMod1" - }; - mods["TestMod1"].AvailableVersions.AddRange(["1.0.0.0", "2.0.0.0", "3.0.0.0"]); - - mods["TestMod2"] = new ModInformation() - { - Name = "TestMod2" - }; - mods["TestMod2"].AvailableVersions.AddRange(["1.0.0.0", "2.0.0.0", "3.0.0.0"]); - - return mods; - } } } diff --git a/StarMapLoader/ModRepository.cs b/StarMapLoader/ModRepository.cs index 5a1bd7b..b118b00 100644 --- a/StarMapLoader/ModRepository.cs +++ b/StarMapLoader/ModRepository.cs @@ -1,59 +1,61 @@ -using System.Text.Json; +using System.Collections; +using System.Text.Json; +using StarMap.Index.API; using StarMap.Types.Proto.IPC; namespace StarMapLoader { internal class ModRepository { - public List LoadedModInformation { get; private set; } = []; + public List LoadedModInformation { get; private set; } = []; public bool HasChanges { get; private set; } private readonly string _modsPath; + private readonly IModRespositoryClient _foreignModRepository; private readonly ModDownloader _downloader = new(); - private ManagedModUpdate[] _changes = []; + private IPCUpdateModInformation[] _changes = []; - public ModRepository(string modsPath) + public ModRepository(string gameLocation, IModRespositoryClient foreignModRepository) { - _modsPath = modsPath; + var gameDirectory = Path.GetDirectoryName(gameLocation); + if (string.IsNullOrEmpty(gameDirectory)) + { + throw new ArgumentException("Invalid game location provided, unable to determine game directory."); + } - if (!Directory.Exists(modsPath)) + _modsPath = Path.Combine(gameDirectory, "mods"); + _foreignModRepository = foreignModRepository; + + if (!Directory.Exists(_modsPath)) { - Directory.CreateDirectory(modsPath); + Directory.CreateDirectory(_modsPath); } - var filePath = Path.Combine(modsPath, "starmap.json"); + var filePath = Path.Combine(_modsPath, "starmap.json"); if (!File.Exists(filePath)) { File.Create(filePath).Dispose(); - File.WriteAllText(filePath, JsonSerializer.Serialize(new List - { - new ManagedModInformation() - { - Name = "TestMod1", - Version = "2.0.0.0" - } - })); + File.WriteAllText(filePath, JsonSerializer.Serialize(new List())); } - string jsonString = File.ReadAllText(Path.Combine(modsPath, "starmap.json")); + string jsonString = File.ReadAllText(Path.Combine(_modsPath, "starmap.json")); - LoadedModInformation = JsonSerializer.Deserialize>(jsonString) ?? []; + LoadedModInformation = JsonSerializer.Deserialize>(jsonString) ?? []; } - public string[] GetPossibleMods() + public async Task GetPossibleMods() { - return [.. _downloader.GetModsFromStore().Keys]; + return await _foreignModRepository.GetMods(); } - public ModInformation GetModInformation(string modName) + public async Task GetModInformation(string modId) { - - return _downloader.GetModsFromStore()[modName]; + return await _foreignModRepository.GetModDetails(Guid.Parse(modId)); } - public void SetModUpdates(ManagedModUpdate[] updates) + public void SetModUpdates(IPCUpdateModInformation[] updates) { _changes = updates; HasChanges = true; @@ -63,11 +65,11 @@ public void ApplyModUpdates() { HasChanges = false; - foreach (var mod in _changes) + foreach (var modChange in _changes) { try { - var directoryPath = Path.Combine(_modsPath, mod.Name); + var directoryPath = Path.Combine(_modsPath, modChange.Mod.Name); if (Directory.Exists(directoryPath)) { @@ -76,21 +78,22 @@ public void ApplyModUpdates() Directory.CreateDirectory(directoryPath); - if (!_downloader.DownloadMod(mod.Name, mod.AfterVersion, directoryPath) && !string.IsNullOrEmpty(mod.BeforeVersion)) + if (!_downloader.DownloadMod(modChange.Mod, modChange.AfterVersion, directoryPath) && modChange.BeforeVersion is not null) { Directory.Delete(directoryPath, true); Directory.CreateDirectory(directoryPath); - _downloader.DownloadMod(mod.Name, mod.BeforeVersion, directoryPath); + _downloader.DownloadMod(modChange.Mod, modChange.BeforeVersion, directoryPath); } else { - var newModInfo = new ManagedModInformation() + var newModInfo = new IPCMod() { - Version = mod.AfterVersion, - Name = mod.Name + Id = modChange.Mod.Id, + Name = modChange.Mod.Name, + Version = modChange.AfterVersion.Version }; - var index = LoadedModInformation.FindIndex(modInfo => modInfo.Name == mod.Name); + var index = LoadedModInformation.FindIndex(modInfo => modInfo.Id == newModInfo.Id); if (index >= 0) { @@ -104,7 +107,7 @@ public void ApplyModUpdates() } catch (Exception ex) { - Console.WriteLine($"Unable to apply update for mod: {mod.Name} to version {mod.AfterVersion}: {ex}"); + Console.WriteLine($"Unable to apply update for mod: {modChange.Mod.Name} to version {modChange.AfterVersion?.Version ?? ""}: {ex}"); } } diff --git a/StarMapLoader/Program.cs b/StarMapLoader/Program.cs index e47fbe1..9ebe886 100644 --- a/StarMapLoader/Program.cs +++ b/StarMapLoader/Program.cs @@ -1,4 +1,6 @@ -using StarMap.Types.Pipes; +using StarMap.Index.API; +using StarMap.Types.Pipes; +using StarMap.Types; using System.Diagnostics; namespace StarMapLoader @@ -13,7 +15,10 @@ static void Main(string[] args) static async Task MainInner() { var config = new LoaderConfig(); - var modRepository = new ModRepository(config.ModPath); + if (!config.TryLoadConfig()) return; + + using var remoteModRepository = new ModRepositoryClient(config.RepositoryLocation); + var modRepository = new ModRepository(config.GameLocation, remoteModRepository); var shouldReload = true; @@ -25,7 +30,7 @@ static async Task MainInner() { CancellationTokenSource stopGameCancelationTokenSource = new(); - var gameSupervisor = new GameProcessSupervisor(config.GamePath, facade, pipeServer); + var gameSupervisor = new GameProcessSupervisor(config.GameLocation, facade, pipeServer); await await gameSupervisor.TryStartGameAsync(stopGameCancelationTokenSource.Token); diff --git a/StarMapLoader/StarMapLoader.csproj b/StarMapLoader/StarMapLoader.csproj index 44126d0..955a821 100644 --- a/StarMapLoader/StarMapLoader.csproj +++ b/StarMapLoader/StarMapLoader.csproj @@ -8,7 +8,8 @@ - + + From eda987bf722497b4fe87bab6f1f0cd2b3a779116 Mon Sep 17 00:00:00 2001 From: KlaasWhite Date: Thu, 13 Nov 2025 23:19:08 +0100 Subject: [PATCH 2/5] Add github nuget repositiory to build step --- .github/workflows/pr-build.yml | 8 ++++++++ .github/workflows/release-zip.yml | 8 ++++++++ 2 files changed, 16 insertions(+) diff --git a/.github/workflows/pr-build.yml b/.github/workflows/pr-build.yml index a21af02..3e6b273 100644 --- a/.github/workflows/pr-build.yml +++ b/.github/workflows/pr-build.yml @@ -26,6 +26,14 @@ jobs: with: dotnet-version: ${{ env.DOTNET_VERSION }} + - name: Setup Github NuGet + run: | + dotnet nuget add source \ + --username ${{ github.actor }} \ + --password ${{ secrets.GITHUB_TOKEN }} \ + --store-password-in-clear-text \ + --name github "https://nuget.pkg.github.com/${{ github.repository_owner }}/index.json" + - name: Restore dependencies run: dotnet restore ${{ env.PROJECT }} diff --git a/.github/workflows/release-zip.yml b/.github/workflows/release-zip.yml index 2dc0991..1255197 100644 --- a/.github/workflows/release-zip.yml +++ b/.github/workflows/release-zip.yml @@ -73,6 +73,14 @@ jobs: git tag "$NEW_VERSION" git push origin "$NEW_VERSION" + - name: Setup Github NuGet + run: | + dotnet nuget add source \ + --username ${{ github.actor }} \ + --password ${{ secrets.GITHUB_TOKEN }} \ + --store-password-in-clear-text \ + --name github "https://nuget.pkg.github.com/${{ github.repository_owner }}/index.json" + - name: Build run: dotnet publish ${{ env.PROJECT }} -c Release -o ${{ env.OUTPUT_PATH }} From e511d21a0f5a50af2fc28ba8ddf352de2cb88c73 Mon Sep 17 00:00:00 2001 From: KlaasWhite Date: Thu, 13 Nov 2025 23:36:02 +0100 Subject: [PATCH 3/5] Another attempt to have the github nuget be accessable --- .github/workflows/pr-build.yml | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/.github/workflows/pr-build.yml b/.github/workflows/pr-build.yml index 3e6b273..4e4d69e 100644 --- a/.github/workflows/pr-build.yml +++ b/.github/workflows/pr-build.yml @@ -16,6 +16,7 @@ jobs: env: DOTNET_VERSION: 9.0 PROJECT: StarMapLoader/StarMapLoader.csproj + NUGET_SOURCE: "https://nuget.pkg.github.com/${{ github.repository_owner }}/index.json" steps: - uses: actions/checkout@v4 @@ -28,11 +29,7 @@ jobs: - name: Setup Github NuGet run: | - dotnet nuget add source \ - --username ${{ github.actor }} \ - --password ${{ secrets.GITHUB_TOKEN }} \ - --store-password-in-clear-text \ - --name github "https://nuget.pkg.github.com/${{ github.repository_owner }}/index.json" + dotnet nuget add source --username "${{ github.actor }}" --password "${{ secrets.GITHUB_TOKEN }}" --store-password-in-clear-text --name github "${{ env.NUGET_SOURCE }}" - name: Restore dependencies run: dotnet restore ${{ env.PROJECT }} From daa27f6ff8cd00c29f05286e59f97325fec6b62f Mon Sep 17 00:00:00 2001 From: KlaasWhite Date: Thu, 13 Nov 2025 23:37:38 +0100 Subject: [PATCH 4/5] Another attempty --- .github/workflows/pr-build.yml | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/.github/workflows/pr-build.yml b/.github/workflows/pr-build.yml index 4e4d69e..1381096 100644 --- a/.github/workflows/pr-build.yml +++ b/.github/workflows/pr-build.yml @@ -27,12 +27,10 @@ jobs: with: dotnet-version: ${{ env.DOTNET_VERSION }} - - name: Setup Github NuGet + - name: Restore dependencies run: | dotnet nuget add source --username "${{ github.actor }}" --password "${{ secrets.GITHUB_TOKEN }}" --store-password-in-clear-text --name github "${{ env.NUGET_SOURCE }}" - - - name: Restore dependencies - run: dotnet restore ${{ env.PROJECT }} + dotnet restore ${{ env.PROJECT }} # - name: Run tests # run: dotnet test --no-build --verbosity normal From dba3c000e5f43a7d9a04bbe8ee0c6356df34933b Mon Sep 17 00:00:00 2001 From: KlaasWhite Date: Thu, 13 Nov 2025 23:39:56 +0100 Subject: [PATCH 5/5] Add package read permission to build step --- .github/workflows/pr-build.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/pr-build.yml b/.github/workflows/pr-build.yml index 1381096..0241080 100644 --- a/.github/workflows/pr-build.yml +++ b/.github/workflows/pr-build.yml @@ -9,6 +9,7 @@ on: permissions: pull-requests: write contents: read + packages: read jobs: preview: