mirror of
https://github.com/soarqin/DSP_Mods.git
synced 2026-08-06 07:30:21 +08:00
1368 lines
40 KiB
Markdown
1368 lines
40 KiB
Markdown
# UXAssist / CheatEnabler / UniverseGenTweaks Refactor Implementation Plan
|
|
|
|
> **For agentic workers:** REQUIRED SUB-SKILL: Use `superpowers:subagent-driven-development` (recommended) or `superpowers:executing-plans` to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.
|
|
|
|
**Goal:** Improve readability and maintainability of `UXAssist`, `CheatEnabler`, and `UniverseGenTweaks` by splitting oversized files, centralizing constants/localization, cleaning static mutable state, and hardening transpilers. Only `UXAssist.UI` and `UXAssist.Common` public APIs are treated as a stable contract; everything else may be refactored freely, and downstream projects are updated to consume the new structure.
|
|
|
|
**Architecture:** Keep the existing BepInEx + Harmony stack. Introduce a reusable, public mod-feature lifecycle abstraction in `UXAssist.Common.ModFeatures` that replaces the current namespace-based reflection on static `Functions`/`Patches` classes. Each static feature class declares `[ModFeature]` and exposes `Init`/`Start`/`Uninit`/`OnInputUpdate`/`OnUpdate` as needed; `ModFeatureRegistry.Discover` finds and registers them, then drives their lifecycle. `CheatEnabler` and `UniverseGenTweaks` adopt the same abstraction, so they benefit from the same architecture rather than using `InternalsVisibleTo`.
|
|
|
|
Split monolithic `Patches/*.cs` and `Functions/*.cs` files into focused classes grouped by subsystem (e.g., `UXAssist.Patches.Factory.*`). Refactor the internals of `UXAssist.UI` and `UXAssist.Common` into smaller helpers while keeping the existing public surface intact (old members become thin forwarding facades or are marked `[Obsolete]`). Introduce `ConfigProvider` helpers and `GameConstants` classes to decouple UI from patch internals. Clean static state through explicit `ResetState` callbacks registered on `GameLogic.OnGameEnd`. Add version/fallback annotations to transpilers to survive game updates.
|
|
|
|
**Tech Stack:** C# (`net472`), BepInEx 5.x, HarmonyLib, SDK-style MSBuild, PowerShell `Compress-Archive`.
|
|
|
|
---
|
|
|
|
## Phase 1 — Structural Split + Public Lifecycle Abstraction
|
|
|
|
### Task 1: Document the public API surface that must stay stable
|
|
|
|
**Files:**
|
|
- Create: `docs/PublicApiSurface.md`
|
|
|
|
- [ ] **Step 1: Inventory `UXAssist.UI` and `UXAssist.Common` public members**
|
|
|
|
Read every file under `UXAssist/UI/` and `UXAssist/Common/` and list every `public` class/struct/enum/delegate/method/property/event/field that is reachable from `CheatEnabler` or `UniverseGenTweaks`.
|
|
|
|
At minimum, the list must include:
|
|
- `UXAssist.Common.I18N` (`Add`, `Apply`, `Translate`, `Init`, `OnInitialized`)
|
|
- `UXAssist.Common.GameLogic` (`Enable`, `OnDataLoaded`, `OnGameBegin`, `OnGameEnd`, `OnFactoryFrameBegin`)
|
|
- `UXAssist.Common.PatchImpl<T>` and `PatchGuidAttribute`
|
|
- `UXAssist.Common.Util` (`GetTypesFiltered`, `GetTypesInNamespace`, `LoadEmbeddedResource`, `LoadEmbeddedTexture`, `LoadEmbeddedSprite`, `PluginFolder`)
|
|
- `UXAssist.UI.MyConfigWindow` (`OnUICreated`, `OnUpdateUI`, `CreateInstance`, `DestroyInstance`)
|
|
- `UXAssist.UI.MyWindow` (`InitBaseObject`, `Create`, `AddText`, `AddText2`, `AddButton`, `AddTipsButton`, `AddTipsButton2`, `Open`, `Close`, `TryClose`, `AutoFitWindowSize`)
|
|
- `UXAssist.UI.MyWindowWithTabs` (`AddTabGroup`, `AddTab`)
|
|
- `UXAssist.UI.MyCheckBox.CreateCheckBox`
|
|
- `UXAssist.UI.MySlider.CreateSlider`
|
|
- `UXAssist.UI.MyWindowManager` (`InitBaseObjects`, `Enable`)
|
|
|
|
- [ ] **Step 2: Commit the inventory**
|
|
|
|
```bash
|
|
git add docs/PublicApiSurface.md
|
|
git commit -m "docs: inventory UXAssist.UI/Common public API surface"
|
|
```
|
|
|
|
---
|
|
|
|
### Task 2: Introduce public `ModFeature` lifecycle abstraction
|
|
|
|
**Files:**
|
|
- Create: `UXAssist/Common/ModFeatures/ModFeatureAttribute.cs`
|
|
- Create: `UXAssist/Common/ModFeatures/IModFeature.cs`
|
|
- Create: `UXAssist/Common/ModFeatures/ModFeatureRegistry.cs`
|
|
- Modify: `UXAssist/Common/Util.cs`
|
|
|
|
- [ ] **Step 1: Add namespace-prefix reflection helper**
|
|
|
|
In `UXAssist/Common/Util.cs`:
|
|
```csharp
|
|
public static Type[] GetTypesInNamespacePrefix(Assembly assembly, string prefix)
|
|
{
|
|
return GetTypesFiltered(assembly, t => t.Namespace != null && t.Namespace.StartsWith(prefix, StringComparison.Ordinal));
|
|
}
|
|
```
|
|
|
|
- [ ] **Step 2: Define the attribute**
|
|
|
|
```csharp
|
|
namespace UXAssist.Common.ModFeatures;
|
|
|
|
[AttributeUsage(AttributeTargets.Class, Inherited = false)]
|
|
public sealed class ModFeatureAttribute : Attribute
|
|
{
|
|
public string Name { get; }
|
|
public int Order { get; set; }
|
|
|
|
public ModFeatureAttribute(string name = null)
|
|
{
|
|
Name = name;
|
|
}
|
|
}
|
|
```
|
|
|
|
- [ ] **Step 3: Define the optional instance interface**
|
|
|
|
```csharp
|
|
namespace UXAssist.Common.ModFeatures;
|
|
|
|
public interface IModFeature
|
|
{
|
|
void Init();
|
|
void Start();
|
|
void Uninit();
|
|
void OnInputUpdate();
|
|
void OnUpdate();
|
|
}
|
|
```
|
|
|
|
- [ ] **Step 4: Implement the registry**
|
|
|
|
```csharp
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using System.Reflection;
|
|
|
|
namespace UXAssist.Common.ModFeatures;
|
|
|
|
public static class ModFeatureRegistry
|
|
{
|
|
private static readonly List<Type> _staticFeatures = [];
|
|
private static readonly List<IModFeature> _instanceFeatures = [];
|
|
private static readonly HashSet<Assembly> _discoveredAssemblies = [];
|
|
|
|
public static void Discover(Assembly assembly)
|
|
{
|
|
if (!_discoveredAssemblies.Add(assembly)) return;
|
|
|
|
var staticTypes = Util.GetTypesFiltered(assembly, t =>
|
|
t.IsClass && t.IsAbstract && t.IsSealed &&
|
|
Attribute.IsDefined(t, typeof(ModFeatureAttribute)));
|
|
|
|
foreach (var type in staticTypes.OrderBy(GetOrder))
|
|
{
|
|
if (!_staticFeatures.Contains(type))
|
|
_staticFeatures.Add(type);
|
|
}
|
|
}
|
|
|
|
public static void Register<T>() where T : class, IModFeature, new()
|
|
{
|
|
var instance = new T();
|
|
_instanceFeatures.Add(instance);
|
|
}
|
|
|
|
public static void InitAll()
|
|
{
|
|
ForEachStatic("Init");
|
|
foreach (var f in _instanceFeatures) f.Init();
|
|
}
|
|
|
|
public static void StartAll()
|
|
{
|
|
ForEachStatic("Start");
|
|
foreach (var f in _instanceFeatures) f.Start();
|
|
}
|
|
|
|
public static void UninitAll()
|
|
{
|
|
ForEachStatic("Uninit");
|
|
foreach (var f in _instanceFeatures) f.Uninit();
|
|
}
|
|
|
|
public static void OnInputUpdateAll()
|
|
{
|
|
ForEachStatic("OnInputUpdate");
|
|
foreach (var f in _instanceFeatures) f.OnInputUpdate();
|
|
}
|
|
|
|
public static void OnUpdateAll()
|
|
{
|
|
ForEachStatic("OnUpdate");
|
|
foreach (var f in _instanceFeatures) f.OnUpdate();
|
|
}
|
|
|
|
private static void ForEachStatic(string methodName)
|
|
{
|
|
foreach (var type in _staticFeatures)
|
|
{
|
|
var method = type.GetMethod(methodName,
|
|
BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static);
|
|
method?.Invoke(null, null);
|
|
}
|
|
}
|
|
|
|
private static int GetOrder(Type type)
|
|
{
|
|
return type.GetCustomAttribute<ModFeatureAttribute>()?.Order ?? 0;
|
|
}
|
|
}
|
|
```
|
|
|
|
- [ ] **Step 5: Build UXAssist**
|
|
|
|
```bash
|
|
dotnet build UXAssist/UXAssist.csproj -c Release
|
|
```
|
|
Expected: 0 errors.
|
|
|
|
- [ ] **Step 6: Commit**
|
|
|
|
```bash
|
|
git add UXAssist/Common/ModFeatures/ UXAssist/Common/Util.cs
|
|
git commit -m "feat(UXAssist): public ModFeature lifecycle registry"
|
|
```
|
|
|
|
---
|
|
|
|
### Task 3: Split `UXAssist/Patches/FactoryPatch.cs` and mark features
|
|
|
|
**Files:**
|
|
- Create: `UXAssist/Patches/Factory/FactoryPatch.cs` (config coordinator)
|
|
- Create: `UXAssist/Patches/Factory/ImmediateBuildPatch.cs`
|
|
- Create: `UXAssist/Patches/Factory/ArchitectModePatch.cs`
|
|
- Create: `UXAssist/Patches/Factory/BuildToolPatch.cs`
|
|
- Create: `UXAssist/Patches/Factory/BeltSignalPatch.cs`
|
|
- Create: `UXAssist/Patches/Factory/BuildingBufferPatch.cs`
|
|
- Create: `UXAssist/Patches/Factory/VeinProtectionPatch.cs`
|
|
- Create: `UXAssist/Patches/Factory/PowerGenerationPatch.cs`
|
|
- Create: `UXAssist/Patches/Factory/RenderingPatch.cs`
|
|
- Delete: `UXAssist/Patches/FactoryPatch.cs`
|
|
|
|
- [ ] **Step 1: Move nested patch classes to new files**
|
|
|
|
Use `git mv` semantics: copy the contents of each nested `PatchImpl<T>` class from the old file into a new file under `UXAssist/Patches/Factory/`. Keep each class `internal` unless it must be public. Use namespace `UXAssist.Patches.Factory`.
|
|
|
|
- [ ] **Step 2: Create the coordinator `FactoryPatch`**
|
|
|
|
Mark it as a mod feature and expose the public `ConfigEntry<T>` fields:
|
|
```csharp
|
|
using UXAssist.Common.ModFeatures;
|
|
|
|
namespace UXAssist.Patches.Factory;
|
|
|
|
[ModFeature("Factory", Order = 10)]
|
|
public static class FactoryPatch
|
|
{
|
|
public static ConfigEntry<bool> UnlimitInteractiveEnabled { get; internal set; }
|
|
// ... all other public ConfigEntry fields from the original file
|
|
|
|
public static void Init()
|
|
{
|
|
ImmediateBuildPatch.Init();
|
|
ArchitectModePatch.Init();
|
|
// ...
|
|
}
|
|
|
|
public static void Start()
|
|
{
|
|
ImmediateBuildPatch.Start();
|
|
// ...
|
|
}
|
|
|
|
public static void Uninit()
|
|
{
|
|
ImmediateBuildPatch.Uninit();
|
|
// ...
|
|
}
|
|
|
|
public static void OnInputUpdate() => BeltSignalPatch.OnInputUpdate();
|
|
public static void Export(BinaryWriter w) => BeltSignalPatch.Export(w);
|
|
public static void Import(BinaryReader r) => BeltSignalPatch.Import(r);
|
|
}
|
|
```
|
|
|
|
`Awake()` in `UXAssist.cs` already assigns every `ConfigEntry`; leave those assignments untouched.
|
|
|
|
- [ ] **Step 3: Build UXAssist**
|
|
|
|
```bash
|
|
dotnet build UXAssist/UXAssist.csproj -c Release
|
|
```
|
|
|
|
- [ ] **Step 4: Commit**
|
|
|
|
```bash
|
|
git add UXAssist/Patches/Factory/
|
|
git rm UXAssist/Patches/FactoryPatch.cs
|
|
git commit -m "refactor(UXAssist): split FactoryPatch into focused classes"
|
|
```
|
|
|
|
---
|
|
|
|
### Task 4: Split `UXAssist/Patches/LogisticsPatch.cs` and mark features
|
|
|
|
**Files:**
|
|
- Create: `UXAssist/Patches/Logistics/LogisticsPatch.cs`
|
|
- Create: `UXAssist/Patches/Logistics/AutoConfigPatch.cs`
|
|
- Create: `UXAssist/Patches/Logistics/CapacityPatch.cs`
|
|
- Create: `UXAssist/Patches/Logistics/OverflowPatch.cs`
|
|
- Create: `UXAssist/Patches/Logistics/RealtimeInfoPanelPatch.cs`
|
|
- Delete: `UXAssist/Patches/LogisticsPatch.cs`
|
|
|
|
- [ ] **Step 1: Move nested classes and create coordinator**
|
|
|
|
Same pattern as Task 3. Coordinator is marked `[ModFeature("Logistics", Order = 11)]` and forwards `OnInputUpdate` / `OnUpdate` to sub-classes.
|
|
|
|
- [ ] **Step 2: Build UXAssist**
|
|
|
|
```bash
|
|
dotnet build UXAssist/UXAssist.csproj -c Release
|
|
```
|
|
|
|
- [ ] **Step 3: Commit**
|
|
|
|
```bash
|
|
git add UXAssist/Patches/Logistics/
|
|
git rm UXAssist/Patches/LogisticsPatch.cs
|
|
git commit -m "refactor(UXAssist): split LogisticsPatch into focused classes"
|
|
```
|
|
|
|
---
|
|
|
|
### Task 5: Split `UXAssist/Functions/UIFunctions.cs` and mark features
|
|
|
|
**Files:**
|
|
- Create: `UXAssist/Functions/UI/StarmapFilterUI.cs`
|
|
- Create: `UXAssist/Functions/UI/MilkyWayUI.cs`
|
|
- Create: `UXAssist/Functions/UI/AutoCruiseUI.cs`
|
|
- Create: `UXAssist/Functions/UI/MenuButtonUI.cs`
|
|
- Modify: `UXAssist/Functions/UIFunctions.cs` (coordinator, marked `[ModFeature("UI", Order = 12)]`)
|
|
- Modify: `UXAssist/UXAssist.cs`
|
|
|
|
- [ ] **Step 1: Move features to sub-files**
|
|
|
|
Namespace `UXAssist.Functions.UI`. Keep `internal` where possible. Keep public `ConfigEntry<T>` fields on `UIFunctions` if bound in `UXAssist.Awake()`.
|
|
|
|
- [ ] **Step 2: Update `UXAssist.Awake()` export/import calls**
|
|
|
|
Replace `UIFunctions.ExportClusterUploadResults(w)` with a coordinator call or direct `MilkyWayUI.Export(w)`.
|
|
|
|
- [ ] **Step 3: Build UXAssist**
|
|
|
|
```bash
|
|
dotnet build UXAssist/UXAssist.csproj -c Release
|
|
```
|
|
|
|
- [ ] **Step 4: Commit**
|
|
|
|
```bash
|
|
git add UXAssist/Functions/UI/ UXAssist/Functions/UIFunctions.cs UXAssist/UXAssist.cs
|
|
git commit -m "refactor(UXAssist): split UIFunctions into UI sub-features"
|
|
```
|
|
|
|
---
|
|
|
|
### Task 6: Update `UXAssist.cs` to drive features through `ModFeatureRegistry`
|
|
|
|
**Files:**
|
|
- Modify: `UXAssist/UXAssist.cs`
|
|
|
|
- [ ] **Step 1: Discover features from UXAssist assembly**
|
|
|
|
In `Awake()`, after config binding:
|
|
```csharp
|
|
ModFeatureRegistry.Discover(Assembly.GetExecutingAssembly());
|
|
ModFeatureRegistry.InitAll();
|
|
```
|
|
|
|
- [ ] **Step 2: Replace lifecycle calls**
|
|
|
|
In `Start()`:
|
|
```csharp
|
|
ModFeatureRegistry.StartAll();
|
|
```
|
|
|
|
In `OnDestroy()`:
|
|
```csharp
|
|
ModFeatureRegistry.UninitAll();
|
|
```
|
|
|
|
- [ ] **Step 3: Replace hard-coded update calls**
|
|
|
|
In `Update()`:
|
|
```csharp
|
|
if (VFInput.inputing) return;
|
|
if (DSPGame.IsMenuDemo)
|
|
{
|
|
ModFeatureRegistry.OnInputUpdateAll();
|
|
return;
|
|
}
|
|
ModFeatureRegistry.OnInputUpdateAll();
|
|
ModFeatureRegistry.OnUpdateAll();
|
|
```
|
|
|
|
Remove the explicit per-class calls (`LogisticsPatch.OnInputUpdate()`, `UIFunctions.OnInputUpdate()`, `GamePatch.OnInputUpdate()`, `FactoryPatch.OnInputUpdate()`, `PlayerPatch.OnInputUpdate()`, `LogisticsPatch.OnUpdate()`).
|
|
|
|
- [ ] **Step 4: Keep compat initialization separate**
|
|
|
|
Keep the `ModsCompat` scan in `Awake()` and `Start()`; compat wrappers are not mod features because they receive a `Harmony` argument.
|
|
|
|
- [ ] **Step 5: Centralize save participants**
|
|
|
|
Add a simple registry in `UXAssist.cs`:
|
|
```csharp
|
|
private static readonly List<Action<BinaryWriter>> _exporters = [];
|
|
private static readonly List<Action<BinaryReader>> _importers = [];
|
|
|
|
public static void RegisterExporter(Action<BinaryWriter> e) => _exporters.Add(e);
|
|
public static void RegisterImporter(Action<BinaryReader> i) => _importers.Add(i);
|
|
```
|
|
|
|
Update `Export`/`Import` to iterate `_exporters`/`_importers`. Remove direct `FactoryPatch.Export` / `UIFunctions.ExportClusterUploadResults` calls; the coordinators register themselves during `Init`.
|
|
|
|
- [ ] **Step 6: Build UXAssist**
|
|
|
|
```bash
|
|
dotnet build UXAssist/UXAssist.csproj -c Release
|
|
```
|
|
|
|
- [ ] **Step 7: Commit**
|
|
|
|
```bash
|
|
git add UXAssist/UXAssist.cs
|
|
git commit -m "refactor(UXAssist): drive lifecycle via ModFeatureRegistry"
|
|
```
|
|
|
|
---
|
|
|
|
### Task 7: Decouple `UXAssist.UIConfigWindow` from patch internals
|
|
|
|
**Files:**
|
|
- Create: `UXAssist/Common/Config/FactoryConfigProvider.cs`
|
|
- Create: `UXAssist/Common/Config/LogisticsConfigProvider.cs`
|
|
- Modify: `UXAssist/UIConfigWindow.cs`
|
|
|
|
- [ ] **Step 1: Create config providers**
|
|
|
|
Each provider exposes only the `ConfigEntry<T>` references that the UI needs:
|
|
```csharp
|
|
public static class FactoryConfigProvider
|
|
{
|
|
public static ConfigEntry<bool> NightLightEnabled => Factory.FactoryPatch.NightLightEnabled;
|
|
// ...
|
|
}
|
|
```
|
|
|
|
- [ ] **Step 2: Update `UIConfigWindow.cs`**
|
|
|
|
Replace direct references like `FactoryPatch.NightLightEnabled` with `FactoryConfigProvider.NightLightEnabled`.
|
|
|
|
- [ ] **Step 3: Build UXAssist**
|
|
|
|
```bash
|
|
dotnet build UXAssist/UXAssist.csproj -c Release
|
|
```
|
|
|
|
- [ ] **Step 4: Commit**
|
|
|
|
```bash
|
|
git add UXAssist/Common/Config/ UXAssist/UIConfigWindow.cs
|
|
git commit -m "refactor(UXAssist): introduce config providers between UI and patches"
|
|
```
|
|
|
|
---
|
|
|
|
### Task 8: Adopt `ModFeatureRegistry` in `CheatEnabler`
|
|
|
|
**Files:**
|
|
- Modify: `CheatEnabler/CheatEnabler.cs`
|
|
|
|
- [ ] **Step 1: Replace exact-namespace reflection with feature discovery**
|
|
|
|
In `Awake()`:
|
|
```csharp
|
|
ModFeatureRegistry.Discover(Assembly.GetExecutingAssembly());
|
|
ModFeatureRegistry.InitAll();
|
|
```
|
|
|
|
In `Start()`:
|
|
```csharp
|
|
ModFeatureRegistry.StartAll();
|
|
```
|
|
|
|
In `OnDestroy()`:
|
|
```csharp
|
|
ModFeatureRegistry.UninitAll();
|
|
```
|
|
|
|
In `Update()`:
|
|
```csharp
|
|
if (VFInput.inputing) return;
|
|
ModFeatureRegistry.OnInputUpdateAll();
|
|
```
|
|
|
|
Remove `_patches` and the reflection-based `Init`/`Start`/`Uninit` loop.
|
|
|
|
- [ ] **Step 2: Build CheatEnabler**
|
|
|
|
```bash
|
|
dotnet build CheatEnabler/CheatEnabler.csproj -c Release
|
|
```
|
|
|
|
- [ ] **Step 3: Commit**
|
|
|
|
```bash
|
|
git add CheatEnabler/CheatEnabler.cs
|
|
git commit -m "refactor(CheatEnabler): adopt ModFeatureRegistry from UXAssist"
|
|
```
|
|
|
|
---
|
|
|
|
### Task 9: Split `CheatEnabler/Patches/FactoryPatch.cs`
|
|
|
|
**Files:**
|
|
- Create: `CheatEnabler/Patches/Factory/FactoryPatch.cs`
|
|
- Create: `CheatEnabler/Patches/Factory/ImmediateBuildPatch.cs`
|
|
- Create: `CheatEnabler/Patches/Factory/ArchitectModePatch.cs`
|
|
- Create: `CheatEnabler/Patches/Factory/BeltSignalPatch.cs`
|
|
- Create: `CheatEnabler/Patches/Factory/PowerBoostPatch.cs`
|
|
- Create: `CheatEnabler/Patches/Factory/LogisticsControlPatch.cs`
|
|
- Delete: `CheatEnabler/Patches/FactoryPatch.cs`
|
|
|
|
- [ ] **Step 1: Apply the coordinator pattern and `[ModFeature]`**
|
|
|
|
Namespace `CheatEnabler.Patches.Factory`. Coordinator exposes the public `ConfigEntry<T>` fields so `CheatEnabler.Awake()` continues to compile without changes. Mark coordinator `[ModFeature("CheatFactory", Order = 10)]`.
|
|
|
|
- [ ] **Step 2: Build CheatEnabler**
|
|
|
|
```bash
|
|
dotnet build CheatEnabler/CheatEnabler.csproj -c Release
|
|
```
|
|
|
|
- [ ] **Step 3: Commit**
|
|
|
|
```bash
|
|
git add CheatEnabler/Patches/Factory/
|
|
git rm CheatEnabler/Patches/FactoryPatch.cs
|
|
git commit -m "refactor(CheatEnabler): split FactoryPatch into focused classes"
|
|
```
|
|
|
|
---
|
|
|
|
### Task 10: Split `CheatEnabler/Functions/DysonSphereFunctions.cs`
|
|
|
|
**Files:**
|
|
- Create: `CheatEnabler/Functions/DysonSphere/DysonSphereResolver.cs`
|
|
- Create: `CheatEnabler/Functions/DysonSphere/ShellCompletionFunctions.cs`
|
|
- Create: `CheatEnabler/Functions/DysonSphere/FrameRemovalFunctions.cs`
|
|
- Create: `CheatEnabler/Functions/DysonSphere/IllegalShellFunctions.cs`
|
|
- Create: `CheatEnabler/Functions/DysonSphere/GeometryHelpers.cs`
|
|
- Modify: `CheatEnabler/Functions/DysonSphereFunctions.cs` (coordinator, or delete if empty)
|
|
- Modify: `CheatEnabler/Patches/DysonSpherePatch.cs` if it calls helpers
|
|
|
|
- [ ] **Step 1: Extract repeated "current sphere / star" logic**
|
|
|
|
```csharp
|
|
[ModFeature("DysonSphereResolver")]
|
|
public static class DysonSphereResolver
|
|
{
|
|
public static (DysonSphere sphere, StarData star)? ResolveCurrent()
|
|
{
|
|
var star = GameMain.localStar;
|
|
if (star == null) return null;
|
|
var sphere = GameMain.data.dysonSpheres[star.index];
|
|
if (sphere == null) return null;
|
|
return (sphere, star);
|
|
}
|
|
}
|
|
```
|
|
|
|
- [ ] **Step 2: Move shell actions to dedicated files**
|
|
|
|
Replace duplicated cleanup blocks with a shared helper:
|
|
```csharp
|
|
public static void NotifyShellChanged(DysonSphere sphere, DysonSphereLayer layer)
|
|
{
|
|
layer?.RecalculateModels();
|
|
sphere?.swarm?.RecalculateModels();
|
|
}
|
|
```
|
|
|
|
- [ ] **Step 3: Build CheatEnabler**
|
|
|
|
```bash
|
|
dotnet build CheatEnabler/CheatEnabler.csproj -c Release
|
|
```
|
|
|
|
- [ ] **Step 4: Commit**
|
|
|
|
```bash
|
|
git add CheatEnabler/Functions/DysonSphere/
|
|
git rm CheatEnabler/Functions/DysonSphereFunctions.cs
|
|
git commit -m "refactor(CheatEnabler): split DysonSphereFunctions into focused helpers"
|
|
```
|
|
|
|
---
|
|
|
|
### Task 11: Adopt `ModFeatureRegistry` in `UniverseGenTweaks`
|
|
|
|
**Files:**
|
|
- Modify: `UniverseGenTweaks/UniverseGenTweaks.cs`
|
|
|
|
- [ ] **Step 1: Replace explicit Init/Uninit with feature discovery**
|
|
|
|
In `Awake()`:
|
|
```csharp
|
|
ModFeatureRegistry.Discover(Assembly.GetExecutingAssembly());
|
|
ModFeatureRegistry.InitAll();
|
|
```
|
|
|
|
In `OnDestroy()`:
|
|
```csharp
|
|
ModFeatureRegistry.UninitAll();
|
|
```
|
|
|
|
Remove explicit `MoreSettings.Init()`, `EpicDifficulty.Init()`, `BirthPlanetPatch.Init()` and their `Uninit()` counterparts.
|
|
|
|
- [ ] **Step 2: Build UniverseGenTweaks**
|
|
|
|
```bash
|
|
dotnet build UniverseGenTweaks/UniverseGenTweaks.csproj -c Release
|
|
```
|
|
|
|
- [ ] **Step 3: Commit**
|
|
|
|
```bash
|
|
git add UniverseGenTweaks/UniverseGenTweaks.cs
|
|
git commit -m "refactor(UniverseGenTweaks): adopt ModFeatureRegistry from UXAssist"
|
|
```
|
|
|
|
---
|
|
|
|
### Task 12: Split `UniverseGenTweaks/MoreSettings.cs`
|
|
|
|
**Files:**
|
|
- Create: `UniverseGenTweaks/Patches/GalaxyGenSettingsPatch.cs`
|
|
- Create: `UniverseGenTweaks/Patches/GalaxySelectUIPatch.cs`
|
|
- Create: `UniverseGenTweaks/Patches/CombatSettingsPatch.cs`
|
|
- Create: `UniverseGenTweaks/Functions/GalaxyGenSave.cs`
|
|
- Modify: `UniverseGenTweaks/MoreSettings.cs` (coordinator, or delete)
|
|
|
|
- [ ] **Step 1: Move UI construction to `GalaxySelectUIPatch`**
|
|
|
|
Mark it `[ModFeature("GalaxySelectUI")]`. Keep slider/text creation helpers there.
|
|
|
|
- [ ] **Step 2: Move transpilers to `GalaxyGenSettingsPatch`**
|
|
|
|
Mark it `[ModFeature("GalaxyGenSettings")]`. Keep the `Init()`/`Uninit()` pattern and the `Harmony` instance local to this class.
|
|
|
|
- [ ] **Step 3: Move combat settings to `CombatSettingsPatch`**
|
|
|
|
Mark it `[ModFeature("CombatSettings")]`. Replace the seven near-identical slider-changed prefix methods with a table-driven mapper.
|
|
|
|
- [ ] **Step 4: Move save serialization to `GalaxyGenSave`**
|
|
|
|
Mark it `[ModFeature("GalaxyGenSave")]`. Implement `Export(BinaryWriter)` / `Import(BinaryReader)` and call them from `UniverseGenTweaks.Export`/`Import`.
|
|
|
|
- [ ] **Step 5: Build UniverseGenTweaks**
|
|
|
|
```bash
|
|
dotnet build UniverseGenTweaks/UniverseGenTweaks.csproj -c Release
|
|
```
|
|
|
|
- [ ] **Step 6: Commit**
|
|
|
|
```bash
|
|
git add UniverseGenTweaks/Patches/ UniverseGenTweaks/Functions/
|
|
git rm UniverseGenTweaks/MoreSettings.cs
|
|
git commit -m "refactor(UniverseGenTweaks): split MoreSettings into focused classes"
|
|
```
|
|
|
|
---
|
|
|
|
### Task 13: Phase 1 cross-project build verification
|
|
|
|
- [ ] **Step 1: Clean and build all three projects**
|
|
|
|
```bash
|
|
dotnet clean UXAssist/UXAssist.csproj -c Release
|
|
dotnet clean CheatEnabler/CheatEnabler.csproj -c Release
|
|
dotnet clean UniverseGenTweaks/UniverseGenTweaks.csproj -c Release
|
|
dotnet build UXAssist/UXAssist.csproj -c Release
|
|
dotnet build CheatEnabler/CheatEnabler.csproj -c Release
|
|
dotnet build UniverseGenTweaks/UniverseGenTweaks.csproj -c Release
|
|
```
|
|
|
|
Expected: all three succeed with no compilation errors.
|
|
|
|
- [ ] **Step 2: Produce packages**
|
|
|
|
```bash
|
|
dotnet build -t:ZipMod -c Release
|
|
dotnet build -t:CopyToParentPackage -c Release
|
|
```
|
|
|
|
Expected: `UXAssist/package/`, `CheatEnabler/package/`, `UniverseGenTweaks/package/`, and `Dustbin/package/patchers/` (if building the full solution) are generated.
|
|
|
|
- [ ] **Step 3: Public API diff check**
|
|
|
|
Use `dotnet build` output or `ildasm` to verify that every member listed in `docs/PublicApiSurface.md` still exists with the same signature.
|
|
|
|
- [ ] **Step 4: Commit a Phase 1 checkpoint tag**
|
|
|
|
```bash
|
|
git tag refactor-phase1
|
|
```
|
|
|
|
---
|
|
|
|
## Phase 2 — UI / Common Internal Refactoring (public surface preserved)
|
|
|
|
### Task 14: Split `UXAssist/Common/Util.cs` into focused helpers
|
|
|
|
**Files:**
|
|
- Create: `UXAssist/Common/Util/ReflectionUtil.cs`
|
|
- Create: `UXAssist/Common/Util/ResourceUtil.cs`
|
|
- Create: `UXAssist/Common/Util/PathUtil.cs`
|
|
- Modify: `UXAssist/Common/Util.cs`
|
|
|
|
- [ ] **Step 1: Move implementations to focused helpers**
|
|
|
|
`ReflectionUtil.cs`:
|
|
```csharp
|
|
public static class ReflectionUtil
|
|
{
|
|
public static Type[] GetTypesFiltered(Assembly assembly, Func<Type, bool> predicate) { ... }
|
|
public static Type[] GetTypesInNamespace(Assembly assembly, string nameSpace) { ... }
|
|
public static Type[] GetTypesInNamespacePrefix(Assembly assembly, string prefix) { ... }
|
|
}
|
|
```
|
|
|
|
`ResourceUtil.cs`:
|
|
```csharp
|
|
public static class ResourceUtil
|
|
{
|
|
public static byte[] LoadEmbeddedResource(...) { ... }
|
|
public static Texture2D LoadEmbeddedTexture(...) { ... }
|
|
public static Sprite LoadEmbeddedSprite(...) { ... }
|
|
}
|
|
```
|
|
|
|
`PathUtil.cs`:
|
|
```csharp
|
|
public static class PathUtil
|
|
{
|
|
public static string PluginFolder(Assembly assembly = null) { ... }
|
|
}
|
|
```
|
|
|
|
- [ ] **Step 2: Keep `Util` as a public forwarding facade**
|
|
|
|
```csharp
|
|
public static class Util
|
|
{
|
|
[Obsolete("Use ReflectionUtil.GetTypesFiltered")]
|
|
public static Type[] GetTypesFiltered(Assembly assembly, Func<Type, bool> predicate)
|
|
=> ReflectionUtil.GetTypesFiltered(assembly, predicate);
|
|
|
|
[Obsolete("Use ReflectionUtil.GetTypesInNamespace")]
|
|
public static Type[] GetTypesInNamespace(Assembly assembly, string nameSpace)
|
|
=> ReflectionUtil.GetTypesInNamespace(assembly, nameSpace);
|
|
|
|
[Obsolete("Use ResourceUtil.LoadEmbeddedResource")]
|
|
public static byte[] LoadEmbeddedResource(string path, Assembly assembly = null)
|
|
=> ResourceUtil.LoadEmbeddedResource(path, assembly);
|
|
|
|
// ... forward all other existing methods
|
|
}
|
|
```
|
|
|
|
New code inside UXAssist may call `ReflectionUtil`/`ResourceUtil`/`PathUtil` directly.
|
|
|
|
- [ ] **Step 3: Build UXAssist**
|
|
|
|
```bash
|
|
dotnet build UXAssist/UXAssist.csproj -c Release
|
|
```
|
|
|
|
- [ ] **Step 4: Commit**
|
|
|
|
```bash
|
|
git add UXAssist/Common/Util/
|
|
git commit -m "refactor(UXAssist): split Util into focused helpers with forwarding facade"
|
|
```
|
|
|
|
---
|
|
|
|
### Task 15: Refactor `UXAssist/Common/GameLogic.cs` event invocation
|
|
|
|
**Files:**
|
|
- Create: `UXAssist/Common/GameEvent.cs`
|
|
- Modify: `UXAssist/Common/GameLogic.cs`
|
|
|
|
- [ ] **Step 1: Introduce a small safe-event wrapper**
|
|
|
|
```csharp
|
|
public static class GameEvent
|
|
{
|
|
public static void InvokeSafe(this Action action, ManualLogSource logger, string name)
|
|
{
|
|
if (action == null) return;
|
|
foreach (var d in action.GetInvocationList())
|
|
{
|
|
try { d.DynamicInvoke(); }
|
|
catch (Exception ex) { logger?.LogWarning($"GameEvent '{name}' handler failed: {ex}"); }
|
|
}
|
|
}
|
|
}
|
|
```
|
|
|
|
- [ ] **Step 2: Use the wrapper inside `GameLogic`**
|
|
|
|
Keep the public event fields unchanged. Replace manual invocation loops with `OnDataLoaded.InvokeSafe(UXAssist.Logger, nameof(OnDataLoaded));`.
|
|
|
|
- [ ] **Step 3: Add XML documentation to all public members**
|
|
|
|
- [ ] **Step 4: Build UXAssist**
|
|
|
|
```bash
|
|
dotnet build UXAssist/UXAssist.csproj -c Release
|
|
```
|
|
|
|
- [ ] **Step 5: Commit**
|
|
|
|
```bash
|
|
git add UXAssist/Common/GameEvent.cs UXAssist/Common/GameLogic.cs
|
|
git commit -m "refactor(UXAssist): safe GameEvent wrapper and XML docs"
|
|
```
|
|
|
|
---
|
|
|
|
### Task 16: Refactor `UXAssist/Common/I18N.cs` internals
|
|
|
|
**Files:**
|
|
- Modify: `UXAssist/Common/I18N.cs`
|
|
|
|
- [ ] **Step 1: Preserve public API**
|
|
|
|
Keep `Add`, `Apply`, `Translate`, `Init`, `OnInitialized` signatures exactly as they are.
|
|
|
|
- [ ] **Step 2: Internal cleanup**
|
|
|
|
Split the internal storage into a private `LocalizedString` record and a dictionary keyed by the English key. Add a public convenience overload:
|
|
```csharp
|
|
public static void Add(string key, string en, string zh)
|
|
```
|
|
(this is the existing signature; keep it).
|
|
|
|
- [ ] **Step 3: Build UXAssist**
|
|
|
|
```bash
|
|
dotnet build UXAssist/UXAssist.csproj -c Release
|
|
```
|
|
|
|
- [ ] **Step 4: Commit**
|
|
|
|
```bash
|
|
git add UXAssist/Common/I18N.cs
|
|
git commit -m "refactor(UXAssist): clean up I18N internals without changing public API"
|
|
```
|
|
|
|
---
|
|
|
|
### Task 17: Extract layout helpers from `UXAssist/UI/MyWindow.cs`
|
|
|
|
**Files:**
|
|
- Create: `UXAssist/UI/LayoutHelper.cs`
|
|
- Modify: `UXAssist/UI/MyWindow.cs`
|
|
|
|
- [ ] **Step 1: Move static layout helpers**
|
|
|
|
Move `AddText`, `AddTipsButton`, `AddButton` (static overloads), and `AddElement` into `LayoutHelper`.
|
|
|
|
```csharp
|
|
public static class LayoutHelper
|
|
{
|
|
public static Text AddText(float x, float y, RectTransform parent, string label, int fontSize = 14, string objName = "label") { ... }
|
|
public static UIButton AddTipsButton(...) { ... }
|
|
public static UIButton AddButton(...) { ... }
|
|
}
|
|
```
|
|
|
|
- [ ] **Step 2: Keep `MyWindow` instance methods as forwarding facades**
|
|
|
|
```csharp
|
|
public Text AddText2(float x, float y, RectTransform parent, string label, int fontSize = 14, string objName = "label")
|
|
{
|
|
var text = LayoutHelper.AddText(x, y, parent, label, fontSize, objName);
|
|
_maxX = Math.Max(_maxX, x + text.rectTransform.sizeDelta.x);
|
|
MaxY = Math.Max(MaxY, y + text.rectTransform.sizeDelta.y);
|
|
return text;
|
|
}
|
|
```
|
|
|
|
Mark the public static helpers on `MyWindow` as `[Obsolete("Use LayoutHelper")]` if desired, but keep them working.
|
|
|
|
- [ ] **Step 3: Build UXAssist**
|
|
|
|
```bash
|
|
dotnet build UXAssist/UXAssist.csproj -c Release
|
|
```
|
|
|
|
- [ ] **Step 4: Commit**
|
|
|
|
```bash
|
|
git add UXAssist/UI/LayoutHelper.cs UXAssist/UI/MyWindow.cs
|
|
git commit -m "refactor(UXAssist): extract UI layout helpers from MyWindow"
|
|
```
|
|
|
|
---
|
|
|
|
### Task 18: Refactor `UXAssist/UI/MyConfigWindow.cs` tab management
|
|
|
|
**Files:**
|
|
- Create: `UXAssist/UI/ConfigTabGroup.cs`
|
|
- Modify: `UXAssist/UI/MyConfigWindow.cs`
|
|
- Modify: `UXAssist/UI/MyWindowWithTabs.cs`
|
|
|
|
- [ ] **Step 1: Extract tab group logic**
|
|
|
|
Move the data structure that tracks tab groups into `ConfigTabGroup` so `MyConfigWindow` does not mix tab state with window lifecycle.
|
|
|
|
- [ ] **Step 2: Preserve public events and methods**
|
|
|
|
Keep `OnUICreated`, `OnUpdateUI`, `CreateInstance`, and `DestroyInstance` on `MyConfigWindow` with identical signatures.
|
|
|
|
- [ ] **Step 3: Build UXAssist**
|
|
|
|
```bash
|
|
dotnet build UXAssist/UXAssist.csproj -c Release
|
|
```
|
|
|
|
- [ ] **Step 4: Commit**
|
|
|
|
```bash
|
|
git add UXAssist/UI/ConfigTabGroup.cs UXAssist/UI/MyConfigWindow.cs UXAssist/UI/MyWindowWithTabs.cs
|
|
git commit -m "refactor(UXAssist): split tab management out of MyConfigWindow"
|
|
```
|
|
|
|
---
|
|
|
|
### Task 19: Phase 2 cross-project build verification
|
|
|
|
- [ ] **Step 1: Build all three projects**
|
|
|
|
```bash
|
|
dotnet build UXAssist/UXAssist.csproj -c Release
|
|
dotnet build CheatEnabler/CheatEnabler.csproj -c Release
|
|
dotnet build UniverseGenTweaks/UniverseGenTweaks.csproj -c Release
|
|
```
|
|
|
|
- [ ] **Step 2: Public API diff check**
|
|
|
|
Confirm every member in `docs/PublicApiSurface.md` still exists with the same signature. New `[Obsolete]` facades are acceptable.
|
|
|
|
- [ ] **Step 3: Commit a Phase 2 checkpoint tag**
|
|
|
|
```bash
|
|
git tag refactor-phase2
|
|
```
|
|
|
|
---
|
|
|
|
## Phase 3 — Constants & Localization
|
|
|
|
### Task 20: Create centralized constants files
|
|
|
|
**Files:**
|
|
- Create: `UXAssist/Common/GameConstants/ItemIds.cs`
|
|
- Create: `UXAssist/Common/GameConstants/TechIds.cs`
|
|
- Create: `UXAssist/Common/GameConstants/LogisticsConstants.cs`
|
|
- Create: `UXAssist/Common/GameConstants/DysonSphereConstants.cs`
|
|
- Create: `UXAssist/Common/GameConstants/UniverseGenConstants.cs`
|
|
|
|
- [ ] **Step 1: Extract item IDs**
|
|
|
|
From `CheatEnabler/Patches/Factory/*.cs` and `UXAssist/Patches/Factory/BeltSignalPatch.cs`, collect hard-coded item IDs:
|
|
```csharp
|
|
public static class ItemIds
|
|
{
|
|
public const int IronOre = 1001;
|
|
public const int CopperOre = 1002;
|
|
// ...
|
|
}
|
|
```
|
|
|
|
- [ ] **Step 2: Extract tech IDs**
|
|
|
|
From `UXAssist/Patches/TechPatch.cs`:
|
|
```csharp
|
|
public static class TechIds
|
|
{
|
|
public const int SorterCargoStacking = 3608;
|
|
public static readonly HashSet<int> CombatTechs = [3301, 3302, ...];
|
|
}
|
|
```
|
|
|
|
- [ ] **Step 3: Extract logistics constants**
|
|
|
|
From `UXAssist/Patches/Logistics/CapacityPatch.cs`:
|
|
```csharp
|
|
public static class LogisticsConstants
|
|
{
|
|
public const int DefaultLocalStorageMax = 5000;
|
|
public const int DefaultRemoteStorageMax = 10000;
|
|
}
|
|
```
|
|
|
|
- [ ] **Step 4: Build UXAssist**
|
|
|
|
```bash
|
|
dotnet build UXAssist/UXAssist.csproj -c Release
|
|
```
|
|
|
|
- [ ] **Step 5: Commit**
|
|
|
|
```bash
|
|
git add UXAssist/Common/GameConstants/
|
|
git commit -m "refactor: centralize game constants"
|
|
```
|
|
|
|
---
|
|
|
|
### Task 21: Replace magic numbers in UXAssist
|
|
|
|
**Files:**
|
|
- Modify: `UXAssist/Patches/Factory/*.cs`
|
|
- Modify: `UXAssist/Patches/Logistics/*.cs`
|
|
- Modify: `UXAssist/Patches/TechPatch.cs`
|
|
- Modify: `UXAssist/Patches/DysonSpherePatch.cs`
|
|
|
|
- [ ] **Step 1: Replace literal IDs and capacities with constants**
|
|
|
|
For example, change:
|
|
```csharp
|
|
if (itemId == 1001) { ... }
|
|
```
|
|
to:
|
|
```csharp
|
|
if (itemId == ItemIds.IronOre) { ... }
|
|
```
|
|
|
|
- [ ] **Step 2: Build UXAssist**
|
|
|
|
```bash
|
|
dotnet build UXAssist/UXAssist.csproj -c Release
|
|
```
|
|
|
|
- [ ] **Step 3: Commit**
|
|
|
|
```bash
|
|
git add UXAssist/Patches/
|
|
git commit -m "refactor(UXAssist): replace magic numbers with constants"
|
|
```
|
|
|
|
---
|
|
|
|
### Task 22: Replace magic numbers in CheatEnabler and UniverseGenTweaks
|
|
|
|
**Files:**
|
|
- Modify: `CheatEnabler/Patches/Factory/*.cs`
|
|
- Modify: `CheatEnabler/Functions/DysonSphere/*.cs`
|
|
- Modify: `CheatEnabler/Functions/PlanetFunctions.cs`
|
|
- Modify: `UniverseGenTweaks/Patches/GalaxyGenSettingsPatch.cs`
|
|
- Modify: `UniverseGenTweaks/Patches/CombatSettingsPatch.cs`
|
|
- Modify: `UniverseGenTweaks/BirthPlanetPatch.cs`
|
|
|
|
- [ ] **Step 1: Reference UXAssist constants where appropriate**
|
|
|
|
CheatEnabler/UniverseGenTweaks already reference `UXAssist.csproj`, so they can use `UXAssist.Common.GameConstants.ItemIds`, etc.
|
|
|
|
- [ ] **Step 2: Build both projects**
|
|
|
|
```bash
|
|
dotnet build CheatEnabler/CheatEnabler.csproj -c Release
|
|
dotnet build UniverseGenTweaks/UniverseGenTweaks.csproj -c Release
|
|
```
|
|
|
|
- [ ] **Step 3: Commit**
|
|
|
|
```bash
|
|
git add CheatEnabler/ UniverseGenTweaks/
|
|
git commit -m "refactor(CheatEnabler/UniverseGen): consume centralized constants"
|
|
```
|
|
|
|
---
|
|
|
|
### Task 23: Localization key governance
|
|
|
|
**Files:**
|
|
- Modify: `UXAssist/UIConfigWindow.cs`
|
|
- Modify: `CheatEnabler/UIConfigWindow.cs`
|
|
- Modify: `UniverseGenTweaks/UIConfigWindow.cs`
|
|
- Modify: `CheatEnabler/Functions/PlayerFunctions.cs`
|
|
- Modify: `UXAssist/Patches/Factory/BeltSignalPatch.cs`
|
|
|
|
- [ ] **Step 1: Replace hard-coded Chinese `.Translate()` keys with `I18N.Add` entries**
|
|
|
|
Example:
|
|
```csharp
|
|
// Before
|
|
var btn = MyWindow.AddButton(..., "确定", ...);
|
|
// After
|
|
I18N.Add("OK", "OK", "确定");
|
|
var btn = MyWindow.AddButton(..., "OK", ...);
|
|
```
|
|
|
|
- [ ] **Step 2: Translate Chinese comments to English**
|
|
|
|
Run a search for `// ` followed by CJK characters and translate or delete stale comments.
|
|
|
|
```bash
|
|
grep -RInP '//.*[\x{4e00}-\x{9fff}]' UXAssist/ CheatEnabler/ UniverseGenTweaks/ --include='*.cs' || true
|
|
```
|
|
|
|
- [ ] **Step 3: Build all three projects**
|
|
|
|
```bash
|
|
dotnet build UXAssist/UXAssist.csproj -c Release
|
|
dotnet build CheatEnabler/CheatEnabler.csproj -c Release
|
|
dotnet build UniverseGenTweaks/UniverseGenTweaks.csproj -c Release
|
|
```
|
|
|
|
- [ ] **Step 4: Commit**
|
|
|
|
```bash
|
|
git add UXAssist/ CheatEnabler/ UniverseGenTweaks/
|
|
git commit -m "refactor: localize hard-coded strings and translate comments"
|
|
```
|
|
|
|
---
|
|
|
|
## Phase 4 — Static State & Lifecycle Cleanup
|
|
|
|
### Task 24: Inventory static mutable state
|
|
|
|
**Files:**
|
|
- Create: `docs/StaticStateInventory.md`
|
|
|
|
- [ ] **Step 1: List all static mutable fields in the three projects**
|
|
|
|
Search:
|
|
```bash
|
|
grep -RInP 'private static (?!readonly)\S+' UXAssist/Patches/ UXAssist/Functions/ CheatEnabler/Patches/ CheatEnabler/Functions/ UniverseGenTweaks/ --include='*.cs' > docs/StaticStateInventory.md
|
|
grep -RInP 'public static (?!readonly)\S+' UXAssist/Patches/ UXAssist/Functions/ CheatEnabler/Patches/ CheatEnabler/Functions/ UniverseGenTweaks/ --include='*.cs' >> docs/StaticStateInventory.md
|
|
```
|
|
|
|
- [ ] **Step 2: Classify each field by subsystem**
|
|
|
|
Mark each as:
|
|
- `LifecycleSafe` — read-only after `Awake`
|
|
- `NeedsReset` — must be cleared on `GameLogic.OnGameEnd`
|
|
- `CandidateForInstancing` — should be owned by a per-game context class
|
|
|
|
- [ ] **Step 3: Commit**
|
|
|
|
```bash
|
|
git add docs/StaticStateInventory.md
|
|
git commit -m "docs: inventory static mutable state"
|
|
```
|
|
|
|
---
|
|
|
|
### Task 25: Add lifecycle reset callbacks
|
|
|
|
**Files:**
|
|
- Modify: `UXAssist/Patches/Factory/BeltSignalPatch.cs`
|
|
- Modify: `UXAssist/Patches/Factory/VeinProtectionPatch.cs`
|
|
- Modify: `UXAssist/Patches/DysonSpherePatch.cs`
|
|
- Modify: `UXAssist/Functions/UI/MilkyWayUI.cs`
|
|
- Modify: `CheatEnabler/Patches/Factory/BeltSignalPatch.cs`
|
|
- Modify: `UniverseGenTweaks/Patches/GalaxySelectUIPatch.cs`
|
|
|
|
- [ ] **Step 1: Add `ResetState` methods**
|
|
|
|
Example:
|
|
```csharp
|
|
internal static void ResetState()
|
|
{
|
|
_signalBelts = null;
|
|
_someCache.Clear();
|
|
}
|
|
```
|
|
|
|
- [ ] **Step 2: Register resets in `Init`**
|
|
|
|
```csharp
|
|
public static void Init()
|
|
{
|
|
GameLogic.OnGameEnd += ResetState;
|
|
// ...
|
|
}
|
|
```
|
|
|
|
- [ ] **Step 3: Build all three projects**
|
|
|
|
```bash
|
|
dotnet build UXAssist/UXAssist.csproj -c Release
|
|
dotnet build CheatEnabler/CheatEnabler.csproj -c Release
|
|
dotnet build UniverseGenTweaks/UniverseGenTweaks.csproj -c Release
|
|
```
|
|
|
|
- [ ] **Step 4: Commit**
|
|
|
|
```bash
|
|
git add UXAssist/ CheatEnabler/ UniverseGenTweaks/
|
|
git commit -m "refactor: register static-state resets on game end"
|
|
```
|
|
|
|
---
|
|
|
|
## Phase 5 — Transpiler Robustness & Quality Gates
|
|
|
|
### Task 26: Annotate transpilers with target version and fallback
|
|
|
|
**Files:**
|
|
- Modify: all `*Transpiler` methods in `UXAssist/Patches/`, `CheatEnabler/Patches/`, `UniverseGenTweaks/Patches/`
|
|
|
|
- [ ] **Step 1: Add header comments**
|
|
|
|
```csharp
|
|
// Target game version: 0.10.34.28505
|
|
// Patches: EjectorComponent.InternalUpdate
|
|
// Falls back to original IL if the pattern is not matched.
|
|
private static IEnumerable<CodeInstruction> ...
|
|
```
|
|
|
|
- [ ] **Step 2: Wrap `CodeMatcher` finalization**
|
|
|
|
Replace bare `.InstructionEnumeration()` with:
|
|
```csharp
|
|
return matcher.ReportFailure(original, Logger)?.InstructionEnumeration() ?? instructions;
|
|
```
|
|
|
|
Implement extension:
|
|
```csharp
|
|
public static CodeMatcher ReportFailure(this CodeMatcher matcher, MethodBase original, ManualLogSource logger)
|
|
{
|
|
if (matcher.IsValid) return matcher;
|
|
logger?.LogWarning($"Transpiler failed for {original.DeclaringType?.Name}.{original.Name}");
|
|
return null;
|
|
}
|
|
```
|
|
|
|
- [ ] **Step 3: Build all three projects**
|
|
|
|
```bash
|
|
dotnet build UXAssist/UXAssist.csproj -c Release
|
|
dotnet build CheatEnabler/CheatEnabler.csproj -c Release
|
|
dotnet build UniverseGenTweaks/UniverseGenTweaks.csproj -c Release
|
|
```
|
|
|
|
- [ ] **Step 4: Commit**
|
|
|
|
```bash
|
|
git add UXAssist/ CheatEnabler/ UniverseGenTweaks/
|
|
git commit -m "refactor: add transpiler version/fallback annotations"
|
|
```
|
|
|
|
---
|
|
|
|
### Task 27: Centralize third-party compat reflection targets
|
|
|
|
**Files:**
|
|
- Create: `UXAssist/ModsCompat/CompatTargets.cs`
|
|
- Modify: `UXAssist/ModsCompat/AuxilaryfunctionWrapper.cs`
|
|
- Modify: `UXAssist/ModsCompat/BulletTimeWrapper.cs`
|
|
- Modify: `UXAssist/ModsCompat/BlueprintTweaks.cs`
|
|
|
|
- [ ] **Step 1: Extract magic strings**
|
|
|
|
```csharp
|
|
internal static class CompatTargets
|
|
{
|
|
public const string Auxilaryfunction = "auxilaryfunction.Auxilaryfunction";
|
|
public const string SpeedUpPatch = "Auxilaryfunction.SpeedUpPatch";
|
|
// ...
|
|
}
|
|
```
|
|
|
|
- [ ] **Step 2: Replace literal strings with constants**
|
|
|
|
- [ ] **Step 3: Build UXAssist**
|
|
|
|
```bash
|
|
dotnet build UXAssist/UXAssist.csproj -c Release
|
|
```
|
|
|
|
- [ ] **Step 4: Commit**
|
|
|
|
```bash
|
|
git add UXAssist/ModsCompat/
|
|
git commit -m "refactor(UXAssist): centralize compat reflection targets"
|
|
```
|
|
|
|
---
|
|
|
|
### Task 28: Add `.editorconfig` and run `dotnet format`
|
|
|
|
**Files:**
|
|
- Create: `.editorconfig`
|
|
- Modify: all touched `.cs` files (format-only changes)
|
|
|
|
- [ ] **Step 1: Create `.editorconfig`**
|
|
|
|
Minimal content:
|
|
```ini
|
|
root = true
|
|
|
|
[*.cs]
|
|
indent_style = space
|
|
indent_size = 4
|
|
charset = utf-8-bom
|
|
end_of_line = crlf
|
|
insert_final_newline = true
|
|
dotnet_sort_system_directives_first = true
|
|
dotnet_separate_import_directive_groups = false
|
|
```
|
|
|
|
- [ ] **Step 2: Run format**
|
|
|
|
```bash
|
|
dotnet format UXAssist/UXAssist.csproj
|
|
dotnet format CheatEnabler/CheatEnabler.csproj
|
|
dotnet format UniverseGenTweaks/UniverseGenTweaks.csproj
|
|
```
|
|
|
|
- [ ] **Step 3: Build all three projects**
|
|
|
|
```bash
|
|
dotnet build UXAssist/UXAssist.csproj -c Release
|
|
dotnet build CheatEnabler/CheatEnabler.csproj -c Release
|
|
dotnet build UniverseGenTweaks/UniverseGenTweaks.csproj -c Release
|
|
```
|
|
|
|
- [ ] **Step 4: Commit**
|
|
|
|
```bash
|
|
git add .editorconfig
|
|
git add -u UXAssist/ CheatEnabler/ UniverseGenTweaks/
|
|
git commit -m "style: add editorconfig and run dotnet format"
|
|
```
|
|
|
|
---
|
|
|
|
## Final Verification
|
|
|
|
- [ ] **Step 1: Full solution build**
|
|
|
|
```bash
|
|
dotnet build DSP_Mods.sln -c Release
|
|
```
|
|
|
|
Expected: 0 errors.
|
|
|
|
- [ ] **Step 2: Package all mods**
|
|
|
|
```bash
|
|
dotnet build -t:ZipMod -c Release
|
|
dotnet build -t:CopyToParentPackage -c Release
|
|
```
|
|
|
|
Expected: all `package/` outputs generated.
|
|
|
|
- [ ] **Step 3: Public API verification**
|
|
|
|
Re-run the `docs/PublicApiSurface.md` checklist and confirm every listed member still exists.
|
|
|
|
- [ ] **Step 4: Update `AGENTS.md`**
|
|
|
|
If any project conventions changed (e.g., new folder structure, naming rules, `.editorconfig`), update `AGENTS.md` accordingly.
|
|
|
|
- [ ] **Step 5: Final commit / tag**
|
|
|
|
```bash
|
|
git tag refactor-complete
|
|
```
|
|
|
|
---
|
|
|
|
## Self-Review Checklist
|
|
|
|
- [ ] Every task references exact file paths.
|
|
- [ ] No `TODO`, `TBD`, or placeholder steps remain.
|
|
- [ ] Public API contract (`UXAssist.UI` + `UXAssist.Common`) is preserved throughout.
|
|
- [ ] `CheatEnabler` and `UniverseGenTweaks` compile after each phase.
|
|
- [ ] Code snippets use types/methods defined in earlier tasks.
|