mirror of
https://github.com/soarqin/DSP_Mods.git
synced 2026-08-05 09:40:18 +08:00
fix(UXAssist): centralize mod-feature lifecycle to prevent duplicate execution
ModFeatureRegistry is a static class with shared collections accumulating features from all mods. Dependent mods (CheatEnabler, UniverseGenTweaks) each independently called InitAll/StartAll/OnInputUpdateAll/OnUpdateAll/ UninitAll, re-running lifecycle for ALL accumulated features including other mods' — per-frame Update ran 2-3x (breaking CheatEnabler key toggles to net no-ops), Init/Start/Uninit ran 2-3x (double RegisterExporter causing save corruption, double SettingChanged subscriptions, double keybind registration). Fix: - Init now runs eagerly at Discover/Register time (Awake-phase), preserving the original timing that keybind registration depends on (game's UIOptionWindow._OnCreate copies keybinds only after all plugins load) - InitAll removed entirely - StartAll/UninitAll/OnInputUpdateAll/OnUpdateAll made internal so only UXAssist (host, same assembly, no InternalsVisibleTo) can drive them - Start deferred to UXAssist.Start (after all dependents' Awake complete; BepInEx runs all Awakes before any Start) - Per-feature Started idempotency + per-frame Time.frameCount guards as defense-in-depth - Dependent mods reduced to Discover-only in Awake Document the Init/Start timing contract on IModFeature and ModFeatureAttribute so future mods can rely on it.
This commit is contained in:
@@ -251,8 +251,11 @@ public class UXAssist : BaseUnityPlugin, IModCanSave
|
||||
object[] parameters = [_harmony];
|
||||
_compats?.Do(type => type.GetMethod("Init")?.Invoke(null, parameters));
|
||||
|
||||
// Register UXAssist's own features (Init runs eagerly here, preserving the original Awake timing
|
||||
// that keybind registration relies on). Dependent mods register theirs during their own Awake
|
||||
// phase. Start is deferred to UXAssist.Start below so that all dependents have registered before
|
||||
// any feature starts.
|
||||
ModFeatureRegistry.Discover(Assembly.GetExecutingAssembly());
|
||||
ModFeatureRegistry.InitAll();
|
||||
|
||||
I18N.Apply();
|
||||
}
|
||||
@@ -262,6 +265,8 @@ public class UXAssist : BaseUnityPlugin, IModCanSave
|
||||
MyWindowManager.InitBaseObjects();
|
||||
MyWindowManager.Enable(true);
|
||||
|
||||
// UXAssist is the sole lifecycle driver. All dependents have already registered (and initialized)
|
||||
// their features during their Awake phase (BepInEx runs every plugin's Awake before any plugin's Start).
|
||||
ModFeatureRegistry.StartAll();
|
||||
|
||||
_patches?.Do(type => type.GetMethod("Start")?.Invoke(null, null));
|
||||
|
||||
Reference in New Issue
Block a user