test: 전투 차등 계측 범위를 엄격하게 보강한다
fixture 시각을 DB 변경 없이 고정하고 활성 스킬과 fixture identity를 노출해 Core의 전체 상태·RNG·로그 비교가 첫 차이에서 실패하도록 한다.
This commit is contained in:
@@ -151,12 +151,37 @@ function comparisonBuildGeneral(
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function comparisonRunBattle(array $fixture): array
|
/**
|
||||||
|
* Some legacy battle items read game time through KVStorage instead of the
|
||||||
|
* General/WarUnit time arguments. Seed only the process-local cache so each
|
||||||
|
* comparison fixture observes its own clock without mutating the shared Ref DB.
|
||||||
|
*/
|
||||||
|
function comparisonOverrideGameTime(int $year, int $month, int $startYear): void
|
||||||
|
{
|
||||||
|
$gameStorage = KVStorage::getStorage(DB::db(), 'game_env');
|
||||||
|
$cacheProperty = new \ReflectionProperty(KVStorage::class, 'cacheData');
|
||||||
|
$cacheProperty->setAccessible(true);
|
||||||
|
$cache = $cacheProperty->getValue($gameStorage);
|
||||||
|
if (!($cache instanceof Map)) {
|
||||||
|
$cache = new Map();
|
||||||
|
}
|
||||||
|
$cache['year'] = $year;
|
||||||
|
$cache['month'] = $month;
|
||||||
|
$cache['startyear'] = $startYear;
|
||||||
|
$cacheProperty->setValue($gameStorage, $cache);
|
||||||
|
}
|
||||||
|
|
||||||
|
function comparisonRunBattle(array $fixture, ?string $fixtureJson = null): array
|
||||||
{
|
{
|
||||||
$seed = (string)($fixture['seed'] ?? 'battle-differential');
|
$seed = (string)($fixture['seed'] ?? 'battle-differential');
|
||||||
|
$identityJson = trim($fixtureJson ?? json_encode(
|
||||||
|
$fixture,
|
||||||
|
JSON_THROW_ON_ERROR | JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES | JSON_PRESERVE_ZERO_FRACTION,
|
||||||
|
));
|
||||||
$year = (int)$fixture['year'];
|
$year = (int)$fixture['year'];
|
||||||
$month = (int)$fixture['month'];
|
$month = (int)$fixture['month'];
|
||||||
$startYear = (int)($fixture['startYear'] ?? 180);
|
$startYear = (int)($fixture['startYear'] ?? 180);
|
||||||
|
comparisonOverrideGameTime($year, $month, $startYear);
|
||||||
$rawAttacker = $fixture['attackerGeneral'];
|
$rawAttacker = $fixture['attackerGeneral'];
|
||||||
$rawAttackerCity = $fixture['attackerCity'];
|
$rawAttackerCity = $fixture['attackerCity'];
|
||||||
$rawAttackerNation = $fixture['attackerNation'];
|
$rawAttackerNation = $fixture['attackerNation'];
|
||||||
@@ -257,6 +282,11 @@ function comparisonRunBattle(array $fixture): array
|
|||||||
return [
|
return [
|
||||||
'engine' => 'ref',
|
'engine' => 'ref',
|
||||||
'seed' => $seed,
|
'seed' => $seed,
|
||||||
|
'fixtureIdentity' => [
|
||||||
|
'schemaVersion' => 1,
|
||||||
|
'seed' => $seed,
|
||||||
|
'sha256' => hash('sha256', $identityJson),
|
||||||
|
],
|
||||||
'conquered' => $conquered,
|
'conquered' => $conquered,
|
||||||
'attacker' => buildWarTraceUnitSnapshot($attacker),
|
'attacker' => buildWarTraceUnitSnapshot($attacker),
|
||||||
'city' => buildWarTraceUnitSnapshot($city),
|
'city' => buildWarTraceUnitSnapshot($city),
|
||||||
@@ -286,7 +316,7 @@ if ($fixturePath === '--jsonl') {
|
|||||||
}
|
}
|
||||||
$fixture = json_decode($line, true, flags: JSON_THROW_ON_ERROR);
|
$fixture = json_decode($line, true, flags: JSON_THROW_ON_ERROR);
|
||||||
echo json_encode(
|
echo json_encode(
|
||||||
comparisonRunBattle($fixture),
|
comparisonRunBattle($fixture, $line),
|
||||||
JSON_THROW_ON_ERROR | JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES | JSON_PRESERVE_ZERO_FRACTION,
|
JSON_THROW_ON_ERROR | JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES | JSON_PRESERVE_ZERO_FRACTION,
|
||||||
), PHP_EOL;
|
), PHP_EOL;
|
||||||
}
|
}
|
||||||
@@ -305,7 +335,7 @@ try {
|
|||||||
$fixtureJson = $fixturePath === '-' ? stream_get_contents(STDIN) : file_get_contents($fixturePath);
|
$fixtureJson = $fixturePath === '-' ? stream_get_contents(STDIN) : file_get_contents($fixturePath);
|
||||||
$fixture = json_decode((string)$fixtureJson, true, flags: JSON_THROW_ON_ERROR);
|
$fixture = json_decode((string)$fixtureJson, true, flags: JSON_THROW_ON_ERROR);
|
||||||
echo json_encode(
|
echo json_encode(
|
||||||
comparisonRunBattle($fixture),
|
comparisonRunBattle($fixture, (string)$fixtureJson),
|
||||||
JSON_THROW_ON_ERROR | JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES | JSON_PRESERVE_ZERO_FRACTION,
|
JSON_THROW_ON_ERROR | JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES | JSON_PRESERVE_ZERO_FRACTION,
|
||||||
), PHP_EOL;
|
), PHP_EOL;
|
||||||
} catch (\Throwable $throwable) {
|
} catch (\Throwable $throwable) {
|
||||||
|
|||||||
+4
-2
@@ -661,12 +661,14 @@ function buildWarTraceUnitSnapshot(WarUnit $unit): array
|
|||||||
'realPhase' => $unit->getRealPhase(),
|
'realPhase' => $unit->getRealPhase(),
|
||||||
'maxPhase' => $unit->getMaxPhase(),
|
'maxPhase' => $unit->getMaxPhase(),
|
||||||
'hp' => $unit->getHP(),
|
'hp' => $unit->getHP(),
|
||||||
'rawWarPower' => $unit->getRawWarPower(),
|
// Ref leaves warPower uninitialized until beginPhase(). Canonical
|
||||||
|
// traces use numeric zero for that not-yet-computed state, as Core does.
|
||||||
|
'rawWarPower' => $unit->getRawWarPower() ?? 0,
|
||||||
'warPower' => $unit->getWarPower(),
|
'warPower' => $unit->getWarPower(),
|
||||||
'warPowerMultiplier' => $unit->getWarPowerMultiply(),
|
'warPowerMultiplier' => $unit->getWarPowerMultiply(),
|
||||||
'killed' => $unit->getKilled(),
|
'killed' => $unit->getKilled(),
|
||||||
'dead' => $unit->getDead(),
|
'dead' => $unit->getDead(),
|
||||||
'activatedSkills' => $unit->getActivatedSkillLog(),
|
'activatedSkills' => $unit->getActivatedSkillTraceSnapshot(),
|
||||||
];
|
];
|
||||||
|
|
||||||
if ($unit instanceof WarUnitGeneral) {
|
if ($unit instanceof WarUnitGeneral) {
|
||||||
|
|||||||
@@ -120,6 +120,24 @@ class WarUnit
|
|||||||
return $this->logActivatedSkill;
|
return $this->logActivatedSkill;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Comparison traces observe a phase before clearActivatedSkill() runs.
|
||||||
|
* Keep the product-facing cumulative accessor above unchanged, while
|
||||||
|
* exposing the canonical logged + currently-active view used by Core's
|
||||||
|
* WarBattleTraceUnitSnapshot.
|
||||||
|
*/
|
||||||
|
function getActivatedSkillTraceSnapshot(): array
|
||||||
|
{
|
||||||
|
$snapshot = $this->logActivatedSkill;
|
||||||
|
foreach ($this->activatedSkill as $skillName => $state) {
|
||||||
|
if (!$state) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
$snapshot[$skillName] = ($snapshot[$skillName] ?? 0) + 1;
|
||||||
|
}
|
||||||
|
return $snapshot;
|
||||||
|
}
|
||||||
|
|
||||||
function getRawNation(): array
|
function getRawNation(): array
|
||||||
{
|
{
|
||||||
return $this->rawNation;
|
return $this->rawNation;
|
||||||
|
|||||||
Reference in New Issue
Block a user