refactor(engine-ambient): ViewerId/RealTimeNetworkAgent/BattleRecoveryInfo read ambient first
Step 4 of multi-instancing migration. Three additional per-battle statics front-fronted by BattleAmbient.Current, each with a static fallback for unwrapped callers. ViewerId's SavedataManager-persisting setter is preserved on the fallback path; inside a scope, the setter is a no-op (the per-battle perspective is fixed at scope entry). Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,61 @@
|
||||
Multi-instancing migration (Step 4): convert Cute.Certification.ViewerId — the per-battle
|
||||
"who is the local seat" identity — to resolve through BattleAmbient.Current when a scope is
|
||||
active, falling back to the legacy SavedataManager-backed static when not. The old `viewer_id`
|
||||
backing field is renamed to `_viewerIdFallback` so unwrapped callers (real client, in-process
|
||||
unit tests without a BattleAmbient scope) keep the original lazy-load-from-savedata + write-
|
||||
through-savedata behavior bit-for-bit; scoped callers get a per-AsyncLocal id without writing
|
||||
to savedata (design 2026-06-07-engine-multi-instancing, Task 4).
|
||||
|
||||
Inside a scope the setter is a NO-OP: ViewerId is an init-time identity (it's set at scope
|
||||
entry via `new BattleAmbientContext { ViewerId = ... }`'s init-only property), and swallowing
|
||||
the write avoids any in-battle setter from mutating sibling-battle perspective. The fallback
|
||||
setter preserves the original sequence exactly: SetInt + Save + assign backing field.
|
||||
|
||||
In-file references (3 total) handled as follows:
|
||||
- line 19 declaration → renamed to `_viewerIdFallback`
|
||||
- line 41 ViewerId property → ambient-first getter; setter swallows when scoped
|
||||
- line 147 InitializeFileds → resets the renamed `_viewerIdFallback`
|
||||
|
||||
External reflection follow-up (NOT in this patch — separate edit, same commit):
|
||||
SVSim.BattleNode/Sessions/Engine/EngineGlobalInit.cs (~line 154) reads the private field
|
||||
by name to seed the headless "who am I" perspective. Renamed there from "viewer_id" to
|
||||
"_viewerIdFallback" to match.
|
||||
|
||||
--- Engine/Cute/Certification.cs (~line 19)
|
||||
- private static int viewer_id;
|
||||
+ private static int _viewerIdFallback;
|
||||
|
||||
--- Engine/Cute/Certification.cs (~lines 41-57)
|
||||
public static int ViewerId
|
||||
{
|
||||
get
|
||||
{
|
||||
- if (viewer_id == 0)
|
||||
+ var c = SVSim.BattleEngine.Ambient.BattleAmbient.Current;
|
||||
+ if (c != null) return c.ViewerId;
|
||||
+ if (_viewerIdFallback == 0)
|
||||
{
|
||||
- viewer_id = Toolbox.SavedataManager.GetInt("VIEWER_ID");
|
||||
+ _viewerIdFallback = Toolbox.SavedataManager.GetInt("VIEWER_ID");
|
||||
}
|
||||
- return viewer_id;
|
||||
+ return _viewerIdFallback;
|
||||
}
|
||||
set
|
||||
{
|
||||
+ var c = SVSim.BattleEngine.Ambient.BattleAmbient.Current;
|
||||
+ if (c != null)
|
||||
+ {
|
||||
+ // Inside a scope, ViewerId is fixed at scope entry — swallow the write.
|
||||
+ return;
|
||||
+ }
|
||||
Toolbox.SavedataManager.SetInt("VIEWER_ID", value);
|
||||
Toolbox.SavedataManager.Save();
|
||||
- viewer_id = value;
|
||||
+ _viewerIdFallback = value;
|
||||
}
|
||||
}
|
||||
|
||||
--- Engine/Cute/Certification.cs (~line 147, InitializeFileds)
|
||||
- viewer_id = 0;
|
||||
+ _viewerIdFallback = 0;
|
||||
34
SVSim.BattleEngine/Patches/Data.ambient-recoveryinfo.patch
Normal file
34
SVSim.BattleEngine/Patches/Data.ambient-recoveryinfo.patch
Normal file
@@ -0,0 +1,34 @@
|
||||
Multi-instancing migration (Step 4): convert Wizard.Data.BattleRecoveryInfo — the per-battle
|
||||
mid-game recovery snapshot (replay/reconnect/late-join state, owned by RecoveryDataHandler /
|
||||
RecoveryNetworkManagerBase / RecoveryController) — to resolve through BattleAmbient.Current
|
||||
when a scope is active, falling back to a `_battleRecoveryInfoFallback` static when not.
|
||||
The original was a plain auto-property `{ get; set; }`; converting to a manual property +
|
||||
ambient-aware getter/setter preserves the public read/write surface byte-identical
|
||||
(design 2026-06-07-engine-multi-instancing, Task 4).
|
||||
|
||||
This is the only of the three Step-4 conversions whose setter we DO route through ambient
|
||||
(unlike ViewerId, where the in-scope setter is a no-op): recovery info is mutated during the
|
||||
battle (new snapshots overwrite old ones as recovery checkpoints stream in), so scoped writes
|
||||
must land on the AsyncLocal slot, not bleed into the process-wide fallback.
|
||||
|
||||
The existing line-348 reset inside `Data.Clear()` (`BattleRecoveryInfo = null;`) keeps working
|
||||
unchanged because it goes through the public setter, which now correctly routes to whichever
|
||||
slot the caller's scope (or lack thereof) points at.
|
||||
|
||||
In-file references (1 declaration; ~5 setter/getter call sites elsewhere in the file go through
|
||||
the public property and need no edits) handled as follows:
|
||||
- line 179 auto-property → manual ambient-first getter + ambient-routed setter
|
||||
|
||||
--- Engine/Wizard/Data.cs (~line 179)
|
||||
- public static BattleRecoveryInfo BattleRecoveryInfo { get; set; }
|
||||
+ private static BattleRecoveryInfo _battleRecoveryInfoFallback;
|
||||
+ public static BattleRecoveryInfo BattleRecoveryInfo
|
||||
+ {
|
||||
+ get => SVSim.BattleEngine.Ambient.BattleAmbient.Current?.RecoveryInfo ?? _battleRecoveryInfoFallback;
|
||||
+ set
|
||||
+ {
|
||||
+ var c = SVSim.BattleEngine.Ambient.BattleAmbient.Current;
|
||||
+ if (c != null) c.RecoveryInfo = value;
|
||||
+ else _battleRecoveryInfoFallback = value;
|
||||
+ }
|
||||
+ }
|
||||
51
SVSim.BattleEngine/Patches/ToolboxGame.ambient-rtna.patch
Normal file
51
SVSim.BattleEngine/Patches/ToolboxGame.ambient-rtna.patch
Normal file
@@ -0,0 +1,51 @@
|
||||
Multi-instancing migration (Step 4): convert Wizard.ToolboxGame.RealTimeNetworkAgent — the
|
||||
per-battle handle to the live PvP/AI network agent (RealTimeNetworkAgent owns the Socket.IO
|
||||
connection, OnEmit pipeline, and ack bookkeeping for one battle) — to resolve through
|
||||
BattleAmbient.Current when a scope is active, falling back to a renamed
|
||||
`_realTimeNetworkAgentFallback` static when not. The original was an auto-property with a
|
||||
private setter, mutated only via SetRealTimeNetworkBattle / DestroyNetworkAgent; converting
|
||||
to a manual property + ambient-aware mutators keeps the public surface byte-identical
|
||||
(design 2026-06-07-engine-multi-instancing, Task 4).
|
||||
|
||||
DestroyNetworkAgent preserves the original Unity DestroyImmediate(.gameObject) call exactly,
|
||||
just reading the "current" agent through the same ambient-first resolution and clearing the
|
||||
slot it came from. Object.DestroyImmediate resolves via the file's existing `using UnityEngine;`
|
||||
(no qualifier change needed — matches the file's existing pattern at line 36/79 that calls
|
||||
`GameObject.Find` unqualified).
|
||||
|
||||
In-file references (3 sites) handled as follows:
|
||||
- line 28 auto-property → renamed backing + manual ambient-first getter
|
||||
- line 57 SetRealTimeNetworkBattle → writes through Current?.NetworkAgent or fallback
|
||||
- line 62 DestroyNetworkAgent → reads current via ambient-first; clears the same slot
|
||||
|
||||
--- Engine/Wizard/ToolboxGame.cs (~line 28)
|
||||
- public static RealTimeNetworkAgent RealTimeNetworkAgent { get; private set; }
|
||||
+ private static RealTimeNetworkAgent _realTimeNetworkAgentFallback;
|
||||
+ public static RealTimeNetworkAgent RealTimeNetworkAgent
|
||||
+ {
|
||||
+ get => SVSim.BattleEngine.Ambient.BattleAmbient.Current?.NetworkAgent ?? _realTimeNetworkAgentFallback;
|
||||
+ }
|
||||
|
||||
--- Engine/Wizard/ToolboxGame.cs (~lines 57-69)
|
||||
public static void SetRealTimeNetworkBattle(RealTimeNetworkAgent agent)
|
||||
{
|
||||
- RealTimeNetworkAgent = agent;
|
||||
+ var c = SVSim.BattleEngine.Ambient.BattleAmbient.Current;
|
||||
+ if (c != null) c.NetworkAgent = agent;
|
||||
+ else _realTimeNetworkAgentFallback = agent;
|
||||
}
|
||||
|
||||
public static void DestroyNetworkAgent()
|
||||
{
|
||||
- if (RealTimeNetworkAgent != null)
|
||||
+ var c = SVSim.BattleEngine.Ambient.BattleAmbient.Current;
|
||||
+ var current = c?.NetworkAgent ?? _realTimeNetworkAgentFallback;
|
||||
+ if (current != null)
|
||||
{
|
||||
- Object.DestroyImmediate(RealTimeNetworkAgent.gameObject);
|
||||
- RealTimeNetworkAgent = null;
|
||||
+ Object.DestroyImmediate(current.gameObject);
|
||||
+ if (c != null) c.NetworkAgent = null;
|
||||
+ else _realTimeNetworkAgentFallback = null;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user