mirror of
https://github.com/soarqin/DSP_Mods.git
synced 2026-08-05 08:50:11 +08:00
fix(CheatEnabler): restore BuildToolOpt station replacement
This commit is contained in:
@@ -150,6 +150,6 @@ The sync is implemented as an inline PowerShell `Exec` step inside the `ZipMod`
|
||||
- **Fail-soft patch application:** `PatchImpl<T>.Enable(true)` applies Harmony patches inside a try/catch. Runtime patching can fail through no fault of ours (Harmony re-runs other mods' transpilers on shared target methods), and an escaping exception would abort the calling `ConfigEntry.SettingChanged` delegate chain, desyncing config UI from config values. On failure it logs a `LogError` with the feature type name, rolls back via `UnpatchSelf()`, and leaves `_patch` null so a later `Enable(true)` can retry.
|
||||
- **Convergent in-game UI state:** In-game overlay widgets whose visibility depends on game state (e.g. `AutoConstructUI`) must not rely solely on one-shot event-driven refreshes (`SettingChanged` handlers, patch `OnEnable`/`OnDisable`), because a thrown exception earlier in a delegate chain or a failed patch application silently drops the refresh. `AutoConstructUI.OnUpdate()` reconciles button visibility and the pending-construction count with actual game state every 30 frames (also effective while paused); the `AutoConstructPatch` postfix on `PlayerAction_Rts.GameTick` only implements the fly-to-target behavior, and `AutoConstructPatch.OnEnable` logs its visibility predicate inputs once per enable as a remote-diagnosis aid.
|
||||
- **Transpiler patches:** Performance-critical mods (LabOpt, MechaDronesTweaks) use `[HarmonyTranspiler]` to rewrite IL instructions directly for maximum efficiency. All transpilers in UXAssist, CheatEnabler, and UniverseGenTweaks carry a standard header comment (`// Harmony transpiler:`, `// Target:`, `// Fallback:`) documenting the target method and fallback behavior. `UXAssist.Common.Patching.TranspilerGuard` provides a reusable `CodeMatcher.Finish` helper that returns original instructions when a matcher becomes invalid.
|
||||
- **Mod-compatibility reflection:** Use `UXAssist.Common.ModCompat.ModCompatHelper` for BepInEx plugin detection, external mod type/method/field resolution, and property-setter lookup. Use `UXAssist.Common.Utils.DysonSphereReflection` for the DSPOptimizations-compatible `DysonSphereLayer` private fields (`totalNodeSP`, `totalFrameSP`, `totalCP`) instead of resolving them locally in each consumer.
|
||||
- **Mod-compatibility reflection:** Use `UXAssist.Common.ModCompat.ModCompatHelper` for BepInEx plugin detection, external mod type/method/field resolution, and property-setter lookup. Preserve the old public type identity with a forwarding or inherited compatibility facade when a refactor moves a type that external mods may locate through reflection; build and verify that the legacy reflection target forwards to the refactored implementation. Use `UXAssist.Common.Utils.DysonSphereReflection` for the DSPOptimizations-compatible `DysonSphereLayer` private fields (`totalNodeSP`, `totalFrameSP`, `totalCP`) instead of resolving them locally in each consumer.
|
||||
- **Build quality gates:** Root `.editorconfig` defines suggestion-only C# style conventions. `Directory.Build.props` enables `TreatWarningsAsErrors` with `NoWarn>0618` for the expected obsolete-API usage, so any new warning fails the build. `.github/workflows/build.yml` runs a Release build and packages the three main mods on every push/PR.
|
||||
- **Save persistence:** Mods that need to persist data use the `IModCanSave` interface from DSPModSave.
|
||||
|
||||
@@ -3,6 +3,7 @@ using BepInEx;
|
||||
using BepInEx.Configuration;
|
||||
using CheatEnabler.Patches;
|
||||
using CheatEnabler.Patches.Factory;
|
||||
using FactoryPatch = CheatEnabler.Patches.Factory.FactoryPatch;
|
||||
using UXAssist.Common;
|
||||
using UXAssist.Common.ModFeatures;
|
||||
|
||||
|
||||
@@ -12,7 +12,7 @@ internal class ArchitectMode : PatchImpl<ArchitectMode>
|
||||
var factory = GameMain.mainPlayer?.factory;
|
||||
if (factory?.planet?.data != null)
|
||||
{
|
||||
FactoryPatch.ArrivePlanet(factory);
|
||||
global::CheatEnabler.Patches.FactoryPatch.ArrivePlanet(factory);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -188,7 +188,7 @@ public class FactoryPatch : PatchImpl<FactoryPatch>
|
||||
var main = GameMain.instance;
|
||||
if (main != null && main._running && __instance.factory?.planet?.data != null)
|
||||
{
|
||||
ArrivePlanet(__instance.factory);
|
||||
global::CheatEnabler.Patches.FactoryPatch.ArrivePlanet(__instance.factory);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -198,7 +198,7 @@ public class FactoryPatch : PatchImpl<FactoryPatch>
|
||||
var factory = GameMain.mainPlayer?.factory;
|
||||
if (factory?.planet?.data != null)
|
||||
{
|
||||
ArrivePlanet(factory);
|
||||
global::CheatEnabler.Patches.FactoryPatch.ArrivePlanet(factory);
|
||||
}
|
||||
GameMain.data?.warningSystem?.UpdateCriticalWarningText();
|
||||
}
|
||||
|
||||
@@ -121,7 +121,7 @@ internal class ImmediateBuild : PatchImpl<ImmediateBuild>
|
||||
var factory = GameMain.mainPlayer?.factory;
|
||||
if (factory?.planet?.data != null)
|
||||
{
|
||||
FactoryPatch.ArrivePlanet(factory);
|
||||
global::CheatEnabler.Patches.FactoryPatch.ArrivePlanet(factory);
|
||||
}
|
||||
}
|
||||
// Harmony transpiler: Transpiler
|
||||
@@ -157,7 +157,7 @@ internal class ImmediateBuild : PatchImpl<ImmediateBuild>
|
||||
matcher.Insert(
|
||||
new CodeInstruction(OpCodes.Ldarg_0).WithLabels(labels),
|
||||
new CodeInstruction(OpCodes.Ldfld, AccessTools.Field(typeof(BuildTool), nameof(BuildTool.factory))),
|
||||
new CodeInstruction(OpCodes.Call, AccessTools.Method(typeof(FactoryPatch), nameof(FactoryPatch.ArrivePlanet)))
|
||||
new CodeInstruction(OpCodes.Call, AccessTools.Method(typeof(global::CheatEnabler.Patches.FactoryPatch), nameof(global::CheatEnabler.Patches.FactoryPatch.ArrivePlanet)))
|
||||
);
|
||||
return matcher.InstructionEnumeration();
|
||||
}
|
||||
@@ -255,7 +255,7 @@ internal class ImmediateBuild : PatchImpl<ImmediateBuild>
|
||||
var factory = GameMain.mainPlayer?.factory;
|
||||
if (factory?.planet?.data != null)
|
||||
{
|
||||
FactoryPatch.ArrivePlanet(factory);
|
||||
global::CheatEnabler.Patches.FactoryPatch.ArrivePlanet(factory);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
namespace CheatEnabler.Patches;
|
||||
|
||||
/// <summary>
|
||||
/// Preserves the pre-refactor type and method identity used by mods that locate FactoryPatch through reflection.
|
||||
/// </summary>
|
||||
public static class FactoryPatch
|
||||
{
|
||||
public static void ArrivePlanet(PlanetFactory factory)
|
||||
{
|
||||
Factory.FactoryPatch.ArrivePlanet(factory);
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,7 @@
|
||||
using CheatEnabler.Functions;
|
||||
using CheatEnabler.Patches;
|
||||
using CheatEnabler.Patches.Factory;
|
||||
using FactoryPatch = CheatEnabler.Patches.Factory.FactoryPatch;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
using UXAssist.UI;
|
||||
|
||||
Reference in New Issue
Block a user