fix: complete logical clock wall-time isolation

This commit is contained in:
2026-08-03 16:09:35 +00:00
parent ed3c84aa8e
commit 41ec80c96b
67 changed files with 689 additions and 231 deletions
+11 -1
View File
@@ -117,6 +117,11 @@ final class GameClock
return self::addTicks($this->anchorTick, $this->ticksBetween($this->wallAnchor, $this->wallNow()));
}
public function nowDateTime(): \DateTimeImmutable
{
return $this->tickToDateTime($this->nowTick());
}
public function ticksFromSeconds(int|float $seconds): int
{
if (is_int($seconds)) {
@@ -207,6 +212,11 @@ final class GameClock
return TimeUtil::format($this->tickToDateTime($tick), $withFraction);
}
public function formatNow(bool $withFraction = false): string
{
return $this->formatTick($this->nowTick(), $withFraction);
}
public static function baseTimeForProjection(
\DateTimeInterface $projectedTime,
int $tick,
@@ -249,7 +259,7 @@ final class GameClock
public function advance(KVStorage $gameStor, int $deltaTick): int
{
$nextTick = $this->nowTick() + $deltaTick;
$nextTick = self::addTicks($this->nowTick(), $deltaTick);
$this->persistTick($gameStor, $nextTick);
return $nextTick;
}
+15 -16
View File
@@ -239,13 +239,16 @@ class Session
$loginDate = $this->get($serverID.static::GAME_KEY_DATE);
$generalID = $this->get($serverID.static::GAME_KEY_GENERAL_ID);
$generalName = $this->get($serverID.static::GAME_KEY_GENERAL_NAME);
$deadTime = $this->get($serverID.static::GAME_KEY_EXPECTED_DEADTIME);
$deadTick = $this->get($serverID.static::GAME_KEY_EXPECTED_DEADTIME);
$now = time();
$wallNow = time();
$db = DB::db();
$gameStor = KVStorage::getStorage($db, 'game_env');
$gameNowTick = GameClock::fromStorage($gameStor)->nowTick();
if (
$globalLoginDate < $loginDate &&
$generalID && $generalName && $loginDate && $deadTime
&& $loginDate + 1800 > $now && $deadTime > $now
$generalID && $generalName && $loginDate && $deadTick
&& $loginDate + 1800 > $wallNow && $deadTick > $gameNowTick
) {
//로그인 정보는 30분간 유지한다.
if ($result !== null) {
@@ -254,13 +257,10 @@ class Session
return $this;
}
if ($generalID || $generalName || $loginDate || $deadTime) {
if ($generalID || $generalName || $loginDate || $deadTick) {
$this->logoutGame();
}
$db = DB::db();
$gameStor = KVStorage::getStorage($db, 'game_env');
$general = $db->queryFirstRow(
'SELECT `no`, `name`, `killturn`, `turntime` from general where `owner` = %i',
$userID
@@ -272,16 +272,15 @@ class Session
return $this;
}
$turnterm = $gameStor->turnterm;
$isUnited = $gameStor->isunited != 0;
$generalID = $general['no'];
$generalName = $general['name'];
$nextTurn = new \DateTime($general['turntime']);
$nextTurn = $nextTurn->getTimestamp();
$deadTime = $nextTurn + $general['killturn'] * $turnterm;
if ($deadTime < $now && !$isUnited) {
$deadTick = GameClock::addTicks(
Util::toInt($general['turntime']),
Util::toInt($general['killturn']) * GameClock::TICKS_PER_TURN,
);
if ($deadTick < $gameNowTick && !$isUnited) {
$locked = $db->queryFirstField('SELECT plock FROM plock WHERE `type` = "GAME" LIMIT 1');
if (!$locked) {
if ($result !== null) {
@@ -291,10 +290,10 @@ class Session
}
}
$this->set($serverID.static::GAME_KEY_DATE, $now);
$this->set($serverID.static::GAME_KEY_DATE, $wallNow);
$this->set($serverID.static::GAME_KEY_GENERAL_ID, $generalID);
$this->set($serverID.static::GAME_KEY_GENERAL_NAME, $generalName);
$this->set($serverID.static::GAME_KEY_EXPECTED_DEADTIME, $deadTime);
$this->set($serverID.static::GAME_KEY_EXPECTED_DEADTIME, $deadTick);
return $this;
}