9.6 KiB
Agent Guidelines
Rules
- Update
AGENTS.mdafter 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.csprojper mod - Package Manager: NuGet (standard feed + BepInEx dev feed)
- Packaging:
ZipModMSBuild target (explicit, not post-build) produces Thunderstore-ready.zipfiles viapowershell.exe Compress-Archive - Game DLL references:
AssemblyFromGame/Assembly-CSharp.dllandUnityEngine.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— sharedPropertyGroupdefaults (TargetFramework,AllowUnsafeBlocks,LangVersion,RestoreAdditionalProjectSources) and sharedItemGroups (BepInEx packages, game DLL references,Microsoft.NETFramework.ReferenceAssemblies).Directory.Build.targets— defines theUpdateGameDlls,ZipMod, andCopyToParentPackagetargets (see below).UpdateGameDlls.ps1— PowerShell script invoked by theUpdateGameDllstarget; locates the DSP installation via Steam registry andlibraryfolders.vdf, compares DLL timestamps, and re-publicizes stale DLLs usingassembly-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 once per solution build by the UpdateGameDlls MSBuild target, which calls UpdateGameDlls.ps1.
The target runs only when the UXAssist project is being built (the designated trigger project), or when either DLL is missing from AssemblyFromGame/. This prevents redundant executions and file-write conflicts when projects are built in parallel (dotnet build -m). The PowerShell script additionally acquires an exclusive file lock (AssemblyFromGame/.update.lock) so that the rare case where the !Exists fallback triggers multiple projects concurrently is also handled safely.
The script:
- Reads the Steam installation path from the Windows registry (
HKCU\Software\Valve\Steam). - Parses
steamapps/libraryfolders.vdfto find the library that contains DSP (AppID1366540). - Locates
<game_root>/DSPGAME_Data/Managed/. - Acquires an exclusive file lock on
AssemblyFromGame/.update.lock(waits up to 60 s). - For each DLL (
Assembly-CSharp.dll,UnityEngine.UI.dll): if the game copy is newer than the local copy, runsassembly-publicizer … --strip --overwriteto 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:ZipMod -c Release
The ZipMod 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).
Note: the target is named
ZipModrather thanPackbecausePackis a reserved target name in the .NET SDK (used for NuGet packaging) and would be silently intercepted.
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 ZipMod:
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 ZipMod target.
Key Architectural Patterns
- Shared library:
UXAssistacts as a common library.CheatEnablerandUniverseGenTweaksreferenceUXAssist.csprojdirectly to reuseCommon/,UI/, and config panel infrastructure. - Preloader pattern:
DustbinPreloaderandLabOptPreloaderuse 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.csprovides 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
IModCanSaveinterface from DSPModSave.