diff --git a/.gitignore b/.gitignore index fcfaa2c..6e79db6 100644 --- a/.gitignore +++ b/.gitignore @@ -4,6 +4,9 @@ # Rider project files /.idea/ +# VS Code project files +/.vscode/ + # C# generated folders bin/ obj/ diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 0000000..0c25d10 --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,131 @@ +# Agent Guidelines + +## Rules + +- Update `AGENTS.md` after completing every task. +- Do not record a changelog in `AGENTS.md`; modify the document content directly instead. +- All documentation and code comments must be written in English. + +## Project Overview + +This repository is a collection of **BepInEx mods** for the game **Dyson Sphere Program (DSP)**, a factory/automation game on Steam. Each subdirectory is an independent mod plugin loaded by the BepInEx framework at game startup. Mods use **HarmonyLib** to patch the game's compiled C# methods at runtime (prefix, postfix, and transpiler patches). + +## Tech Stack + +- **Language:** C# (`net472` / `netstandard2.1`, latest LangVersion) +- **Modding Framework:** BepInEx 5.x +- **Patching Library:** HarmonyLib (runtime IL patching via `[HarmonyPatch]` attributes) +- **Build System:** Visual Studio solution (`DSP_Mods.sln`), SDK-style `.csproj` per mod +- **Package Manager:** NuGet (standard feed + BepInEx dev feed) +- **Packaging:** PowerShell `Compress-Archive` in post-build produces Thunderstore-ready `.zip` files +- **Game DLL references:** `AssemblyFromGame/Assembly-CSharp.dll` and `UnityEngine.UI.dll` +- **Notable dependencies:** DSPModSave, NebulaMultiplayer API, CommonAPI, NLua, obs-websocket-dotnet, Mono.Cecil + +## Repository Structure + +``` +DSP_Mods/ +├── DSP_Mods.sln # Visual Studio solution +├── AssemblyFromGame/ # Game DLLs used as compile-time references +├── UXAssist/ # Core UX mod + shared library (largest mod) +├── CheatEnabler/ # Cheat functions mod (depends on UXAssist) +├── Dustbin/ # Storage/tank dustbin mod +├── DustbinPreloader/ # BepInEx preloader for Dustbin +├── HideTips/ # Hides tutorial/tip popups +├── LabOpt/ # Lab performance optimizations +├── LabOptPreloader/ # BepInEx preloader for LabOpt +├── LogisticMiner/ # Logistic stations auto-mine ores +├── LuaScriptEngine/ # Lua scripting support for the game +├── MechaDronesTweaks/ # Mecha drone speed/energy tweaks +├── OverclockEverything/ # Speed/power multipliers for all buildings +├── PoolOpt/ # Memory pool optimization on save loading +├── UniverseGenTweaks/ # Universe generator parameter tweaks +├── UserCloak/ # Hides/fakes Steam account info +└── CompressSave/ # Stub only (moved to external repo) +``` + +## Mods Summary + +| Mod | GUID | Description | +|-----|------|-------------| +| **UXAssist** | `org.soardev.uxassist` | Core QoL mod and shared library. Window resize, profile-based saves, FPS control, factory/logistics/navigation/Dyson Sphere tweaks, UI improvements, config panel UI, and `Common/` + `UI/` widget library shared by other mods. | +| **CheatEnabler** | `org.soardev.cheatenabler` | Cheat pack (depends on UXAssist). Instant build, architect mode, infinite resources, power boosts, Dyson Sphere cheats, mecha invincibility, and more. | +| **LogisticMiner** | — | Makes logistic stations automatically mine ores and water from the current planet. | +| **HideTips** | — | Suppresses all tutorial popups, random tips, achievement/milestone cards, and skips the prologue cutscene. | +| **MechaDronesTweaks** | — | Configurable drone speed multiplier, skip stage-1 animation, reduce energy consumption. Successor to FastDrones. | +| **OverclockEverything** | — | Multiplies speed and power consumption of belts, sorters, assemblers, labs, miners, generators, ejectors, and silos. | +| **PoolOpt** | — | Shrinks all object pool arrays to actual used size on save load, then forces GC to reduce memory footprint. | +| **UniverseGenTweaks** | — | Adds Epic difficulty, expands max star count to 1024, allows rare veins and flat terrain on birth planet. | +| **UserCloak** | — | Prevents Steam leaderboard/achievement uploads; can fake or block Steam user identity. | +| **Dustbin** | — | Turns storage boxes and tanks into item-destroying dustbins. Supports Nebula multiplayer and DSPModSave. Requires DustbinPreloader. | +| **DustbinPreloader** | — | Mono.Cecil preloader that injects `bool IsDustbin` into `StorageComponent` and `TankComponent` before game load. | +| **LabOpt** | — | Optimizes stacked Matrix Lab updates via a `rootLabId` concept. Temporarily marked obsolete. Requires LabOptPreloader. | +| **LabOptPreloader** | — | Mono.Cecil preloader that injects `int rootLabId` into `LabComponent` before game load. | +| **LuaScriptEngine** | `org.soardev.luascriptengine` | Embeds NLua runtime; loads `.lua` files from `scripts/`; exposes game lifecycle hooks and OBS WebSocket integration. | +| **CompressSave** | — | Stub only; functionality moved to external repository `soarqin/DSP_Mods_TO`. | + +## Build System + +### Shared MSBuild Configuration + +Common properties and references are factored into two root-level files that MSBuild automatically imports for every project: + +- **`Directory.Build.props`** — shared `PropertyGroup` defaults (`TargetFramework`, `AllowUnsafeBlocks`, `LangVersion`, `RestoreAdditionalProjectSources`) and shared `ItemGroup`s (BepInEx packages, game DLL references, `Microsoft.NETFramework.ReferenceAssemblies`). +- **`Directory.Build.targets`** — defines the `UpdateGameDlls`, `Pack`, and `CopyToParentPackage` targets (see below). +- **`UpdateGameDlls.ps1`** — PowerShell script invoked by the `UpdateGameDlls` target; locates the DSP installation via Steam registry and `libraryfolders.vdf`, compares DLL timestamps, and re-publicizes stale DLLs using `assembly-publicizer`. + +Individual `.csproj` files only declare what is unique to that project (GUID, version, extra packages, embedded resources). + +### Automatic Game DLL Update + +`AssemblyFromGame/` holds publicized copies of two game DLLs used as compile-time references. They are refreshed automatically **before every build** by the `UpdateGameDlls` MSBuild target, which calls `UpdateGameDlls.ps1`. + +The script: +1. Reads the Steam installation path from the Windows registry (`HKCU\Software\Valve\Steam`). +2. Parses `steamapps/libraryfolders.vdf` to find the library that contains DSP (AppID `1366540`). +3. Locates `/DSPGAME_Data/Managed/`. +4. For each DLL (`Assembly-CSharp.dll`, `UnityEngine.UI.dll`): if the game copy is newer than the local copy, runs `assembly-publicizer … --strip --overwrite` to regenerate the local file and stamps it with the source timestamp. + +The target can also be run explicitly: +``` +dotnet build -t:UpdateGameDlls +``` + +**Prerequisite:** `assembly-publicizer` must be installed as a .NET global tool: +``` +dotnet tool install -g BepInEx.AssemblyPublicizer.Cli +``` +If the tool is missing or DSP is not found, the target prints a warning and continues without failing the build. + +### Packaging + +Packaging is a **separate, explicit build target** — it does not run on every normal build. + +To produce a Thunderstore-ready zip: +``` +dotnet build -t:Pack -c Release +``` + +The `Pack` target (defined in `Directory.Build.targets`) uses pure MSBuild tasks (`MakeDir`, `Copy`, `Delete`) plus `powershell.exe -NoProfile -Command` for `Compress-Archive`. Calling `powershell.exe` as an explicit executable path works correctly from any shell environment (cmd, PowerShell, bash/WSL). + +**Per-project packaging properties** (set in the project's `PropertyGroup`): + +| Property | Default | Description | +|----------|---------|-------------| +| `PackHasChangelog` | `false` | Include `CHANGELOG.md` in the zip | +| `PackUsePluginsLayout` | `false` | Use `plugins/` + `patchers/` folder layout (Dustbin, LabOpt) | +| `PackPreloaderTargetDir` | *(empty)* | Preloader projects: destination folder for `CopyToParentPackage` | + +**Preloader projects** (DustbinPreloader, LabOptPreloader) use `CopyToParentPackage` instead of `Pack`: +``` +dotnet build -t:CopyToParentPackage -c Release +``` +This copies the preloader DLL into the sibling main mod's `package/patchers/` directory, ready to be zipped by the main mod's `Pack` target. + +## Key Architectural Patterns + +- **Shared library:** `UXAssist` acts as a common library. `CheatEnabler` and `UniverseGenTweaks` reference `UXAssist.csproj` directly to reuse `Common/`, `UI/`, and config panel infrastructure. +- **Preloader pattern:** `DustbinPreloader` and `LabOptPreloader` use Mono.Cecil to inject new fields into game assemblies at BepInEx preload time, enabling their corresponding main mods to read/write those fields via normal C# without reflection. +- **Internationalization:** `UXAssist/Common/I18N.cs` provides bilingual (EN + ZH) string lookup used across UXAssist and CheatEnabler. +- **Transpiler patches:** Performance-critical mods (LabOpt, MechaDronesTweaks) use `[HarmonyTranspiler]` to rewrite IL instructions directly for maximum efficiency. +- **Save persistence:** Mods that need to persist data use the `IModCanSave` interface from DSPModSave. diff --git a/CheatEnabler/CheatEnabler.csproj b/CheatEnabler/CheatEnabler.csproj index e91ccd6..712b85c 100644 --- a/CheatEnabler/CheatEnabler.csproj +++ b/CheatEnabler/CheatEnabler.csproj @@ -1,44 +1,15 @@ - - net472 org.soardev.cheatenabler DSP MOD - CheatEnabler 2.4.2 - true - latest CheatEnabler CheatEnabler - https://nuget.bepinex.dev/v3/index.json + true - - - - - - - - - - ..\AssemblyFromGame\Assembly-CSharp.dll - - - ..\AssemblyFromGame\UnityEngine.UI.dll - - - - - - - - - - - diff --git a/Directory.Build.props b/Directory.Build.props new file mode 100644 index 0000000..465b09c --- /dev/null +++ b/Directory.Build.props @@ -0,0 +1,36 @@ + + + + + net472 + true + latest + https://nuget.bepinex.dev/v3/index.json + + false + + false + + + + + + + + + + + + + $(MSBuildThisFileDirectory)AssemblyFromGame\Assembly-CSharp.dll + + + $(MSBuildThisFileDirectory)AssemblyFromGame\UnityEngine.UI.dll + + + + + + + + diff --git a/Directory.Build.targets b/Directory.Build.targets new file mode 100644 index 0000000..efe678a --- /dev/null +++ b/Directory.Build.targets @@ -0,0 +1,141 @@ + + + + + + + + + + + + + <_PackageDir>$(MSBuildProjectDirectory)\package + <_StagingDir>$(MSBuildProjectDirectory)\obj\pack-staging + <_ZipPath>$(_PackageDir)\$(ProjectName)-$(Version).zip + + + + + <_PackFiles Include="$(TargetPath)" /> + <_PackFiles Include="$(_PackageDir)\icon.png" /> + <_PackFiles Include="$(_PackageDir)\manifest.json" /> + <_PackFiles Include="$(MSBuildProjectDirectory)\README.md" /> + <_PackFiles Include="$(MSBuildProjectDirectory)\CHANGELOG.md" Condition="'$(PackHasChangelog)' == 'true'" /> + + + + + + + + + + + + + + + + + + + + + + + <_PackageDir>$(MSBuildProjectDirectory)\package + <_StagingDir>$(MSBuildProjectDirectory)\obj\pack-staging + <_ZipPath>$(_PackageDir)\$(ProjectName)-$(Version).zip + + + + + + + + + <_PackRootFiles Include="$(_PackageDir)\icon.png" /> + <_PackRootFiles Include="$(_PackageDir)\manifest.json" /> + <_PackRootFiles Include="$(MSBuildProjectDirectory)\README.md" /> + <_PackRootFiles Include="$(MSBuildProjectDirectory)\CHANGELOG.md" Condition="'$(PackHasChangelog)' == 'true'" /> + + + + + + + + + + + + <_PluginFiles Include="$(_PackageDir)\plugins\**\*" /> + <_PatcherFiles Include="$(_PackageDir)\patchers\**\*" /> + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Dustbin/Dustbin.csproj b/Dustbin/Dustbin.csproj index 3cdc459..0bb338c 100644 --- a/Dustbin/Dustbin.csproj +++ b/Dustbin/Dustbin.csproj @@ -1,46 +1,21 @@ - - net472 org.soardev.dustbin DSP MOD - Dustbin 1.4.0 - true - latest Dustbin Dustbin - https://nuget.bepinex.dev/v3/index.json + true + true - - - - - - - - - ..\AssemblyFromGame\Assembly-CSharp.dll - - - ..\AssemblyFromGame\UnityEngine.UI.dll - - - - - - - - - diff --git a/DustbinPreloader/DustbinPreloader.csproj b/DustbinPreloader/DustbinPreloader.csproj index ab0a219..439d58a 100644 --- a/DustbinPreloader/DustbinPreloader.csproj +++ b/DustbinPreloader/DustbinPreloader.csproj @@ -1,37 +1,9 @@ - - net472 DustbinPreloader - DSP MOD - Prealoder for Dustbin + DSP MOD - Preloader for Dustbin 1.3.1 - true - latest - https://nuget.bepinex.dev/v3/index.json + ..\Dustbin\package\patchers - - - - - - - - - - - ..\AssemblyFromGame\Assembly-CSharp.dll - - - ..\AssemblyFromGame\UnityEngine.UI.dll - - - - - - - - - - diff --git a/HideTips/HideTips.csproj b/HideTips/HideTips.csproj index 367870b..43ca70f 100644 --- a/HideTips/HideTips.csproj +++ b/HideTips/HideTips.csproj @@ -1,38 +1,10 @@ - - net472 HideTips org.soardev.hidetips DSP MOD - HideTips 1.0.4 - true - latest - https://nuget.bepinex.dev/v3/index.json + true - - - - - - - - - - - ..\AssemblyFromGame\Assembly-CSharp.dll - - - ..\AssemblyFromGame\UnityEngine.UI.dll - - - - - - - - - - diff --git a/LabOpt/LabOpt.csproj b/LabOpt/LabOpt.csproj index a73a30d..3c9a5d7 100644 --- a/LabOpt/LabOpt.csproj +++ b/LabOpt/LabOpt.csproj @@ -1,38 +1,10 @@ - - net472 LabOpt org.soardev.labopt DSP MOD - LabOpt 0.3.6 - true - latest - https://nuget.bepinex.dev/v3/index.json + true - - - - - - - - - - - ..\AssemblyFromGame\Assembly-CSharp.dll - - - ..\AssemblyFromGame\UnityEngine.UI.dll - - - - - - - - - - diff --git a/LabOptPreloader/LabOptPreloader.csproj b/LabOptPreloader/LabOptPreloader.csproj index a95a026..28e1c29 100644 --- a/LabOptPreloader/LabOptPreloader.csproj +++ b/LabOptPreloader/LabOptPreloader.csproj @@ -1,37 +1,9 @@ - - net472 LabOptPreloader - DSP MOD - Prealoder for LabOpt + DSP MOD - Preloader for LabOpt 0.2.1 - true - latest - https://nuget.bepinex.dev/v3/index.json + ..\LabOpt\package\patchers - - - - - - - - - - - ..\AssemblyFromGame\Assembly-CSharp.dll - - - ..\AssemblyFromGame\UnityEngine.UI.dll - - - - - - - - - - diff --git a/LogisticMiner/LogisticMiner.csproj b/LogisticMiner/LogisticMiner.csproj index c4b1896..682a6d3 100644 --- a/LogisticMiner/LogisticMiner.csproj +++ b/LogisticMiner/LogisticMiner.csproj @@ -1,34 +1,9 @@ - - net472 LogisticMiner org.soardev.logisticminer DSP MOD - LogisticMiner 0.2.0 - true - latest - https://nuget.bepinex.dev/v3/index.json - - - - - - - - - - - ..\AssemblyFromGame\Assembly-CSharp.dll - - - ..\AssemblyFromGame\UnityEngine.UI.dll - - - - - - diff --git a/LuaScriptEngine/LuaScriptEngine.csproj b/LuaScriptEngine/LuaScriptEngine.csproj index 8b5a262..ad186ef 100644 --- a/LuaScriptEngine/LuaScriptEngine.csproj +++ b/LuaScriptEngine/LuaScriptEngine.csproj @@ -1,37 +1,17 @@ - + netstandard2.1 LuaScriptEngine org.soardev.luascriptengine DSP MOD - LuaScriptEngine 1.0.0 - true - latest PackageReference - https://nuget.bepinex.dev/v3/index.json - - - - - - - - - ..\AssemblyFromGame\Assembly-CSharp.dll - - - ..\AssemblyFromGame\UnityEngine.UI.dll - - - - - diff --git a/MechaDronesTweaks/MechaDronesTweaks.csproj b/MechaDronesTweaks/MechaDronesTweaks.csproj index 823533c..a8f5ae2 100644 --- a/MechaDronesTweaks/MechaDronesTweaks.csproj +++ b/MechaDronesTweaks/MechaDronesTweaks.csproj @@ -1,38 +1,10 @@ - - net472 MechaDronesTweaks org.soardev.mechadronestweaks DSP MOD - MechaDronesTweaks 1.1.4 - true - latest - https://nuget.bepinex.dev/v3/index.json + true - - - - - - - - - - - ..\AssemblyFromGame\Assembly-CSharp.dll - - - ..\AssemblyFromGame\UnityEngine.UI.dll - - - - - - - - - - diff --git a/OverclockEverything/OverclockEverything.csproj b/OverclockEverything/OverclockEverything.csproj index 3577823..508e5af 100644 --- a/OverclockEverything/OverclockEverything.csproj +++ b/OverclockEverything/OverclockEverything.csproj @@ -1,40 +1,14 @@ - - net472 org.soardev.overclockeverything DSP MOD - OverclockEverything 1.0.0 - true - latest OverclockEverything OverclockEverything - https://nuget.bepinex.dev/v3/index.json - - - - - - - - ..\AssemblyFromGame\Assembly-CSharp.dll - - - ..\AssemblyFromGame\UnityEngine.UI.dll - - - - - - - - - - diff --git a/PoolOpt/PoolOpt.csproj b/PoolOpt/PoolOpt.csproj index e697fb3..3b22e48 100644 --- a/PoolOpt/PoolOpt.csproj +++ b/PoolOpt/PoolOpt.csproj @@ -1,38 +1,9 @@ - - net472 PoolOpt org.soardev.poolopt DSP MOD - PoolOpt 0.9.3 - true - latest - https://nuget.bepinex.dev/v3/index.json - - - - - - - - - - - ..\AssemblyFromGame\Assembly-CSharp.dll - - - ..\AssemblyFromGame\UnityEngine.UI.dll - - - - - - - - - - diff --git a/UXAssist/UXAssist.csproj b/UXAssist/UXAssist.csproj index 587582d..308375e 100644 --- a/UXAssist/UXAssist.csproj +++ b/UXAssist/UXAssist.csproj @@ -1,35 +1,19 @@ - net472 org.soardev.uxassist DSP MOD - UXAssist 1.5.5 - true - latest UXAssist UXAssist - https://nuget.bepinex.dev/v3/index.json + true - - - - - - - ..\AssemblyFromGame\Assembly-CSharp.dll - - - ..\AssemblyFromGame\UnityEngine.UI.dll - - - @@ -56,13 +40,4 @@ - - - - - - - - diff --git a/UniverseGenTweaks/UniverseGenTweaks.csproj b/UniverseGenTweaks/UniverseGenTweaks.csproj index 1c011cd..c9e9fa7 100644 --- a/UniverseGenTweaks/UniverseGenTweaks.csproj +++ b/UniverseGenTweaks/UniverseGenTweaks.csproj @@ -1,43 +1,18 @@ - - net472 UniverseGenTweaks org.soardev.universegentweaks DSP MOD - UniverseGenTweaks 1.2.11 - true - latest - https://nuget.bepinex.dev/v3/index.json + true - - - - - - - ..\AssemblyFromGame\Assembly-CSharp.dll - - - ..\AssemblyFromGame\UnityEngine.UI.dll - - - - - - - - - - - diff --git a/UpdateGameDlls.ps1 b/UpdateGameDlls.ps1 new file mode 100644 index 0000000..9fadf80 --- /dev/null +++ b/UpdateGameDlls.ps1 @@ -0,0 +1,178 @@ +# UpdateGameDlls.ps1 +# Finds the Dyson Sphere Program installation via Steam registry and libraryfolders.vdf, +# then uses assembly-publicizer to refresh AssemblyFromGame/ if the game DLLs are newer. + +param( + [string]$ProjectRoot = $PSScriptRoot +) + +Set-StrictMode -Version Latest +$ErrorActionPreference = 'Stop' + +$DSP_APPID = '1366540' +$DSP_DLLS = @('Assembly-CSharp.dll', 'UnityEngine.UI.dll') +$MANAGED_SUBPATH = 'DSPGAME_Data\Managed' +$OUTPUT_DIR = Join-Path $ProjectRoot 'AssemblyFromGame' + +# --------------------------------------------------------------------------- +# 1. Locate Steam installation via registry +# --------------------------------------------------------------------------- +$steamPath = $null +foreach ($regPath in @( + 'HKCU:\Software\Valve\Steam', + 'HKLM:\Software\Valve\Steam', + 'HKLM:\Software\Wow6432Node\Valve\Steam' +)) { + try { + $val = (Get-ItemProperty -LiteralPath $regPath -Name SteamPath -ErrorAction Stop).SteamPath + if ($val -and (Test-Path $val)) { + $steamPath = $val + break + } + } catch { } +} + +if (-not $steamPath) { + Write-Warning 'UpdateGameDlls: Steam installation not found in registry; skipping DLL update.' + exit 0 +} + +# --------------------------------------------------------------------------- +# 2. Parse libraryfolders.vdf to find all Steam library paths +# --------------------------------------------------------------------------- +$vdfPath = Join-Path $steamPath 'steamapps\libraryfolders.vdf' +if (-not (Test-Path $vdfPath)) { + Write-Warning "UpdateGameDlls: $vdfPath not found; skipping DLL update." + exit 0 +} + +$vdfContent = Get-Content $vdfPath -Raw -Encoding UTF8 + +# Extract all library folder paths that contain the DSP app id. +# VDF structure: "path" "" followed (somewhere) by "" +# Strategy: split into per-library-entry blocks, then check each block. +$libraryPaths = @() + +# Match each top-level numbered entry block +$blockPattern = '"(?:\d+)"\s*\{([^{}]*(?:\{[^{}]*\}[^{}]*)*)\}' +$pathPattern = '"path"\s+"([^"]+)"' +$appPattern = '"' + $DSP_APPID + '"\s+"[^"]+"' + +$blockMatches = [regex]::Matches($vdfContent, $blockPattern, [System.Text.RegularExpressions.RegexOptions]::Singleline) +foreach ($block in $blockMatches) { + $blockText = $block.Groups[1].Value + if ($blockText -match $appPattern) { + $pathMatch = [regex]::Match($blockText, $pathPattern) + if ($pathMatch.Success) { + # VDF uses forward slashes and may double-escape backslashes + $libPath = $pathMatch.Groups[1].Value -replace '\\\\', '\' -replace '/', '\' + $libraryPaths += $libPath + } + } +} + +if ($libraryPaths.Count -eq 0) { + Write-Warning "UpdateGameDlls: DSP (AppID $DSP_APPID) not found in any Steam library; skipping DLL update." + exit 0 +} + +# --------------------------------------------------------------------------- +# 3. Find the game's Managed directory +# --------------------------------------------------------------------------- +$managedDir = $null +foreach ($lib in $libraryPaths) { + $candidate = Join-Path $lib "steamapps\common\Dyson Sphere Program\$MANAGED_SUBPATH" + if (Test-Path $candidate) { + $managedDir = $candidate + break + } +} + +if (-not $managedDir) { + Write-Warning 'UpdateGameDlls: Dyson Sphere Program Managed directory not found; skipping DLL update.' + exit 0 +} + +Write-Host "UpdateGameDlls: Game Managed directory: $managedDir" + +# --------------------------------------------------------------------------- +# 4. Locate assembly-publicizer +# --------------------------------------------------------------------------- +$publicizer = $null +foreach ($candidate in @( + 'assembly-publicizer', # on PATH + "$env:USERPROFILE\.dotnet\tools\assembly-publicizer.exe", + "$env:ProgramFiles\dotnet\tools\assembly-publicizer.exe" +)) { + try { + $resolved = (Get-Command $candidate -ErrorAction Stop).Source + $publicizer = $resolved + break + } catch { } +} + +if (-not $publicizer) { + Write-Host 'UpdateGameDlls: assembly-publicizer not found; installing via dotnet tool install -g BepInEx.AssemblyPublicizer.Cli ...' + dotnet tool install -g BepInEx.AssemblyPublicizer.Cli + if ($LASTEXITCODE -ne 0) { + Write-Warning 'UpdateGameDlls: Failed to install assembly-publicizer; skipping DLL update.' + exit 0 + } + # Refresh PATH for the current process so the newly installed tool is found + $env:PATH = [System.Environment]::GetEnvironmentVariable('PATH', 'User') + ';' + $env:PATH + try { + $publicizer = (Get-Command 'assembly-publicizer' -ErrorAction Stop).Source + } catch { + Write-Warning 'UpdateGameDlls: assembly-publicizer still not found after install; skipping DLL update.' + exit 0 + } + Write-Host "UpdateGameDlls: assembly-publicizer installed at $publicizer" +} + +# --------------------------------------------------------------------------- +# 5. For each DLL: compare timestamps, publicize if game copy is newer +# --------------------------------------------------------------------------- +$updated = 0 +foreach ($dll in $DSP_DLLS) { + $srcFile = Join-Path $managedDir $dll + $dstFile = Join-Path $OUTPUT_DIR $dll + + if (-not (Test-Path $srcFile)) { + Write-Warning "UpdateGameDlls: Source DLL not found: $srcFile" + continue + } + + $srcTime = (Get-Item $srcFile).LastWriteTimeUtc + $needsUpdate = $true + + if (Test-Path $dstFile) { + $dstTime = (Get-Item $dstFile).LastWriteTimeUtc + if ($srcTime -le $dstTime) { + Write-Host "UpdateGameDlls: $dll is up-to-date (game: $srcTime, local: $dstTime)" + $needsUpdate = $false + } + } + + if ($needsUpdate) { + Write-Host "UpdateGameDlls: Publicizing $dll (game: $srcTime) ..." + # --overwrite writes directly to / (no -publicized postfix) + & $publicizer $srcFile --strip --overwrite --output $OUTPUT_DIR + if ($LASTEXITCODE -ne 0) { + Write-Error "UpdateGameDlls: assembly-publicizer failed for $dll (exit code $LASTEXITCODE)" + exit 1 + } + # Preserve the source timestamp on the output so future comparisons are stable + $outFile = Join-Path $OUTPUT_DIR $dll + if (Test-Path $outFile) { + (Get-Item $outFile).LastWriteTimeUtc = $srcTime + } + $updated++ + Write-Host "UpdateGameDlls: $dll updated." + } +} + +if ($updated -gt 0) { + Write-Host "UpdateGameDlls: $updated DLL(s) refreshed." +} else { + Write-Host 'UpdateGameDlls: All DLLs are up-to-date.' +} diff --git a/UserCloak/UserCloak.csproj b/UserCloak/UserCloak.csproj index 116cecb..923bb05 100644 --- a/UserCloak/UserCloak.csproj +++ b/UserCloak/UserCloak.csproj @@ -1,38 +1,10 @@ - net472 org.soardev.usercloak DSP MOD - UserCloak 1.0.0 - true - latest UserCloak UserCloak - https://nuget.bepinex.dev/v3/index.json - - - - - - - - - - - ..\AssemblyFromGame\Assembly-CSharp.dll - - - ..\AssemblyFromGame\UnityEngine.UI.dll - - - - - - - - - -