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:
gamer147
2026-06-07 21:37:58 -04:00
parent 4e756a6c46
commit fe146fde50
9 changed files with 230 additions and 16 deletions

View File

@@ -178,7 +178,7 @@ Cute\AudioManager.cs Cute\AudioManager.cs 5e0cce94bcfad63266cd298aef89bb383e541f
Cute\BootApp.cs Cute\BootApp.cs 1a6b3066b6155aba225b9ca4e79655e428fc7b24cb16569717b53600b1f23bb5 0
Cute\BootNetwork.cs Cute\BootNetwork.cs 99769dd6c38b2ee2ef7ad02e14530c658576e5c4a2188ed1cbcdd563f68443f6 0
Cute\BootSystem.cs Cute\BootSystem.cs 61afa7a7c8df705504031629965440d491603dec531b047a36b9294f255ee04e 0
Cute\Certification.cs Cute\Certification.cs 8c143ee5f98e99332bbd1d6ec091d7590004b3b7215f1dc234d39bb5402f8531 0
Cute\Certification.cs Cute\Certification.cs ea018062d8823eb3527e7fd5e07d094a6fd444c1ad5a368bcf9132315cac99ac 1
Cute\CryptAES.cs Cute\CryptAES.cs d3022b9e1be75bc07e57aef61093717a84b60383608eba5daa9b7dc6605b1e75 0
Cute\Cryptographer.cs Cute\Cryptographer.cs f61bc1f4727d323004c443c9db30a4f221db3309be2cb14d6f51fc6a39590908 0
Cute\CustomPreference.cs Cute\CustomPreference.cs ddc46cc13bf2728e4fcee7db550ec093ec3acf651ea48d3dbb5f5099d5a20f89 0
@@ -2624,7 +2624,7 @@ Wizard\CrossoverRewardInfo.cs Wizard\CrossoverRewardInfo.cs bb3763306d0e7d3feefb
Wizard\CsvColumns.cs Wizard\CsvColumns.cs d113f92e1f0145adb323c093deca81aab1889e8de34ed78c852b8e5a764c1c4c 0
Wizard\CustomEasing.cs Wizard\CustomEasing.cs c7ac36e40e66f046d42e1d688db22f2acc2567399ce23c0512e3e2c8beefa598 0
Wizard\DamagedTagCollection.cs Wizard\DamagedTagCollection.cs 8e6ecf677b4da8e16a68d3336959cd6d08af4830a0214297d65e96243f777c3f 0
Wizard\Data.cs Wizard\Data.cs 26bd39c591da328c1a30eccf773064be022145dad1f11a29584832b8a81d36e1 0
Wizard\Data.cs Wizard\Data.cs 88529d834ee64a12288ae2a40062824ea594f6d1b6c95d3cab2776f499369e77 1
Wizard\DeckAttributeType.cs Wizard\DeckAttributeType.cs 006bb4c04d8a60c9caf04873dde6c962366348db03ec40a8bbc0071392f656dd 0
Wizard\DeckAutoCreateTask.cs Wizard\DeckAutoCreateTask.cs e8c21d513114d2c42ad85a28da4adb48642bd36dc012f6029fbc8a8d72b78d6c 0
Wizard\DeckBuildShortageCardView.cs Wizard\DeckBuildShortageCardView.cs 34428e4efb614c4fd59136d1bb87485ce117a97b2c6668f0481fff4b510a31d3 0
@@ -3237,7 +3237,7 @@ Wizard\TargetSelectType.cs Wizard\TargetSelectType.cs 91ab18f9c069784e1140a187ea
Wizard\TargetTagCollection.cs Wizard\TargetTagCollection.cs 1bd2fb66e58c9fae3d23fbce351972577da664c2b959ee92e0547e2396c82eb9 0
Wizard\TextLineCreater.cs Wizard\TextLineCreater.cs fdb7f0a918c2f5b92268954b3980724f29cb16a8098ea67c2d99633ae5bd1e92 0
Wizard\TokenPlayPattern.cs Wizard\TokenPlayPattern.cs c14d846afb81b876291013c077cbd503bebd27b651b5b78708e93d68758e2e7b 0
Wizard\ToolboxGame.cs Wizard\ToolboxGame.cs f0a39a9ec7a06d08cc2594cc93f010c602946492ed93c002775c41000f30ef75 0
Wizard\ToolboxGame.cs Wizard\ToolboxGame.cs ac0bde1ef076672c6e19969c5f9ec172aee79e7d5ee5bdf660e89166e8ff07ce 1
Wizard\TournamentCell.cs Wizard\TournamentCell.cs b07b968c6768b74b9345ab3aa1ae138950de022b08f92a16966b3daef81d379c 0
Wizard\TournamentCellData.cs Wizard\TournamentCellData.cs ecc457bdf2dbaa7db9de893f69a07ac43e589ca140dad29866d658af386e605e 0
Wizard\TournamentController.cs Wizard\TournamentController.cs 236122aa73487c600114c9b0010ab9e9c85a5745a267550088c8f790532647c9 0
1 # engine-relpath source-relpath sha256 patched(0|1)
178 Cute\BootApp.cs Cute\BootApp.cs 1a6b3066b6155aba225b9ca4e79655e428fc7b24cb16569717b53600b1f23bb5 0
179 Cute\BootNetwork.cs Cute\BootNetwork.cs 99769dd6c38b2ee2ef7ad02e14530c658576e5c4a2188ed1cbcdd563f68443f6 0
180 Cute\BootSystem.cs Cute\BootSystem.cs 61afa7a7c8df705504031629965440d491603dec531b047a36b9294f255ee04e 0
181 Cute\Certification.cs Cute\Certification.cs 8c143ee5f98e99332bbd1d6ec091d7590004b3b7215f1dc234d39bb5402f8531 ea018062d8823eb3527e7fd5e07d094a6fd444c1ad5a368bcf9132315cac99ac 0 1
182 Cute\CryptAES.cs Cute\CryptAES.cs d3022b9e1be75bc07e57aef61093717a84b60383608eba5daa9b7dc6605b1e75 0
183 Cute\Cryptographer.cs Cute\Cryptographer.cs f61bc1f4727d323004c443c9db30a4f221db3309be2cb14d6f51fc6a39590908 0
184 Cute\CustomPreference.cs Cute\CustomPreference.cs ddc46cc13bf2728e4fcee7db550ec093ec3acf651ea48d3dbb5f5099d5a20f89 0
2624 Wizard\CsvColumns.cs Wizard\CsvColumns.cs d113f92e1f0145adb323c093deca81aab1889e8de34ed78c852b8e5a764c1c4c 0
2625 Wizard\CustomEasing.cs Wizard\CustomEasing.cs c7ac36e40e66f046d42e1d688db22f2acc2567399ce23c0512e3e2c8beefa598 0
2626 Wizard\DamagedTagCollection.cs Wizard\DamagedTagCollection.cs 8e6ecf677b4da8e16a68d3336959cd6d08af4830a0214297d65e96243f777c3f 0
2627 Wizard\Data.cs Wizard\Data.cs 26bd39c591da328c1a30eccf773064be022145dad1f11a29584832b8a81d36e1 88529d834ee64a12288ae2a40062824ea594f6d1b6c95d3cab2776f499369e77 0 1
2628 Wizard\DeckAttributeType.cs Wizard\DeckAttributeType.cs 006bb4c04d8a60c9caf04873dde6c962366348db03ec40a8bbc0071392f656dd 0
2629 Wizard\DeckAutoCreateTask.cs Wizard\DeckAutoCreateTask.cs e8c21d513114d2c42ad85a28da4adb48642bd36dc012f6029fbc8a8d72b78d6c 0
2630 Wizard\DeckBuildShortageCardView.cs Wizard\DeckBuildShortageCardView.cs 34428e4efb614c4fd59136d1bb87485ce117a97b2c6668f0481fff4b510a31d3 0
3237 Wizard\TargetTagCollection.cs Wizard\TargetTagCollection.cs 1bd2fb66e58c9fae3d23fbce351972577da664c2b959ee92e0547e2396c82eb9 0
3238 Wizard\TextLineCreater.cs Wizard\TextLineCreater.cs fdb7f0a918c2f5b92268954b3980724f29cb16a8098ea67c2d99633ae5bd1e92 0
3239 Wizard\TokenPlayPattern.cs Wizard\TokenPlayPattern.cs c14d846afb81b876291013c077cbd503bebd27b651b5b78708e93d68758e2e7b 0
3240 Wizard\ToolboxGame.cs Wizard\ToolboxGame.cs f0a39a9ec7a06d08cc2594cc93f010c602946492ed93c002775c41000f30ef75 ac0bde1ef076672c6e19969c5f9ec172aee79e7d5ee5bdf660e89166e8ff07ce 0 1
3241 Wizard\TournamentCell.cs Wizard\TournamentCell.cs b07b968c6768b74b9345ab3aa1ae138950de022b08f92a16966b3daef81d379c 0
3242 Wizard\TournamentCellData.cs Wizard\TournamentCellData.cs ecc457bdf2dbaa7db9de893f69a07ac43e589ca140dad29866d658af386e605e 0
3243 Wizard\TournamentController.cs Wizard\TournamentController.cs 236122aa73487c600114c9b0010ab9e9c85a5745a267550088c8f790532647c9 0

View File

@@ -16,7 +16,7 @@ public class Certification : MonoBehaviour
private static string udid;
private static int viewer_id;
private static int _viewerIdFallback;
private static int short_udid;
@@ -42,17 +42,25 @@ public class Certification : MonoBehaviour
{
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;
}
}
@@ -144,7 +152,7 @@ public class Certification : MonoBehaviour
{
sessionId = null;
udid = null;
viewer_id = 0;
_viewerIdFallback = 0;
short_udid = 0;
Toolbox.SavedataManager.SetInt("VIEWER_ID", 0);
Toolbox.SavedataManager.SetInt("SHORT_UDID", 0);

View File

@@ -176,7 +176,17 @@ public static class Data
public static ReplayDetailInfo ReplayBattleInfo { get; set; }
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;
}
}
public static VoteData VoteInfo { get; set; }

View File

@@ -25,7 +25,11 @@ public static class ToolboxGame
private static Transform _gameTransform = null;
public static RealTimeNetworkAgent RealTimeNetworkAgent { get; private set; }
private static RealTimeNetworkAgent _realTimeNetworkAgentFallback;
public static RealTimeNetworkAgent RealTimeNetworkAgent
{
get => SVSim.BattleEngine.Ambient.BattleAmbient.Current?.NetworkAgent ?? _realTimeNetworkAgentFallback;
}
public static Transform GameTransform
{
@@ -56,15 +60,20 @@ public static class ToolboxGame
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;
}
}

View File

@@ -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;

View 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;
+ }
+ }

View 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;
}
}