test(compare): 대규모 이민족 소환 시간 경계를 재현한다

This commit is contained in:
2026-08-23 12:01:30 +00:00
parent 857778e3cf
commit 5a7ab4d5ce
2 changed files with 301 additions and 1 deletions
+59 -1
View File
@@ -875,13 +875,40 @@ function comparisonUnificationInvaderResumeTrace(array $request, array $environm
$pausedAnchor = '2000-01-01 00:00:00.000000';
$gameStorage->autoreset_united_wall_anchor = $pausedAnchor;
$selectedMessageId = $invaderMessages[array_key_last($invaderMessages)]['id'];
$preSummonGeneralCopies = $request['preSummonGeneralCopies'] ?? 0;
if (!is_int($preSummonGeneralCopies) || $preSummonGeneralCopies < 0 || $preSummonGeneralCopies > 1000) {
throw new \InvalidArgumentException('preSummonGeneralCopies must be an integer between 0 and 1000');
}
if ($preSummonGeneralCopies > 0) {
$templateGeneral = $db->queryFirstRow('SELECT * FROM general WHERE no = %i', $winnerGeneralId);
if (!$templateGeneral) {
throw new \RuntimeException('winner general template is missing');
}
unset($templateGeneral['no']);
$templateGeneral['owner'] = 0;
$templateGeneral['owner_name'] = null;
$templateGeneral['npc'] = 2;
$templateGeneral['npc_org'] = 2;
$templateGeneral['officer_level'] = 0;
for ($copyIndex = 1; $copyIndex <= $preSummonGeneralCopies; $copyIndex++) {
$templateGeneral['name'] = "ⓧ재현장수{$copyIndex}";
$db->insert('general', $templateGeneral);
}
}
$invaderChoiceIndex = $request['invaderChoiceIndex'] ?? array_key_last($invaderMessages);
if (!is_int($invaderChoiceIndex) || !array_key_exists($invaderChoiceIndex, $invaderMessages)) {
throw new \InvalidArgumentException('invaderChoiceIndex must select one of the three invader messages');
}
$selectedMessageId = $invaderMessages[$invaderChoiceIndex]['id'];
$message = Message::getMessageByID($selectedMessageId);
if (!$message instanceof RaiseInvaderMessage) {
throw new \RuntimeException('selected invader message did not hydrate as RaiseInvaderMessage');
}
$reason = '';
$summonStartedAt = hrtime(true);
$decisionResult = $message->agreeMessage($winnerGeneralId, $reason);
$summonElapsedMs = (hrtime(true) - $summonStartedAt) / 1_000_000;
$gameStorage->resetCache();
$afterSummon = [
@@ -898,19 +925,50 @@ function comparisonUnificationInvaderResumeTrace(array $request, array $environm
'eventCount' => (int)$db->queryFirstField(
"SELECT COUNT(*) FROM event WHERE action LIKE '%Invader%'",
),
'selectedChoiceIndex' => $invaderChoiceIndex,
'preSummonGeneralCopies' => $preSummonGeneralCopies,
'summonElapsedMs' => round($summonElapsedMs, 3),
'generalCount' => (int)$db->queryFirstField('SELECT COUNT(*) FROM general'),
'minimumInvaderGeneralCount' => (int)$db->queryFirstField(
"SELECT MIN(general_count) FROM (SELECT COUNT(*) AS general_count FROM general g JOIN nation n ON n.nation = g.nation WHERE n.name LIKE 'ⓞ%족' GROUP BY g.nation) invader_counts",
),
'maximumInvaderGeneralCount' => (int)$db->queryFirstField(
"SELECT MAX(general_count) FROM (SELECT COUNT(*) AS general_count FROM general g JOIN nation n ON n.nation = g.nation WHERE n.name LIKE 'ⓞ%족' GROUP BY g.nation) invader_counts",
),
'autoresetAnchor' => $gameStorage->autoreset_united_wall_anchor,
'autoresetAnchorRefreshed' => $gameStorage->autoreset_united_wall_anchor !== $pausedAnchor,
];
$maxSummonElapsedMs = $request['maxSummonElapsedMs'] ?? null;
if ($maxSummonElapsedMs !== null && (!is_int($maxSummonElapsedMs) || $maxSummonElapsedMs <= 0)) {
throw new \InvalidArgumentException('maxSummonElapsedMs must be a positive integer');
}
if (
$decisionResult !== RaiseInvaderMessage::ACCEPTED
|| $afterSummon['isunited'] !== 1
|| $afterSummon['plock'] !== 0
|| $afterSummon['invaderNationCount'] !== 7
|| $afterSummon['autoresetAnchorRefreshed'] !== true
|| ($maxSummonElapsedMs !== null && $summonElapsedMs >= $maxSummonElapsedMs)
) {
throw new \RuntimeException('invader choice did not start an unlocked, watchdog-active event game');
}
$stopAfterSummon = $request['stopAfterSummon'] ?? false;
if (!is_bool($stopAfterSummon)) {
throw new \InvalidArgumentException('stopAfterSummon must be a boolean');
}
if ($stopAfterSummon) {
return [
'schemaVersion' => 1,
'engine' => 'ref',
'action' => 'UnificationInvaderResume',
'phase' => 'summon',
'before' => $before,
'buttonSnapshot' => $buttonSnapshot,
'afterSummon' => $afterSummon,
];
}
$resumeBoundary = addTurn(
cutTurn(Util::toInt($gameStorage->turntime), Util::toInt($gameStorage->turnterm)),
Util::toInt($gameStorage->turnterm),