fix: support mixed wall and game clock servers

This commit is contained in:
2026-08-04 01:09:18 +00:00
parent 41ec80c96b
commit 68a82c066b
8 changed files with 153 additions and 25 deletions
+16 -3
View File
@@ -114,7 +114,11 @@ final class GameClockBoundaryTest extends TestCase
$source = file_get_contents(__DIR__ . '/../src/sammo/Session.php');
self::assertIsString($source);
self::assertMatchesRegularExpression(
'/function loginGame\(.*?GameClock::fromStorage\(\$gameStor\)->nowTick\(\).*?GameClock::TICKS_PER_TURN.*?function logoutGame\(/s',
'/function loginGame\(.*?GameClock::isInitialized\(\$gameStor\).*?GameClock::fromStorage\(\$gameStor\)->nowTick\(\).*?GameClock::TICKS_PER_TURN.*?function logoutGame\(/s',
$source,
);
self::assertMatchesRegularExpression(
'/function loginGame\(.*?new \\\\DateTimeImmutable.*?getTimestamp\(\).*?function logoutGame\(/s',
$source,
);
self::assertDoesNotMatchRegularExpression(
@@ -128,7 +132,7 @@ final class GameClockBoundaryTest extends TestCase
$expectations = [
'hwe/ts/PageVote.vue' => ['currentVote.value.isOpen'],
'hwe/ts/components/MessagePlate.vue' => ['msg.clockMode === "manual"'],
'hwe/ts/gateway/entrance.ts' => ['game.isOpen'],
'hwe/ts/gateway/entrance.ts' => ['resolveGatewayOpenState(game.isOpen, game.opentime, now)'],
'hwe/ts/select_npc.ts' => ['logicalClockRunning'],
'hwe/ts/select_general_from_pool.ts' => ['logicalClockRunning'],
];
@@ -140,7 +144,16 @@ final class GameClockBoundaryTest extends TestCase
}
}
self::assertStringNotContainsString('formatTime(new Date())', file_get_contents(__DIR__ . '/../hwe/ts/PageVote.vue'));
self::assertStringNotContainsString('game.opentime <= now', file_get_contents(__DIR__ . '/../hwe/ts/gateway/entrance.ts'));
}
public function testGatewayFormatsLogicalOpenTimeBeforeReturningIt(): void
{
$source = file_get_contents(__DIR__ . '/../hwe/j_server_basic_info.php');
self::assertIsString($source);
self::assertStringContainsString(
'$admin[\'opentime\'] = $clock->formatTick(Util::toInt($admin[\'opentime\']));',
$source,
);
}
}
+27
View File
@@ -91,6 +91,33 @@ final class GameClockTest extends TestCase
self::assertSame(7_600, $clock->nowTick());
}
public function testStorageInitializationDetectionSupportsMixedLegacyProfiles(): void
{
$logicalStorage = $this->createMock(KVStorage::class);
$logicalStorage->method('getValues')->willReturn([
'clock_base_time' => '2026-08-03 00:00:00.000000',
'clock_tick' => 0,
'clock_mode' => GameClock::MODE_REALTIME,
'clock_wall_anchor' => '2026-08-03 00:00:00.000000',
'turnterm' => 60,
]);
self::assertTrue(GameClock::isInitialized($logicalStorage));
$legacyStorage = $this->createMock(KVStorage::class);
$legacyStorage->method('getValues')->willReturn([
'turnterm' => 60,
]);
self::assertFalse(GameClock::isInitialized($legacyStorage));
$partialStorage = $this->createMock(KVStorage::class);
$partialStorage->method('getValues')->willReturn([
'clock_tick' => 0,
'turnterm' => 60,
]);
$this->expectException(\RuntimeException::class);
GameClock::isInitialized($partialStorage);
}
public function testTickArithmeticRejectsValuesThatJavaScriptCannotRepresentExactly(): void
{
self::assertSame(GameClock::MAX_SAFE_TICK, GameClock::addTicks(GameClock::MAX_SAFE_TICK - 1, 1));