merge: refresh ng_compare for logical game clock
This commit is contained in:
@@ -16,6 +16,18 @@ require_once 'lib.php';
|
||||
require_once 'func.php';
|
||||
require_once __DIR__ . '/turn_state_snapshot.php';
|
||||
|
||||
function comparisonGameTick(mixed $value, string $label): int
|
||||
{
|
||||
if (is_int($value)) {
|
||||
return GameClock::requireSafeTick($value);
|
||||
}
|
||||
if (!is_string($value) || $value === '') {
|
||||
throw new \InvalidArgumentException("{$label} must be a game tick or projected date string");
|
||||
}
|
||||
$gameStorage = KVStorage::getStorage(DB::db(), 'game_env');
|
||||
return GameClock::fromStorage($gameStorage)->dateTimeToTick(new \DateTimeImmutable($value));
|
||||
}
|
||||
|
||||
/** @param array<string, mixed> $values */
|
||||
function comparisonMonthlyPatch(string $table, int $id, array $values): void
|
||||
{
|
||||
@@ -1073,6 +1085,14 @@ function comparisonMonthlyEventTraceMain(): void
|
||||
if (!is_array($environment)) {
|
||||
throw new \InvalidArgumentException('environment must be an object');
|
||||
}
|
||||
foreach (['starttime', 'turntime'] as $timeKey) {
|
||||
if (array_key_exists($timeKey, $environment)) {
|
||||
$environment[$timeKey] = comparisonGameTick(
|
||||
$environment[$timeKey],
|
||||
"environment.{$timeKey}",
|
||||
);
|
||||
}
|
||||
}
|
||||
$year = $environment['year'] ?? null;
|
||||
$month = $environment['month'] ?? null;
|
||||
$startYear = $environment['startyear'] ?? null;
|
||||
@@ -1089,9 +1109,6 @@ function comparisonMonthlyEventTraceMain(): void
|
||||
'turnterm' => $environment['turnterm'] ?? $gameStorage->turnterm,
|
||||
];
|
||||
if (isset($environment['starttime'])) {
|
||||
if (!is_string($environment['starttime']) || $environment['starttime'] === '') {
|
||||
throw new \InvalidArgumentException('environment.starttime must be a non-empty string');
|
||||
}
|
||||
$environmentValues['starttime'] = $environment['starttime'];
|
||||
}
|
||||
foreach ($environmentValues as $key => $value) {
|
||||
@@ -1232,12 +1249,12 @@ function comparisonMonthlyEventTraceMain(): void
|
||||
if (
|
||||
!is_int($turnterm)
|
||||
|| $turnterm <= 0
|
||||
|| !is_string($turntime)
|
||||
|| !is_int($turntime)
|
||||
|| !is_int($showImgLevel)
|
||||
|| !is_array($fiction)
|
||||
) {
|
||||
throw new \InvalidArgumentException(
|
||||
"{$actionName} requires positive turnterm, string turntime, integer show_img_level, and array fiction",
|
||||
"{$actionName} requires positive turnterm, game-tick turntime, integer show_img_level, and array fiction",
|
||||
);
|
||||
}
|
||||
$actionEnvironment += [
|
||||
@@ -1267,7 +1284,7 @@ function comparisonMonthlyEventTraceMain(): void
|
||||
))));
|
||||
} elseif ($actionName === 'MonthlyBoundary') {
|
||||
$turntime = $environment['turntime'] ?? null;
|
||||
if (!is_string($turntime) || $turntime === '') {
|
||||
if (!is_int($turntime)) {
|
||||
throw new \InvalidArgumentException('MonthlyBoundary requires turntime');
|
||||
}
|
||||
$gameStorage = KVStorage::getStorage($db, 'game_env');
|
||||
|
||||
@@ -42,10 +42,13 @@ function monthlySnapshotPick(array $row, array $mapping, array $jsonColumns = []
|
||||
$db = DB::db();
|
||||
$game = KVStorage::getStorage($db, 'game_env');
|
||||
$game->resetCache();
|
||||
$clock = GameClock::fromStorage($game);
|
||||
$world = $game->getValues([
|
||||
'scenario', 'year', 'month', 'turnterm', 'turntime', 'starttime',
|
||||
'init_year', 'init_month', 'develcost', 'killturn', 'isunited',
|
||||
]);
|
||||
$world['turntime'] = $clock->formatTick(Util::toInt($world['turntime']), true);
|
||||
$world['starttime'] = $clock->formatTick(Util::toInt($world['starttime']), true);
|
||||
|
||||
$generals = [];
|
||||
foreach ($db->query('SELECT * FROM general ORDER BY no') as $row) {
|
||||
@@ -69,6 +72,10 @@ foreach ($db->query('SELECT * FROM general ORDER BY no') as $row) {
|
||||
'dex4', 'dex5', 'killTurn', 'affinity', 'birthYear', 'deathYear', 'specAge', 'specAge2'] as $key) {
|
||||
$general[$key] = (int)$general[$key];
|
||||
}
|
||||
$general['turnTime'] = $clock->formatTick(Util::toInt($general['turnTime']), true);
|
||||
$general['recentWarTime'] = $general['recentWarTime'] === null
|
||||
? null
|
||||
: $clock->formatTick(Util::toInt($general['recentWarTime']), true);
|
||||
$generals[] = $general;
|
||||
}
|
||||
|
||||
|
||||
@@ -110,12 +110,12 @@ function comparisonNpcState(): array
|
||||
* @param array<string, mixed> $case
|
||||
* @return array<string, mixed>
|
||||
*/
|
||||
function comparisonNpcRunCase(array $case, string|int $hiddenSeed, int $owner, string $now): array
|
||||
function comparisonNpcRunCase(array $case, string|int $hiddenSeed, int $owner, int $now, GameClock $clock): array
|
||||
{
|
||||
$db = DB::db();
|
||||
$db->delete('select_npc_token', '1=1');
|
||||
|
||||
$insertReserved = static function (int $reservedOwner, array $reservedIds, string $validUntil) use ($db): void {
|
||||
$insertReserved = static function (int $reservedOwner, array $reservedIds, int $validUntil) use ($db, $now): void {
|
||||
if ($reservedIds === []) {
|
||||
return;
|
||||
}
|
||||
@@ -126,7 +126,7 @@ function comparisonNpcRunCase(array $case, string|int $hiddenSeed, int $owner, s
|
||||
$db->insert('select_npc_token', [
|
||||
'owner' => $reservedOwner,
|
||||
'valid_until' => $validUntil,
|
||||
'pick_more_from' => '2000-01-01 01:00:00',
|
||||
'pick_more_from' => $now,
|
||||
'pick_result' => json_encode((object)$reservedPick, JSON_THROW_ON_ERROR | JSON_UNESCAPED_UNICODE),
|
||||
'nonce' => 1,
|
||||
]);
|
||||
@@ -140,8 +140,8 @@ function comparisonNpcRunCase(array $case, string|int $hiddenSeed, int $owner, s
|
||||
$case['expiredReservedIds'] ?? [],
|
||||
'expiredReservedIds',
|
||||
);
|
||||
$expiredAt = (new \DateTimeImmutable($now))->modify('-1 second')->format('Y-m-d H:i:s');
|
||||
$insertReserved($owner + 1, $reservedIds, '2099-12-31 23:59:59');
|
||||
$expiredAt = $now - $clock->ticksFromSeconds(1);
|
||||
$insertReserved($owner + 1, $reservedIds, GameClock::MAX_SAFE_TICK);
|
||||
$insertReserved($owner + 2, $boundaryReservedIds, $now);
|
||||
$insertReserved($owner + 3, $expiredReservedIds, $expiredAt);
|
||||
|
||||
@@ -156,7 +156,7 @@ function comparisonNpcRunCase(array $case, string|int $hiddenSeed, int $owner, s
|
||||
$candidates,
|
||||
$weights,
|
||||
$db->queryFirstColumn(
|
||||
'SELECT pick_result FROM select_npc_token WHERE `owner`!=%i AND valid_until >=%s',
|
||||
'SELECT pick_result FROM select_npc_token WHERE `owner`!=%i AND valid_until >=%i',
|
||||
$owner,
|
||||
$now,
|
||||
),
|
||||
@@ -176,8 +176,8 @@ function comparisonNpcRunCase(array $case, string|int $hiddenSeed, int $owner, s
|
||||
if ($hasPreviousToken) {
|
||||
$db->insert('select_npc_token', [
|
||||
'owner' => $owner,
|
||||
'valid_until' => '2099-12-31 23:59:59',
|
||||
'pick_more_from' => '2000-01-01 01:00:00',
|
||||
'valid_until' => GameClock::MAX_SAFE_TICK,
|
||||
'pick_more_from' => $now,
|
||||
'pick_result' => json_encode((object)$oldPick, JSON_THROW_ON_ERROR | JSON_UNESCAPED_UNICODE),
|
||||
'nonce' => 2,
|
||||
]);
|
||||
@@ -259,6 +259,9 @@ if ($date === false || $date->format('Y-m-d H:i:s') !== $now) {
|
||||
}
|
||||
|
||||
$db = DB::db();
|
||||
$gameStorage = KVStorage::getStorage($db, 'game_env');
|
||||
$clock = GameClock::fromStorage($gameStorage);
|
||||
$nowTick = $clock->dateTimeToTick($date);
|
||||
$db->update('general', ['npc' => 1], '1=1');
|
||||
$fixtureIds = [];
|
||||
foreach ($candidateFixtures as $candidate) {
|
||||
@@ -295,7 +298,7 @@ foreach ($cases as $case) {
|
||||
if (!is_array($case)) {
|
||||
throw new \InvalidArgumentException('case must be an object');
|
||||
}
|
||||
$results[] = comparisonNpcRunCase($case, $hiddenSeed, $owner, $now);
|
||||
$results[] = comparisonNpcRunCase($case, $hiddenSeed, $owner, $nowTick, $clock);
|
||||
}
|
||||
|
||||
echo json_encode(
|
||||
|
||||
@@ -4,6 +4,7 @@ declare(strict_types=1);
|
||||
|
||||
use sammo\DB;
|
||||
use sammo\Event\Action\OpenNationBetting;
|
||||
use sammo\GameClock;
|
||||
use sammo\Json;
|
||||
use sammo\KVStorage;
|
||||
|
||||
@@ -46,8 +47,12 @@ if ($uniqueCount === 0) {
|
||||
if ($generalID <= 0) {
|
||||
throw new RuntimeException('Ref GUI parity fixture requires at least one general.');
|
||||
}
|
||||
$openDate = new DateTimeImmutable('now');
|
||||
$closeDate = $openDate->modify('+1 day');
|
||||
$gameStorage = KVStorage::getStorage($db, 'game_env');
|
||||
$clock = GameClock::fromStorage($gameStorage);
|
||||
$openTick = $clock->nowTick();
|
||||
$closeTick = GameClock::addTicks($openTick, $clock->ticksFromMinutes(24 * 60));
|
||||
$latestBidCloseTick = GameClock::addTicks($openTick, $clock->ticksFromMinutes(2 * 24 * 60));
|
||||
$openDate = $clock->tickToDateTime($openTick);
|
||||
$detail = [
|
||||
'title' => '손자병법 경매',
|
||||
'hostName' => '청룡',
|
||||
@@ -56,7 +61,7 @@ if ($uniqueCount === 0) {
|
||||
'startBidAmount' => 1000,
|
||||
'finishBidAmount' => null,
|
||||
'remainCloseDateExtensionCnt' => 1,
|
||||
'availableLatestBidCloseDate' => $openDate->modify('+2 days')->format('Y-m-d H:i:s'),
|
||||
'availableLatestBidCloseTick' => $latestBidCloseTick,
|
||||
];
|
||||
$db->insert('ng_auction', [
|
||||
'type' => 'uniqueItem',
|
||||
@@ -64,8 +69,8 @@ if ($uniqueCount === 0) {
|
||||
'target' => 'che_서적_15_손자병법',
|
||||
'host_general_id' => $generalID,
|
||||
'req_resource' => 'inheritPoint',
|
||||
'open_date' => $openDate->format('Y-m-d H:i:s'),
|
||||
'close_date' => $closeDate->format('Y-m-d H:i:s'),
|
||||
'open_tick' => $openTick,
|
||||
'close_tick' => $closeTick,
|
||||
'detail' => Json::encode($detail),
|
||||
]);
|
||||
$auctionID = (int)$db->insertId();
|
||||
|
||||
@@ -231,6 +231,7 @@ function comparisonTurnStateSnapshot(array $request): array
|
||||
|
||||
$game = KVStorage::getStorage($db, 'game_env');
|
||||
$game->resetCache();
|
||||
$clock = GameClock::fromStorage($game);
|
||||
$worldValues = $game->getValues([
|
||||
'year',
|
||||
'month',
|
||||
@@ -270,7 +271,7 @@ function comparisonTurnStateSnapshot(array $request): array
|
||||
);
|
||||
|
||||
$generals = array_map(
|
||||
static function (array $row): array {
|
||||
static function (array $row) use ($clock): array {
|
||||
$result = comparisonPickRow(
|
||||
$row,
|
||||
[
|
||||
@@ -338,6 +339,10 @@ function comparisonTurnStateSnapshot(array $request): array
|
||||
] as $key) {
|
||||
$result[$key] = comparisonOptionalCode($result[$key] ?? null);
|
||||
}
|
||||
$result['turnTime'] = $clock->formatTick(Util::toInt($row['turntime']), true);
|
||||
$result['recentWarTime'] = $row['recent_war'] === null
|
||||
? null
|
||||
: $clock->formatTick(Util::toInt($row['recent_war']), true);
|
||||
$result['maxBelong'] = (int)($result['meta']['max_belong'] ?? 0);
|
||||
$ownerId = (int)($row['owner'] ?? 0);
|
||||
$activeActionPoints = 0;
|
||||
@@ -576,19 +581,23 @@ function comparisonTurnStateSnapshot(array $request): array
|
||||
}
|
||||
|
||||
$messages = array_map(
|
||||
static fn(array $row): array => comparisonPickRow(
|
||||
$row,
|
||||
[
|
||||
'id' => 'id',
|
||||
'mailbox' => 'mailbox',
|
||||
'type' => 'type',
|
||||
'sourceId' => 'src',
|
||||
'destinationId' => 'dest',
|
||||
'createdAt' => 'time',
|
||||
'payload' => 'message',
|
||||
],
|
||||
['message'],
|
||||
),
|
||||
static function (array $row) use ($clock): array {
|
||||
$result = comparisonPickRow(
|
||||
$row,
|
||||
[
|
||||
'id' => 'id',
|
||||
'mailbox' => 'mailbox',
|
||||
'type' => 'type',
|
||||
'sourceId' => 'src',
|
||||
'destinationId' => 'dest',
|
||||
'createdAt' => 'time',
|
||||
'payload' => 'message',
|
||||
],
|
||||
['message'],
|
||||
);
|
||||
$result['createdAt'] = $clock->formatTick(Util::toInt($row['time']), true);
|
||||
return $result;
|
||||
},
|
||||
$db->query(
|
||||
'SELECT id, mailbox, type, src, dest, time, message FROM message WHERE id > %i ORDER BY id',
|
||||
$messageAfterId,
|
||||
@@ -602,7 +611,7 @@ function comparisonTurnStateSnapshot(array $request): array
|
||||
'year' => (int)$worldValues['year'],
|
||||
'month' => (int)$worldValues['month'],
|
||||
'tickMinutes' => (int)$worldValues['turnterm'],
|
||||
'turnTime' => (string)$worldValues['turntime'],
|
||||
'turnTime' => $clock->formatTick(Util::toInt($worldValues['turntime']), true),
|
||||
'isUnited' => (int)$worldValues['isunited'],
|
||||
'scenarioId' => (int)$worldValues['scenario'],
|
||||
'initYear' => (int)$worldValues['init_year'],
|
||||
|
||||
Reference in New Issue
Block a user