test(battle-engine M13): NewNetworkEmitBattle harness + OnEmit capture seam
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -343,6 +343,46 @@ namespace SVSim.BattleEngine.Tests
|
||||
return mgr;
|
||||
}
|
||||
|
||||
// M13 emit-path read. Builds a HeadlessNetworkBattleMgr (the emitting twin of the
|
||||
// HeadlessBattleMgr NewAuthoritativeBattle returns) and stands up the OnEmit capture seam: the
|
||||
// engine's own RealTimeNetworkAgent.OnEmit event (RealTimeNetworkAgent.cs:1268) fires the played
|
||||
// URI before both emit guards, so capturing it needs no Engine/shim edit — just an injected agent.
|
||||
// Returns (mgr, emitted-URI list). The caller seeds the hand and drives mgr.OperateMgr.PlayCard.
|
||||
public static (HeadlessNetworkBattleMgr mgr, System.Collections.Generic.List<NetworkBattleDefine.NetworkBattleURI> emitted)
|
||||
NewNetworkEmitBattle(IRandomSource rng = null)
|
||||
{
|
||||
EnsureInitialized(); // sets IsForecast = true among other globals
|
||||
var mgr = new HeadlessNetworkBattleMgr(new HeadlessContentsCreator(), rng);
|
||||
mgr.IsRecovery = true; // collapse wait delays to 0 (F1)
|
||||
|
||||
var player = mgr.BattlePlayer;
|
||||
var enemy = mgr.BattleEnemy;
|
||||
SetField(player, "_opponentBattlePlayer", enemy);
|
||||
SetField(enemy, "_opponentBattlePlayer", player);
|
||||
player.IsSelfTurn = true;
|
||||
enemy.IsSelfTurn = false;
|
||||
|
||||
InitLeaderLife(mgr); // a 0-life leader reads as game-over and blocks plays
|
||||
InitCardTemplates(mgr); // play/draw VFX touches the card view layer
|
||||
|
||||
// Inject a headless RealTimeNetworkAgent so NetworkBattleSender's ToolboxGame.RealTimeNetworkAgent
|
||||
// .* calls resolve, and subscribe OnEmit. GetUninitializedObject skips the MonoBehaviour Awake.
|
||||
var agent = (RealTimeNetworkAgent)System.Runtime.Serialization.FormatterServices
|
||||
.GetUninitializedObject(typeof(RealTimeNetworkAgent));
|
||||
// CurrentMatchingStatus has a protected setter; seed it non-Disconnected so EmitMsgPack does not
|
||||
// early-return at RealTimeNetworkAgent.cs:1272 (needed only for the best-effort payload read, Task 4;
|
||||
// OnEmit fires regardless). The default on the uninitialized object is OffLine (0), which clears the
|
||||
// SetCurrentMatchingStatus guards; the only side effect is a static-StringBuilder trace log, so the
|
||||
// public setter runs cleanly headless. Prepared (50) is the real enum member (RealTimeNetworkAgent.cs:35).
|
||||
agent.SetCurrentMatchingStatus(RealTimeNetworkAgent.MatchingStatus.Prepared);
|
||||
|
||||
var emitted = new System.Collections.Generic.List<NetworkBattleDefine.NetworkBattleURI>();
|
||||
agent.OnEmit += uri => emitted.Add(uri);
|
||||
Wizard.ToolboxGame.SetRealTimeNetworkBattle(agent);
|
||||
|
||||
return (mgr, emitted);
|
||||
}
|
||||
|
||||
private static void SetField(object obj, string name, object value)
|
||||
{
|
||||
var f = obj.GetType().GetField(name,
|
||||
|
||||
@@ -21,5 +21,15 @@ namespace SVSim.BattleEngine.Tests
|
||||
Assert.That(mgr, Is.Not.Null);
|
||||
});
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void OnEmit_capture_seam_is_wired_via_injected_agent()
|
||||
{
|
||||
var (mgr, emitted) = HeadlessEngineEnv.NewNetworkEmitBattle();
|
||||
Assert.That(mgr, Is.Not.Null);
|
||||
Assert.That(Wizard.ToolboxGame.RealTimeNetworkAgent, Is.Not.Null,
|
||||
"agent must be injected so NetworkBattleSender's ToolboxGame.RealTimeNetworkAgent.* calls resolve");
|
||||
Assert.That(emitted, Is.Empty, "no emit yet — only the seam is wired");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user