fix: complete logical clock wall-time isolation

This commit is contained in:
2026-08-04 20:37:56 +09:00
committed by Hide_D
parent 5d9512ced7
commit fc6f84ce23
67 changed files with 689 additions and 231 deletions
+4 -3
View File
@@ -10,7 +10,6 @@ use sammo\GameConst;
use sammo\GameClock;
use sammo\Json;
use sammo\KVStorage;
use sammo\TimeUtil;
use sammo\Util;
use function sammo\cutTurn;
@@ -33,6 +32,7 @@ class GetReservedCommand extends \sammo\BaseAPI
$commandList = [];
$gameStor = KVStorage::getStorage($db, 'game_env');
$clock = GameClock::fromStorage($gameStor);
$generalID = $session->generalID;
$invalidTurnList = 0;
@@ -85,11 +85,12 @@ class GetReservedCommand extends \sammo\BaseAPI
return [
'result' => true,
'turnTimeTick' => Util::toInt($turnTime),
'turnTime' => GameClock::fromStorage($gameStor)->formatTick(Util::toInt($turnTime)),
'turnTime' => $clock->formatTick(Util::toInt($turnTime)),
'turnTerm' => $turnTerm,
'year' => $year,
'month' => $month,
'date' => GameClock::fromStorage($gameStor)->formatTick(GameClock::fromStorage($gameStor)->nowTick(), true),
'date' => $clock->formatTick($clock->nowTick(), true),
'clockMode' => $clock->getMode(),
'turn' => $commandList,
'autorun_limit' => $generalAux['autorun_limit'] ?? null,
];
+3 -3
View File
@@ -21,7 +21,6 @@ use sammo\LastTurn;
use sammo\Validator;
use sammo\Session;
use sammo\TimeUtil;
use sammo\Util;
use function sammo\buildNationCommandClass;
@@ -185,8 +184,9 @@ class GetFrontInfo extends \sammo\BaseAPI
$lastVote = null;
if ($lastVoteID) {
$voteStor = KVStorage::getStorage($db, 'vote');
$lastVote = VoteInfo::fromArray($voteStor->getValue("vote_{$lastVoteID}"));
if ($lastVote->endDate && $lastVote->endDate < TimeUtil::now()) {
$rawLastVote = VoteInfo::normalizeGameStorage($voteStor->getValue("vote_{$lastVoteID}"), $clock);
$lastVote = VoteInfo::fromGameStorage($rawLastVote, $clock);
if ($rawLastVote['endTick'] !== null && $rawLastVote['endTick'] < $clock->nowTick()) {
$lastVote = null;
}
}
@@ -10,7 +10,6 @@ use sammo\Enums\RankColumn;
use sammo\GameConst;
use sammo\General;
use sammo\KVStorage;
use sammo\TimeUtil;
use sammo\UserLogger;
class BuyRandomUnique extends \sammo\BaseAPI
@@ -56,7 +55,7 @@ class BuyRandomUnique extends \sammo\BaseAPI
$userLogger->push("{$reqAmount} 포인트로 랜덤 유니크 구입", "inheritPoint");
$userLogger->flush();
$general->setAuxVar('inheritRandomUnique', TimeUtil::now());
$general->setAuxVar('inheritRandomUnique', true);
$inheritStor->setValue('previous', [$previousPoint - $reqAmount, null]);
$general->increaseRankVar(RankColumn::inherit_point_spent_dynamic, $reqAmount);
$general->applyDB($db);
+2 -2
View File
@@ -116,7 +116,7 @@ class CheckOwner extends \sammo\BaseAPI
$src,
$dest,
"{$destGeneralName}의 소유자는 {$destGeneralOwnerName} 입니다.",
new \DateTime(),
Message::gameNow(),
new \DateTime('9999-12-31'),
[]
);
@@ -142,7 +142,7 @@ class CheckOwner extends \sammo\BaseAPI
$src,
$dest,
"소유자명이 누군가에 의해 확인되었습니다.",
new \DateTime(),
Message::gameNow(),
new \DateTime('9999-12-31'),
[]
);
+4 -4
View File
@@ -44,7 +44,7 @@ class SendMessage extends \sammo\BaseAPI
private function genPublicMessage(MessageTarget $src, string $text): Message
{
$now = new \DateTime();
$now = Message::gameNow();
$unlimited = new \DateTime('9999-12-31');
$msg = new Message(
@@ -62,7 +62,7 @@ class SendMessage extends \sammo\BaseAPI
private function genNationalMessage(MessageTarget $src, string $text): Message
{
$now = new \DateTime();
$now = Message::gameNow();
$unlimited = new \DateTime('9999-12-31');
$dest = new MessageTarget(0, '', $src->nationID, $src->nationName, $src->color);
@@ -82,7 +82,7 @@ class SendMessage extends \sammo\BaseAPI
private function genDiplomacyMessage(MessageTarget $src, int $destNationID, string $text): Message|string
{
$now = new \DateTime();
$now = Message::gameNow();
$unlimited = new \DateTime('9999-12-31');
$destNation = getNationStaticInfo($destNationID);
@@ -107,7 +107,7 @@ class SendMessage extends \sammo\BaseAPI
private function genPrivateMessage(MessageTarget $src, int $destGeneralID, int $permission, string $text): Message|string
{
$now = new \DateTime();
$now = Message::gameNow();
$unlimited = new \DateTime('9999-12-31');
$db = DB::db();
+3 -2
View File
@@ -6,8 +6,8 @@ use sammo\Session;
use DateTimeInterface;
use sammo\DB;
use sammo\Enums\APIRecoveryType;
use sammo\GameClock;
use sammo\KVStorage;
use sammo\TimeUtil;
use sammo\Validator;
use sammo\WebUtil;
@@ -51,8 +51,9 @@ class SetNotice extends \sammo\BaseAPI
$nationID = $me['nation'];
$nationStor = KVStorage::getStorage($db, $nationID, 'nation_env');
$gameNow = GameClock::fromStorage(KVStorage::getStorage($db, 'game_env'))->formatNow();
$nationStor->nationNotice = [
'date'=>TimeUtil::now(),
'date'=>$gameNow,
'msg'=>WebUtil::htmlPurify($msg),
'author'=>$me['name'],
'authorID'=>$me['no'],
@@ -12,7 +12,6 @@ use sammo\GameClock;
use sammo\General;
use sammo\Json;
use sammo\KVStorage;
use sammo\TimeUtil;
use sammo\Util;
use function sammo\checkLimit;
@@ -40,6 +39,7 @@ class GetReservedCommand extends \sammo\BaseAPI
increaseRefresh("사령부", 1);
$gameStor = KVStorage::getStorage($db, 'game_env');
$clock = GameClock::fromStorage($gameStor);
$userID = $session->userID;
$me = $db->queryFirstRow(
@@ -158,7 +158,8 @@ class GetReservedCommand extends \sammo\BaseAPI
'year' => $year,
'month' => $month,
'turnTerm' => $turnTerm,
'date' => TimeUtil::now(true),
'date' => $clock->formatTick($clock->nowTick(), true),
'clockMode' => $clock->getMode(),
'chiefList' => $nationChiefList,
'troopList' => $troopList,
'isChief' => ($me['officer_level'] > 4),
+4 -3
View File
@@ -10,8 +10,9 @@ use sammo\Enums\GeneralLiteQueryMode;
use sammo\Enums\GeneralQueryMode;
use sammo\General;
use sammo\GeneralLite;
use sammo\GameClock;
use sammo\KVStorage;
use sammo\Session;
use sammo\TimeUtil;
use sammo\Validator;
class AddComment extends \sammo\BaseAPI
@@ -47,7 +48,8 @@ class AddComment extends \sammo\BaseAPI
$generalName = $general->getName();
$nationID = $general->getNationID();
$nationName = $general->getStaticNation()['name'];
$date = TimeUtil::now();
$db = DB::db();
$date = GameClock::fromStorage(KVStorage::getStorage($db, 'game_env'))->formatNow();
$comment = new VoteComment(
@@ -61,7 +63,6 @@ class AddComment extends \sammo\BaseAPI
date: $date
);
$db = DB::db();
$db->insert('vote_comment', $comment->toArray());
return null;
+6 -1
View File
@@ -8,6 +8,7 @@ use sammo\DB;
use sammo\DTO\VoteComment;
use sammo\DTO\VoteInfo;
use sammo\Enums\APIRecoveryType;
use sammo\GameClock;
use sammo\Json;
use sammo\KVStorage;
use sammo\Validator;
@@ -35,13 +36,16 @@ class GetVoteDetail extends \sammo\BaseAPI
{
$voteID = $this->args['voteID'];
$db = DB::db();
$clock = GameClock::fromStorage(KVStorage::getStorage($db, 'game_env'));
$voteStor = KVStorage::getStorage($db, 'vote');
$rawVote = $voteStor->getValue("vote_{$voteID}");
if (!$rawVote) {
return '설문조사가 없습니다.';
}
$voteInfo = VoteInfo::fromArray($rawVote);
$rawVote = VoteInfo::normalizeGameStorage($rawVote, $clock);
$voteInfo = VoteInfo::fromGameStorage($rawVote, $clock);
$isOpen = $rawVote['endTick'] === null || $rawVote['endTick'] >= $clock->nowTick();
$votes = array_map(fn ($arr) => [Json::decode($arr[0]), $arr[1]], $db->queryAllLists(
@@ -70,6 +74,7 @@ class GetVoteDetail extends \sammo\BaseAPI
'comments' => $comments,
'myVote' => $myVote,
'userCnt' => $userCnt,
'isOpen' => $isOpen,
];
}
}
+5 -3
View File
@@ -6,6 +6,7 @@ use DateTimeInterface;
use sammo\DB;
use sammo\DTO\VoteInfo;
use sammo\Enums\APIRecoveryType;
use sammo\GameClock;
use sammo\KVStorage;
use sammo\Session;
@@ -25,16 +26,17 @@ class GetVoteList extends \sammo\BaseAPI
public function launch(Session $session, ?DateTimeInterface $modifiedSince, ?string $reqEtag): null | string | array | APIRecoveryType
{
$db = DB::db();
$clock = GameClock::fromStorage(KVStorage::getStorage($db, 'game_env'));
$voteStor = KVStorage::getStorage($db, 'vote');
$votes = [];
foreach($voteStor->getAll() as $voteKey => $rawVote){
if(!str_starts_with($voteKey, 'vote_')){
if(preg_match('/^vote_(\d+)$/D', $voteKey, $matches) !== 1){
continue;
}
$voteID = (int)substr($voteKey, 5);
$votes[$voteID] = VoteInfo::fromArray($rawVote);
$voteID = (int)$matches[1];
$votes[$voteID] = VoteInfo::fromGameStorage($rawVote, $clock);
}
return [
+19 -15
View File
@@ -9,7 +9,7 @@ use sammo\Enums\APIRecoveryType;
use sammo\KVStorage;
use sammo\RootDB;
use sammo\Session;
use sammo\TimeUtil;
use sammo\GameClock;
use sammo\Util;
use sammo\Validator;
@@ -37,7 +37,7 @@ class NewVote extends \sammo\BaseAPI
return null;
}
function closeOldVote(int $voteID, KVStorage $voteStor)
function closeOldVote(int $voteID, KVStorage $voteStor, GameClock $clock)
{
$db = DB::db();
$voteStor = KVStorage::getStorage($db, 'vote');
@@ -45,13 +45,14 @@ class NewVote extends \sammo\BaseAPI
if (!$rawLastVoteInfo) {
return;
}
$lastVoteInfo = VoteInfo::fromArray($rawLastVoteInfo);
if ($lastVoteInfo->endDate) {
$rawLastVoteInfo = VoteInfo::normalizeGameStorage($rawLastVoteInfo, $clock);
if ($rawLastVoteInfo['endTick'] !== null) {
return;
}
$lastVoteInfo->endDate = TimeUtil::now();
$voteStor->setValue("vote_{$voteID}", $lastVoteInfo->toArray());
$rawLastVoteInfo['endTick'] = $clock->nowTick();
$rawLastVoteInfo['endDate'] = $clock->formatTick($rawLastVoteInfo['endTick']);
$voteStor->setValue("vote_{$voteID}", $rawLastVoteInfo);
}
function launch(Session $session, ?DateTimeInterface $modifiedSince, ?string $reqEtag): null | string | array | APIRecoveryType
@@ -71,7 +72,11 @@ class NewVote extends \sammo\BaseAPI
$multipleOptions = 0;
}
$now = TimeUtil::now();
$db = DB::db();
$gameStor = KVStorage::getStorage($db, 'game_env');
$clock = GameClock::fromStorage($gameStor);
$nowTick = $clock->nowTick();
$now = $clock->formatTick($nowTick);
/** @var ?string */
$endDate = $this->args['endDate'] ?? null;
/** @var string[] */
@@ -83,9 +88,9 @@ class NewVote extends \sammo\BaseAPI
if($endDate !== null){
try{
$oNow = new \DateTimeImmutable($now);
$oEndDate = new \DateTimeImmutable($endDate);
if($oEndDate < $oNow){
$endTick = $clock->dateTimeToTick($oEndDate);
if($endTick < $nowTick){
return '종료일이 이미 지났습니다.';
}
}
@@ -96,17 +101,13 @@ class NewVote extends \sammo\BaseAPI
$userName = $session->userName;
$db = DB::db();
$gameStor = KVStorage::getStorage($db, 'game_env');
$lastVote = $gameStor->getValue('lastVote') ?? 0;
$voteID = $lastVote + 1;
$voteStor = KVStorage::getStorage($db, 'vote');
if (!($this->args['keepOldVote'] ?? false)) {
$this->closeOldVote($lastVote, $voteStor);
$this->closeOldVote($lastVote, $voteStor, $clock);
}
$multipleOptions = Util::valueFit($multipleOptions, 0, count($options));
@@ -122,7 +123,10 @@ class NewVote extends \sammo\BaseAPI
options: $options,
);
$voteStor->setValue("vote_{$voteID}", $voteInfo->toArray());
$voteStor->setValue("vote_{$voteID}", $voteInfo->toArray() + [
'startTick' => $nowTick,
'endTick' => $endDate === null ? null : $clock->dateTimeToTick(new \DateTimeImmutable($endDate)),
]);
$gameStor->setValue('lastVote', $voteID);
$db->update('general', [
+5 -2
View File
@@ -8,6 +8,7 @@ use sammo\DTO\VoteInfo;
use sammo\Enums\APIRecoveryType;
use sammo\Enums\GeneralQueryMode;
use sammo\General;
use sammo\GameClock;
use sammo\Json;
use sammo\KVStorage;
use sammo\LiteHashDRBG;
@@ -54,15 +55,17 @@ class Vote extends \sammo\BaseAPI
return '선택한 항목이 없습니다.';
}
$db = DB::db();
$clock = GameClock::fromStorage(KVStorage::getStorage($db, 'game_env'));
$voteStor = KVStorage::getStorage($db, 'vote');
$rawVoteInfo = $voteStor->getValue("vote_{$voteID}");
if (!$rawVoteInfo) {
return '설문조사가 없습니다.';
}
$voteInfo = VoteInfo::fromArray($rawVoteInfo);
$rawVoteInfo = VoteInfo::normalizeGameStorage($rawVoteInfo, $clock);
$voteInfo = VoteInfo::fromGameStorage($rawVoteInfo, $clock);
if ($voteInfo->endDate && $voteInfo->endDate < new \DateTimeImmutable()) {
if ($rawVoteInfo['endTick'] !== null && $rawVoteInfo['endTick'] < $clock->nowTick()) {
return '설문조사가 종료되었습니다.';
}