diff --git a/.github/workflows/pr-build.yml b/.github/workflows/pr-build.yml index 69d144b..c8ac194 100644 --- a/.github/workflows/pr-build.yml +++ b/.github/workflows/pr-build.yml @@ -12,7 +12,9 @@ permissions: packages: read jobs: - preview: + preview-build: + # Only run for local PRs + if: github.event.pull_request.head.repo.full_name == github.repository runs-on: ubuntu-latest env: DOTNET_VERSION: 9.0 diff --git a/.github/workflows/pr-version.yml b/.github/workflows/pr-version.yml index af81f92..dcafbee 100644 --- a/.github/workflows/pr-version.yml +++ b/.github/workflows/pr-version.yml @@ -11,7 +11,9 @@ permissions: contents: read jobs: - preview: + preview-version: + # Only run for local PRs + if: github.event.pull_request.head.repo.full_name == github.repository runs-on: ubuntu-latest steps: @@ -29,8 +31,8 @@ jobs: git fetch --tags || true current=$(git describe --tags --abbrev=0 2>/dev/null || true) if [ -z "$current" ]; then - echo "No tags found, defaulting to v0.0.0" - current="v0.0.0" + echo "No tags found, defaulting to 0.0.0" + current="0.0.0" fi # Remove leading 'v' then extract parts using awk @@ -49,7 +51,7 @@ jobs: patch=$((patch+1)); type="patch" fi - next="v${major}.${minor}.${patch}" + next="${major}.${minor}.${patch}" # Safely write outputs if [ -n "$GITHUB_OUTPUT" ]; then diff --git a/.github/workflows/rc-build.yml b/.github/workflows/rc-build.yml index b15d176..7498361 100644 --- a/.github/workflows/rc-build.yml +++ b/.github/workflows/rc-build.yml @@ -1,4 +1,4 @@ -name: Release new version +name: Release new RC release on: push: @@ -62,6 +62,11 @@ jobs: echo "new_version=$new_version" >> $GITHUB_OUTPUT echo "hash_version=$hash_version" >> $GITHUB_OUTPUT + - name: Update RC tag + run: | + git tag -f rc + git push origin rc --force + - name: Setup NuGet source run: | dotnet nuget add source \ @@ -195,8 +200,3 @@ jobs: ./build_artifacts/version.txt env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - - - name: Update RC tag - run: | - git tag -f rc - git push origin rc --force diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 4c1b814..6c184d4 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -41,8 +41,8 @@ jobs: git fetch --tags || true current=$(git describe --tags --abbrev=0 2>/dev/null || true) if [ -z "$current" ]; then - echo "No tags found, defaulting to v0.0.0" - current="v0.0.0" + echo "No tags found, defaulting to 0.0.0" + current="0.0.0" fi # Remove leading 'v' then extract parts using awk @@ -69,6 +69,15 @@ jobs: echo "prev_version=$current" >> $GITHUB_OUTPUT echo "new_version=$new_version" >> $GITHUB_OUTPUT + - name: Tag and push new version + run: | + git config user.name "github-actions" + git config user.email "actions@github.com" + + NEW_VERSION="${{ steps.version.outputs.new_version }}" + git tag "$NEW_VERSION" + git push origin "$NEW_VERSION" + - name: Setup NuGet source run: | dotnet nuget add source \ @@ -106,18 +115,10 @@ jobs: mv ${{ env.LAUNCHER_OUTPUT_PATH }}/StarMap.Launcher.exe ${{ env.LAUNCHER_OUTPUT_PATH }}/StarMap.exe mv ${{ env.STANDALONE_OUTPUT_PATH }}/StarMap.Loader.exe ${{ env.STANDALONE_OUTPUT_PATH }}/StarMap.exe - - name: Tag and push new version - run: | - git config user.name "github-actions" - git config user.email "actions@github.com" - - NEW_VERSION="${{ steps.version.outputs.new_version }}" - git tag "$NEW_VERSION" - git push origin "$NEW_VERSION" - name: Upload build artifacts uses: actions/upload-artifact@v4 with: - name: rc-build + name: publish path: | ${{ env.LAUNCHER_OUTPUT_PATH }} ${{ env.STANDALONE_OUTPUT_PATH }} @@ -170,7 +171,7 @@ jobs: - name: Download build artifacts uses: actions/download-artifact@v4 with: - name: rc-build + name: publish path: ./build_artifacts - name: Setup NuGet source @@ -207,7 +208,7 @@ jobs: - name: Download build artifacts uses: actions/download-artifact@v4 with: - name: rc-build + name: publish path: ./build_artifacts - name: Ensure zip is available @@ -250,7 +251,7 @@ jobs: uses: actions/download-artifact@v4 with: name: publish - path: publish + path: ./build_artifacts # Install Inno Setup via Chocolatey - name: Install Inno Setup diff --git a/README.md b/README.md index 2f08e97..aec0447 100644 --- a/README.md +++ b/README.md @@ -15,7 +15,12 @@ It makes use of Assembly Load Contexts to ensure mod dependencies are managed se ## Mod location -Mods should be installed in the contents folder in the KSA installation, StarMap makes use of the +Mods can be placed in either of these two locations: + +- `Documents/My Games/Kitten Space Agency/mods//` (recommended, persists across game updates) +- `/Content//` + +StarMap uses the game's manifest system to discover mods from both locations. ## Mod creation diff --git a/StarMap.API/StarMap.API.csproj b/StarMap.API/StarMap.API.csproj index 71d564e..8d55bad 100644 --- a/StarMap.API/StarMap.API.csproj +++ b/StarMap.API/StarMap.API.csproj @@ -18,7 +18,7 @@ - + compile; build; analyzers all diff --git a/StarMap.Core/ModRepository/ModLoader.cs b/StarMap.Core/ModRepository/ModLoader.cs index c0a8754..caa743c 100644 --- a/StarMap.Core/ModRepository/ModLoader.cs +++ b/StarMap.Core/ModRepository/ModLoader.cs @@ -56,19 +56,14 @@ private void PrepareMods() var mods = ModLibrary.Manifest.Mods; if (mods is null) return; - string rootPath = "Content"; - string path = Path.Combine(new ReadOnlySpan(in rootPath)); - foreach (var mod in mods) { if (!mod.Enabled) { - Console.WriteLine($"StarMap - Nod loading mod: {mod.Id} because it is disable in manifest"); + Console.WriteLine($"StarMap - Not loading mod: {mod.Id} because it is disable in manifest"); continue; } - var modPath = Path.Combine(path, mod.Id); - if (!RuntimeMod.TryCreateMod(mod, _coreAssemblyLoadContext, out var runtimeMod)) continue; diff --git a/StarMap.Core/ModRepository/RuntimeMod.cs b/StarMap.Core/ModRepository/RuntimeMod.cs index 25bea2e..1cb09b8 100644 --- a/StarMap.Core/ModRepository/RuntimeMod.cs +++ b/StarMap.Core/ModRepository/RuntimeMod.cs @@ -38,7 +38,12 @@ public static bool TryCreateMod(ModEntry manifestEntry, AssemblyLoadContext core var modPath = Path.Combine(_rootContentPath, manifestEntry.Id); var modTomlPath = Path.Combine(modPath, "mod.toml"); - if (!File.Exists(modTomlPath)) return false; + if (!File.Exists(modTomlPath)) + { + modPath = Path.Combine(ModLibrary.LocalModsFolderPath, manifestEntry.Id); + modTomlPath = Path.Combine(modPath, "mod.toml"); + if (!File.Exists(modTomlPath)) return false; + } var tomlConfig = TomletMain.To(File.ReadAllText(modTomlPath)); if (tomlConfig?.StarMap is not StarMapConfig starMapConfig) { diff --git a/StarMap.Core/Patches/ProgramPatcher.cs b/StarMap.Core/Patches/ProgramPatcher.cs index 5c819d7..33d2f77 100644 --- a/StarMap.Core/Patches/ProgramPatcher.cs +++ b/StarMap.Core/Patches/ProgramPatcher.cs @@ -7,10 +7,11 @@ namespace StarMap.Core.Patches [HarmonyPatch(typeof(Program))] internal static class ProgramPatcher { - private const string OnDrawUiMethodName = "OnDrawUi"; + private const string OnBeforeDrawUiMethodName = "OnDrawUiFrame"; + private const string OnAfterDrawUiMethodName = "OnDrawUiViewports"; private const string OnFrameMethodName = "OnFrame"; - [HarmonyPatch(OnDrawUiMethodName)] + [HarmonyPatch(OnBeforeDrawUiMethodName)] [HarmonyPrefix] public static void BeforeOnDrawUi(double dt) { @@ -22,7 +23,7 @@ public static void BeforeOnDrawUi(double dt) } } - [HarmonyPatch(OnDrawUiMethodName)] + [HarmonyPatch(OnAfterDrawUiMethodName)] [HarmonyPostfix] public static void AfterOnDrawUi(double dt) { diff --git a/StarMap.Core/StarMap.Core.csproj b/StarMap.Core/StarMap.Core.csproj index 53dc1d7..3859eda 100644 --- a/StarMap.Core/StarMap.Core.csproj +++ b/StarMap.Core/StarMap.Core.csproj @@ -23,7 +23,7 @@ - + runtime diff --git a/StarMap.Loader/GameSurveyer.cs b/StarMap.Loader/GameSurveyer.cs index 371a191..2500aa1 100644 --- a/StarMap.Loader/GameSurveyer.cs +++ b/StarMap.Loader/GameSurveyer.cs @@ -10,15 +10,17 @@ internal class GameSurveyer : IDisposable private readonly IGameFacade _facade; private readonly AssemblyLoadContext _gameAssemblyContext; private readonly string _gameLocation; + private readonly string[] _args; private Assembly? _game; private IStarMapCore? _core; - public GameSurveyer(IGameFacade facade, AssemblyLoadContext alc, string location) + public GameSurveyer(IGameFacade facade, AssemblyLoadContext alc, string location, string[] args) { _facade = facade; _gameAssemblyContext = alc; _gameLocation = location; + _args = args; } public bool TryLoadCoreAndGame() @@ -51,9 +53,7 @@ public void RunGame() { Debug.Assert(_game is not null, "Load needs to be called before running game"); - string[] args = []; - - _game.EntryPoint!.Invoke(null, [args]); + _game.EntryPoint!.Invoke(null, [_args]); } public void Dispose() diff --git a/StarMap.Loader/Program.cs b/StarMap.Loader/Program.cs index b5a212a..63b75c7 100644 --- a/StarMap.Loader/Program.cs +++ b/StarMap.Loader/Program.cs @@ -36,7 +36,7 @@ static void SoleModeInner() var gameAssemblyContext = new GameAssemblyLoadContext(gameConfig.GameLocation); var dumbFacade = new SoloGameFacade(); - using var gameSurveyer = new GameSurveyer(dumbFacade, gameAssemblyContext, gameConfig.GameLocation); + using var gameSurveyer = new GameSurveyer(dumbFacade, gameAssemblyContext, gameConfig.GameLocation, gameConfig.GameArguments); if (!gameSurveyer.TryLoadCoreAndGame()) { Console.WriteLine("StarMap - Unable to load mod manager and game in solo mode."); @@ -55,7 +55,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); + var gameSurveyer = new GameSurveyer(facade, gameAssemblyContext, gameLocation, []); if (!gameSurveyer.TryLoadCoreAndGame()) return; gameSurveyer.RunGame(); diff --git a/StarMap.Types/LoaderConfig.cs b/StarMap.Types/LoaderConfig.cs index aede82b..4f4309e 100644 --- a/StarMap.Types/LoaderConfig.cs +++ b/StarMap.Types/LoaderConfig.cs @@ -40,10 +40,14 @@ public bool TryLoadConfig() } GameLocation = path; + + GameArguments = config.GameArguments; + return true; } public string GameLocation { get; set; } = ""; public string RepositoryLocation { get; set; } = ""; + public string[] GameArguments { get; set; } = []; } }