From fe221a7bd92a423d2bbc64f04aba45ab6e2e478f Mon Sep 17 00:00:00 2001 From: hided62 Date: Thu, 30 Jul 2026 18:38:35 +0000 Subject: [PATCH] test(compare): trace scenario action effects --- hwe/compare/battle_trace.php | 29 +++++++++++++++++++++++++++++ hwe/compare/turn_command_trace.php | 15 +++++++++++++++ 2 files changed, 44 insertions(+) diff --git a/hwe/compare/battle_trace.php b/hwe/compare/battle_trace.php index 3d71c8ae..1af87df4 100644 --- a/hwe/compare/battle_trace.php +++ b/hwe/compare/battle_trace.php @@ -120,6 +120,19 @@ function comparisonRunBattle(array $fixture): array $rawAttackerNation = $fixture['attackerNation']; $rawDefenderCity = $fixture['defenderCity']; $rawDefenderNation = $fixture['defenderNation']; + // 비교 fixture에 명시된 경우에만 ref runtime의 scenario action chain을 + // 활성화합니다. 일반 비교 fixture의 기존 동작은 그대로 유지합니다. + $scenarioEffect = $fixture['scenarioEffect'] ?? null; + if ($scenarioEffect === '' || $scenarioEffect === 'None') { + $scenarioEffect = null; + } + if ( + $scenarioEffect !== null + && (!is_string($scenarioEffect) || getScenarioEffectClass($scenarioEffect) === null) + ) { + throw new \InvalidArgumentException('scenarioEffect is invalid'); + } + GameConst::$scenarioEffect = $scenarioEffect; $tracingRng = new ComparisonTracingRNG(new LiteHashDRBG($seed)); $warRng = new RandUtil($tracingRng); @@ -182,6 +195,17 @@ function comparisonRunBattle(array $fixture): array }, ); + $attackerLogs = $attacker->getLogger()->rollback(); + $defenderLogs = []; + foreach ($defenderList as $defenderUnit) { + if (!($defenderUnit instanceof WarUnitGeneral)) { + continue; + } + $snapshot = buildWarTraceUnitSnapshot($defenderUnit); + $defenderLogs[(string)$snapshot['id']] = $defenderUnit->getLogger()->rollback(); + } + $cityLogs = $city->getLogger()->rollback(); + return [ 'engine' => 'ref', 'seed' => $seed, @@ -191,6 +215,11 @@ function comparisonRunBattle(array $fixture): array 'finishedDefenders' => $finishedDefenders, 'events' => $events, 'rng' => $tracingRng->calls, + 'logs' => [ + 'attacker' => $attackerLogs, + 'defenders' => $defenderLogs, + 'city' => $cityLogs, + ], ]; } diff --git a/hwe/compare/turn_command_trace.php b/hwe/compare/turn_command_trace.php index 2b82f5a3..6f7236ce 100644 --- a/hwe/compare/turn_command_trace.php +++ b/hwe/compare/turn_command_trace.php @@ -128,6 +128,21 @@ function comparisonApplyTurnFixtureSetup(mixed $setup): void } UniqueConst::$hiddenSeed = $hiddenSeed; } + // 비교 fixture는 전역 상태에 의존하지 않도록 effect 기본값을 null로 고정하고, + // 명시된 경우에만 해당 effect를 활성화합니다. + GameConst::$scenarioEffect = null; + if (array_key_exists('scenarioEffect', $world)) { + $scenarioEffect = $world['scenarioEffect']; + if ($scenarioEffect === '' || $scenarioEffect === 'None') { + $scenarioEffect = null; + } + if ($scenarioEffect !== null) { + if (!is_string($scenarioEffect) || getScenarioEffectClass($scenarioEffect) === null) { + throw new \InvalidArgumentException('setup.world.scenarioEffect is invalid'); + } + } + GameConst::$scenarioEffect = $scenarioEffect; + } if (array_key_exists('staticEventHandlers', $world)) { $handlersByEvent = $world['staticEventHandlers']; if (!is_array($handlersByEvent)) {