Compare commits
24
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
bf3725e040 | ||
|
|
504b4cda69 | ||
|
|
d9ad14c027 | ||
|
|
dc56ee1c06 | ||
|
|
463554654c | ||
|
|
5317cb306e | ||
|
|
db9c7ea828 | ||
|
|
f3bf490df3 | ||
|
|
eeb931d3f0 | ||
|
|
b095fb4bf1 | ||
|
|
234ec919bc | ||
|
|
a953ab4154 | ||
|
|
56a023e195 | ||
|
|
69fb122ab1 | ||
|
|
f9b5733fb8 | ||
|
|
66e2e28df2 | ||
|
|
a38a8867ee | ||
|
|
9da44d0001 | ||
|
|
fc6f84ce23 | ||
|
|
5d9512ced7 | ||
|
|
136acadd04 | ||
|
|
f4a1e2258d | ||
|
|
e7c773709d | ||
|
|
4aa09a294e |
@@ -42,7 +42,32 @@ sudo -u www-data git clone https://storage.hided.net/gitea/devsam/core.git
|
||||
sudo -u www-data git clone https://storage.hided.net/gitea/devsam/image.git
|
||||
```
|
||||
|
||||
> 이미지는 hook/git_hook.php을 통해 동기화되며, 서버 설치 과정에 이미지 갱신 키를 지정하는 것으로 '훼' 서버 업데이트 시 동기화됩니다. 이미지 서버가 게임 서버와 별개여도 동작하나, php와 git을 지원해야합니다.
|
||||
> 이미지는 Gitea webhook을 기본으로 동기화합니다. Webhook 전달이 누락된 경우에도 서버 설치 과정에서 이미지 갱신 API와 `core` 전용 비밀값을 지정하면 게임 서버 업데이트 명령이 서명된 동기화를 요청합니다. 이미지 서버의 브랜치 변경 권한은 부여되지 않습니다.
|
||||
|
||||
CLI에서 수동으로 복구 동기화를 요청할 수도 있습니다.
|
||||
|
||||
```sh
|
||||
IMAGE_SYNC_SECRET_FILE=/run/secrets/image_sync_core_secret \
|
||||
php scripts/sync-image-repository.php
|
||||
```
|
||||
|
||||
Ref의 사용자 아이콘 원격 업로드 구현은 기본적으로 꺼져 있습니다. 이미지 서버의
|
||||
`image_upload_core_secret`과 동일한 값을 Git 제외 파일
|
||||
`d_setting/image_upload_core_secret`에 저장한 뒤 실제
|
||||
`d_setting/ServConfig.php`에서 다음 값만 변경하면 기존 화면을 그대로 둔 채
|
||||
원격 bind 저장소로 전환됩니다.
|
||||
|
||||
```php
|
||||
public static $remoteUserIconUploadEnabled = true;
|
||||
public static $remoteUserIconUploadPath = 'https://sam-image.hided.net';
|
||||
public static $remoteUserIconUploadSecretFile = 'd_setting/image_upload_core_secret';
|
||||
```
|
||||
|
||||
플래그가 `false`이면 기존 `d_pic` 및 `IMGSVR=1` 동작을 유지합니다. `true`이면
|
||||
PHP 서버가 인증 사용자와 이미지 규격을 먼저 검사한 후 60초 HMAC 권한으로
|
||||
이미지 서버에 직접 업로드하고 `IMGSVR=0` 공유 이미지 경로를 저장합니다.
|
||||
국방·외교 등 TipTap 편집기 첨부 이미지도 같은 플래그로 `/uploads/core/` bind
|
||||
저장소로 전환됩니다. 공유 비밀값은 브라우저나 Cloudflare로 보내지 않습니다.
|
||||
|
||||
### 설치
|
||||
|
||||
@@ -67,4 +92,4 @@ Database 수는 로그인 관리 서버 1개, 내부 서버 7개로, 총 8개의
|
||||
* MIT License
|
||||
* GPL 2.0 또는 이후
|
||||
|
||||
만약 별도의 라이선스를 적용하고자 할 경우 Hide_D에게 문의하여 주십시오.
|
||||
만약 별도의 라이선스를 적용하고자 할 경우 Hide_D에게 문의하여 주십시오.
|
||||
|
||||
+11
-4
@@ -86,21 +86,28 @@ require(__DIR__ . '/../vendor/autoload.php');
|
||||
<div class="form-group row">
|
||||
<label for="shared_icon_path" class="col-sm-4 col-form-label">공용 아이콘 주소</label>
|
||||
<div class="col-sm-8">
|
||||
<input type="text" class="form-control" name="shared_icon_path" id="shared_icon_path" placeholder="공용 아이콘 주소(웹 주소, 또는 접속 경로에 따른 상대 주소)" value="../image/icons" />
|
||||
<input type="text" class="form-control" name="shared_icon_path" id="shared_icon_path" placeholder="공용 아이콘 주소(웹 주소, 또는 접속 경로에 따른 상대 주소)" value="https://sam-image.hided.net/icons" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group row">
|
||||
<label for="game_image_path" class="col-sm-4 col-form-label">게임 이미지 주소</label>
|
||||
<div class="col-sm-8">
|
||||
<input type="text" class="form-control" name="game_image_path" id="game_image_path" placeholder="게임 이미지 주소(웹 주소, 또는 접속 경로에 따른 상대 주소)" value="../image/game" />
|
||||
<input type="text" class="form-control" name="game_image_path" id="game_image_path" placeholder="게임 이미지 주소(웹 주소, 또는 접속 경로에 따른 상대 주소)" value="https://sam-image.hided.net/game" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group row">
|
||||
<label for="image_request_path" class="col-sm-4 col-form-label">이미지 갱신 API</label>
|
||||
<div class="col-sm-8">
|
||||
<input type="url" class="form-control" name="image_request_path" id="image_request_path" value="https://sam-image.hided.net/v1/sync" required />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group row">
|
||||
<label for="image_request_key" class="col-sm-4 col-form-label">이미지 갱신 키</label>
|
||||
<div class="input-group col-sm-8">
|
||||
<input type="text" class="form-control" name="image_request_key" id="image_request_key" placeholder="이미지 서버의 hook/HashKey.php의 값과 동일하게" value="" />
|
||||
<input type="text" class="form-control" name="image_request_key" id="image_request_key" placeholder="이미지 서버의 core 동기화 비밀값과 동일하게" value="" />
|
||||
<div class="input-group-text">
|
||||
<button id="btn_random_generate_key" class="btn btn-secondary" type="button">랜덤 생성</button>
|
||||
</div>
|
||||
@@ -189,4 +196,4 @@ require(__DIR__ . '/../vendor/autoload.php');
|
||||
</div>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
</html>
|
||||
|
||||
@@ -12,13 +12,14 @@ $dbName = Util::getPost('db_name');
|
||||
$servHost = Util::getPost('serv_host');
|
||||
$sharedIconPath = Util::getPost('shared_icon_path');
|
||||
$gameImagePath = Util::getPost('game_image_path');
|
||||
$imageRequestPath = Util::getPost('image_request_path');
|
||||
$imageRequestKey = Util::getPost('image_request_key');
|
||||
|
||||
$kakaoRESTKey = Util::getPost('kakao_rest_key', 'string', '');
|
||||
$kakaoAdminKey = Util::getPost('kakao_admin_key', 'string', '');
|
||||
|
||||
|
||||
if (!$host || !$port || !$username || !$password || !$dbName || !$servHost || !$sharedIconPath || !$gameImagePath) {
|
||||
if (!$host || !$port || !$username || !$password || !$dbName || !$servHost || !$sharedIconPath || !$gameImagePath || !$imageRequestPath) {
|
||||
Json::die([
|
||||
'result' => false,
|
||||
'reason' => '입력 값이 올바르지 않습니다'
|
||||
@@ -32,6 +33,21 @@ if (!filter_var($servHost, FILTER_VALIDATE_URL)) {
|
||||
]);
|
||||
}
|
||||
|
||||
if (!filter_var($imageRequestPath, FILTER_VALIDATE_URL)
|
||||
|| parse_url($imageRequestPath, PHP_URL_SCHEME) !== 'https') {
|
||||
Json::die([
|
||||
'result' => false,
|
||||
'reason' => '이미지 갱신 API는 HTTPS URL이어야 합니다.'
|
||||
]);
|
||||
}
|
||||
|
||||
if ($imageRequestKey !== null && $imageRequestKey !== '' && strlen($imageRequestKey) < 32) {
|
||||
Json::die([
|
||||
'result' => false,
|
||||
'reason' => '이미지 동기화 비밀값은 32자 이상이어야 합니다.'
|
||||
]);
|
||||
}
|
||||
|
||||
if (file_exists(ROOT . '/d_setting/RootDB.php') && is_dir(ROOT . '/d_setting/RootDB.php')) {
|
||||
Json::die([
|
||||
'result' => false,
|
||||
@@ -185,8 +201,7 @@ $globalSalt = bin2hex(random_bytes(16));
|
||||
|
||||
$sharedIconPath = WebUtil::resolveRelativePath($sharedIconPath, $servHost);
|
||||
$gameImagePath = WebUtil::resolveRelativePath($gameImagePath, $servHost);
|
||||
$imageRequestPath = WebUtil::resolveRelativePath($gameImagePath . '/../hook/git_pull.php', $servHost);
|
||||
$imageKeyInstallPath = WebUtil::resolveRelativePath($gameImagePath . '/../hook/InstallKey.php', $servHost);
|
||||
$imageRequestPath = WebUtil::resolveRelativePath($imageRequestPath, $servHost);
|
||||
|
||||
$result = Util::generateFileUsingSimpleTemplate(
|
||||
__DIR__ . '/templates/ServConfig.orig.php',
|
||||
@@ -197,6 +212,9 @@ $result = Util::generateFileUsingSimpleTemplate(
|
||||
'gameImagePath' => $gameImagePath,
|
||||
'imageRequestPath' => $imageRequestPath,
|
||||
'imageRequestKey' => $imageRequestKey,
|
||||
'remoteUserIconUploadEnabled' => 'false',
|
||||
'remoteUserIconUploadPath' => 'https://sam-image.hided.net',
|
||||
'remoteUserIconUploadSecretFile' => 'd_setting/image_upload_core_secret',
|
||||
'serverList' => [
|
||||
['che', '체', 'white'],
|
||||
['kwe', '퀘', 'yellow'],
|
||||
@@ -209,10 +227,6 @@ $result = Util::generateFileUsingSimpleTemplate(
|
||||
true
|
||||
);
|
||||
|
||||
if ($imageRequestKey) {
|
||||
@file_get_contents($imageKeyInstallPath . '?key=' . $imageRequestKey);
|
||||
}
|
||||
|
||||
if ($result !== true) {
|
||||
Json::die([
|
||||
'result' => false,
|
||||
|
||||
@@ -33,7 +33,12 @@ if ($servHost) {
|
||||
[
|
||||
'serverBasePath' => $servHost,
|
||||
'sharedIconPath' => $sharedIconPath,
|
||||
'gameImagePath' => $gameImagePath
|
||||
'gameImagePath' => $gameImagePath,
|
||||
'imageRequestPath' => ServConfig::$imageRequestPath,
|
||||
'imageRequestKey' => ServConfig::$imageRequestKey,
|
||||
'remoteUserIconUploadEnabled' => ServConfig::$remoteUserIconUploadEnabled ? 'true' : 'false',
|
||||
'remoteUserIconUploadPath' => ServConfig::$remoteUserIconUploadPath,
|
||||
'remoteUserIconUploadSecretFile' => ServConfig::$remoteUserIconUploadSecretFile
|
||||
],
|
||||
true
|
||||
);
|
||||
@@ -64,7 +69,12 @@ if ($servHost) {
|
||||
[
|
||||
'serverBasePath' => $servHost,
|
||||
'sharedIconPath' => $sharedIconPath,
|
||||
'gameImagePath' => $gameImagePath
|
||||
'gameImagePath' => $gameImagePath,
|
||||
'imageRequestPath' => ServConfig::$imageRequestPath,
|
||||
'imageRequestKey' => ServConfig::$imageRequestKey,
|
||||
'remoteUserIconUploadEnabled' => ServConfig::$remoteUserIconUploadEnabled ? 'true' : 'false',
|
||||
'remoteUserIconUploadPath' => ServConfig::$remoteUserIconUploadPath,
|
||||
'remoteUserIconUploadSecretFile' => ServConfig::$remoteUserIconUploadSecretFile
|
||||
],
|
||||
true
|
||||
);
|
||||
|
||||
@@ -13,6 +13,9 @@ class ServConfig
|
||||
public static $gameImagePath = "_tK_gameImagePath_";
|
||||
public static $imageRequestPath = "_tK_imageRequestPath_";
|
||||
public static $imageRequestKey = '_tK_imageRequestKey_';
|
||||
public static $remoteUserIconUploadEnabled = _tK_remoteUserIconUploadEnabled_;
|
||||
public static $remoteUserIconUploadPath = '_tK_remoteUserIconUploadPath_';
|
||||
public static $remoteUserIconUploadSecretFile = '_tK_remoteUserIconUploadSecretFile_';
|
||||
private static $serverList = null;
|
||||
|
||||
public static function getSharedIconPath(string $filepath = ''): string
|
||||
@@ -38,9 +41,33 @@ class ServConfig
|
||||
|
||||
public static function getImagePullURI(): string
|
||||
{
|
||||
$now = time();
|
||||
$req_hash = Util::hashPassword(sprintf("%016x", $now), static::$imageRequestKey);
|
||||
return static::$imageRequestPath . "?req={$req_hash}&time={$now}";
|
||||
return static::$imageRequestPath;
|
||||
}
|
||||
|
||||
public static function isRemoteUserIconUploadEnabled(): bool
|
||||
{
|
||||
return static::$remoteUserIconUploadEnabled;
|
||||
}
|
||||
|
||||
public static function getRemoteUserIconUploadURI(string $filename): string
|
||||
{
|
||||
return rtrim(static::$remoteUserIconUploadPath, '/') . '/v1/uploads/user-icons/core/' . $filename;
|
||||
}
|
||||
|
||||
public static function getRemoteUserIconUploadSecret(): string
|
||||
{
|
||||
$path = static::$remoteUserIconUploadSecretFile;
|
||||
if ($path === '' || str_contains($path, "\0")) {
|
||||
throw new \RuntimeException('Remote user icon upload secret file is not configured');
|
||||
}
|
||||
if ($path[0] !== '/') {
|
||||
$path = ROOT . '/' . $path;
|
||||
}
|
||||
$secret = trim((string)file_get_contents($path));
|
||||
if (strlen($secret) < 32) {
|
||||
throw new \RuntimeException('Remote user icon upload secret must be at least 32 characters');
|
||||
}
|
||||
return $secret;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
+5
-2
@@ -13,6 +13,9 @@ $db = DB::db();
|
||||
$gameStor = KVStorage::getStorage($db, 'game_env');
|
||||
|
||||
[$turntime, $tnmt_time] = $gameStor->getValuesAsArray(['turntime','tnmt_time']);
|
||||
$clock = GameClock::fromStorage($gameStor);
|
||||
$turntimeDisplay = $clock->formatTick(Util::toInt($turntime), true);
|
||||
$tnmtTimeDisplay = $tnmt_time === null ? '-' : $clock->formatTick(Util::toInt($tnmt_time), true);
|
||||
|
||||
$plock = $db->queryFirstField('SELECT plock FROM plock WHERE `type` ="GAME"');
|
||||
?>
|
||||
@@ -30,8 +33,8 @@ $plock = $db->queryFirstField('SELECT plock FROM plock WHERE `type` ="GAME"');
|
||||
</head>
|
||||
<body>
|
||||
<form action=_119_b.php method=post>
|
||||
시간조정 : <input type=text size=3 name=minute><input type=submit name=btn value='분당김'><input type=submit name=btn value='분지연'> 최종갱신 : <?=$turntime?><br>
|
||||
시간조정 : <input type=text size=3 name=minute2><input type=submit name=btn value='토너분당김'><input type=submit name=btn value='토너분지연'> 토너먼트 : <?=$tnmt_time?><br>
|
||||
시간조정 : <input type=text size=3 name=minute><input type=submit name=btn value='분당김'><input type=submit name=btn value='분지연'> 최종갱신 : <?=$turntimeDisplay?> (tick <?=$turntime?>)<br>
|
||||
시간조정 : <input type=text size=3 name=minute2><input type=submit name=btn value='토너분당김'><input type=submit name=btn value='토너분지연'> 토너먼트 : <?=$tnmtTimeDisplay?> (tick <?=$tnmt_time?>)<br>
|
||||
봉급지급 : <input type=submit name=btn value='금지급'><input type=submit name=btn value='쌀지급'><br>
|
||||
락 풀 기 : <input type=submit name=btn value='락걸기'><input type=submit name=btn value='락풀기'> 현재 : <?=$plock>0?"동결중":"가동중"?><br>
|
||||
</form>
|
||||
|
||||
+9
-36
@@ -38,21 +38,9 @@ switch ($btn) {
|
||||
usleep(500000);
|
||||
}
|
||||
|
||||
$gameStor->cacheValues(['turntime', 'starttime', 'tnmt_time']);
|
||||
$turntime = (new \DateTimeImmutable($gameStor->turntime))->sub(new \DateInterval("PT{$minute}M"));
|
||||
$starttime = (new \DateTimeImmutable($gameStor->starttime))->sub(new \DateInterval("PT{$minute}M"));
|
||||
$tnmt_time = (new \DateTimeImmutable($gameStor->tnmt_time))->sub(new \DateInterval("PT{$minute}M"));
|
||||
|
||||
$gameStor->turntime = $turntime->format('Y-m-d H:i:s.u');
|
||||
$gameStor->starttime = $starttime->format('Y-m-d H:i:s');
|
||||
$gameStor->tnmt_time = $tnmt_time->format('Y-m-d H:i:s');
|
||||
|
||||
$db->update('general', [
|
||||
'turntime' => $db->sqleval('DATE_SUB(turntime, INTERVAL %i MINUTE)', $minute)
|
||||
], true);
|
||||
$db->update('ng_auction', [
|
||||
'close_date' => $db->sqleval('DATE_SUB(close_date, INTERVAL %i MINUTE)', $minute)
|
||||
], 'finished = 0');
|
||||
$clock = GameClock::fromStorage($gameStor);
|
||||
// 스케줄 전체를 벽시계에서 빼지 않고 논리 현재 tick만 앞으로 이동합니다.
|
||||
$clock->advance($gameStor, $clock->ticksFromMinutes($minute));
|
||||
if ($locked) {
|
||||
unlock();
|
||||
}
|
||||
@@ -66,34 +54,19 @@ switch ($btn) {
|
||||
}
|
||||
usleep(500000);
|
||||
}
|
||||
$gameStor->cacheValues(['turntime', 'starttime', 'tnmt_time']);
|
||||
$turntime = (new \DateTimeImmutable($gameStor->turntime))->add(new \DateInterval("PT{$minute}M"));
|
||||
$starttime = (new \DateTimeImmutable($gameStor->starttime))->add(new \DateInterval("PT{$minute}M"));
|
||||
$tnmt_time = (new \DateTimeImmutable($gameStor->tnmt_time))->add(new \DateInterval("PT{$minute}M"));
|
||||
|
||||
$gameStor->turntime = $turntime->format('Y-m-d H:i:s.u');
|
||||
$gameStor->starttime = $starttime->format('Y-m-d H:i:s');
|
||||
$gameStor->tnmt_time = $tnmt_time->format('Y-m-d H:i:s');
|
||||
|
||||
$db->update('general', [
|
||||
'turntime' => $db->sqleval('DATE_ADD(turntime, INTERVAL %i MINUTE)', $minute)
|
||||
], true);
|
||||
$db->update('ng_auction', [
|
||||
'close_date' => $db->sqleval('DATE_ADD(close_date, INTERVAL %i MINUTE)', $minute)
|
||||
], 'finished = 0');
|
||||
$clock = GameClock::fromStorage($gameStor);
|
||||
$clock->advance($gameStor, -$clock->ticksFromMinutes($minute));
|
||||
if ($locked) {
|
||||
unlock();
|
||||
}
|
||||
break;
|
||||
case "토너분당김":
|
||||
$tnmt_time = new \DateTime($gameStor->tnmt_time);
|
||||
$tnmt_time->sub(new \DateInterval("PT{$minute2}M"));
|
||||
$gameStor->tnmt_time = $tnmt_time->format('Y-m-d H:i:s');
|
||||
$clock = GameClock::fromStorage($gameStor);
|
||||
$gameStor->tnmt_time = Util::toInt($gameStor->tnmt_time) - $clock->ticksFromMinutes($minute2);
|
||||
break;
|
||||
case "토너분지연":
|
||||
$tnmt_time = new \DateTimeImmutable($gameStor->tnmt_time);
|
||||
$tnmt_time->add(new \DateInterval("PT{$minute2}M"));
|
||||
$gameStor->tnmt_time = $tnmt_time->format('Y-m-d H:i:s');
|
||||
$clock = GameClock::fromStorage($gameStor);
|
||||
$gameStor->tnmt_time = Util::toInt($gameStor->tnmt_time) + $clock->ticksFromMinutes($minute2);
|
||||
break;
|
||||
case "금지급":
|
||||
processGoldIncome();
|
||||
|
||||
+2
-2
@@ -40,7 +40,7 @@ $admin = getAdmin();
|
||||
</tr>
|
||||
<tr>
|
||||
<td width=110 align=right>시작시간변경</td>
|
||||
<td width=285><input type=text size=20 maxlength=20 style=color:white;background-color:black;text-align:right; name=starttime value='<?=substr($admin['starttime'], 0, 19)?>'><input type=submit name=btn value=변경1></td>
|
||||
<td width=285><input type=text size=20 maxlength=20 style=color:white;background-color:black;text-align:right; name=starttime value='<?=substr($admin['starttime_display'], 0, 19)?>'><input type=submit name=btn value=변경1></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width=110 align=right>최대 장수</td>
|
||||
@@ -52,7 +52,7 @@ $admin = getAdmin();
|
||||
<td width=110 align=right>시작 년도</td>
|
||||
<td width=285><input type=text size=3 maxlength=3 style=color:white;background-color:black;text-align:right; name=startyear value='<?=$admin['startyear']?>'><input type=submit name=btn value=변경4></td>
|
||||
<td width=110 align=right>최근 갱신 시간</td>
|
||||
<td width=285> <?=$admin['turntime']?></td>
|
||||
<td width=285> <?=$admin['turntime_display']?> (tick <?=$admin['turntime']?>)</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width=110 align=right>턴시간</td>
|
||||
|
||||
@@ -25,13 +25,15 @@ if (!$v->validate()) {
|
||||
$msg = Util::getPost('msg');
|
||||
$btn = Util::getPost('btn');
|
||||
$log = Util::getPost('log');
|
||||
$starttime = Util::getPost('starttime', 'string', (new \DateTime())->format('Y-m-d H:i:s'));
|
||||
$starttime = Util::getPost('starttime', 'string', null);
|
||||
$maxgeneral = Util::getPost('maxgeneral', 'int', GameConst::$defaultMaxGeneral);
|
||||
$maxnation = Util::getPost('maxnation', 'int', GameConst::$defaultMaxNation);
|
||||
$startyear = Util::getPost('startyear', 'int', GameConst::$defaultStartYear);
|
||||
|
||||
$db = DB::db();
|
||||
$gameStor = KVStorage::getStorage($db, 'game_env');
|
||||
$clock = GameClock::fromStorage($gameStor);
|
||||
$starttime ??= $clock->formatTick($clock->nowTick());
|
||||
|
||||
$admin = getAdmin();
|
||||
|
||||
@@ -43,7 +45,11 @@ switch ($btn) {
|
||||
pushGlobalHistoryLog(["<R>★</><S>{$log}</>"]);
|
||||
break;
|
||||
case "변경1":
|
||||
$gameStor->starttime = (new \DateTime($starttime))->format('Y-m-d H:i:s');
|
||||
$gameStor->clock_base_time = TimeUtil::format(GameClock::baseTimeForProjection(
|
||||
new \DateTimeImmutable($starttime),
|
||||
Util::toInt($gameStor->starttime),
|
||||
$clock->getTurnTermMinutes(),
|
||||
), true);
|
||||
break;
|
||||
case "변경2":
|
||||
$gameStor->maxgeneral = $maxgeneral;
|
||||
@@ -78,4 +84,4 @@ switch ($btn) {
|
||||
break;
|
||||
}
|
||||
|
||||
header('location:_admin1.php');
|
||||
header('location:_admin1.php');
|
||||
|
||||
@@ -99,7 +99,7 @@ switch ($btn) {
|
||||
], '`no` IN %li', $genlist);
|
||||
break;
|
||||
case "강제 사망":
|
||||
$date = TimeUtil::now(true);
|
||||
$date = GameClock::fromStorage($gameStor)->nowTick();
|
||||
$db->update('general', [
|
||||
'killturn' => 0,
|
||||
'turntime' => $date,
|
||||
@@ -113,7 +113,7 @@ switch ($btn) {
|
||||
case "경험치1000":
|
||||
$text = $btn . " 지급!";
|
||||
foreach ($genlist as $generalID) {
|
||||
$msg = new Message(MessageType::private, $src, MessageTarget::buildQuick($generalID), $text, new \DateTime(), new \DateTime('9999-12-31'), []);
|
||||
$msg = new Message(MessageType::private, $src, MessageTarget::buildQuick($generalID), $text, Message::gameNow(), new \DateTime('9999-12-31'), []);
|
||||
$msg->send(true);
|
||||
}
|
||||
$db->update('general', [
|
||||
@@ -124,7 +124,7 @@ switch ($btn) {
|
||||
case "공헌치1000":
|
||||
$text = $btn . " 지급!";
|
||||
foreach ($genlist as $generalID) {
|
||||
$msg = new Message(MessageType::private, $src, MessageTarget::buildQuick($generalID), $text, new \DateTime(), new \DateTime('9999-12-31'), []);
|
||||
$msg = new Message(MessageType::private, $src, MessageTarget::buildQuick($generalID), $text, Message::gameNow(), new \DateTime('9999-12-31'), []);
|
||||
$msg->send(true);
|
||||
}
|
||||
$db->update('general', [
|
||||
@@ -135,7 +135,7 @@ switch ($btn) {
|
||||
case "보숙10000":
|
||||
$text = "보병숙련도+10000 지급!";
|
||||
foreach ($genlist as $generalID) {
|
||||
$msg = new Message(MessageType::private, $src, MessageTarget::buildQuick($generalID), $text, new \DateTime(), new \DateTime('9999-12-31'), []);
|
||||
$msg = new Message(MessageType::private, $src, MessageTarget::buildQuick($generalID), $text, Message::gameNow(), new \DateTime('9999-12-31'), []);
|
||||
$msg->send(true);
|
||||
}
|
||||
$db->update('general', [
|
||||
@@ -145,7 +145,7 @@ switch ($btn) {
|
||||
case "궁숙10000":
|
||||
$text = "궁병숙련도+10000 지급!";
|
||||
foreach ($genlist as $generalID) {
|
||||
$msg = new Message(MessageType::private, $src, MessageTarget::buildQuick($generalID), $text, new \DateTime(), new \DateTime('9999-12-31'), []);
|
||||
$msg = new Message(MessageType::private, $src, MessageTarget::buildQuick($generalID), $text, Message::gameNow(), new \DateTime('9999-12-31'), []);
|
||||
$msg->send(true);
|
||||
}
|
||||
$db->update('general', [
|
||||
@@ -156,7 +156,7 @@ switch ($btn) {
|
||||
$src = MessageTarget::buildQuick($session->generalID);
|
||||
$text = "기병숙련도+10000 지급!";
|
||||
foreach ($genlist as $generalID) {
|
||||
$msg = new Message(MessageType::private, $src, MessageTarget::buildQuick($generalID), $text, new \DateTime(), new \DateTime('9999-12-31'), []);
|
||||
$msg = new Message(MessageType::private, $src, MessageTarget::buildQuick($generalID), $text, Message::gameNow(), new \DateTime('9999-12-31'), []);
|
||||
$msg->send(true);
|
||||
}
|
||||
$db->update('general', [
|
||||
@@ -167,7 +167,7 @@ switch ($btn) {
|
||||
$src = MessageTarget::buildQuick($session->generalID);
|
||||
$text = "귀병숙련도+10000 지급!";
|
||||
foreach ($genlist as $generalID) {
|
||||
$msg = new Message(MessageType::private, $src, MessageTarget::buildQuick($generalID), $text, new \DateTime(), new \DateTime('9999-12-31'), []);
|
||||
$msg = new Message(MessageType::private, $src, MessageTarget::buildQuick($generalID), $text, Message::gameNow(), new \DateTime('9999-12-31'), []);
|
||||
$msg->send(true);
|
||||
}
|
||||
$db->update('general', [
|
||||
@@ -178,7 +178,7 @@ switch ($btn) {
|
||||
$src = MessageTarget::buildQuick($session->generalID);
|
||||
$text = "차병숙련도+10000 지급!";
|
||||
foreach ($genlist as $generalID) {
|
||||
$msg = new Message(MessageType::private, $src, MessageTarget::buildQuick($generalID), $text, new \DateTime(), new \DateTime('9999-12-31'), []);
|
||||
$msg = new Message(MessageType::private, $src, MessageTarget::buildQuick($generalID), $text, Message::gameNow(), new \DateTime('9999-12-31'), []);
|
||||
$msg->send(true);
|
||||
}
|
||||
$db->update('general', [
|
||||
@@ -198,7 +198,7 @@ switch ($btn) {
|
||||
case "메세지 전달":
|
||||
$text = $msg ?? '';
|
||||
foreach ($genlist as $generalID) {
|
||||
$msg = new Message(MessageType::private, $src, MessageTarget::buildQuick($generalID), $text, new \DateTime(), new \DateTime('9999-12-31'), []);
|
||||
$msg = new Message(MessageType::private, $src, MessageTarget::buildQuick($generalID), $text, Message::gameNow(), new \DateTime('9999-12-31'), []);
|
||||
$msg->send(true);
|
||||
}
|
||||
break;
|
||||
|
||||
+3
-2
@@ -42,6 +42,7 @@ if ($session->userGrade < 6) {
|
||||
}
|
||||
|
||||
$db = DB::db();
|
||||
$clock = GameClock::fromStorage(KVStorage::getStorage($db, 'game_env'));
|
||||
|
||||
if ($btn == '정렬하기') {
|
||||
$gen = 0;
|
||||
@@ -111,7 +112,7 @@ $generalObj = General::createObjFromDB($gen, null, GeneralQueryMode::FullWithAcc
|
||||
대상장수 :
|
||||
<select name=gen size=1>
|
||||
<?php foreach ($generalBasicList as $general) : ?>
|
||||
<option <?= $gen == $general['no'] ? 'selected' : '' ?> value='<?= $general['no'] ?>'><?= $general['name'] ?> (<?= substr($general['turntime'], 14, 5) ?>)</option>
|
||||
<option <?= $gen == $general['no'] ? 'selected' : '' ?> value='<?= $general['no'] ?>'><?= $general['name'] ?> (<?= substr($clock->formatTick(Util::toInt($general['turntime'])), 14, 5) ?>)</option>
|
||||
<?php endforeach; ?>
|
||||
</select>
|
||||
<input type=submit name=btn value='조회하기'>
|
||||
@@ -179,4 +180,4 @@ $generalObj = General::createObjFromDB($gen, null, GeneralQueryMode::FullWithAcc
|
||||
</table>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
</html>
|
||||
|
||||
+1
-3
@@ -100,8 +100,6 @@ $sel[$type] = "selected";
|
||||
throw new \Exception("알 수 없는 외교 상태: {$dip['state']}");
|
||||
}
|
||||
|
||||
$date = TimeUtil::now();
|
||||
|
||||
echo "
|
||||
<tr>
|
||||
<td align=center style=color:" . newColor($nationColor[$me]) . ";background-color:{$nationColor[$me]};>$nationName[$me]</td>
|
||||
@@ -122,4 +120,4 @@ $sel[$type] = "selected";
|
||||
</table>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
</html>
|
||||
|
||||
+2
-1
@@ -9,6 +9,7 @@ include "func.php";
|
||||
|
||||
$db = DB::db();
|
||||
$gameStor = KVStorage::getStorage($db, 'game_env');
|
||||
$clock = GameClock::fromStorage($gameStor);
|
||||
|
||||
increaseRefresh("갱신정보", 1);
|
||||
|
||||
@@ -23,7 +24,7 @@ $recentTraffic[] = [
|
||||
'month' => $admin['month'],
|
||||
'refresh' => $admin['refresh'],
|
||||
'online' => $curonline,
|
||||
'date' => TimeUtil::now()
|
||||
'date' => $clock->formatNow()
|
||||
];
|
||||
|
||||
if ($admin['maxrefresh'] == 0) {
|
||||
|
||||
@@ -16,7 +16,7 @@ $db = DB::db();
|
||||
$gameStor = KVStorage::getStorage($db, 'game_env');
|
||||
increaseRefresh("현재도시", 1);
|
||||
|
||||
$lastExecute = substr($gameStor->turntime, 5, 14);
|
||||
$lastExecute = substr(GameClock::fromStorage($gameStor)->formatTick(Util::toInt($gameStor->turntime)), 5, 14);
|
||||
|
||||
$me = $db->queryFirstRow('SELECT no,nation,officer_level,city from general where owner=%i', $userID);
|
||||
$myNation = $db->queryFirstRow('SELECT nation,level,spy FROM nation WHERE nation=%i', $me['nation']) ?? [
|
||||
@@ -537,4 +537,4 @@ $templates = new \League\Plates\Engine('templates');
|
||||
</table>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
</html>
|
||||
|
||||
+3
-1
@@ -129,6 +129,7 @@ $templates = new \League\Plates\Engine('templates');
|
||||
);
|
||||
|
||||
$generalTurnList = [];
|
||||
$clock = GameClock::fromStorage($gameStor);
|
||||
|
||||
foreach ($db->queryAllLists(
|
||||
'SELECT general_id, turn_idx, brief FROM general_turn WHERE general_id IN %li AND turn_idx < 5 ORDER BY general_id ASC, turn_idx ASC',
|
||||
@@ -142,6 +143,7 @@ $templates = new \League\Plates\Engine('templates');
|
||||
|
||||
$genCntEff = 0;
|
||||
foreach ($generals as &$general) {
|
||||
$general['turntime'] = $clock->formatTick(Util::toInt($general['turntime']), true);
|
||||
$general['cityText'] = CityConst::byID($general['city'])->name;
|
||||
$general['troopText'] = $troopName[$general['troop']] ?? '-';
|
||||
|
||||
@@ -284,4 +286,4 @@ $templates = new \League\Plates\Engine('templates');
|
||||
</table>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
</html>
|
||||
|
||||
+12
-8
@@ -19,8 +19,10 @@ $userID = Session::getUserID();
|
||||
$generalID = $session->generalID;
|
||||
|
||||
$db = DB::db();
|
||||
$gameStor = KVStorage::getStorage($db, 'game_env');
|
||||
$gameStor->cacheValues(['turntime', 'opentime', 'autorun_user', 'npcmode']);
|
||||
$gameStor = KVStorage::getStorage($db, 'game_env');
|
||||
$gameStor->cacheValues(['turntime', 'opentime', 'autorun_user', 'npcmode']);
|
||||
$clock = GameClock::fromStorage($gameStor);
|
||||
$nowTick = $clock->nowTick();
|
||||
|
||||
$me = General::createObjFromDB($generalID, null, GeneralQueryMode::FullWithAccessLog);
|
||||
|
||||
@@ -40,27 +42,29 @@ $lastRefresh = $db->queryFirstField(
|
||||
);
|
||||
|
||||
$nextChange = $me->getAuxVar('next_change');
|
||||
if (!is_string($nextChange) || $nextChange === '') {
|
||||
if (!is_int($nextChange)) {
|
||||
$nextChange = null;
|
||||
}
|
||||
$nextChangeDisplay = $nextChange === null ? null : $clock->formatTick($nextChange);
|
||||
|
||||
increaseRefresh("내정보", 1);
|
||||
if ($gameStor->turntime <= $gameStor->opentime) {
|
||||
$targetTime = $me->getAuxVar('prestart_delete_after');
|
||||
if (!is_string($targetTime) || $targetTime === '') {
|
||||
if (!is_int($targetTime)) {
|
||||
$targetTime = addTurn(
|
||||
$lastRefresh ?: TimeUtil::now(),
|
||||
$lastRefresh === null ? $nowTick : Util::toInt($lastRefresh),
|
||||
$gameStor->turnterm,
|
||||
GameConst::$minTurnDieOnPrestart
|
||||
);
|
||||
$me->setAuxVar('prestart_delete_after', $targetTime);
|
||||
$me->applyDB($db);
|
||||
}
|
||||
$targetTimeDisplay = $clock->formatTick($targetTime);
|
||||
|
||||
//서버 가오픈시 할 수 있는 행동
|
||||
if ($me->getNPCType() == 0 && $me->getNationID() == 0) {
|
||||
$showDieOnPrestartBtn = true;
|
||||
if ($targetTime <= TimeUtil::now()) {
|
||||
if ($targetTime <= $nowTick) {
|
||||
$availableDieOnPrestart = true;
|
||||
}
|
||||
}
|
||||
@@ -173,7 +177,7 @@ $changeDefence999Atmos = $me->onCalcDomestic('changeDefenceTrain', "atmos999", $
|
||||
<a href="b_myPage.php?detachNPC=1"><button type="button" style=background-color:<?= GameConst::$basecolor2 ?>;color:white;width:160px;height:30px;font-size:14px;>빙의 해체 요청</button></a>-->
|
||||
|
||||
<?php if ($showDieOnPrestartBtn) : ?>
|
||||
가오픈 기간 내 장수 삭제 (<?= substr($targetTime, 0, 19) ?> 부터)<br>
|
||||
가오픈 기간 내 장수 삭제 (<?= $targetTimeDisplay ?> 부터)<br>
|
||||
<button type="button" id='dieOnPrestart' style=background-color:<?= GameConst::$basecolor2 ?>;color:white;width:160px;height:30px;font-size:14px;>장수 삭제</button><br><br>
|
||||
<?php endif; ?>
|
||||
|
||||
@@ -188,7 +192,7 @@ $changeDefence999Atmos = $me->onCalcDomestic('changeDefenceTrain', "atmos999", $
|
||||
<?php endif; ?>
|
||||
|
||||
<?php if ($gameStor->npcmode == 2 && $me->getNPCType() == 0) : ?>
|
||||
다른 장수 선택 (<?= $nextChange ? substr($nextChange, 0, 19) : '지금' ?>부터)<br>
|
||||
다른 장수 선택 (<?= $nextChangeDisplay ?? '지금' ?>부터)<br>
|
||||
<a href="select_general_from_pool.php" id='select_general_from_pool'><button type="button" style=background-color:<?= GameConst::$basecolor2 ?>;color:white;width:160px;height:30px;font-size:14px;>다른 장수 선택</button></a><br><br>
|
||||
<?php endif; ?>
|
||||
|
||||
|
||||
@@ -228,10 +228,10 @@ if($btn == "자동개최설정") {
|
||||
$phase = 0;
|
||||
startBetting($admin['tnmt_type'], 720);
|
||||
} elseif($btn == "베팅마감") {
|
||||
$dt = date("Y-m-d H:i:s", time() + 60);
|
||||
$clock = GameClock::fromStorage($gameStor);
|
||||
$gameStor->tournament=7;
|
||||
$gameStor->phase=0;
|
||||
$gameStor->tnmt_time = $dt;
|
||||
$gameStor->tnmt_time = $clock->nowTick() + $clock->ticksFromSeconds(60);
|
||||
} elseif($btn == "16강") {
|
||||
finalFight($admin['tnmt_type'], $admin['tournament'], $admin['phase'], 16);
|
||||
} elseif($btn == "8강") {
|
||||
@@ -248,4 +248,4 @@ if($btn == "자동개최설정") {
|
||||
$gameStor->tnmt_msg = $msg;
|
||||
}
|
||||
|
||||
header('location:b_tournament.php');
|
||||
header('location:b_tournament.php');
|
||||
|
||||
+116
-120
@@ -630,7 +630,11 @@ function generalInfo(General $generalObj)
|
||||
$injury = "건강";
|
||||
}
|
||||
|
||||
$remaining = (new \DateTimeImmutable($generalObj->getTurnTime()))->diff(new \DateTimeImmutable())->i;
|
||||
$clock = GameClock::fromStorage(KVStorage::getStorage(DB::db(), 'game_env'));
|
||||
$remaining = max(0, intdiv(
|
||||
$generalObj->getTurnTick() - $clock->nowTick(),
|
||||
$clock->ticksFromMinutes(1),
|
||||
));
|
||||
|
||||
if ($nation['color'] == "") {
|
||||
$nation['color'] = "#000000";
|
||||
@@ -921,45 +925,37 @@ function banner()
|
||||
);
|
||||
}
|
||||
|
||||
function addTurn($date, int $turnterm, int $turn = 1, bool $withFraction = true)
|
||||
{
|
||||
$date = new \DateTime($date);
|
||||
$target = $turnterm * $turn;
|
||||
$date->add(new \DateInterval("PT{$target}M"));
|
||||
if ($withFraction) {
|
||||
return $date->format('Y-m-d H:i:s.u');
|
||||
}
|
||||
return $date->format('Y-m-d H:i:s');
|
||||
}
|
||||
|
||||
function subTurn($date, int $turnterm, int $turn = 1, bool $withFraction = true)
|
||||
{
|
||||
$date = new \DateTime($date);
|
||||
$target = $turnterm * $turn;
|
||||
$date->sub(new \DateInterval("PT{$target}M"));
|
||||
if ($withFraction) {
|
||||
return $date->format('Y-m-d H:i:s.u');
|
||||
}
|
||||
return $date->format('Y-m-d H:i:s');
|
||||
}
|
||||
|
||||
function cutTurn($date, int $turnterm, bool $withFraction = true)
|
||||
{
|
||||
$date = new \DateTime($date);
|
||||
|
||||
$baseDate = new \DateTime($date->format('Y-m-d'));
|
||||
$baseDate->sub(new \DateInterval("P1D"));
|
||||
$baseDate->add(new \DateInterval("PT1H"));
|
||||
|
||||
$diffMin = intdiv($date->getTimeStamp() - $baseDate->getTimeStamp(), 60);
|
||||
$diffMin -= $diffMin % $turnterm;
|
||||
|
||||
$baseDate->add(new \DateInterval("PT{$diffMin}M"));
|
||||
if ($withFraction) {
|
||||
return $baseDate->format('Y-m-d H:i:s.u');
|
||||
}
|
||||
return $baseDate->format('Y-m-d H:i:s');
|
||||
}
|
||||
function addTurn(int $tick, int $turnterm, int $turn = 1, bool $withFraction = true): int
|
||||
{
|
||||
return $tick + GameClock::TICKS_PER_TURN * $turn;
|
||||
}
|
||||
|
||||
function subTurn(int $tick, int $turnterm, int $turn = 1, bool $withFraction = true): int
|
||||
{
|
||||
return $tick - GameClock::TICKS_PER_TURN * $turn;
|
||||
}
|
||||
|
||||
function cutTurn(int $tick, int $turnterm, bool $withFraction = true): int
|
||||
{
|
||||
$remainder = $tick % GameClock::TICKS_PER_TURN;
|
||||
if ($remainder < 0) {
|
||||
$remainder += GameClock::TICKS_PER_TURN;
|
||||
}
|
||||
return $tick - $remainder;
|
||||
}
|
||||
|
||||
/** 시나리오 초기화 입력인 벽시계를 기존 01:00 기준 월 경계로 정렬합니다. */
|
||||
function cutTurnDateTime(string $date, int $turnterm, bool $withFraction = true): string
|
||||
{
|
||||
$dateObj = new \DateTime($date);
|
||||
$baseDate = new \DateTime($dateObj->format('Y-m-d'));
|
||||
$baseDate->sub(new \DateInterval('P1D'));
|
||||
$baseDate->add(new \DateInterval('PT1H'));
|
||||
$diffMin = intdiv($dateObj->getTimestamp() - $baseDate->getTimestamp(), 60);
|
||||
$diffMin -= $diffMin % $turnterm;
|
||||
$baseDate->add(new \DateInterval("PT{$diffMin}M"));
|
||||
return $baseDate->format($withFraction ? 'Y-m-d H:i:s.u' : 'Y-m-d H:i:s');
|
||||
}
|
||||
|
||||
function cutDay($date, int $turnterm, bool $withFraction = true)
|
||||
{
|
||||
@@ -1001,11 +997,9 @@ function increaseRefresh($type = "", $cnt = 1)
|
||||
$generalID = $session->generalID;
|
||||
$userGrade = $session->userGrade;
|
||||
|
||||
$dateObj = new \DateTimeImmutable();
|
||||
$date = TimeUtil::format($dateObj, false);
|
||||
|
||||
$db = DB::db();
|
||||
$gameStor = KVStorage::getStorage($db, 'game_env');
|
||||
$db = DB::db();
|
||||
$gameStor = KVStorage::getStorage($db, 'game_env');
|
||||
$date = GameClock::fromStorage($gameStor)->nowTick();
|
||||
$isunited = $gameStor->isunited;
|
||||
$opentime = $gameStor->opentime;
|
||||
|
||||
@@ -1088,12 +1082,12 @@ function updateTraffic()
|
||||
if(count($recentTraffic) >= 5){
|
||||
array_shift($recentTraffic);
|
||||
}
|
||||
$recentTraffic[] = [
|
||||
$recentTraffic[] = [
|
||||
'year'=>$admin['year'],
|
||||
'month' => $admin['month'],
|
||||
'refresh' => $admin['refresh'],
|
||||
'online' => $online,
|
||||
'date' => TimeUtil::now(),
|
||||
'date' => GameClock::fromStorage($gameStor)->formatNow(),
|
||||
];
|
||||
$gameStor->recentTraffic = $recentTraffic;
|
||||
|
||||
@@ -1145,18 +1139,19 @@ function unlock(): bool
|
||||
return $db->affectedRows() > 0;
|
||||
}
|
||||
|
||||
function timeover(): bool
|
||||
function timeover(): bool
|
||||
{
|
||||
$db = DB::db();
|
||||
$gameStor = KVStorage::getStorage($db, 'game_env');
|
||||
|
||||
list($turnterm, $turntime) = $gameStor->getValuesAsArray(['turnterm', 'turntime']);
|
||||
$diff = (new \DateTime())->getTimestamp() - (new \DateTime($turntime))->getTimestamp();
|
||||
list($turnterm, $turntime) = $gameStor->getValuesAsArray(['turnterm', 'turntime']);
|
||||
$clock = GameClock::fromStorage($gameStor);
|
||||
$diff = $clock->nowTick() - Util::toInt($turntime);
|
||||
|
||||
$t = min($turnterm, 5);
|
||||
|
||||
$term = $diff;
|
||||
if ($term >= $t || $term < 0) {
|
||||
$term = $clock->ticksFromSeconds($t);
|
||||
if ($diff >= $term || $diff < 0) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
@@ -1169,9 +1164,8 @@ function checkDelay()
|
||||
$gameStor = KVStorage::getStorage($db, 'game_env');
|
||||
|
||||
//서버정보
|
||||
$now = new \DateTimeImmutable();
|
||||
$turntime = new \DateTimeImmutable($gameStor->turntime);
|
||||
$timeMinDiff = intdiv($now->getTimestamp() - $turntime->getTimestamp(), 60);
|
||||
$clock = GameClock::fromStorage($gameStor);
|
||||
$timeMinDiff = intdiv($clock->nowTick() - Util::toInt($gameStor->turntime), $clock->ticksFromMinutes(1));
|
||||
|
||||
// 1턴이상 갱신 없었으면 서버 지연
|
||||
$term = $gameStor->turnterm;
|
||||
@@ -1185,20 +1179,17 @@ function checkDelay()
|
||||
//지연 해야할 밀린 턴 횟수
|
||||
$iter = intdiv($timeMinDiff, $term);
|
||||
if ($iter > $threshold) {
|
||||
$minute = $iter * $term;
|
||||
$newTurntime = $turntime->add(new \DateInterval("PT{$minute}M"));
|
||||
$newNextTurntime = $turntime->add(new \DateInterval("PT{$term}M"));
|
||||
$gameStor->turntime = $newTurntime->format('Y-m-d H:i:s');
|
||||
$gameStor->starttime = (new \DateTimeImmutable($gameStor->starttime))
|
||||
->add(new \DateInterval("PT{$minute}M"))
|
||||
->format('Y-m-d H:i:s');
|
||||
|
||||
$db->update('general', [
|
||||
'turntime' => $db->sqleval('DATE_ADD(turntime, INTERVAL %i MINUTE)', $minute)
|
||||
], 'turntime<=DATE_ADD(turntime, INTERVAL %i MINUTE)', $term);
|
||||
$db->update('ng_auction', [
|
||||
'close_date' => $db->sqleval('DATE_ADD(close_date, INTERVAL %i MINUTE)', $minute)
|
||||
], 'finished = 0');
|
||||
$minute = $iter * $term;
|
||||
$delayTick = $clock->ticksFromMinutes($minute);
|
||||
$gameStor->turntime = Util::toInt($gameStor->turntime) + $delayTick;
|
||||
$gameStor->starttime = Util::toInt($gameStor->starttime) + $delayTick;
|
||||
|
||||
$db->update('general', [
|
||||
'turntime' => $db->sqleval('turntime + %i', $delayTick)
|
||||
], true);
|
||||
$db->update('ng_auction', [
|
||||
'close_tick' => $db->sqleval('close_tick + %i', $delayTick)
|
||||
], 'finished = 0');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1247,17 +1238,15 @@ function updateOnline()
|
||||
$gameStor->online_nation = join(', ', $onlineNation);
|
||||
}
|
||||
|
||||
function turnDate($curtime)
|
||||
function turnDate($curtime)
|
||||
{
|
||||
$db = DB::db();
|
||||
$gameStor = KVStorage::getStorage($db, 'game_env');
|
||||
$admin = $gameStor->getValues(['startyear', 'starttime', 'turnterm', 'year', 'month']);
|
||||
|
||||
$turn = $admin['starttime'];
|
||||
$curturn = cutTurn($curtime, $admin['turnterm']);
|
||||
$term = $admin['turnterm'];
|
||||
|
||||
$num = intdiv((strtotime($curturn) - strtotime($turn)), $term * 60);
|
||||
$curturn = cutTurn(Util::toInt($curtime), $admin['turnterm']);
|
||||
$num = intdiv($curturn - Util::toInt($turn), GameClock::TICKS_PER_TURN);
|
||||
|
||||
$date = $admin['startyear'] * 12;
|
||||
$date += $num;
|
||||
@@ -1387,12 +1376,14 @@ function CheckHall($no)
|
||||
return;
|
||||
}
|
||||
|
||||
$unitedDate = TimeUtil::now();
|
||||
$clock = GameClock::fromStorage($gameStor);
|
||||
$unitedDate = $clock->formatTick($clock->nowTick());
|
||||
$nation = $generalObj->getStaticNation();
|
||||
|
||||
$serverCnt = $db->queryFirstField('SELECT count(*) FROM ng_games');
|
||||
|
||||
[$scenarioIdx, $scenarioName, $startTime] = $gameStor->getValuesAsArray(['scenario', 'scenario_text', 'starttime']);
|
||||
[$scenarioIdx, $scenarioName, $startTick] = $gameStor->getValuesAsArray(['scenario', 'scenario_text', 'starttime']);
|
||||
$startTime = $clock->formatTick(Util::toInt($startTick));
|
||||
|
||||
$ownerName = $generalObj->getVar('owner_name');
|
||||
if ($generalObj->getVar('owner')) {
|
||||
@@ -1705,12 +1696,21 @@ function tryUniqueItemLottery(RandUtil $rng, General $general, string $acquireTy
|
||||
return giveRandomUniqueItem($rng, $general, $acquireType);
|
||||
}
|
||||
|
||||
function getAdmin()
|
||||
{
|
||||
$db = DB::db();
|
||||
$gameStor = KVStorage::getStorage($db, 'game_env');
|
||||
return $gameStor->getAll();
|
||||
}
|
||||
function getAdmin()
|
||||
{
|
||||
$db = DB::db();
|
||||
$gameStor = KVStorage::getStorage($db, 'game_env');
|
||||
$admin = $gameStor->getAll();
|
||||
$clock = GameClock::fromStorage($gameStor);
|
||||
foreach (['turntime', 'starttime', 'opentime', 'tnmt_time'] as $key) {
|
||||
if (($admin[$key] ?? null) !== null) {
|
||||
$admin["{$key}_display"] = $clock->formatTick(Util::toInt($admin[$key]), true);
|
||||
}
|
||||
}
|
||||
$admin['clock_now_tick'] = $clock->nowTick();
|
||||
$admin['clock_now_display'] = $clock->formatTick($admin['clock_now_tick'], true);
|
||||
return $admin;
|
||||
}
|
||||
|
||||
/** @return General[] */
|
||||
function deleteNation(General $lord, bool $applyDB): array
|
||||
@@ -1734,7 +1734,7 @@ function deleteNation(General $lord, bool $applyDB): array
|
||||
|
||||
$nationGeneralList = General::createObjListFromDB(
|
||||
$db->queryFirstColumn(
|
||||
'SELECT `no` FROM general WHERE nation=%i AND no != %i',
|
||||
'SELECT `no` FROM general WHERE nation=%i AND no != %i ORDER BY no ASC',
|
||||
$nationID,
|
||||
$lordID
|
||||
),
|
||||
@@ -1788,11 +1788,13 @@ function deleteNation(General $lord, bool $applyDB): array
|
||||
// 부대 삭제
|
||||
$db->delete('troop', 'nation=%i', $nationID);
|
||||
|
||||
// 국가 삭제
|
||||
$db->insert('ng_old_nations', [
|
||||
'server_id' => UniqueConst::$serverID,
|
||||
'nation' => $nationID,
|
||||
'data' => Json::encode($nation)
|
||||
// 국가 삭제
|
||||
$gameDate = GameClock::fromStorage(KVStorage::getStorage($db, 'game_env'))->formatNow();
|
||||
$db->insert('ng_old_nations', [
|
||||
'server_id' => UniqueConst::$serverID,
|
||||
'nation' => $nationID,
|
||||
'date' => $gameDate,
|
||||
'data' => Json::encode($nation)
|
||||
]);
|
||||
$db->delete('nation', 'nation=%i', $nationID);
|
||||
$db->delete('nation_turn', 'nation_id=%i', $nationID);
|
||||
@@ -2199,35 +2201,29 @@ function SabotageInjury(RandUtil $rng, array $cityGeneralList, string $reason):
|
||||
return $injuryCount;
|
||||
}
|
||||
|
||||
function getRandTurn(RandUtil $rng, $term, ?\DateTimeInterface $baseDateTime = null)
|
||||
{
|
||||
if ($baseDateTime === null) {
|
||||
$baseDateTime = new \DateTimeImmutable();
|
||||
} else if ($baseDateTime instanceof \DateTime) {
|
||||
$baseDateTime = \DateTimeImmutable::createFromMutable($baseDateTime);
|
||||
} else if ($baseDateTime instanceof \DateTimeImmutable) {
|
||||
//do Nothing
|
||||
} else {
|
||||
throw new MustNotBeReachedException();
|
||||
}
|
||||
|
||||
$randSecond = $rng->nextRangeInt(0, 60 * $term - 1);
|
||||
$randFraction = $rng->nextRangeInt(0, 999999) / 1000000; //6자리 소수
|
||||
|
||||
return TimeUtil::format($baseDateTime->add(TimeUtil::secondsToDateInterval($randSecond + $randFraction)), true);
|
||||
}
|
||||
|
||||
function getRandTurn2(RandUtil $rng, $term, ?\DateTimeInterface $baseDateTime = null)
|
||||
{
|
||||
if ($baseDateTime === null) {
|
||||
$baseDateTime = new \DateTimeImmutable();
|
||||
} else if ($baseDateTime instanceof \DateTime) {
|
||||
$baseDateTime = \DateTimeImmutable::createFromMutable($baseDateTime);
|
||||
} else {
|
||||
throw new MustNotBeReachedException();
|
||||
}
|
||||
$randSecond = $rng->nextRangeInt(0, 60 * $term - 1);
|
||||
$randFraction = $rng->nextRangeInt(0, 999999) / 1000000; //6자리 소수
|
||||
|
||||
return $baseDateTime->sub(TimeUtil::secondsToDateInterval($randSecond + $randFraction))->format('Y-m-d H:i:s.u');
|
||||
}
|
||||
function getRandTurn(RandUtil $rng, int $term, ?int $baseTick = null): int
|
||||
{
|
||||
$db = DB::db();
|
||||
$clock = GameClock::fromStorage(KVStorage::getStorage($db, 'game_env'));
|
||||
$baseTick ??= $clock->nowTick();
|
||||
|
||||
$randSecond = $rng->nextRangeInt(0, 60 * $term - 1);
|
||||
$randMicrosecond = $rng->nextRangeInt(0, 999999); // 레거시 RNG 소비 6자리 유지
|
||||
|
||||
return $baseTick
|
||||
+ $clock->ticksFromSeconds($randSecond)
|
||||
+ intdiv($randMicrosecond * $clock->ticksPerSecond(), 1_000_000);
|
||||
}
|
||||
|
||||
function getRandTurn2(RandUtil $rng, int $term, ?int $baseTick = null): int
|
||||
{
|
||||
$db = DB::db();
|
||||
$clock = GameClock::fromStorage(KVStorage::getStorage($db, 'game_env'));
|
||||
$baseTick ??= $clock->nowTick();
|
||||
$randSecond = $rng->nextRangeInt(0, 60 * $term - 1);
|
||||
$randMicrosecond = $rng->nextRangeInt(0, 999999); // 레거시 RNG 소비 6자리 유지
|
||||
|
||||
return $baseTick
|
||||
- $clock->ticksFromSeconds($randSecond)
|
||||
- intdiv($randMicrosecond * $clock->ticksPerSecond(), 1_000_000);
|
||||
}
|
||||
|
||||
@@ -62,11 +62,12 @@ function processAuction()
|
||||
{
|
||||
$db = DB::db();
|
||||
|
||||
$now = TimeUtil::now();
|
||||
$gameStor = KVStorage::getStorage($db, 'game_env');
|
||||
$nowTick = GameClock::fromStorage($gameStor)->nowTick();
|
||||
|
||||
$auctionList = $db->queryAllLists(
|
||||
'SELECT id, `type` FROM ng_auction WHERE `close_date` <= %s AND finished = 0',
|
||||
$now
|
||||
'SELECT id, `type` FROM ng_auction WHERE `close_tick` <= %i AND finished = 0',
|
||||
$nowTick
|
||||
);
|
||||
|
||||
if (!$auctionList) {
|
||||
|
||||
+65
-37
@@ -42,15 +42,21 @@ function pushGeneralCommand(int $generalID, int $turnCnt=1){
|
||||
|
||||
$db = DB::db();
|
||||
|
||||
$db->update('general_turn', [
|
||||
'turn_idx'=>$db->sqleval('turn_idx + %i', $turnCnt)
|
||||
], 'general_id=%i ORDER BY turn_idx DESC', $generalID);
|
||||
$db->update('general_turn', [
|
||||
'turn_idx'=>$db->sqleval('turn_idx - %i', GameConst::$maxTurn),
|
||||
'action'=>'휴식',
|
||||
'arg'=>'{}',
|
||||
'brief'=>'휴식'
|
||||
], 'general_id=%i AND turn_idx >= %i', $generalID, GameConst::$maxTurn);
|
||||
$db->query(
|
||||
'UPDATE general_turn AS dst
|
||||
LEFT JOIN general_turn AS src
|
||||
ON src.general_id = dst.general_id
|
||||
AND src.turn_idx = dst.turn_idx - %i
|
||||
SET dst.action = IF(src.id IS NULL, %s, src.action),
|
||||
dst.arg = IF(src.id IS NULL, %s, src.arg),
|
||||
dst.brief = IF(src.id IS NULL, %s, src.brief)
|
||||
WHERE dst.general_id = %i',
|
||||
$turnCnt,
|
||||
'휴식',
|
||||
'{}',
|
||||
'휴식',
|
||||
$generalID
|
||||
);
|
||||
}
|
||||
|
||||
function pullGeneralCommand(int $generalID, int $turnCnt=1){
|
||||
@@ -67,15 +73,21 @@ function pullGeneralCommand(int $generalID, int $turnCnt=1){
|
||||
|
||||
$db = DB::db();
|
||||
|
||||
$db->update('general_turn', [
|
||||
'turn_idx'=>$db->sqleval('turn_idx + %i', GameConst::$maxTurn),
|
||||
'action'=>'휴식',
|
||||
'arg'=>'{}',
|
||||
'brief'=>'휴식'
|
||||
], 'general_id=%i AND turn_idx < %i', $generalID, $turnCnt);
|
||||
$db->update('general_turn', [
|
||||
'turn_idx'=>$db->sqleval('turn_idx - %i', $turnCnt)
|
||||
], 'general_id=%i ORDER BY turn_idx ASC', $generalID);
|
||||
$db->query(
|
||||
'UPDATE general_turn AS dst
|
||||
LEFT JOIN general_turn AS src
|
||||
ON src.general_id = dst.general_id
|
||||
AND src.turn_idx = dst.turn_idx + %i
|
||||
SET dst.action = IF(src.id IS NULL, %s, src.action),
|
||||
dst.arg = IF(src.id IS NULL, %s, src.arg),
|
||||
dst.brief = IF(src.id IS NULL, %s, src.brief)
|
||||
WHERE dst.general_id = %i',
|
||||
$turnCnt,
|
||||
'휴식',
|
||||
'{}',
|
||||
'휴식',
|
||||
$generalID
|
||||
);
|
||||
}
|
||||
|
||||
function repeatGeneralCommand(int $generalId, int $turnCnt){
|
||||
@@ -126,15 +138,23 @@ function pushNationCommand(int $nationID, int $officerLevel, int $turnCnt=1){
|
||||
|
||||
$db = DB::db();
|
||||
|
||||
$db->update('nation_turn', [
|
||||
'turn_idx'=>$db->sqleval('turn_idx + %i', $turnCnt)
|
||||
], 'nation_id=%i AND officer_level=%i ORDER BY turn_idx DESC', $nationID, $officerLevel);
|
||||
$db->update('nation_turn', [
|
||||
'turn_idx'=>$db->sqleval('turn_idx - %i', GameConst::$maxChiefTurn),
|
||||
'action'=>'휴식',
|
||||
'arg'=>'{}',
|
||||
'brief'=>'휴식'
|
||||
], 'nation_id=%i AND officer_level=%i AND turn_idx >= %i ORDER BY turn_idx ASC', $nationID, $officerLevel, GameConst::$maxChiefTurn);
|
||||
$db->query(
|
||||
'UPDATE nation_turn AS dst
|
||||
LEFT JOIN nation_turn AS src
|
||||
ON src.nation_id = dst.nation_id
|
||||
AND src.officer_level = dst.officer_level
|
||||
AND src.turn_idx = dst.turn_idx - %i
|
||||
SET dst.action = IF(src.id IS NULL, %s, src.action),
|
||||
dst.arg = IF(src.id IS NULL, %s, src.arg),
|
||||
dst.brief = IF(src.id IS NULL, %s, src.brief)
|
||||
WHERE dst.nation_id = %i AND dst.officer_level = %i',
|
||||
$turnCnt,
|
||||
'휴식',
|
||||
'{}',
|
||||
'휴식',
|
||||
$nationID,
|
||||
$officerLevel
|
||||
);
|
||||
}
|
||||
|
||||
function pullNationCommand(int $nationID, int $officerLevel, int $turnCnt=1){
|
||||
@@ -157,15 +177,23 @@ function pullNationCommand(int $nationID, int $officerLevel, int $turnCnt=1){
|
||||
|
||||
$db = DB::db();
|
||||
|
||||
$db->update('nation_turn', [
|
||||
'turn_idx'=>$db->sqleval('turn_idx + %i', GameConst::$maxChiefTurn),
|
||||
'action'=>'휴식',
|
||||
'arg'=>'{}',
|
||||
'brief'=>'휴식',
|
||||
], 'nation_id=%i AND officer_level=%i AND turn_idx < %i', $nationID, $officerLevel, $turnCnt);
|
||||
$db->update('nation_turn', [
|
||||
'turn_idx'=>$db->sqleval('turn_idx - %i', $turnCnt)
|
||||
], 'nation_id=%i AND officer_level=%i ORDER BY turn_idx ASC', $nationID, $officerLevel);
|
||||
$db->query(
|
||||
'UPDATE nation_turn AS dst
|
||||
LEFT JOIN nation_turn AS src
|
||||
ON src.nation_id = dst.nation_id
|
||||
AND src.officer_level = dst.officer_level
|
||||
AND src.turn_idx = dst.turn_idx + %i
|
||||
SET dst.action = IF(src.id IS NULL, %s, src.action),
|
||||
dst.arg = IF(src.id IS NULL, %s, src.arg),
|
||||
dst.brief = IF(src.id IS NULL, %s, src.brief)
|
||||
WHERE dst.nation_id = %i AND dst.officer_level = %i',
|
||||
$turnCnt,
|
||||
'휴식',
|
||||
'{}',
|
||||
'휴식',
|
||||
$nationID,
|
||||
$officerLevel
|
||||
);
|
||||
}
|
||||
|
||||
function repeatNationCommand(int $nationID, int $officerLevel, int $turnCnt){
|
||||
@@ -494,4 +522,4 @@ function setNationCommand(int $generalID, array $turnList, string $command, ?arr
|
||||
'arg_test'=>true,
|
||||
'reason'=>'success'
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
+36
-17
@@ -651,16 +651,24 @@ function checkStatistic()
|
||||
}
|
||||
|
||||
|
||||
function convForOldGeneral(array $general, int $year, int $month)
|
||||
{
|
||||
$general['history'] = getGeneralHistoryLogAll($general['no']);
|
||||
return [
|
||||
function convForOldGeneral(array $general, int $year, int $month)
|
||||
{
|
||||
$general['history'] = getGeneralHistoryLogAll($general['no']);
|
||||
$clock = GameClock::fromStorage(KVStorage::getStorage(DB::db(), 'game_env'));
|
||||
$turnTimeDisplay = $clock->formatTick(Util::toInt($general['turntime']), true);
|
||||
$general['turntime_tick'] = Util::toInt($general['turntime']);
|
||||
$general['turntime'] = $turnTimeDisplay;
|
||||
if ($general['recent_war'] !== null) {
|
||||
$general['recent_war_tick'] = Util::toInt($general['recent_war']);
|
||||
$general['recent_war'] = $clock->formatTick(Util::toInt($general['recent_war']), true);
|
||||
}
|
||||
return [
|
||||
'server_id' => UniqueConst::$serverID,
|
||||
'general_no' => $general['no'],
|
||||
'owner' => $general['owner'],
|
||||
'name' => $general['name'],
|
||||
'last_yearmonth' => $year * 100 + $month,
|
||||
'turntime' => $general['turntime'],
|
||||
'turntime' => $turnTimeDisplay,
|
||||
'data' => Json::encode($general)
|
||||
];
|
||||
}
|
||||
@@ -734,7 +742,7 @@ function checkEmperior()
|
||||
|
||||
/** @var int[] */
|
||||
$auctionList = $db->queryFirstColumn(
|
||||
'SELECT `id` FROM `ng_auction` WHERE `type` = %s AND `finished` = 0 ORDER BY `close_date` ASC',
|
||||
'SELECT `id` FROM `ng_auction` WHERE `type` = %s AND `finished` = 0 ORDER BY `close_tick` ASC',
|
||||
AuctionType::UniqueItem->value
|
||||
);
|
||||
foreach($auctionList as $auctionID){
|
||||
@@ -772,7 +780,7 @@ function checkEmperior()
|
||||
|
||||
$chiefs = Util::convertArrayToDict(
|
||||
$db->query(
|
||||
'SELECT no,npc,name,picture,belong,officer_level FROM general WHERE nation=%i AND officer_level >= 5',
|
||||
'SELECT no,npc,name,picture,imgsvr,belong,officer_level FROM general WHERE nation=%i AND officer_level >= 5',
|
||||
$nationID
|
||||
),
|
||||
'officer_level'
|
||||
@@ -830,20 +838,23 @@ function checkEmperior()
|
||||
$nation['aux'] += $nationStor->max_power ?? [];
|
||||
$nation['history'] = getNationHistoryLogAll($nation['nation']);
|
||||
|
||||
storeOldGenerals(0, $admin['year'], $admin['month']);
|
||||
storeOldGenerals($nation['nation'], $admin['year'], $admin['month']);
|
||||
|
||||
$db->insert('ng_old_nations', [
|
||||
'server_id' => UniqueConst::$serverID,
|
||||
'nation' => $nation['nation'],
|
||||
'data' => Json::encode($nation)
|
||||
storeOldGenerals(0, $admin['year'], $admin['month']);
|
||||
storeOldGenerals($nation['nation'], $admin['year'], $admin['month']);
|
||||
$gameDate = GameClock::fromStorage($gameStor)->formatNow();
|
||||
|
||||
$db->insert('ng_old_nations', [
|
||||
'server_id' => UniqueConst::$serverID,
|
||||
'nation' => $nation['nation'],
|
||||
'date' => $gameDate,
|
||||
'data' => Json::encode($nation)
|
||||
]);
|
||||
|
||||
$noNationGeneral = $db->queryFirstColumn('SELECT `no` FROM general WHERE nation=0');
|
||||
$db->insert('ng_old_nations', [
|
||||
'server_id' => UniqueConst::$serverID,
|
||||
'nation' => 0,
|
||||
'data' => Json::encode([
|
||||
'server_id' => UniqueConst::$serverID,
|
||||
'nation' => 0,
|
||||
'date' => $gameDate,
|
||||
'data' => Json::encode([
|
||||
'nation' => 0,
|
||||
'name' => '재야',
|
||||
'generals' => $noNationGeneral
|
||||
@@ -882,20 +893,28 @@ function checkEmperior()
|
||||
'rice' => $nation['rice'],
|
||||
'l12name' => $chiefs[12]['name'],
|
||||
'l12pic' => $chiefs[12]['picture'],
|
||||
'l12imgsvr' => $chiefs[12]['imgsvr'],
|
||||
'l11name' => $chiefs[11]['name'],
|
||||
'l11pic' => $chiefs[11]['picture'],
|
||||
'l11imgsvr' => $chiefs[11]['imgsvr'],
|
||||
'l10name' => $chiefs[10]['name'],
|
||||
'l10pic' => $chiefs[10]['picture'],
|
||||
'l10imgsvr' => $chiefs[10]['imgsvr'],
|
||||
'l9name' => $chiefs[9]['name'],
|
||||
'l9pic' => $chiefs[9]['picture'],
|
||||
'l9imgsvr' => $chiefs[9]['imgsvr'],
|
||||
'l8name' => $chiefs[8]['name'],
|
||||
'l8pic' => $chiefs[8]['picture'],
|
||||
'l8imgsvr' => $chiefs[8]['imgsvr'],
|
||||
'l7name' => $chiefs[7]['name'],
|
||||
'l7pic' => $chiefs[7]['picture'],
|
||||
'l7imgsvr' => $chiefs[7]['imgsvr'],
|
||||
'l6name' => $chiefs[6]['name'],
|
||||
'l6pic' => $chiefs[6]['picture'],
|
||||
'l6imgsvr' => $chiefs[6]['imgsvr'],
|
||||
'l5name' => $chiefs[5]['name'],
|
||||
'l5pic' => $chiefs[5]['picture'],
|
||||
'l5imgsvr' => $chiefs[5]['imgsvr'],
|
||||
'tiger' => $tigerstr,
|
||||
'eagle' => $eaglestr,
|
||||
'gen' => $gen,
|
||||
|
||||
@@ -4,6 +4,10 @@ namespace sammo;
|
||||
|
||||
function printLimitMsg($turntime)
|
||||
{
|
||||
if (is_int($turntime) || (is_string($turntime) && ctype_digit(ltrim($turntime, '-')))) {
|
||||
$gameStor = KVStorage::getStorage(DB::db(), 'game_env');
|
||||
$turntime = GameClock::fromStorage($gameStor)->formatTick(Util::toInt($turntime), true);
|
||||
}
|
||||
//FIXME: template로 이동.
|
||||
?>
|
||||
<!DOCTYPE html>
|
||||
|
||||
@@ -61,8 +61,12 @@ function chiefTurnTable()
|
||||
";
|
||||
}
|
||||
|
||||
function templateLimitMsg(string $turntime): string
|
||||
{
|
||||
function templateLimitMsg(string $turntime): string
|
||||
{
|
||||
if (ctype_digit(ltrim($turntime, '-'))) {
|
||||
$gameStor = KVStorage::getStorage(DB::db(), 'game_env');
|
||||
$turntime = GameClock::fromStorage($gameStor)->formatTick(Util::toInt($turntime), true);
|
||||
}
|
||||
return "이미 너무 많은 접속을 하셨습니다. 다음 턴에 다시 시도해주세요. (턴시간: {$turntime})";
|
||||
}
|
||||
|
||||
|
||||
+11
-8
@@ -17,10 +17,10 @@ function processTournament()
|
||||
{
|
||||
$db = DB::db();
|
||||
$gameStor = KVStorage::getStorage($db, 'game_env');
|
||||
$clock = GameClock::fromStorage($gameStor);
|
||||
|
||||
$admin = $gameStor->getValues(['tournament', 'phase', 'tnmt_type', 'tnmt_auto', 'tnmt_time', 'turnterm', 'last_tournament_betting_id']);
|
||||
$now = new \DateTime();
|
||||
$offset = $now->getTimestamp() - (new \DateTime($admin['tnmt_time']))->getTimestamp();
|
||||
$offset = intdiv($clock->nowTick() - Util::toInt($admin['tnmt_time']), $clock->ticksPerSecond());
|
||||
|
||||
//수동일땐 무시
|
||||
if (!$admin['tnmt_auto']) {
|
||||
@@ -122,10 +122,10 @@ function processTournament()
|
||||
if ($tnmt == 6) {
|
||||
$betTerm = Util::valueFit($unit * 60, null, 3600);
|
||||
//처리 초 더한 날짜
|
||||
$dt = date("Y-m-d H:i:s", strtotime($admin['tnmt_time']) + $unit * $i + $betTerm);
|
||||
$gameStor->tournament = $tnmt;
|
||||
$gameStor->phase = $phase;
|
||||
$gameStor->tnmt_time = $dt;
|
||||
$gameStor->tnmt_time = Util::toInt($admin['tnmt_time'])
|
||||
+ $clock->ticksFromSeconds($unit * $i + $betTerm);
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -133,7 +133,7 @@ function processTournament()
|
||||
$second = $unit * $iter;
|
||||
$gameStor->tournament = $tnmt;
|
||||
$gameStor->phase = $phase;
|
||||
$gameStor->tnmt_time = (new \DateTimeImmutable($admin['tnmt_time']))->add(new \DateInterval("PT{$second}S"))->format('Y-m-d H:i:s');
|
||||
$gameStor->tnmt_time = Util::toInt($admin['tnmt_time']) + $clock->ticksFromSeconds($second);
|
||||
}
|
||||
|
||||
function getTournamentTermText(int $turnTerm)
|
||||
@@ -160,7 +160,8 @@ function getTournamentTime()
|
||||
$gameStor = KVStorage::getStorage($db, 'game_env');
|
||||
|
||||
list($tnmt, $tnmt_time) = $gameStor->getValuesAsArray(['tournament', 'tnmt_time']);
|
||||
$dt = substr($tnmt_time, 11, 5);
|
||||
$clock = GameClock::fromStorage($gameStor);
|
||||
$dt = substr($clock->formatTick(Util::toInt($tnmt_time)), 11, 5);
|
||||
switch ($tnmt) {
|
||||
case 1:
|
||||
$tnmt = "개막시간 {$dt}";
|
||||
@@ -284,9 +285,11 @@ function startTournament($type)
|
||||
$admin = $gameStor->getValues(['year', 'month', 'turnterm']);
|
||||
$turnTerm = $admin['turnterm'];
|
||||
$unit = calcTournamentTerm($turnTerm);
|
||||
$clock = GameClock::fromStorage($gameStor);
|
||||
|
||||
$gameStor->tnmt_auto = true;
|
||||
$gameStor->tnmt_time = (new \DateTimeImmutable())->add(new \DateInterval("PT{$unit}M"))->format('Y-m-d H:i:s');
|
||||
// 기존 startTournament은 unit을 분으로 더하므로 그 계약을 유지합니다.
|
||||
$gameStor->tnmt_time = $clock->nowTick() + $clock->ticksFromMinutes($unit);
|
||||
$gameStor->tournament = 1;
|
||||
$gameStor->tnmt_type = $type;
|
||||
$gameStor->last_tournament_betting_id = 0;
|
||||
@@ -1171,7 +1174,7 @@ function fight($tnmt_type, $tnmt, $phs, $group, $g1, $g2, $type)
|
||||
}
|
||||
$damage1 *= $factor1;
|
||||
$damage2 *= $factor2;
|
||||
|
||||
|
||||
//1합 승부
|
||||
if ($phase == 1) {
|
||||
|
||||
|
||||
+3
-2
@@ -7,6 +7,7 @@ include "func.php";
|
||||
Session::requireLogin()->loginGame()->setReadOnly();
|
||||
|
||||
$mapName = GameConst::$mapName;
|
||||
$frontClock = GameClock::fromStorage(KVStorage::getStorage(DB::db(), 'game_env'));
|
||||
|
||||
?>
|
||||
<!DOCTYPE html>
|
||||
@@ -28,7 +29,7 @@ $mapName = GameConst::$mapName;
|
||||
|
||||
'maxTurn' => GameConst::$maxTurn,
|
||||
'maxPushTurn' => 12,
|
||||
'serverNow' => TimeUtil::now(false),
|
||||
'serverNow' => $frontClock->formatTick($frontClock->nowTick()),
|
||||
]
|
||||
], false) ?>
|
||||
<?= WebUtil::printJS('../d_shared/common_path.js') ?>
|
||||
@@ -42,4 +43,4 @@ $mapName = GameConst::$mapName;
|
||||
<div id="app"></div>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
</html>
|
||||
|
||||
+15
-12
@@ -25,21 +25,24 @@ if(!$reserved){
|
||||
]);
|
||||
}
|
||||
|
||||
$reservedDate = new \DateTime($reserved['date']);
|
||||
$now = new \DateTime();
|
||||
$reservedDate = new \DateTimeImmutable($reserved['date']);
|
||||
$now = GameClock::readWallTime();
|
||||
|
||||
|
||||
$status = 'not_yet';
|
||||
|
||||
list($isUnited, $lastTurn) = $gameStor->getValuesAsArray(['isunited', 'turntime']);
|
||||
if($isUnited === null || $lastTurn === null){
|
||||
$isUnited = 2;
|
||||
$lastTurn = '2000-01-01';
|
||||
}
|
||||
|
||||
if($lastTurn !== null){
|
||||
$lastTurn = new \DateTime($lastTurn);
|
||||
}
|
||||
list($isUnited, $unitedWallAnchor) = $gameStor->getValuesAsArray(['isunited', 'autoreset_united_wall_anchor']);
|
||||
if($isUnited === null){
|
||||
$isUnited = 2;
|
||||
}
|
||||
$lastTurn = null;
|
||||
if($isUnited > 0){
|
||||
if(!is_string($unitedWallAnchor) || $unitedWallAnchor === ''){
|
||||
$unitedWallAnchor = TimeUtil::format($now, true);
|
||||
$gameStor->autoreset_united_wall_anchor = $unitedWallAnchor;
|
||||
}
|
||||
$lastTurn = new \DateTimeImmutable($unitedWallAnchor);
|
||||
}
|
||||
|
||||
if($lastTurn === null){
|
||||
//이미 리셋된 상태임
|
||||
@@ -99,4 +102,4 @@ $result['affected']=1;
|
||||
$prefix = DB::prefix();
|
||||
ServConfig::getServerList()[$prefix]->openServer();
|
||||
|
||||
Json::die($result);
|
||||
Json::die($result);
|
||||
|
||||
@@ -10,6 +10,7 @@ $session = Session::requireGameLogin()->setReadOnly();
|
||||
$userID = Session::getUserID();
|
||||
|
||||
$db = DB::db();
|
||||
$clock = GameClock::fromStorage(KVStorage::getStorage($db, 'game_env'));
|
||||
|
||||
$isSecretBoard = Util::getPost('isSecret', 'bool', false);
|
||||
$title = Util::getPost('title');
|
||||
@@ -67,7 +68,7 @@ $icon = GetImageURL($me['imgsvr'], $me['picture']);
|
||||
$db->insert('board', [
|
||||
'nation_no'=>$me['nation'],
|
||||
'is_secret'=>$isSecretBoard,
|
||||
'date'=>TimeUtil::now(),
|
||||
'date'=>$clock->formatNow(),
|
||||
'general_no'=>$me['no'],
|
||||
'author'=>$me['name'],
|
||||
'author_icon'=>$icon,
|
||||
@@ -79,4 +80,4 @@ Json::die([
|
||||
'result'=>true,
|
||||
'reason'=>'success',
|
||||
'row_id'=>$db->insertId()
|
||||
]);
|
||||
]);
|
||||
|
||||
@@ -10,6 +10,7 @@ $session = Session::requireGameLogin()->setReadOnly();
|
||||
$userID = Session::getUserID();
|
||||
|
||||
$db = DB::db();
|
||||
$clock = GameClock::fromStorage(KVStorage::getStorage($db, 'game_env'));
|
||||
|
||||
$articleNo = Util::getPost('articleNo', 'int');
|
||||
$text = Util::getPost('text');
|
||||
@@ -73,7 +74,7 @@ else if ($isSecretBoard && $permission < 2) {
|
||||
$db->insert('comment', [
|
||||
'nation_no'=>$me['nation'],
|
||||
'is_secret'=>$isSecretBoard,
|
||||
'date'=>TimeUtil::now(),
|
||||
'date'=>$clock->formatNow(),
|
||||
'document_no'=>$articleNo,
|
||||
'general_no'=>$me['no'],
|
||||
'author'=>$me['name'],
|
||||
@@ -84,4 +85,4 @@ Json::die([
|
||||
'result'=>true,
|
||||
'reason'=>'success',
|
||||
'row_id'=>$db->insertId()
|
||||
]);
|
||||
]);
|
||||
|
||||
@@ -83,7 +83,7 @@ else{
|
||||
}
|
||||
|
||||
|
||||
$now = new \DateTime();
|
||||
$now = Message::gameNow();
|
||||
$unlimited = new \DateTime('9999-12-31');
|
||||
|
||||
if(in_array($stateOpt, ['try_destroy_src', 'try_destroy_dest'])){
|
||||
@@ -138,4 +138,4 @@ Json::die([
|
||||
'result'=>true,
|
||||
'reason'=>'success',
|
||||
'state'=>$lastState
|
||||
]);
|
||||
]);
|
||||
|
||||
@@ -69,7 +69,7 @@ $destNation = getNationStaticInfo($letter['dest_nation_id']);
|
||||
$src = new MessageTarget($me['no'], $me['name'], $destNation['nation'], $destNation['name'], $destNation['color'], $me['icon']);
|
||||
$dest = new MessageTarget(0, '', $srcNation['nation'], $srcNation['name'], $srcNation['color']);
|
||||
|
||||
$now = new \DateTime();
|
||||
$now = Message::gameNow();
|
||||
$unlimited = new \DateTime('9999-12-31');
|
||||
|
||||
if($isAgree){
|
||||
@@ -133,4 +133,4 @@ $msgID = $msg->send();
|
||||
Json::die([
|
||||
'result'=>true,
|
||||
'reason'=>'success'
|
||||
]);
|
||||
]);
|
||||
|
||||
@@ -63,7 +63,7 @@ $destNation = getNationStaticInfo($letter['dest_nation_id']);
|
||||
$src = new MessageTarget($me['no'], $me['name'], $srcNation['nation'], $srcNation['name'], $srcNation['color'], $me['icon']);
|
||||
$dest = new MessageTarget(0, '', $destNation['nation'], $destNation['name'], $destNation['color']);
|
||||
|
||||
$now = new \DateTime();
|
||||
$now = Message::gameNow();
|
||||
$unlimited = new \DateTime('9999-12-31');
|
||||
|
||||
$aux['reason'] = [
|
||||
@@ -91,4 +91,4 @@ $msgID = $msg->send();
|
||||
Json::die([
|
||||
'result'=>true,
|
||||
'reason'=>'success'
|
||||
]);
|
||||
]);
|
||||
|
||||
@@ -140,6 +140,8 @@ else{
|
||||
|
||||
$me['icon'] = GetImageURL($me['imgsvr'], $me['picture']);
|
||||
|
||||
$clock = GameClock::fromStorage($gameStor);
|
||||
$gameNow = $clock->nowDateTime();
|
||||
$db->insert('ng_diplomacy', [
|
||||
'src_nation_id'=>$srcNation['nation'],
|
||||
'dest_nation_id'=>$destNation['nation'],
|
||||
@@ -147,7 +149,7 @@ $db->insert('ng_diplomacy', [
|
||||
'state'=>'proposed',
|
||||
'text_brief'=>$textBrief,
|
||||
'text_detail'=>$textDetail,
|
||||
'date'=>TimeUtil::now(),
|
||||
'date'=>TimeUtil::format($gameNow),
|
||||
'src_signer'=>$me['no'],
|
||||
'dest_signer'=>null,
|
||||
'aux'=>Json::encode([
|
||||
@@ -168,7 +170,7 @@ $newLetterNo = $db->insertId();
|
||||
$src = new MessageTarget($me['no'], $me['name'], $srcNation['nation'], $srcNation['name'], $srcNation['color'], $me['icon']);
|
||||
$dest = new MessageTarget(0, '', $destNation['nation'], $destNation['name'], $destNation['color']);
|
||||
|
||||
$now = new \DateTime();
|
||||
$now = \DateTime::createFromImmutable($gameNow);
|
||||
$unlimited = new \DateTime('9999-12-31');
|
||||
|
||||
$josaYi = JosaUtil::pick($newLetterNo, '이');
|
||||
@@ -195,4 +197,4 @@ Json::die([
|
||||
'result'=>true,
|
||||
'reason'=>'success',
|
||||
'row_id'=>$db->insertId()
|
||||
]);
|
||||
]);
|
||||
|
||||
@@ -16,12 +16,10 @@ $session = Session::requireLogin([])->setReadOnly();
|
||||
$userID = Session::getUserID();
|
||||
|
||||
|
||||
$oNow = new \DateTimeImmutable();
|
||||
|
||||
$now = $oNow->format('Y-m-d H:i:s');
|
||||
|
||||
$db = DB::db();
|
||||
$gameStor = KVStorage::getStorage($db, 'game_env');
|
||||
$clock = GameClock::fromStorage($gameStor);
|
||||
$now = $clock->nowTick();
|
||||
|
||||
$oldGeneral = $db->queryFirstField('SELECT `no` FROM general WHERE `owner`=%i', $userID);
|
||||
if($oldGeneral !== null){
|
||||
@@ -44,15 +42,14 @@ if($npcmode!=1){
|
||||
]);
|
||||
}
|
||||
|
||||
$token = $db->queryFirstRow('SELECT * FROM select_npc_token WHERE `owner`=%i AND `valid_until`>=%s', $userID, $now);
|
||||
$token = $db->queryFirstRow('SELECT * FROM select_npc_token WHERE `owner`=%i AND `valid_until`>=%i', $userID, $now);
|
||||
$pickResult = [];
|
||||
|
||||
|
||||
if($token && $refresh){
|
||||
$pickMoreFrom = (new \DateTime($token['pick_more_from']))->getTimestamp();
|
||||
$nowT = $oNow->getTimestamp();
|
||||
$pickMoreFrom = Util::toInt($token['pick_more_from']);
|
||||
|
||||
if($nowT >= $pickMoreFrom){
|
||||
if($now >= $pickMoreFrom){
|
||||
$oldPickResult = Json::decode($token['pick_result']);
|
||||
|
||||
foreach($keepResult as $keepId){
|
||||
@@ -75,15 +72,16 @@ if($token && $refresh){
|
||||
}
|
||||
|
||||
if($token && !$refresh){
|
||||
$pickMoreFrom = (new \DateTime($token['pick_more_from']))->getTimestamp();
|
||||
$nowT = $oNow->getTimestamp();
|
||||
$pickMoreFrom = Util::toInt($token['pick_more_from']);
|
||||
|
||||
Json::die([
|
||||
'result'=>true,
|
||||
'pick'=>Json::decode($token['pick_result']),
|
||||
'pickMoreFrom'=>$token['pick_more_from'],
|
||||
'pickMoreSeconds'=>$pickMoreFrom-$nowT,
|
||||
'validUntil'=>$token['valid_until']
|
||||
'pickMoreFrom'=>$clock->formatTick($pickMoreFrom),
|
||||
'pickMoreSeconds'=>intdiv($pickMoreFrom - $now, $clock->ticksPerSecond()),
|
||||
'validUntil'=>$clock->formatTick(Util::toInt($token['valid_until'])),
|
||||
'validForSeconds'=>max(0, intdiv(Util::toInt($token['valid_until']) - $now, $clock->ticksPerSecond())),
|
||||
'clockMode'=>$clock->getMode(),
|
||||
]);
|
||||
}
|
||||
|
||||
@@ -100,7 +98,7 @@ foreach($db->query('SELECT `no`, `name`, leadership, strength, intel, nation, im
|
||||
$weight[$general['no']] = pow($allStat, 1.5);
|
||||
}
|
||||
|
||||
foreach($db->queryFirstColumn('SELECT pick_result FROM select_npc_token WHERE `owner`!=%i AND valid_until >=%s', $userID, $now) as $reserved){
|
||||
foreach($db->queryFirstColumn('SELECT pick_result FROM select_npc_token WHERE `owner`!=%i AND valid_until >=%i', $userID, $now) as $reserved){
|
||||
$reserved = Json::decode($reserved);
|
||||
foreach(array_keys($reserved) as $reservedNPC){
|
||||
if(key_exists($reservedNPC, $weight)){
|
||||
@@ -131,8 +129,8 @@ $newNonce = random_int(0, 0xfffffff);
|
||||
$validSecond = max(VALID_SECOND, $turnterm*40);
|
||||
$pickMoreSecond = max(PICK_MORE_SECOND, Util::round(pow($turnterm, 0.672)*8));
|
||||
|
||||
$validUntil = $oNow->add(new \DateInterval(sprintf('PT%dS', $validSecond)));
|
||||
$pickMoreFrom = $oNow->add(new \DateInterval(sprintf('PT%dS', $pickMoreSecond)));
|
||||
$validUntil = $now + $clock->ticksFromSeconds($validSecond);
|
||||
$pickMoreFrom = $now + $clock->ticksFromSeconds($pickMoreSecond);
|
||||
|
||||
$db->delete('select_npc_token', 'valid_until < %s', $now);
|
||||
|
||||
@@ -140,8 +138,8 @@ $inserted = 0;
|
||||
|
||||
if($token){
|
||||
$db->update('select_npc_token', [
|
||||
'valid_until'=>$validUntil->format('Y-m-d H:i:s'),
|
||||
'pick_more_from'=>$pickMoreFrom->format('Y-m-d H:i:s'),
|
||||
'valid_until'=>$validUntil,
|
||||
'pick_more_from'=>$pickMoreFrom,
|
||||
'pick_result'=>Json::encode($pickResult),
|
||||
'nonce'=>$newNonce
|
||||
], 'owner = %i AND nonce = %i', $userID, $token['nonce']);
|
||||
@@ -152,8 +150,8 @@ if($token){
|
||||
else{
|
||||
$db->insertIgnore('select_npc_token', [
|
||||
'owner'=>$userID,
|
||||
'valid_until'=>$validUntil->format('Y-m-d H:i:s'),
|
||||
'pick_more_from'=>'2000-01-01 01:00:00',
|
||||
'valid_until'=>$validUntil,
|
||||
'pick_more_from'=>$now,
|
||||
'pick_result'=>Json::encode($pickResult),
|
||||
'nonce'=>$newNonce
|
||||
]);
|
||||
@@ -173,7 +171,9 @@ if($inserted === 0){
|
||||
Json::die([
|
||||
'result'=>true,
|
||||
'pick'=>$pickResult,
|
||||
'pickMoreFrom'=>($inserted===-1)?$pickMoreFrom->format('Y-m-d H:i:s'):'2000-01-01 01:00:00',
|
||||
'pickMoreFrom'=>$clock->formatTick(($inserted===-1)?$pickMoreFrom:$now),
|
||||
'pickMoreSeconds'=>($inserted===-1)?$pickMoreSecond:0,
|
||||
'validUntil'=>$validUntil->format('Y-m-d H:i:s')
|
||||
]);
|
||||
'validUntil'=>$clock->formatTick($validUntil),
|
||||
'validForSeconds'=>max(0, intdiv($validUntil - $now, $clock->ticksPerSecond())),
|
||||
'clockMode'=>$clock->getMode(),
|
||||
]);
|
||||
|
||||
@@ -43,12 +43,10 @@ function putInfoText(&$info, ?array $currentTargetEnv){
|
||||
$session = Session::requireLogin([])->setReadOnly();
|
||||
$userID = Session::getUserID();
|
||||
|
||||
$oNow = new \DateTimeImmutable();
|
||||
|
||||
$now = $oNow->format('Y-m-d H:i:s');
|
||||
|
||||
$db = DB::db();
|
||||
$gameStor = KVStorage::getStorage($db, 'game_env');
|
||||
$db = DB::db();
|
||||
$gameStor = KVStorage::getStorage($db, 'game_env');
|
||||
$clock = GameClock::fromStorage($gameStor);
|
||||
$now = $clock->nowTick();
|
||||
|
||||
$eventEnv = $gameStor->getValues(['npcmode', 'startyear', 'year', 'month']);
|
||||
$npcmode = $eventEnv['npcmode'];
|
||||
@@ -88,7 +86,9 @@ if($tokens){
|
||||
Json::die([
|
||||
'result'=>true,
|
||||
'pick'=>$pick,
|
||||
'validUntil'=>$valid_until
|
||||
'validUntil'=>$clock->formatTick(Util::toInt($valid_until)),
|
||||
'validForSeconds'=>max(0, intdiv(Util::toInt($valid_until) - $now, $clock->ticksPerSecond())),
|
||||
'clockMode'=>$clock->getMode(),
|
||||
]);
|
||||
}
|
||||
|
||||
@@ -108,5 +108,7 @@ sortTokens($pick);//좀 무식하지만..
|
||||
Json::die([
|
||||
'result'=>true,
|
||||
'pick'=>$pick,
|
||||
'validUntil'=>$valid_until
|
||||
]);
|
||||
'validUntil'=>$valid_until === null ? null : $clock->formatTick(Util::toInt($valid_until)),
|
||||
'validForSeconds'=>$valid_until === null ? 0 : max(0, intdiv(Util::toInt($valid_until) - $now, $clock->ticksPerSecond())),
|
||||
'clockMode'=>$clock->getMode(),
|
||||
]);
|
||||
|
||||
+2
-2
@@ -211,7 +211,7 @@ try{
|
||||
$show_img_level,
|
||||
!!$tournament_trig,
|
||||
$join_mode,
|
||||
TimeUtil::now(),
|
||||
TimeUtil::format(GameClock::readWallTime(), false),
|
||||
$autorun_user
|
||||
));
|
||||
}
|
||||
@@ -220,4 +220,4 @@ catch(\Exception $e){
|
||||
'result'=>false,
|
||||
'reason'=>$e->getMessage()
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -290,7 +290,7 @@ function do추방(General $general, int $myOfficerLevel): ?string
|
||||
$src,
|
||||
$src,
|
||||
$str,
|
||||
new \DateTime(),
|
||||
Message::gameNow(),
|
||||
new \DateTime('9999-12-31'),
|
||||
[]
|
||||
);
|
||||
|
||||
@@ -24,8 +24,8 @@ $db = DB::db();
|
||||
$gameStor = KVStorage::getStorage($db, 'game_env');
|
||||
$rootDB = RootDB::db();
|
||||
|
||||
$oNow = new \DateTimeImmutable();
|
||||
$now = $oNow->format('Y-m-d H:i:s');
|
||||
$clock = GameClock::fromStorage($gameStor);
|
||||
$now = $clock->nowTick();
|
||||
|
||||
$member = $rootDB->queryFirstRow('SELECT `name`, `penalty` FROM member WHERE `NO`=%i', $userID);
|
||||
if(!$member){
|
||||
@@ -139,4 +139,4 @@ $rootDB->insert('member_log', [
|
||||
Json::die([
|
||||
'result'=>true,
|
||||
'reason'=>'success'
|
||||
]);
|
||||
]);
|
||||
|
||||
@@ -37,8 +37,8 @@ $db = DB::db();
|
||||
$gameStor = KVStorage::getStorage($db, 'game_env');
|
||||
|
||||
$rootDB = RootDB::db();
|
||||
$oNow = new \DateTimeImmutable();
|
||||
$now = $oNow->format('Y-m-d H:i:s');
|
||||
$clock = GameClock::fromStorage($gameStor);
|
||||
$now = $clock->nowTick();
|
||||
|
||||
$hasGeneralID = $db->queryFirstField('SELECT no FROM general WHERE owner = %i', $userID);
|
||||
if($hasGeneralID){
|
||||
@@ -176,7 +176,7 @@ $builder->setOwner($userID);
|
||||
$builder->setOwnerName($userNick);
|
||||
$builder->setKillturn(5);
|
||||
$builder->setNPCType(0);
|
||||
$builder->setAuxVar('next_change', TimeUtil::nowAddMinutes(12 * $env['turnterm']));
|
||||
$builder->setAuxVar('next_change', $now + GameClock::TICKS_PER_TURN * 12);
|
||||
$builder->setAuxVar(
|
||||
'prestart_delete_after',
|
||||
addTurn($now, $env['turnterm'], GameConst::$minTurnDieOnPrestart)
|
||||
|
||||
@@ -70,13 +70,24 @@ if(file_exists(__DIR__.'/.htaccess')){
|
||||
|
||||
//TODO: 천통시에도 예약 오픈 알림이 필요..?
|
||||
|
||||
$usesLogicalClock = GameClock::isInitialized($gameStor);
|
||||
$admin = $gameStor->getValues(['isunited', 'npcmode', 'year', 'month', 'scenario', 'scenario_text', 'maxgeneral', 'turnterm', 'opentime', 'turntime', 'join_mode', 'fiction', 'block_general_create', 'autorun_user']);
|
||||
$admin['maxUserCnt'] = $admin['maxgeneral'];
|
||||
$admin['npcMode'] = $admin['npcmode'];
|
||||
$admin['turnTerm'] = $admin['turnterm'];
|
||||
$admin['isUnited'] = $admin['isunited'];
|
||||
$admin['starttime'] = substr($admin['opentime'], 5, 11);
|
||||
$admin['turntime'] = substr($admin['turntime'], 5, 11);
|
||||
if($usesLogicalClock){
|
||||
$clock = GameClock::fromStorage($gameStor);
|
||||
$admin['isOpen'] = $clock->nowTick() >= Util::toInt($admin['opentime']);
|
||||
$admin['opentime'] = $clock->formatTick(Util::toInt($admin['opentime']));
|
||||
$admin['starttime'] = substr($admin['opentime'], 5, 11);
|
||||
$admin['turntime'] = substr($clock->formatTick(Util::toInt($admin['turntime'])), 5, 11);
|
||||
}
|
||||
else{
|
||||
$admin['isOpen'] = new \DateTimeImmutable((string)$admin['opentime']) <= GameClock::readWallTime();
|
||||
$admin['starttime'] = substr((string)$admin['opentime'], 5, 11);
|
||||
$admin['turntime'] = substr((string)$admin['turntime'], 5, 11);
|
||||
}
|
||||
unset($admin['npcmode']);
|
||||
unset($admin['maxgeneral']);
|
||||
unset($admin['turnterm']);
|
||||
@@ -131,4 +142,4 @@ if($general){
|
||||
Json::die([
|
||||
'game'=>$admin,
|
||||
'me'=>$me?:null
|
||||
]);
|
||||
]);
|
||||
|
||||
@@ -64,6 +64,7 @@ if ($permission < 3) {
|
||||
function applyNationPolicy($policy, $nationID, $generalName): ?string
|
||||
{
|
||||
$db = DB::db();
|
||||
$gameNow = GameClock::fromStorage(KVStorage::getStorage($db, 'game_env'))->formatNow();
|
||||
$nationStor = KVStorage::getStorage($db, $nationID, 'nation_env');
|
||||
|
||||
$defaultPolicy = AutorunNationPolicy::$defaultPolicy;
|
||||
@@ -139,7 +140,7 @@ function applyNationPolicy($policy, $nationID, $generalName): ?string
|
||||
|
||||
$nationPolicyRoot['values'] = $nationPolicy;
|
||||
$nationPolicyRoot['valueSetter'] = $generalName;
|
||||
$nationPolicyRoot['valueSetTime'] = TimeUtil::now();
|
||||
$nationPolicyRoot['valueSetTime'] = $gameNow;
|
||||
$nationStor->npc_nation_policy = $nationPolicyRoot;
|
||||
return null;
|
||||
}
|
||||
@@ -147,6 +148,7 @@ function applyNationPolicy($policy, $nationID, $generalName): ?string
|
||||
function applyNationPriority($priority, $nationID, $generalName): ?string
|
||||
{
|
||||
$db = DB::db();
|
||||
$gameNow = GameClock::fromStorage(KVStorage::getStorage($db, 'game_env'))->formatNow();
|
||||
$nationStor = KVStorage::getStorage($db, $nationID, 'nation_env');
|
||||
$nationPolicyRoot = $nationStor->npc_nation_policy;
|
||||
|
||||
@@ -158,7 +160,7 @@ function applyNationPriority($priority, $nationID, $generalName): ?string
|
||||
}
|
||||
$nationPolicyRoot['priority'] = $priority;
|
||||
$nationPolicyRoot['prioritySetter'] = $generalName;
|
||||
$nationPolicyRoot['prioritySetTime'] = TimeUtil::now();
|
||||
$nationPolicyRoot['prioritySetTime'] = $gameNow;
|
||||
$nationStor->npc_nation_policy = $nationPolicyRoot;
|
||||
return null;
|
||||
}
|
||||
@@ -166,6 +168,7 @@ function applyNationPriority($priority, $nationID, $generalName): ?string
|
||||
function applyGeneralPriority($priority, $nationID, $generalName): ?string
|
||||
{
|
||||
$db = DB::db();
|
||||
$gameNow = GameClock::fromStorage(KVStorage::getStorage($db, 'game_env'))->formatNow();
|
||||
$nationStor = KVStorage::getStorage($db, $nationID, 'nation_env');
|
||||
$generalPolicyRoot = $nationStor->npc_general_policy;
|
||||
|
||||
@@ -206,7 +209,7 @@ function applyGeneralPriority($priority, $nationID, $generalName): ?string
|
||||
|
||||
$generalPolicyRoot['priority'] = $priority;
|
||||
$generalPolicyRoot['prioritySetter'] = $generalName;
|
||||
$generalPolicyRoot['prioritySetTime'] = TimeUtil::now();
|
||||
$generalPolicyRoot['prioritySetTime'] = $gameNow;
|
||||
$nationStor->npc_general_policy = $generalPolicyRoot;
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -77,7 +77,8 @@ $month = $query['month'];
|
||||
$repeatCnt = $query['repeatCnt'];
|
||||
|
||||
$rawAttacker = $query['attackerGeneral'];
|
||||
$rawAttacker['turntime'] = TimeUtil::now();
|
||||
$battleClock = GameClock::fromStorage(KVStorage::getStorage(DB::db(), 'game_env'));
|
||||
$rawAttacker['turntime'] = $battleClock->formatTick($battleClock->nowTick());
|
||||
$rawAttackerCity = $query['attackerCity'];
|
||||
$rawAttackerNation = $query['attackerNation'];
|
||||
|
||||
|
||||
@@ -22,8 +22,8 @@ $db = DB::db();
|
||||
$gameStor = KVStorage::getStorage($db, 'game_env');
|
||||
|
||||
$rootDB = RootDB::db();
|
||||
$oNow = new \DateTimeImmutable();
|
||||
$now = $oNow->format('Y-m-d H:i:s');
|
||||
$clock = GameClock::fromStorage($gameStor);
|
||||
$now = $clock->nowTick();
|
||||
|
||||
$generalID = $db->queryFirstField('SELECT no FROM general WHERE owner = %i', $userID);
|
||||
if(!$generalID){
|
||||
@@ -181,7 +181,7 @@ if ($isCentennialAllStar) {
|
||||
if(key_exists('generalName', $info)){
|
||||
$generalObj->updateVar('name', $info['generalName']);
|
||||
}
|
||||
$generalObj->setAuxVar('next_change', TimeUtil::nowAddMinutes(12 * $turnterm));
|
||||
$generalObj->setAuxVar('next_change', $now + GameClock::TICKS_PER_TURN * 12);
|
||||
|
||||
$userNick = $ownerInfo['name'];
|
||||
$generalObj->setVar('owner_name', $userNick);
|
||||
|
||||
+4
-2
@@ -11,9 +11,11 @@ $db = DB::db();
|
||||
$updated = false;
|
||||
$locked = false;
|
||||
$lastExecuted = TurnExecutionHelper::executeAllCommand($updated, $locked);
|
||||
$clock = GameClock::fromStorage(KVStorage::getStorage($db, 'game_env'));
|
||||
Json::die([
|
||||
'result' => true,
|
||||
'updated' => $updated,
|
||||
'locked' => $locked,
|
||||
'lastExecuted' => $lastExecuted,
|
||||
]);
|
||||
'lastExecutedTick' => $lastExecuted,
|
||||
'lastExecuted' => $clock->formatTick($lastExecuted, true),
|
||||
]);
|
||||
|
||||
+1
-1
@@ -37,7 +37,7 @@ function processWar(string $warSeed, General $attackerGeneral, array $rawAttacke
|
||||
|
||||
$city = new WarUnitCity($rng, $rawDefenderCity, $rawDefenderNation, $year, $month, $startYear);
|
||||
|
||||
$defenderCityGeneralIDList = $db->queryFirstColumn('SELECT no FROM general WHERE nation=%i AND city=%i AND nation!=0', $city->getVar('nation'), $city->getVar('city'));
|
||||
$defenderCityGeneralIDList = $db->queryFirstColumn('SELECT no FROM general WHERE nation=%i AND city=%i AND nation!=0 ORDER BY no', $city->getVar('nation'), $city->getVar('city'));
|
||||
$defenderCityGeneralList = General::createObjListFromDB($defenderCityGeneralIDList, null);
|
||||
|
||||
/** @var WarUnit[] */
|
||||
|
||||
@@ -21,7 +21,7 @@ class BidUniqueAuction extends \sammo\BaseAPI
|
||||
])
|
||||
->rule('int', 'amount')
|
||||
->rule('int', 'auctionID')
|
||||
->rule('boolean', 'extendCloseDate');
|
||||
->rule('boolean', 'extendCloseTick');
|
||||
|
||||
if (!$v->validate()) {
|
||||
return $v->errorStr();
|
||||
@@ -38,7 +38,7 @@ class BidUniqueAuction extends \sammo\BaseAPI
|
||||
{
|
||||
$auctionID = $this->args['auctionID'];
|
||||
$amount = $this->args['amount'];
|
||||
$tryExtendCloseDate = $this->args['extendCloseDate'] ?? false;
|
||||
$tryExtendCloseDate = $this->args['extendCloseTick'] ?? false;
|
||||
|
||||
$generalID = $session->generalID;
|
||||
$general = General::createObjFromDB($generalID);
|
||||
|
||||
@@ -15,6 +15,8 @@ use sammo\General;
|
||||
use sammo\Json;
|
||||
use sammo\TimeUtil;
|
||||
use sammo\Util;
|
||||
use sammo\GameClock;
|
||||
use sammo\KVStorage;
|
||||
|
||||
use function sammo\getAuctionLogRecent;
|
||||
|
||||
@@ -33,12 +35,13 @@ class GetActiveResourceAuctionList 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'));
|
||||
|
||||
$buyRiceList = [];
|
||||
$sellRiceList = [];
|
||||
/** @var AuctionInfo[] */
|
||||
$auctions = array_map(fn ($raw) => AuctionInfo::fromArray($raw), $db->query(
|
||||
'SELECT * FROM `ng_auction` WHERE `type` IN %ls AND `finished` = 0 ORDER BY `close_date` ASC',
|
||||
'SELECT * FROM `ng_auction` WHERE `type` IN %ls AND `finished` = 0 ORDER BY `close_tick` ASC',
|
||||
[
|
||||
AuctionType::BuyRice->value,
|
||||
AuctionType::SellRice->value,
|
||||
@@ -87,8 +90,8 @@ class GetActiveResourceAuctionList extends \sammo\BaseAPI
|
||||
'type' => $auction->type->value,
|
||||
'hostGeneralID' => $auction->hostGeneralID,
|
||||
'hostName' => $auction->detail->hostName,
|
||||
'openDate' => TimeUtil::format($auction->openDate, false),
|
||||
'closeDate' => TimeUtil::format($auction->closeDate, false),
|
||||
'openDate' => $clock->formatTick($auction->openTick),
|
||||
'closeDate' => $clock->formatTick($auction->closeTick),
|
||||
'amount' => $auction->detail->amount,
|
||||
'startBidAmount' => $auction->detail->startBidAmount,
|
||||
'finishBidAmount' => $auction->detail->finishBidAmount,
|
||||
|
||||
@@ -14,6 +14,8 @@ use sammo\Enums\GeneralQueryMode;
|
||||
use sammo\Enums\InheritanceKey;
|
||||
use sammo\InheritancePointManager;
|
||||
use sammo\TimeUtil;
|
||||
use sammo\GameClock;
|
||||
use sammo\KVStorage;
|
||||
use sammo\Validator;
|
||||
use sammo\General;
|
||||
|
||||
@@ -42,6 +44,7 @@ class GetUniqueItemAuctionDetail 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'));
|
||||
|
||||
$generalID = $session->generalID;
|
||||
$auctionID = $this->args['auctionID'];
|
||||
@@ -92,9 +95,11 @@ class GetUniqueItemAuctionDetail extends \sammo\BaseAPI
|
||||
'target' => $auction->target,
|
||||
'isCallerHost' => $auction->hostGeneralID === $generalID,
|
||||
'hostName' => $auction->detail->hostName,
|
||||
'closeDate' => TimeUtil::format($auction->closeDate, false),
|
||||
'closeDate' => $clock->formatTick($auction->closeTick),
|
||||
'remainCloseDateExtensionCnt' => $auction->detail->remainCloseDateExtensionCnt,
|
||||
'availableLatestBidCloseDate' => TimeUtil::format($auction->detail->availableLatestBidCloseDate, false),
|
||||
'availableLatestBidCloseDate' => $auction->detail->availableLatestBidCloseTick === null
|
||||
? null
|
||||
: $clock->formatTick($auction->detail->availableLatestBidCloseTick),
|
||||
],
|
||||
'bidList' => $responseBid,
|
||||
'obfuscatedName' => $obfuscatedName,
|
||||
|
||||
@@ -12,6 +12,8 @@ use sammo\Enums\APIRecoveryType;
|
||||
use sammo\Enums\AuctionType;
|
||||
use sammo\TimeUtil;
|
||||
use sammo\Util;
|
||||
use sammo\GameClock;
|
||||
use sammo\KVStorage;
|
||||
|
||||
class GetUniqueItemAuctionList extends \sammo\BaseAPI
|
||||
{
|
||||
@@ -28,12 +30,13 @@ class GetUniqueItemAuctionList 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'));
|
||||
|
||||
$generalID = $session->generalID;
|
||||
|
||||
/** @var AuctionInfo[] */
|
||||
$auctions = array_map(fn($raw)=>AuctionInfo::fromArray($raw), $db->query(
|
||||
'SELECT * FROM `ng_auction` WHERE `type` = %s ORDER BY `close_date` ASC',
|
||||
'SELECT * FROM `ng_auction` WHERE `type` = %s ORDER BY `close_tick` ASC',
|
||||
AuctionType::UniqueItem->value
|
||||
) ?? []);
|
||||
|
||||
@@ -85,9 +88,11 @@ class GetUniqueItemAuctionList extends \sammo\BaseAPI
|
||||
'target' => $auction->target,
|
||||
'isCallerHost' => $auction->hostGeneralID === $generalID,
|
||||
'hostName' => $auction->detail->hostName,
|
||||
'closeDate' => TimeUtil::format($auction->closeDate, false),
|
||||
'closeDate' => $clock->formatTick($auction->closeTick),
|
||||
'remainCloseDateExtensionCnt' => $auction->detail->remainCloseDateExtensionCnt,
|
||||
'availableLatestBidCloseDate' => TimeUtil::format($auction->detail->availableLatestBidCloseDate, false),
|
||||
'availableLatestBidCloseDate' => $auction->detail->availableLatestBidCloseTick === null
|
||||
? null
|
||||
: $clock->formatTick($auction->detail->availableLatestBidCloseTick),
|
||||
'highestBid' => [
|
||||
'generalName' => $highestBid->aux->generalName,
|
||||
'amount' => $highestBid->amount,
|
||||
|
||||
@@ -7,9 +7,10 @@ use DateTimeInterface;
|
||||
use sammo\DB;
|
||||
use sammo\Enums\APIRecoveryType;
|
||||
use sammo\GameConst;
|
||||
use sammo\GameClock;
|
||||
use sammo\Json;
|
||||
use sammo\KVStorage;
|
||||
use sammo\TimeUtil;
|
||||
use sammo\Util;
|
||||
|
||||
use function sammo\cutTurn;
|
||||
|
||||
@@ -31,6 +32,7 @@ class GetReservedCommand extends \sammo\BaseAPI
|
||||
|
||||
$commandList = [];
|
||||
$gameStor = KVStorage::getStorage($db, 'game_env');
|
||||
$clock = GameClock::fromStorage($gameStor);
|
||||
$generalID = $session->generalID;
|
||||
|
||||
$invalidTurnList = 0;
|
||||
@@ -82,11 +84,13 @@ class GetReservedCommand extends \sammo\BaseAPI
|
||||
|
||||
return [
|
||||
'result' => true,
|
||||
'turnTime' => $turnTime,
|
||||
'turnTimeTick' => Util::toInt($turnTime),
|
||||
'turnTime' => $clock->formatTick(Util::toInt($turnTime)),
|
||||
'turnTerm' => $turnTerm,
|
||||
'year' => $year,
|
||||
'month' => $month,
|
||||
'date' => TimeUtil::now(true),
|
||||
'date' => $clock->formatTick($clock->nowTick(), true),
|
||||
'clockMode' => $clock->getMode(),
|
||||
'turn' => $commandList,
|
||||
'autorun_limit' => $generalAux['autorun_limit'] ?? null,
|
||||
];
|
||||
|
||||
@@ -11,7 +11,8 @@ use sammo\Session;
|
||||
use sammo\General;
|
||||
use sammo\JosaUtil;
|
||||
use sammo\KVStorage;
|
||||
use sammo\TimeUtil;
|
||||
use sammo\GameClock;
|
||||
use sammo\Util;
|
||||
|
||||
use function sammo\addTurn;
|
||||
use function sammo\increaseRefresh;
|
||||
@@ -37,6 +38,8 @@ class DieOnPrestart extends \sammo\BaseAPI
|
||||
$db = DB::db();
|
||||
$gameStor = KVStorage::getStorage($db, 'game_env');
|
||||
$gameStor->cacheValues(['turnterm', 'opentime', 'turntime', 'year', 'month']);
|
||||
$clock = GameClock::fromStorage($gameStor);
|
||||
$nowTick = $clock->nowTick();
|
||||
|
||||
$general = $db->queryFirstRow('SELECT no,name,nation,owner_name,npc FROM general WHERE owner=%i AND npc = 0', $userID);
|
||||
if (!$general) {
|
||||
@@ -67,9 +70,9 @@ class DieOnPrestart extends \sammo\BaseAPI
|
||||
}
|
||||
|
||||
$targetTime = $generalObj->getAuxVar('prestart_delete_after');
|
||||
if (!is_string($targetTime) || $targetTime === '') {
|
||||
if (!is_int($targetTime)) {
|
||||
$targetTime = addTurn(
|
||||
$lastRefresh ?: TimeUtil::now(),
|
||||
$lastRefresh === null ? $nowTick : Util::toInt($lastRefresh),
|
||||
$gameStor->turnterm,
|
||||
GameConst::$minTurnDieOnPrestart
|
||||
);
|
||||
@@ -78,8 +81,8 @@ class DieOnPrestart extends \sammo\BaseAPI
|
||||
}
|
||||
|
||||
//서버 가오픈시 할 수 있는 행동
|
||||
if ($targetTime > TimeUtil::now()) {
|
||||
$targetTimeShort = substr($targetTime, 0, 19);
|
||||
if ($targetTime > $nowTick) {
|
||||
$targetTimeShort = $clock->formatTick($targetTime);
|
||||
return "아직 삭제할 수 없습니다. {$targetTimeShort} 부터 가능합니다.";
|
||||
}
|
||||
|
||||
|
||||
@@ -14,13 +14,13 @@ use sammo\Enums\GeneralColumn;
|
||||
use sammo\Enums\GeneralQueryMode;
|
||||
use sammo\Enums\RankColumn;
|
||||
use sammo\GameConst;
|
||||
use sammo\GameClock;
|
||||
use sammo\General;
|
||||
use sammo\KVStorage;
|
||||
use sammo\LastTurn;
|
||||
use sammo\Validator;
|
||||
|
||||
use sammo\Session;
|
||||
use sammo\TimeUtil;
|
||||
use sammo\Util;
|
||||
|
||||
use function sammo\buildNationCommandClass;
|
||||
@@ -105,6 +105,7 @@ class GetFrontInfo extends \sammo\BaseAPI
|
||||
$db = DB::db();
|
||||
|
||||
$gameStor = KVStorage::getStorage($db, 'game_env');
|
||||
$clock = GameClock::fromStorage($gameStor);
|
||||
$gameStor->cacheValues(['isunited', 'opentime', 'refresh']);
|
||||
|
||||
$lastHistoryID = $this->args['lastWorldHistoryID'];
|
||||
@@ -158,6 +159,7 @@ class GetFrontInfo extends \sammo\BaseAPI
|
||||
private function generateGlobalInfo(MeekroDB $db): array
|
||||
{
|
||||
$gameStor = KVStorage::getStorage($db, 'game_env');
|
||||
$clock = GameClock::fromStorage($gameStor);
|
||||
|
||||
[
|
||||
$scenarioText, $extendedGeneral, $isFiction, $npcMode,
|
||||
@@ -182,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;
|
||||
}
|
||||
}
|
||||
@@ -210,7 +213,8 @@ class GetFrontInfo extends \sammo\BaseAPI
|
||||
'month' => $month,
|
||||
'autorunUser' => $autorunUser,
|
||||
'turnterm' => $turnterm,
|
||||
'lastExecuted' => $lastExecuted,
|
||||
'lastExecutedTick' => $lastExecuted,
|
||||
'lastExecuted' => $clock->formatTick(Util::toInt($lastExecuted), true),
|
||||
'lastVoteID' => $lastVoteID,
|
||||
'develCost' => $develCost,
|
||||
'noticeMsg' => $noticeMsg,
|
||||
@@ -224,7 +228,8 @@ class GetFrontInfo extends \sammo\BaseAPI
|
||||
'isLocked' => $isLocked,
|
||||
'tournamentType' => $tournamentType,
|
||||
'tournamentState' => $tournamentState,
|
||||
'tournamentTime' => $tournamentTime,
|
||||
'tournamentTimeTick' => $tournamentTime,
|
||||
'tournamentTime' => $tournamentTime === null ? null : $clock->formatTick(Util::toInt($tournamentTime)),
|
||||
'genCount' => $globalGenCount,
|
||||
'generalCntLimit' => $generalCntLimit,
|
||||
'serverCnt' => $serverCnt,
|
||||
@@ -361,6 +366,7 @@ class GetFrontInfo extends \sammo\BaseAPI
|
||||
|
||||
public function generateGeneralInfo(MeekroDB $db, General $general, array $rawNation): array
|
||||
{
|
||||
$clock = GameClock::fromStorage(KVStorage::getStorage($db, 'game_env'));
|
||||
|
||||
$permission = checkSecretPermission($general->getRaw());
|
||||
|
||||
@@ -425,8 +431,12 @@ class GetFrontInfo extends \sammo\BaseAPI
|
||||
'crew' => $general->getVar(GeneralColumn::crew), // number;
|
||||
'train' => $general->getVar(GeneralColumn::train), // number;
|
||||
'atmos' => $general->getVar(GeneralColumn::atmos), // number;
|
||||
'turntime' => $general->getVar(GeneralColumn::turntime), // string;
|
||||
'recent_war' => $general->getVar(GeneralColumn::recent_war), // string;
|
||||
'turntimeTick' => $general->getTurnTick(), // number;
|
||||
'turntime' => $general->getTurnTime(), // string;
|
||||
'recent_war_tick' => $general->getVar(GeneralColumn::recent_war), // number|null;
|
||||
'recent_war' => $general->getVar(GeneralColumn::recent_war) === null
|
||||
? null
|
||||
: $clock->formatTick(Util::toInt($general->getVar(GeneralColumn::recent_war)), true), // string|null;
|
||||
'horse' => $general->getVar(GeneralColumn::horse), // GameObjClassKey;
|
||||
'weapon' => $general->getVar(GeneralColumn::weapon), // GameObjClassKey;
|
||||
'book' => $general->getVar(GeneralColumn::book), // GameObjClassKey;
|
||||
@@ -544,7 +554,7 @@ class GetFrontInfo extends \sammo\BaseAPI
|
||||
'result' => false,
|
||||
'reason' => '접속 제한중입니다.',
|
||||
'recovery' => APIRecoveryType::GameQuota,
|
||||
'recovery_arg' => $general->getVar('turntime'),
|
||||
'recovery_arg' => $general->getTurnTime(),
|
||||
];
|
||||
}
|
||||
|
||||
|
||||
@@ -11,6 +11,7 @@ use sammo\Enums\APIRecoveryType;
|
||||
use sammo\Enums\GeneralAccessLogColumn;
|
||||
use sammo\Enums\RankColumn;
|
||||
use sammo\GameConst;
|
||||
use sammo\GameClock;
|
||||
use sammo\GameUnitConst;
|
||||
use sammo\General;
|
||||
use sammo\InheritancePointManager;
|
||||
@@ -165,6 +166,7 @@ class Join extends \sammo\BaseAPI
|
||||
$db = DB::db();
|
||||
$gameStor = KVStorage::getStorage($db, 'game_env');
|
||||
$gameStor->cacheValues(['year', 'month', 'maxgeneral', 'scenario', 'show_img_level', 'block_general_create', 'turnterm', 'turntime', 'genius', 'npcmode']);
|
||||
$clock = GameClock::fromStorage($gameStor);
|
||||
########## 동일 정보 존재여부 확인. ##########
|
||||
|
||||
$block_general_create = $gameStor->getValue('block_general_create');
|
||||
@@ -222,7 +224,7 @@ class Join extends \sammo\BaseAPI
|
||||
|
||||
$userLogger = new UserLogger($userID, $admin['year'], $admin['month'], false);
|
||||
|
||||
$now = TimeUtil::now(false);
|
||||
$now = $clock->nowTick();
|
||||
$rng = new RandUtil(new LiteHashDRBG(Util::simpleSerialize(
|
||||
UniqueConst::$hiddenSeed,
|
||||
'MakeGeneral',
|
||||
@@ -360,17 +362,14 @@ class Join extends \sammo\BaseAPI
|
||||
|
||||
$userLogger->push(sprintf("턴 시간 %02d:%02d 로 지정", intdiv($inheritTurntime, 60), $inheritTurntime % 60), "inheritPoint");
|
||||
|
||||
$inheritTurntime += $rng->nextRangeInt(0, 999999) / 1000000;
|
||||
|
||||
$turntime = new \DateTimeImmutable(cutTurn($admin['turntime'], $admin['turnterm']));
|
||||
$turntime = $turntime->add(TimeUtil::secondsToDateInterval($inheritTurntime));
|
||||
$turntime = TimeUtil::format($turntime, true);
|
||||
$inheritTurnMicrosecond = $rng->nextRangeInt(0, 999999);
|
||||
$turntime = cutTurn(Util::toInt($admin['turntime']), $admin['turnterm'])
|
||||
+ $clock->ticksFromSeconds($inheritTurntime)
|
||||
+ intdiv($inheritTurnMicrosecond * $clock->ticksPerSecond(), 1_000_000);
|
||||
} else {
|
||||
$turntime = getRandTurn($rng, $admin['turnterm'], new \DateTimeImmutable($admin['turntime']));
|
||||
$turntime = getRandTurn($rng, $admin['turnterm'], Util::toInt($admin['turntime']));
|
||||
}
|
||||
|
||||
|
||||
$now = TimeUtil::now(true);
|
||||
if ($now >= $turntime) {
|
||||
$turntime = addTurn($turntime, $admin['turnterm']);
|
||||
}
|
||||
|
||||
@@ -8,6 +8,8 @@ use DateTimeInterface;
|
||||
use sammo\Enums\APIRecoveryType;
|
||||
use sammo\TurnExecutionHelper;
|
||||
use sammo\UniqueConst;
|
||||
use sammo\GameClock;
|
||||
use sammo\KVStorage;
|
||||
|
||||
class ExecuteEngine extends \sammo\BaseAPI
|
||||
{
|
||||
@@ -35,11 +37,13 @@ class ExecuteEngine extends \sammo\BaseAPI
|
||||
$updated = false;
|
||||
$locked = false;
|
||||
$lastExecuted = TurnExecutionHelper::executeAllCommand($updated, $locked);
|
||||
$clock = GameClock::fromStorage(KVStorage::getStorage(DB::db(), 'game_env'));
|
||||
return [
|
||||
'result' => true,
|
||||
'updated' => $updated,
|
||||
'locked' => $locked,
|
||||
'lastExecuted' => $lastExecuted,
|
||||
'lastExecutedTick' => $lastExecuted,
|
||||
'lastExecuted' => $clock->formatTick($lastExecuted, true),
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
namespace sammo\API\Global;
|
||||
|
||||
use sammo\DB;
|
||||
use sammo\GameClock;
|
||||
use sammo\Enums\APIRecoveryType;
|
||||
use sammo\Json;
|
||||
use sammo\KVStorage;
|
||||
@@ -145,7 +146,8 @@ class GeneralList extends \sammo\BaseAPI
|
||||
|
||||
|
||||
if (static::$withToken) {
|
||||
$now = (new \DateTimeImmutable())->format('Y-m-d H:i:s');
|
||||
$gameStor = KVStorage::getStorage($db, 'game_env');
|
||||
$now = GameClock::fromStorage($gameStor)->nowTick();
|
||||
$tokens = [];
|
||||
foreach ($db->query('SELECT * FROM select_npc_token WHERE `valid_until`>=%s', $now) as $token) {
|
||||
$validUntil = $token['valid_until'];
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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'),
|
||||
[]
|
||||
);
|
||||
|
||||
@@ -64,13 +64,11 @@ class ResetTurnTime extends \sammo\BaseAPI
|
||||
$gameStor = KVStorage::getStorage($db, 'game_env');
|
||||
$turnTerm = $gameStor->getValue('turnterm');
|
||||
|
||||
$currTurnTime = new DateTimeImmutable($general->getTurnTime());
|
||||
|
||||
$rng = new RandUtil(new LiteHashDRBG(Util::simpleSerialize(
|
||||
UniqueConst::$hiddenSeed,
|
||||
'ResetTurnTime',
|
||||
$userID,
|
||||
$general->getAuxVar('nextTurnTimeBase') ?? $general->getTurnTime()
|
||||
$general->getAuxVar('nextTurnTimeBase') ?? $general->getTurnTick()
|
||||
)));
|
||||
|
||||
$afterTurn = $rng->nextFloat1() * $turnTerm * 60;
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -8,6 +8,7 @@ use sammo\AppConf;
|
||||
use sammo\Enums\APIRecoveryType;
|
||||
use sammo\KVStorage;
|
||||
use sammo\RootDB;
|
||||
use sammo\RemoteUserIconUploadClient;
|
||||
use sammo\TimeUtil;
|
||||
use sammo\UniqueConst;
|
||||
use sammo\Validator;
|
||||
@@ -60,22 +61,33 @@ class UploadImage extends \sammo\BaseAPI
|
||||
$imgName = hash_final($oMD);
|
||||
$imgFullName = "{$imgName}.{$extension}";
|
||||
|
||||
$destDir = AppConf::getUserIconPathFS() . '/uploaded_image';
|
||||
$destPath = "{$destDir}/{$imgFullName}";
|
||||
$remotePath = null;
|
||||
if (RemoteUserIconUploadClient::isConfiguredEnabled()) {
|
||||
try {
|
||||
RemoteUserIconUploadClient::uploadContentConfigured($imgFullName, $contentType, $imageData);
|
||||
$remotePath = RemoteUserIconUploadClient::getConfiguredContentPublicUrl($imgFullName);
|
||||
} catch (\Throwable $error) {
|
||||
RemoteUserIconUploadClient::logFailure('content-image', $error);
|
||||
return '원격 이미지 저장소 업로드에 실패했습니다!';
|
||||
}
|
||||
} else {
|
||||
$destDir = AppConf::getUserIconPathFS() . '/uploaded_image';
|
||||
$destPath = "{$destDir}/{$imgFullName}";
|
||||
|
||||
if (!file_exists($destPath)) {
|
||||
if (!file_exists($destDir)) {
|
||||
mkdir($destDir);
|
||||
}
|
||||
if (!is_dir($destDir)) {
|
||||
return '버그! 업로드 경로 확인!';
|
||||
}
|
||||
if (!is_writable($destDir)) {
|
||||
return '버그! 업로드 권한 확인!';
|
||||
}
|
||||
if (!file_exists($destPath)) {
|
||||
if (!file_exists($destDir)) {
|
||||
mkdir($destDir);
|
||||
}
|
||||
if (!is_dir($destDir)) {
|
||||
return '버그! 업로드 경로 확인!';
|
||||
}
|
||||
if (!is_writable($destDir)) {
|
||||
return '버그! 업로드 권한 확인!';
|
||||
}
|
||||
|
||||
if (!file_put_contents($destPath, $imageData)) {
|
||||
return '업로드에 실패했습니다!';
|
||||
if (!file_put_contents($destPath, $imageData)) {
|
||||
return '업로드에 실패했습니다!';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -96,7 +108,7 @@ class UploadImage extends \sammo\BaseAPI
|
||||
|
||||
return [
|
||||
'result' => true,
|
||||
'path'=>AppConf::getUserIconPathWeb().'/uploaded_image/'.$imgFullName,
|
||||
'path'=>$remotePath ?? AppConf::getUserIconPathWeb().'/uploaded_image/'.$imgFullName,
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,6 +8,7 @@ use sammo\Enums\APIRecoveryType;
|
||||
use sammo\Enums\GeneralLiteQueryMode;
|
||||
use sammo\Enums\GeneralQueryMode;
|
||||
use sammo\General;
|
||||
use sammo\GameClock;
|
||||
use sammo\GeneralLite;
|
||||
use sammo\Session;
|
||||
use sammo\Util;
|
||||
@@ -150,6 +151,11 @@ class GeneralList extends \sammo\BaseAPI
|
||||
|
||||
$gameStor = \sammo\KVStorage::getStorage($db, 'game_env');
|
||||
$env = $gameStor->getValues(['year', 'month', 'turntime', 'turnterm', 'autorun_user', 'killturn']);
|
||||
$clock = GameClock::isInitialized($gameStor) ? GameClock::fromStorage($gameStor) : null;
|
||||
$formatStoredTime = static fn (mixed $value): string => $clock === null
|
||||
? (string)$value
|
||||
: $clock->formatTick(Util::toInt($value));
|
||||
$env['turntime'] = $formatStoredTime($env['turntime']);
|
||||
|
||||
$me = $db->queryFirstRow(
|
||||
'SELECT refresh_score, turntime, belong, nation, officer_level, permission, penalty FROM `general`
|
||||
@@ -186,7 +192,7 @@ class GeneralList extends \sammo\BaseAPI
|
||||
if (!key_exists($troopLeaderID, $rawGeneralList)) {
|
||||
continue;
|
||||
}
|
||||
$troopTurnTime = $rawGeneralList[$troopLeaderID]['turntime'];
|
||||
$troopTurnTime = $formatStoredTime($rawGeneralList[$troopLeaderID]['turntime']);
|
||||
$troops[$troopLeaderID] = new ArrayObject([
|
||||
'id' => $troopLeaderID,
|
||||
'name' => $troopName,
|
||||
@@ -264,8 +270,10 @@ class GeneralList extends \sammo\BaseAPI
|
||||
'honorText' => fn ($rawGeneral) => getHonor($rawGeneral['experience']),
|
||||
'dedLevelText' => fn ($rawGeneral) => getDedLevelText($rawGeneral['dedlevel']),
|
||||
//'0000-00-00 11:23';
|
||||
'turntime' => fn ($rawGeneral) => substr($rawGeneral['turntime'], 0, 19),
|
||||
'recent_war' => fn ($rawGeneral) => substr($rawGeneral['recent_war'], 0, 19),
|
||||
'turntime' => fn ($rawGeneral) => substr($formatStoredTime($rawGeneral['turntime']), 0, 19),
|
||||
'recent_war' => fn ($rawGeneral) => $rawGeneral['recent_war'] === null
|
||||
? null
|
||||
: substr($formatStoredTime($rawGeneral['recent_war']), 0, 19),
|
||||
'bill' => fn ($rawGeneral) => getBillByLevel($rawGeneral['dedlevel']),
|
||||
'reservedCommand' => fn ($rawGeneral) => $reservedCommand[$rawGeneral['no']] ?? null,
|
||||
'autorun_limit' => fn ($rawGeneral) => ($rawGeneral['aux'] ?? [])['autorun_limit'] ?? 0,
|
||||
|
||||
@@ -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'],
|
||||
|
||||
@@ -8,10 +8,10 @@ use sammo\DB;
|
||||
use sammo\Enums\APIRecoveryType;
|
||||
use sammo\Enums\GeneralQueryMode;
|
||||
use sammo\GameConst;
|
||||
use sammo\GameClock;
|
||||
use sammo\General;
|
||||
use sammo\Json;
|
||||
use sammo\KVStorage;
|
||||
use sammo\TimeUtil;
|
||||
use sammo\Util;
|
||||
|
||||
use function sammo\checkLimit;
|
||||
@@ -39,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(
|
||||
@@ -51,7 +52,8 @@ class GetReservedCommand extends \sammo\BaseAPI
|
||||
$nationID = $me['nation'];
|
||||
$limitState = checkLimit($me['refresh_score']);
|
||||
if ($limitState >= 2) {
|
||||
return "접속 제한중입니다. 1턴 이내에 너무 많은 갱신을 하셨습니다. (다음 갱신 가능 시각 : {$me['turntime']})";
|
||||
$limitTime = GameClock::fromStorage($gameStor)->formatTick(Util::toInt($me['turntime']), true);
|
||||
return "접속 제한중입니다. 1턴 이내에 너무 많은 갱신을 하셨습니다. (다음 갱신 가능 시각 : {$limitTime})";
|
||||
}
|
||||
|
||||
$permission = checkSecretPermission($me);
|
||||
@@ -156,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),
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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,
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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 [
|
||||
|
||||
@@ -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', [
|
||||
|
||||
@@ -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 '설문조사가 종료되었습니다.';
|
||||
}
|
||||
|
||||
|
||||
@@ -30,8 +30,9 @@ abstract class AbsFromUserPool extends AbsGeneralPool{
|
||||
}
|
||||
|
||||
static public function pickGeneralFromPool(\MeekroDB $db, RandUtil $rng, int $owner, int $pickCnt, ?string $prefix=null):array{
|
||||
$oNow = new \DateTimeImmutable();
|
||||
$now = $oNow->format('Y-m-d H:i:s');
|
||||
$gameStor = KVStorage::getStorage($db, 'game_env');
|
||||
$clock = GameClock::fromStorage($gameStor);
|
||||
$now = $clock->nowTick();
|
||||
|
||||
$db->update('select_pool', [
|
||||
'reserved_until'=>null,
|
||||
@@ -48,9 +49,8 @@ abstract class AbsFromUserPool extends AbsGeneralPool{
|
||||
throw new \RuntimeException('pool 부족');
|
||||
}
|
||||
|
||||
$gameStor = KVStorage::getStorage($db, 'game_env');
|
||||
$result = [];
|
||||
$validUntil = TimeUtil::nowAddMinutes(2 * $gameStor->turnterm);
|
||||
$result = [];
|
||||
$validUntil = $now + GameClock::TICKS_PER_TURN * 2;
|
||||
while(count($result) < $pickCnt){
|
||||
$cand = $rng->choiceUsingWeightPair($pool);
|
||||
$poolID = $cand['id'];
|
||||
|
||||
@@ -34,7 +34,7 @@ abstract class AbsGeneralPool{
|
||||
* specialWar
|
||||
*/
|
||||
|
||||
public function __construct(\MeekroDB $db, RandUtil $rng, array $info, string $validUntil)
|
||||
public function __construct(\MeekroDB $db, RandUtil $rng, array $info, int $validUntil)
|
||||
{
|
||||
$this->db = $db;
|
||||
$this->info = $info;
|
||||
@@ -92,7 +92,7 @@ abstract class AbsGeneralPool{
|
||||
return $this->builder;
|
||||
}
|
||||
|
||||
public function getValidUntil():string{
|
||||
public function getValidUntil():int{
|
||||
return $this->validUntil;
|
||||
}
|
||||
|
||||
@@ -109,4 +109,4 @@ abstract class AbsGeneralPool{
|
||||
|
||||
abstract public static function getPoolName():string;
|
||||
abstract public static function initPool(\MeekroDB $db);
|
||||
}
|
||||
}
|
||||
|
||||
+55
-54
@@ -146,40 +146,35 @@ abstract class Auction
|
||||
return $this->info;
|
||||
}
|
||||
|
||||
public function shrinkCloseDate(?DateTimeInterface $date): ?string
|
||||
public function shrinkCloseTick(?int $tick): ?string
|
||||
{
|
||||
if ($date === null) {
|
||||
$date = new DateTimeImmutable();
|
||||
}
|
||||
|
||||
$this->info->closeDate = $date;
|
||||
$db = DB::db();
|
||||
$clock = GameClock::fromStorage(KVStorage::getStorage($db, 'game_env'));
|
||||
$this->info->closeTick = $tick ?? $clock->nowTick();
|
||||
$db->update('ng_auction', $this->info->toArray('id'), 'id = %i', $this->info->id);
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public function extendLatestBidCloseDate(?DateTimeInterface $date): ?string
|
||||
public function extendLatestBidCloseTick(?int $tick): ?string
|
||||
{
|
||||
if ($date === null) {
|
||||
if ($tick === null) {
|
||||
$db = DB::db();
|
||||
$gameStor = KVStorage::getStorage($db, 'game_env');
|
||||
$clock = GameClock::fromStorage($gameStor);
|
||||
$turnTerm = $gameStor->getValue('turnterm');
|
||||
$date = $this->info->closeDate->add(TimeUtil::secondsToDateInterval(
|
||||
max(static::MIN_EXTENSION_MINUTES_PER_BID, $turnTerm * static::COEFF_EXTENSION_MINUTES_PER_BID) * 60
|
||||
));
|
||||
$tick = $this->info->closeTick + $clock->ticksFromMinutes(
|
||||
max(static::MIN_EXTENSION_MINUTES_PER_BID, $turnTerm * static::COEFF_EXTENSION_MINUTES_PER_BID)
|
||||
);
|
||||
}
|
||||
else{
|
||||
$date = DateTimeImmutable::createFromInterface($date);
|
||||
}
|
||||
if ($this->info->detail->availableLatestBidCloseDate !== null && $date < $this->info->detail->availableLatestBidCloseDate) {
|
||||
if ($this->info->detail->availableLatestBidCloseTick !== null && $tick < $this->info->detail->availableLatestBidCloseTick) {
|
||||
return '기간보다 짧습니다.';
|
||||
}
|
||||
$this->info->detail->availableLatestBidCloseDate = $date;
|
||||
$this->info->detail->availableLatestBidCloseTick = $tick;
|
||||
return null;
|
||||
}
|
||||
|
||||
public function extendCloseDate(DateTimeInterface $date, bool $force = false): ?string
|
||||
public function extendCloseTick(int $tick, bool $force = false): ?string
|
||||
{
|
||||
if (!$force) {
|
||||
if ($this->info->detail->remainCloseDateExtensionCnt === null) {
|
||||
@@ -193,12 +188,11 @@ abstract class Auction
|
||||
}
|
||||
}
|
||||
|
||||
if ($date < $this->info->closeDate) {
|
||||
if ($tick < $this->info->closeTick) {
|
||||
return '종료 기간보다 짧습니다.';
|
||||
}
|
||||
|
||||
$closeDate = DateTimeImmutable::createFromInterface($date);
|
||||
$this->info->closeDate = $closeDate;
|
||||
$this->info->closeTick = $tick;
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -245,12 +239,13 @@ abstract class Auction
|
||||
|
||||
//TODO: 전역 알림이 나타나야한다. 일반 메시지보다는 중요하고, 메시지보단 약하게..
|
||||
//TODO: 바로가기를 제공하는 편이 좋을 것 같다.
|
||||
$clock = GameClock::fromStorage(KVStorage::getStorage($db, 'game_env'));
|
||||
$msg = new Message(
|
||||
MessageType::private,
|
||||
$src,
|
||||
$dest,
|
||||
$reason,
|
||||
new DateTime(),
|
||||
DateTime::createFromImmutable($clock->tickToDateTime($clock->nowTick())),
|
||||
new DateTime('9999-12-31'),
|
||||
[]
|
||||
);
|
||||
@@ -275,7 +270,12 @@ abstract class Auction
|
||||
$db->update('ng_auction', $this->info->toArray('id'), 'id = %i', $this->info->id);
|
||||
}
|
||||
|
||||
private function bidInheritPoint(int $amount, \DateTimeImmutable $now, bool $tryExtendCloseDate): ?string
|
||||
private function bidInheritPoint(
|
||||
int $amount,
|
||||
int $nowTick,
|
||||
\DateTimeImmutable $nowDate,
|
||||
bool $tryExtendCloseDate,
|
||||
): ?string
|
||||
{
|
||||
$db = DB::db();
|
||||
|
||||
@@ -311,7 +311,7 @@ abstract class Auction
|
||||
$general->getVar('owner'),
|
||||
$general->getID(),
|
||||
$amount,
|
||||
$now,
|
||||
$nowDate,
|
||||
new AuctionBidItemData(
|
||||
$general->getVar('owner_name'),
|
||||
$obfuscatedName,
|
||||
@@ -324,15 +324,16 @@ abstract class Auction
|
||||
}
|
||||
|
||||
$gameStor = KVStorage::getStorage($db, 'game_env');
|
||||
$clock = GameClock::fromStorage($gameStor);
|
||||
$turnTerm = $gameStor->getValue('turnterm');
|
||||
|
||||
if ($this->info->detail->availableLatestBidCloseDate !== null) {
|
||||
$extendedCloseDate = $now->add(TimeUtil::secondsToDateInterval(
|
||||
max(static::MIN_EXTENSION_MINUTES_PER_BID, $turnTerm * static::COEFF_EXTENSION_MINUTES_PER_BID) * 60
|
||||
));
|
||||
if ($this->info->detail->availableLatestBidCloseTick !== null) {
|
||||
$extendedCloseTick = $nowTick + $clock->ticksFromMinutes(
|
||||
max(static::MIN_EXTENSION_MINUTES_PER_BID, $turnTerm * static::COEFF_EXTENSION_MINUTES_PER_BID)
|
||||
);
|
||||
|
||||
if ($extendedCloseDate > $this->info->closeDate && $this->info->closeDate < $this->info->detail->availableLatestBidCloseDate) {
|
||||
$this->extendCloseDate(min($extendedCloseDate, $this->info->detail->availableLatestBidCloseDate), true);
|
||||
if ($extendedCloseTick > $this->info->closeTick && $this->info->closeTick < $this->info->detail->availableLatestBidCloseTick) {
|
||||
$this->extendCloseTick(min($extendedCloseTick, $this->info->detail->availableLatestBidCloseTick), true);
|
||||
$this->applyDB();
|
||||
}
|
||||
}
|
||||
@@ -356,12 +357,16 @@ abstract class Auction
|
||||
return '경매가 이미 끝났습니다.';
|
||||
}
|
||||
|
||||
$now = new \DateTimeImmutable();
|
||||
$db = DB::db();
|
||||
$gameStor = KVStorage::getStorage($db, 'game_env');
|
||||
$clock = GameClock::fromStorage($gameStor);
|
||||
$nowTick = $clock->nowTick();
|
||||
$nowDate = $clock->tickToDateTime($nowTick);
|
||||
|
||||
if ($auctionInfo->closeDate < $now) {
|
||||
if ($auctionInfo->closeTick < $nowTick) {
|
||||
return '경매가 이미 끝났습니다.';
|
||||
}
|
||||
if ($auctionInfo->openDate > $now) {
|
||||
if ($auctionInfo->openTick > $nowTick) {
|
||||
return '경매가 아직 시작되지 않았습니다.';
|
||||
}
|
||||
|
||||
@@ -377,13 +382,11 @@ abstract class Auction
|
||||
|
||||
|
||||
if ($auctionInfo->reqResource === ResourceType::inheritancePoint) {
|
||||
return $this->bidInheritPoint($amount, $now, $tryExtendCloseDate);
|
||||
return $this->bidInheritPoint($amount, $nowTick, $nowDate, $tryExtendCloseDate);
|
||||
}
|
||||
|
||||
//reqResource는 말 그대로 '구매자가 내야하는 자원'이다.
|
||||
|
||||
$db = DB::db();
|
||||
|
||||
$highestBid = $this->getHighestBid();
|
||||
if (!$auctionInfo->detail->isReverse) {
|
||||
if ($highestBid !== null && $amount <= $highestBid->amount) {
|
||||
@@ -421,7 +424,7 @@ abstract class Auction
|
||||
$general->getVar('owner'),
|
||||
$general->getID(),
|
||||
$amount,
|
||||
$now,
|
||||
$nowDate,
|
||||
new AuctionBidItemData(
|
||||
$general->getVar('owner_name'),
|
||||
$general->getName(),
|
||||
@@ -436,14 +439,13 @@ abstract class Auction
|
||||
|
||||
$general->increaseVar($resType->value, -$morePoint);
|
||||
|
||||
$gameStor = KVStorage::getStorage($db, 'game_env');
|
||||
$turnTerm = $gameStor->getValue('turnterm');
|
||||
$extendedCloseDate = $now->add(TimeUtil::secondsToDateInterval(
|
||||
max(static::MIN_EXTENSION_MINUTES_PER_BID, $turnTerm * static::COEFF_EXTENSION_MINUTES_PER_BID) * 60
|
||||
));
|
||||
$extendedCloseTick = $nowTick + $clock->ticksFromMinutes(
|
||||
max(static::MIN_EXTENSION_MINUTES_PER_BID, $turnTerm * static::COEFF_EXTENSION_MINUTES_PER_BID)
|
||||
);
|
||||
|
||||
if ($extendedCloseDate > $this->info->closeDate) {
|
||||
$this->extendCloseDate($extendedCloseDate, true);
|
||||
if ($extendedCloseTick > $this->info->closeTick) {
|
||||
$this->extendCloseTick($extendedCloseTick, true);
|
||||
$this->applyDB();
|
||||
}
|
||||
|
||||
@@ -456,10 +458,10 @@ abstract class Auction
|
||||
|
||||
public function tryFinish(): ?bool
|
||||
{
|
||||
$now = new DateTimeImmutable();
|
||||
if ($now < $this->info->closeDate) {
|
||||
return null;
|
||||
}
|
||||
$db = DB::db();
|
||||
$gameStor = KVStorage::getStorage($db, 'game_env');
|
||||
$clock = GameClock::fromStorage($gameStor);
|
||||
if ($clock->nowTick() < $this->info->closeTick) return null;
|
||||
|
||||
//경매를 닫아야한다.
|
||||
$highestBid = $this->getHighestBid();
|
||||
@@ -469,17 +471,15 @@ abstract class Auction
|
||||
}
|
||||
|
||||
if ($highestBid->aux->tryExtendCloseDate) {
|
||||
$db = DB::db();
|
||||
$gameStor = KVStorage::getStorage($db, 'game_env');
|
||||
$turnTerm = $gameStor->getValue('turnterm');
|
||||
|
||||
//연장 요청이 있었다.
|
||||
$extendedCloseDate = $this->info->closeDate->add(TimeUtil::secondsToDateInterval(
|
||||
max(static::MIN_EXTENSION_MINUTES_BY_EXTENSION_QUERY, $turnTerm * static::COEFF_EXTENSION_MINUTES_BY_EXTENSION_QUERY) * 60
|
||||
));
|
||||
$extendedCloseTick = $this->info->closeTick + $clock->ticksFromMinutes(
|
||||
max(static::MIN_EXTENSION_MINUTES_BY_EXTENSION_QUERY, $turnTerm * static::COEFF_EXTENSION_MINUTES_BY_EXTENSION_QUERY)
|
||||
);
|
||||
|
||||
if ($this->extendCloseDate($extendedCloseDate) === null) {
|
||||
$this->extendLatestBidCloseDate(null);
|
||||
if ($this->extendCloseTick($extendedCloseTick) === null) {
|
||||
$this->extendLatestBidCloseTick(null);
|
||||
$this->applyDB();
|
||||
return false;
|
||||
}
|
||||
@@ -509,12 +509,13 @@ abstract class Auction
|
||||
|
||||
//TODO: 전역 알림이 나타나야한다. 일반 메시지보다는 중요하고, 메시지보단 약하게..
|
||||
//TODO: 바로가기를 제공하는 편이 좋을 것 같다.
|
||||
$clock = GameClock::fromStorage(KVStorage::getStorage($db, 'game_env'));
|
||||
$msg = new Message(
|
||||
MessageType::private,
|
||||
$src,
|
||||
$dest,
|
||||
$failReason,
|
||||
new \DateTime(),
|
||||
DateTime::createFromImmutable($clock->tickToDateTime($clock->nowTick())),
|
||||
new \DateTime('9999-12-31'),
|
||||
[]
|
||||
);
|
||||
|
||||
@@ -56,10 +56,11 @@ abstract class AuctionBasicResource extends Auction
|
||||
}
|
||||
|
||||
|
||||
$now = new \DateTimeImmutable();
|
||||
$gameStor = KVStorage::getStorage($db, 'game_env');
|
||||
$clock = GameClock::fromStorage($gameStor);
|
||||
$nowTick = $clock->nowTick();
|
||||
$turnTerm = $gameStor->getValue('turnterm');
|
||||
$closeDate = $now->add(TimeUtil::secondsToDateInterval($closeTurnCnt * $turnTerm * 60));
|
||||
$closeTick = $nowTick + GameClock::TICKS_PER_TURN * $closeTurnCnt;
|
||||
|
||||
$openResult = static::openAuction(new AuctionInfo(
|
||||
null,
|
||||
@@ -68,8 +69,8 @@ abstract class AuctionBasicResource extends Auction
|
||||
"$amount",
|
||||
$general->getId(),
|
||||
$bidderRes,
|
||||
$now,
|
||||
$closeDate,
|
||||
$nowTick,
|
||||
$closeTick,
|
||||
new AuctionInfoDetail(
|
||||
"{$hostResName} {$amount} 경매",
|
||||
$general->getName(),
|
||||
@@ -145,12 +146,13 @@ abstract class AuctionBasicResource extends Auction
|
||||
|
||||
//TODO: 전역 알림이 나타나야한다. 일반 메시지보다는 중요하고, 메시지보단 약하게..
|
||||
//TODO: 바로가기를 제공하는 편이 좋을 것 같다.
|
||||
$clock = GameClock::fromStorage(KVStorage::getStorage(DB::db(), 'game_env'));
|
||||
$msg = new Message(
|
||||
MessageType::private,
|
||||
$src,
|
||||
$dest,
|
||||
"{$this->auctionID}번 {$hostResName} 경매에 입찰이 없어 취소되었습니다.",
|
||||
new \DateTime(),
|
||||
\DateTime::createFromImmutable($clock->tickToDateTime($clock->nowTick())),
|
||||
new \DateTime('9999-12-31'),
|
||||
[]
|
||||
);
|
||||
@@ -246,8 +248,8 @@ abstract class AuctionBasicResource extends Auction
|
||||
$db = DB::db();
|
||||
$gameStor = KVStorage::getStorage($db, 'game_env');
|
||||
$turnTerm = $gameStor->getValue('turnterm');
|
||||
$date = (new DateTimeImmutable())->add(TimeUtil::secondsToDateInterval($turnTerm * 60));
|
||||
$this->shrinkCloseDate($date);
|
||||
$clock = GameClock::fromStorage($gameStor);
|
||||
$this->shrinkCloseTick($clock->nowTick() + GameClock::TICKS_PER_TURN);
|
||||
}
|
||||
|
||||
return null;
|
||||
|
||||
@@ -72,16 +72,15 @@ class AuctionUniqueItem extends Auction
|
||||
|
||||
$gameStor = KVStorage::getStorage($db, 'game_env');
|
||||
|
||||
$now = new DateTimeImmutable();
|
||||
|
||||
[$turnTerm, $year, $month] = $gameStor->getValuesAsArray(['turnterm', 'year', 'month']);
|
||||
|
||||
$closeDate = $now->add(TimeUtil::secondsToDateInterval(
|
||||
max(static::MIN_AUCTION_CLOSE_MINUTES, $turnTerm * static::COEFF_AUCTION_CLOSE_MINUTES) * 60
|
||||
));
|
||||
$availableLatestBidCloseDate = $closeDate->add(TimeUtil::secondsToDateInterval(
|
||||
max(static::MIN_EXTENSION_MINUTES_LIMIT_BY_BID, $turnTerm * static::COEFF_EXTENSION_MINUTES_LIMIT_BY_BID) * 60
|
||||
));
|
||||
$clock = GameClock::fromStorage($gameStor);
|
||||
$nowTick = $clock->nowTick();
|
||||
$closeTick = $nowTick + $clock->ticksFromMinutes(
|
||||
max(static::MIN_AUCTION_CLOSE_MINUTES, $turnTerm * static::COEFF_AUCTION_CLOSE_MINUTES)
|
||||
);
|
||||
$availableLatestBidCloseTick = $closeTick + $clock->ticksFromMinutes(
|
||||
max(static::MIN_EXTENSION_MINUTES_LIMIT_BY_BID, $turnTerm * static::COEFF_EXTENSION_MINUTES_LIMIT_BY_BID)
|
||||
);
|
||||
|
||||
$info = new AuctionInfo(
|
||||
null,
|
||||
@@ -90,8 +89,8 @@ class AuctionUniqueItem extends Auction
|
||||
$itemKey,
|
||||
$general->getID(),
|
||||
ResourceType::inheritancePoint,
|
||||
$now,
|
||||
$closeDate,
|
||||
$nowTick,
|
||||
$closeTick,
|
||||
new AuctionInfoDetail(
|
||||
"{$item->getName()} 경매",
|
||||
static::genObfuscatedName($general->getID()),
|
||||
@@ -100,7 +99,7 @@ class AuctionUniqueItem extends Auction
|
||||
$startAmount,
|
||||
null,
|
||||
1,
|
||||
$availableLatestBidCloseDate,
|
||||
$availableLatestBidCloseTick,
|
||||
)
|
||||
);
|
||||
|
||||
@@ -267,21 +266,22 @@ class AuctionUniqueItem extends Auction
|
||||
|
||||
if ($availableEquipUniqueCnt <= 0) {
|
||||
$turnTerm = $gameStor->getValue('turnterm');
|
||||
$clock = GameClock::fromStorage($gameStor);
|
||||
//제한에 걸렸다면 자동 연장
|
||||
$extendedCloseDate = $this->info->closeDate->add(TimeUtil::secondsToDateInterval(
|
||||
max(static::MIN_EXTENSION_MINUTES_BY_EXTENSION_QUERY, $turnTerm * static::COEFF_EXTENSION_MINUTES_LIMIT_UNIQUE_CNT) * 60
|
||||
));
|
||||
$extendedCloseTick = $this->info->closeTick + $clock->ticksFromMinutes(
|
||||
max(static::MIN_EXTENSION_MINUTES_BY_EXTENSION_QUERY, $turnTerm * static::COEFF_EXTENSION_MINUTES_LIMIT_UNIQUE_CNT)
|
||||
);
|
||||
|
||||
if($bidder->getID() != $this->info->hostGeneralID){
|
||||
$this->setHostAsNeutral();
|
||||
}
|
||||
$this->extendCloseDate($extendedCloseDate, true);
|
||||
$this->extendLatestBidCloseDate(null);
|
||||
$this->extendCloseTick($extendedCloseTick, true);
|
||||
$this->extendLatestBidCloseTick(null);
|
||||
$this->applyDB();
|
||||
return '유니크 아이템 소유 제한 상태입니다. 종료 시간이 연장됩니다.';
|
||||
}
|
||||
|
||||
$isExtendCloseDateRequired = false;
|
||||
$isExtendCloseTickRequired = false;
|
||||
foreach (GameConst::$allItems as $itemType => $itemList) {
|
||||
//아직은 그런 경우는 없지만 동일 유니크를 여러 부위에 장착할 수 있을지도 모름
|
||||
if (!key_exists($itemKey, $itemList)) {
|
||||
@@ -291,13 +291,13 @@ class AuctionUniqueItem extends Auction
|
||||
$ownItem = $general->getItem($itemType);
|
||||
if ($ownItem->getRawClassName() == $itemKey) {
|
||||
//FIXME: 이 경우에는 환불이 되던가 해야함.
|
||||
$isExtendCloseDateRequired = true;
|
||||
$isExtendCloseTickRequired = true;
|
||||
$reasons[] = '이미 그 유니크를 가지고 있습니다.';
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!$ownItem->isBuyable()) {
|
||||
$isExtendCloseDateRequired = true;
|
||||
$isExtendCloseTickRequired = true;
|
||||
$reasons[] = '이미 다른 유니크를 가지고 있습니다.';
|
||||
continue;
|
||||
}
|
||||
@@ -313,18 +313,19 @@ class AuctionUniqueItem extends Auction
|
||||
}
|
||||
|
||||
if (!$availableItemTypes) {
|
||||
if ($isExtendCloseDateRequired) {
|
||||
if ($isExtendCloseTickRequired) {
|
||||
$turnTerm = $gameStor->getValue('turnterm');
|
||||
$clock = GameClock::fromStorage($gameStor);
|
||||
//동일 부위 제한에 걸렸다면 자동 연장
|
||||
$extendedCloseDate = $this->info->closeDate->add(TimeUtil::secondsToDateInterval(
|
||||
max(static::MIN_EXTENSION_MINUTES_LIMIT_BY_BID, $turnTerm * static::COEFF_EXTENSION_MINUTES_LIMIT_BY_BID) * 60
|
||||
));
|
||||
$extendedCloseTick = $this->info->closeTick + $clock->ticksFromMinutes(
|
||||
max(static::MIN_EXTENSION_MINUTES_LIMIT_BY_BID, $turnTerm * static::COEFF_EXTENSION_MINUTES_LIMIT_BY_BID)
|
||||
);
|
||||
|
||||
if($bidder->getID() != $this->info->hostGeneralID){
|
||||
$this->setHostAsNeutral();
|
||||
}
|
||||
$this->extendCloseDate($extendedCloseDate, true);
|
||||
$this->extendLatestBidCloseDate(null);
|
||||
$this->extendCloseTick($extendedCloseTick, true);
|
||||
$this->extendLatestBidCloseTick(null);
|
||||
$this->applyDB();
|
||||
}
|
||||
return join(' ', $reasons);
|
||||
|
||||
@@ -10,8 +10,6 @@ final class CentennialAllStarGrowthService
|
||||
public const AUX_KEY = 'event100_allstar';
|
||||
public const TRAIT_UNLOCK_PROGRESS = 0.4;
|
||||
public const NPC_PROGRESS_MULTIPLIER = 0.9;
|
||||
public const DEX_EXTENSION_START_YEAR_OFFSET = 20;
|
||||
public const DEX_EXTENSION_YEARS = 5;
|
||||
|
||||
private const STAT_KEYS = ['leadership', 'strength', 'intel'];
|
||||
private const DEX_KEYS = ['dex1', 'dex2', 'dex3', 'dex4', 'dex5'];
|
||||
@@ -43,7 +41,6 @@ final class CentennialAllStarGrowthService
|
||||
'dexFloor' => array_fill_keys(self::DEX_KEYS, 0),
|
||||
'progressMonth' => -1,
|
||||
'milestone' => 0,
|
||||
'dexExtensionMilestone' => 0,
|
||||
'naturalSpecialDomestic' => null,
|
||||
'eventSpecialDomestic' => null,
|
||||
'userInitialStats' => $userInitialStats,
|
||||
@@ -239,7 +236,7 @@ final class CentennialAllStarGrowthService
|
||||
if ($targetRatio < 0 || $targetRatio > 1) {
|
||||
throw new \InvalidArgumentException('dex target ratio must be between 0 and 1');
|
||||
}
|
||||
$target = self::calculateDexExtendedTarget($target, $env);
|
||||
$target = min(GameConst::$dexLimit, max(0, $target));
|
||||
$scaledTarget = (int) floor($target * $targetRatio);
|
||||
$progress = self::calculateProgress(
|
||||
(int) $env['startyear'],
|
||||
@@ -249,34 +246,10 @@ final class CentennialAllStarGrowthService
|
||||
return CentennialAllStarGrowth::dexFloor($scaledTarget, $progress);
|
||||
}
|
||||
|
||||
public static function calculateDexExtensionProgress(array $env): float
|
||||
{
|
||||
return CentennialAllStarGrowth::progress(
|
||||
(int) $env['startyear'] + self::DEX_EXTENSION_START_YEAR_OFFSET,
|
||||
(int) $env['year'],
|
||||
(int) $env['month'],
|
||||
self::DEX_EXTENSION_YEARS
|
||||
);
|
||||
}
|
||||
|
||||
public static function calculateDexExtendedTarget(int $target, array $env): int
|
||||
{
|
||||
$target = max(0, $target);
|
||||
$baseTarget = min(GameConst::$dexLimit, $target);
|
||||
$extensionTarget = max(0, $target - $baseTarget);
|
||||
if ($extensionTarget === 0) {
|
||||
return $baseTarget;
|
||||
}
|
||||
|
||||
return $baseTarget + (int) floor(
|
||||
$extensionTarget * self::calculateDexExtensionProgress($env)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Mutates the General object but leaves persistence to the caller.
|
||||
*
|
||||
* @return array{progress:float,milestone:int,previousMilestone:int,dexExtensionMilestone:int,previousDexExtensionMilestone:int,hasDexExtensionTarget:bool,targetChanged:bool,changed:bool}
|
||||
* @return array{progress:float,milestone:int,previousMilestone:int,targetChanged:bool,changed:bool}
|
||||
*/
|
||||
public static function applyTarget(
|
||||
General $general,
|
||||
@@ -366,14 +339,10 @@ final class CentennialAllStarGrowthService
|
||||
}
|
||||
|
||||
$targetDex = $targetInfo['dex'] ?? [];
|
||||
$hasDexExtensionTarget = false;
|
||||
foreach (self::DEX_KEYS as $idx => $key) {
|
||||
if (!array_key_exists($idx, $targetDex)) {
|
||||
continue;
|
||||
}
|
||||
if ((int) $targetDex[$idx] > GameConst::$dexLimit) {
|
||||
$hasDexExtensionTarget = true;
|
||||
}
|
||||
$floor = max(
|
||||
0,
|
||||
self::calculateDexTargetFloor(
|
||||
@@ -430,21 +399,12 @@ final class CentennialAllStarGrowthService
|
||||
|
||||
$previousMilestone = (int) ($aux['milestone'] ?? 0);
|
||||
$milestone = min(5, (int) floor($progress * 5 + 0.0000001));
|
||||
$previousDexExtensionMilestone = (int) ($aux['dexExtensionMilestone'] ?? 0);
|
||||
$dexExtensionProgress = self::calculateDexExtensionProgress($env);
|
||||
$dexExtensionMilestone = $hasDexExtensionTarget
|
||||
? min(5, (int) floor($dexExtensionProgress * 5 + 0.0000001))
|
||||
: 0;
|
||||
$aux['targetId'] = $targetId;
|
||||
$aux['granted'] = $granted;
|
||||
$aux['dexConsumed'] = $dexConsumed;
|
||||
$aux['dexFloor'] = $dexFloor;
|
||||
$aux['progressMonth'] = max((int) ($aux['progressMonth'] ?? -1), $progressMonth);
|
||||
$aux['milestone'] = max($previousMilestone, $milestone);
|
||||
$aux['dexExtensionMilestone'] = max(
|
||||
$previousDexExtensionMilestone,
|
||||
$dexExtensionMilestone
|
||||
);
|
||||
$aux['userInitialStats'] = $nextUserInitialStats;
|
||||
$aux['dexTargetRatio'] = $dexTargetRatio;
|
||||
$general->setAuxVar(self::AUX_KEY, $aux);
|
||||
@@ -453,14 +413,8 @@ final class CentennialAllStarGrowthService
|
||||
'progress' => $progress,
|
||||
'milestone' => $milestone,
|
||||
'previousMilestone' => $previousMilestone,
|
||||
'dexExtensionMilestone' => $dexExtensionMilestone,
|
||||
'previousDexExtensionMilestone' => $previousDexExtensionMilestone,
|
||||
'hasDexExtensionTarget' => $hasDexExtensionTarget,
|
||||
'targetChanged' => $targetChanged,
|
||||
'changed' => $changed
|
||||
|| $targetChanged
|
||||
|| $milestone > $previousMilestone
|
||||
|| $dexExtensionMilestone > $previousDexExtensionMilestone,
|
||||
'changed' => $changed || $targetChanged || $milestone > $previousMilestone,
|
||||
];
|
||||
}
|
||||
|
||||
|
||||
@@ -193,7 +193,7 @@ class che_몰수 extends Command\NationCommand
|
||||
$src,
|
||||
$src,
|
||||
$text,
|
||||
new \DateTime(),
|
||||
Message::gameNow(),
|
||||
new \DateTime('9999-12-31'),
|
||||
[]
|
||||
);
|
||||
|
||||
@@ -159,7 +159,7 @@ class che_발령 extends Command\NationCommand
|
||||
$destGeneral->getLogger()->pushGeneralActionLog("<Y>{$generalName}</>에 의해 <G><b>{$destCityName}</b></>{$josaRo} 발령됐습니다. <1>$date</>");
|
||||
|
||||
$yearMonth = Util::joinYearMonth($this->env['year'], $this->env['month']);
|
||||
if (cutTurn($general->getTurnTime(), $this->env['turnterm']) != cutTurn($destGeneral->getTurnTime(), $this->env['turnterm'])) {
|
||||
if (cutTurn($general->getTurnTick(), $this->env['turnterm']) != cutTurn($destGeneral->getTurnTick(), $this->env['turnterm'])) {
|
||||
$yearMonth += 1;
|
||||
}
|
||||
$destGeneral->setAuxVar('last발령', $yearMonth);
|
||||
|
||||
@@ -198,8 +198,9 @@ class che_불가침제의 extends Command\NationCommand
|
||||
$destNation['color']
|
||||
);
|
||||
|
||||
$now = new \DateTime($date);
|
||||
$validUntil = new \DateTime($date);
|
||||
$clock = \sammo\GameClock::fromStorage(\sammo\KVStorage::getStorage($db, 'game_env'));
|
||||
$now = \DateTime::createFromImmutable($clock->tickToDateTime($general->getTurnTick()));
|
||||
$validUntil = clone $now;
|
||||
$validMinutes = max(30, $env['turnterm'] * 3);
|
||||
$validUntil->add(new \DateInterval("PT{$validMinutes}M"));
|
||||
|
||||
|
||||
@@ -147,8 +147,9 @@ class che_불가침파기제의 extends Command\NationCommand{
|
||||
$destNation['color']
|
||||
);
|
||||
|
||||
$now = new \DateTime($date);
|
||||
$validUntil = new \DateTime($date);
|
||||
$clock = \sammo\GameClock::fromStorage(\sammo\KVStorage::getStorage($db, 'game_env'));
|
||||
$now = \DateTime::createFromImmutable($clock->tickToDateTime($general->getTurnTick()));
|
||||
$validUntil = clone $now;
|
||||
$validMinutes = max(30, $env['turnterm']*3);
|
||||
$validUntil->add(new \DateInterval("PT{$validMinutes}M"));
|
||||
|
||||
@@ -217,4 +218,4 @@ class che_불가침파기제의 extends Command\NationCommand{
|
||||
],
|
||||
];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -145,8 +145,9 @@ class che_종전제의 extends Command\NationCommand{
|
||||
$destNation['color']
|
||||
);
|
||||
|
||||
$now = new \DateTime($date);
|
||||
$validUntil = new \DateTime($date);
|
||||
$clock = \sammo\GameClock::fromStorage(\sammo\KVStorage::getStorage($db, 'game_env'));
|
||||
$now = \DateTime::createFromImmutable($clock->tickToDateTime($general->getTurnTick()));
|
||||
$validUntil = clone $now;
|
||||
$validMinutes = max(30, $env['turnterm']*3);
|
||||
$validUntil->add(new \DateInterval("PT{$validMinutes}M"));
|
||||
|
||||
@@ -203,4 +204,4 @@ class che_종전제의 extends Command\NationCommand{
|
||||
],
|
||||
];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -137,7 +137,7 @@ class che_천도 extends Command\NationCommand
|
||||
$nationID = $general->getNationID();
|
||||
$nationStor = \sammo\KVStorage::getStorage(DB::db(), $nationID, 'nation_env');
|
||||
|
||||
$nationStor->last천도Trial = [$general->getVar('officer_level'), $general->getTurnTime()];
|
||||
$nationStor->last천도Trial = [$general->getVar('officer_level'), $general->getTurnTick()];
|
||||
|
||||
if ($lastTurn->getCommand() != $commandName || $lastTurn->getArg() !== $this->arg) {
|
||||
$this->setResultTurn(new LastTurn(
|
||||
|
||||
@@ -2,11 +2,9 @@
|
||||
|
||||
namespace sammo\DTO;
|
||||
|
||||
use LDTO\Attr\Convert;
|
||||
use LDTO\Attr\JsonString;
|
||||
use LDTO\Attr\NullIsUndefined;
|
||||
use LDTO\Attr\RawName;
|
||||
use LDTO\Converter\DateTimeConverter;
|
||||
use sammo\Enums\AuctionType;
|
||||
use sammo\Enums\ResourceType;
|
||||
|
||||
@@ -23,12 +21,10 @@ class AuctionInfo extends \LDTO\DTO
|
||||
#[RawName('req_resource')]
|
||||
public ResourceType $reqResource,
|
||||
|
||||
#[RawName('open_date')]
|
||||
#[Convert(DateTimeConverter::class)]
|
||||
public \DateTimeImmutable $openDate,
|
||||
#[RawName('close_date')]
|
||||
#[Convert(DateTimeConverter::class)]
|
||||
public \DateTimeImmutable $closeDate,
|
||||
#[RawName('open_tick')]
|
||||
public int $openTick,
|
||||
#[RawName('close_tick')]
|
||||
public int $closeTick,
|
||||
|
||||
#[JsonString]
|
||||
public AuctionInfoDetail $detail,
|
||||
|
||||
@@ -2,9 +2,7 @@
|
||||
|
||||
namespace sammo\DTO;
|
||||
|
||||
use LDTO\Attr\Convert;
|
||||
use LDTO\Attr\NullIsUndefined;
|
||||
use LDTO\Converter\DateTimeConverter;
|
||||
|
||||
class AuctionInfoDetail extends \LDTO\DTO
|
||||
{
|
||||
@@ -21,8 +19,7 @@ class AuctionInfoDetail extends \LDTO\DTO
|
||||
#[NullIsUndefined]
|
||||
public ?int $remainCloseDateExtensionCnt,
|
||||
#[NullIsUndefined]
|
||||
#[Convert(DateTimeConverter::class)]
|
||||
public ?\DateTimeImmutable $availableLatestBidCloseDate,
|
||||
public ?int $availableLatestBidCloseTick,
|
||||
) {
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,10 +2,8 @@
|
||||
|
||||
namespace sammo\DTO;
|
||||
|
||||
use LDTO\Attr\Convert;
|
||||
use LDTO\Attr\NullIsUndefined;
|
||||
use LDTO\Attr\RawName;
|
||||
use LDTO\Converter\DateTimeConverter;
|
||||
|
||||
class GeneralAccessLog extends \LDTO\DTO
|
||||
{
|
||||
@@ -20,8 +18,7 @@ class GeneralAccessLog extends \LDTO\DTO
|
||||
public ?int $userID,
|
||||
|
||||
#[RawName('last_refresh')]
|
||||
#[Convert(DateTimeConverter::class)]
|
||||
public \DateTimeImmutable $lastRefresh,
|
||||
public ?int $lastRefresh,
|
||||
|
||||
public int $refresh,
|
||||
|
||||
@@ -35,4 +32,4 @@ class GeneralAccessLog extends \LDTO\DTO
|
||||
public int $refreshScoreTotal,
|
||||
) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,8 +2,41 @@
|
||||
|
||||
namespace sammo\DTO;
|
||||
|
||||
use sammo\GameClock;
|
||||
use sammo\Util;
|
||||
|
||||
class VoteInfo extends \LDTO\DTO
|
||||
{
|
||||
/**
|
||||
* 기존 문자열만 가진 vote도 읽되, 저장 경계에서는 반드시 tick을 함께 둡니다.
|
||||
*
|
||||
* @return array<string,mixed>
|
||||
*/
|
||||
public static function normalizeGameStorage(array $raw, GameClock $clock): array
|
||||
{
|
||||
if (!array_key_exists('startTick', $raw)) {
|
||||
$raw['startTick'] = $clock->dateTimeToTick(new \DateTimeImmutable((string)$raw['startDate']));
|
||||
}
|
||||
if (!array_key_exists('endTick', $raw)) {
|
||||
$raw['endTick'] = ($raw['endDate'] ?? null) === null
|
||||
? null
|
||||
: $clock->dateTimeToTick(new \DateTimeImmutable((string)$raw['endDate']));
|
||||
}
|
||||
|
||||
$raw['startTick'] = Util::toInt($raw['startTick']);
|
||||
$raw['endTick'] = $raw['endTick'] === null ? null : Util::toInt($raw['endTick']);
|
||||
$raw['startDate'] = $clock->formatTick($raw['startTick']);
|
||||
$raw['endDate'] = $raw['endTick'] === null ? null : $clock->formatTick($raw['endTick']);
|
||||
return $raw;
|
||||
}
|
||||
|
||||
public static function fromGameStorage(array $raw, GameClock $clock): self
|
||||
{
|
||||
$raw = self::normalizeGameStorage($raw, $clock);
|
||||
unset($raw['startTick'], $raw['endTick']);
|
||||
return self::fromArray($raw);
|
||||
}
|
||||
|
||||
public function __construct(
|
||||
public int $id,
|
||||
public string $title,
|
||||
|
||||
@@ -49,7 +49,7 @@ class DiplomaticMessage extends Message{
|
||||
$this->validDiplomacy = false;
|
||||
}
|
||||
|
||||
if($this->validUntil < (new \DateTime())){
|
||||
if($this->validUntil < $this->date){
|
||||
$this->validDiplomacy = false;
|
||||
}
|
||||
}
|
||||
@@ -215,7 +215,7 @@ class DiplomaticMessage extends Message{
|
||||
$this->dest,
|
||||
$this->src,
|
||||
"【외교】{$year}년 {$month}월: {$this->src->nationName}{$josaYi} {$this->dest->nationName}에게 제안한 {$this->diplomacyDetail}",
|
||||
new \DateTime(),
|
||||
Message::gameNow(),
|
||||
new \DateTime('9999-12-31'),
|
||||
[
|
||||
'delete'=>$this->id,
|
||||
@@ -231,7 +231,7 @@ class DiplomaticMessage extends Message{
|
||||
$this->dest,
|
||||
$this->src,
|
||||
"【외교】{$year}년 {$month}월: {$this->src->nationName}{$josaYi} {$this->dest->nationName}에게 제안한 {$this->diplomacyDetail}",
|
||||
new \DateTime(),
|
||||
Message::gameNow(),
|
||||
new \DateTime('9999-12-31'),
|
||||
[
|
||||
'delete'=>$this->id,
|
||||
@@ -281,4 +281,4 @@ class DiplomaticMessage extends Message{
|
||||
return self::DECLINED;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -45,18 +45,6 @@ class AdvanceCentennialAllStar extends \sammo\Event\Action
|
||||
"<L>올스타 동조율 {$percent}% 달성</>"
|
||||
);
|
||||
}
|
||||
if ($result['hasDexExtensionTarget']
|
||||
&& $result['dexExtensionMilestone'] > $result['previousDexExtensionMilestone']
|
||||
) {
|
||||
$percent = $result['dexExtensionMilestone'] * 20;
|
||||
$general->getLogger()->pushGeneralActionLog(
|
||||
"<L>추가 숙련 동조율</>이 <C>{$percent}%</>에 도달했습니다!",
|
||||
ActionLogger::PLAIN
|
||||
);
|
||||
$general->getLogger()->pushGeneralHistoryLog(
|
||||
"<L>추가 숙련 동조율 {$percent}% 달성</>"
|
||||
);
|
||||
}
|
||||
if ($general->applyDB($db)) {
|
||||
$updated++;
|
||||
}
|
||||
|
||||
@@ -37,7 +37,7 @@ class AssignGeneralSpeciality extends \sammo\Event\Action
|
||||
$month,
|
||||
)));
|
||||
|
||||
foreach ($db->query('SELECT no,name,nation,leadership,strength,intel,aux from general where specage<=age and special=%s', GameConst::$defaultSpecialDomestic) as $general) {
|
||||
foreach ($db->query('SELECT no,name,nation,leadership,strength,intel,aux from general where specage<=age and special=%s ORDER BY no ASC', GameConst::$defaultSpecialDomestic) as $general) {
|
||||
$generalID = $general['no'];
|
||||
$special = SpecialityHelper::pickSpecialDomestic(
|
||||
$rng,
|
||||
@@ -57,7 +57,7 @@ class AssignGeneralSpeciality extends \sammo\Event\Action
|
||||
$logger->pushGeneralHistoryLog("특기 【<b><C>{$specialText}</></b>】{$josaUl} 습득");
|
||||
}
|
||||
|
||||
foreach ($db->query('SELECT no,name,nation,leadership,strength,intel,npc,dex1,dex2,dex3,dex4,dex5,aux from general where specage2<=age and special2=%s', GameConst::$defaultSpecialWar) as $general) {
|
||||
foreach ($db->query('SELECT no,name,nation,leadership,strength,intel,npc,dex1,dex2,dex3,dex4,dex5,aux from general where specage2<=age and special2=%s ORDER BY no ASC', GameConst::$defaultSpecialWar) as $general) {
|
||||
$generalID = $general['no'];
|
||||
$generalAux = Json::decode($general['aux']);
|
||||
|
||||
|
||||
@@ -123,7 +123,7 @@ class OpenNationBetting extends \sammo\Event\Action
|
||||
}
|
||||
|
||||
$logger->flush();
|
||||
$now = new DateTime();
|
||||
$now = Message::gameNow();
|
||||
$text = "새로운 {$name} 내기가 열렸습니다. 천통국 베팅란을 확인해주세요.";
|
||||
|
||||
$src = new MessageTarget(0, '', 0, 'System', '#000000');
|
||||
|
||||
+70
-26
@@ -281,16 +281,13 @@ class General extends GeneralBase implements iAction
|
||||
$this->calcCache[$cacheKey] = $result;
|
||||
return $result;
|
||||
}
|
||||
$recwar = new \DateTimeImmutable($this->getVar('recent_war'));
|
||||
$turnNow = new \DateTimeImmutable($this->getVar('turntime'));
|
||||
$secDiff = TimeUtil::DateIntervalToSeconds($recwar->diff($turnNow));
|
||||
|
||||
if ($secDiff <= 0) {
|
||||
$this->calcCache[$cacheKey] = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
$result = intdiv(Util::toInt($secDiff), 60 * $turnTerm);
|
||||
$tickDiff = Util::toInt($this->getVar('turntime')) - Util::toInt($this->getVar('recent_war'));
|
||||
if ($tickDiff <= 0) {
|
||||
$this->calcCache[$cacheKey] = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
$result = intdiv($tickDiff, GameClock::TICKS_PER_TURN);
|
||||
$this->calcCache[$cacheKey] = $result;
|
||||
return $result;
|
||||
}
|
||||
@@ -1045,18 +1042,64 @@ class General extends GeneralBase implements iAction
|
||||
|
||||
/** @var Map<GeneralAccessLog,int>|null */
|
||||
$rawAccessLog = null;
|
||||
$rankColumnValues = array_map(fn (\BackedEnum $e) => $e->value, $rankColumn);
|
||||
|
||||
if (!$accessLogColumn) {
|
||||
$rawGeneral = $db->queryFirstRow('SELECT %l FROM general WHERE no = %i', Util::formatListOfBackticks($column), $generalID);
|
||||
if ($rankColumn) {
|
||||
$rawGeneral = $db->queryFirstRow(
|
||||
'SELECT %l, (
|
||||
SELECT GROUP_CONCAT(
|
||||
CONCAT(`type`, CHAR(61), `value`)
|
||||
ORDER BY `type`
|
||||
)
|
||||
FROM rank_data
|
||||
WHERE rank_data.general_id = general.no
|
||||
AND `type` IN %ls
|
||||
) AS `_rank_values`
|
||||
FROM general WHERE no = %i',
|
||||
Util::formatListOfBackticks($column),
|
||||
$rankColumnValues,
|
||||
$generalID
|
||||
);
|
||||
} else {
|
||||
$rawGeneral = $db->queryFirstRow(
|
||||
'SELECT %l FROM general WHERE no = %i',
|
||||
Util::formatListOfBackticks($column),
|
||||
$generalID
|
||||
);
|
||||
}
|
||||
} else {
|
||||
$rawGeneral = $db->queryFirstRow(
|
||||
'SELECT %l, %l FROM `general` LEFT JOIN general_access_log
|
||||
ON general.no = general_access_log.general_id WHERE no = %i',
|
||||
Util::formatListOfBackticks($column),
|
||||
Util::formatListOfBackticks($accessLogColumn),
|
||||
$generalID
|
||||
);
|
||||
if ($rankColumn) {
|
||||
$rawGeneral = $db->queryFirstRow(
|
||||
'SELECT %l, %l, (
|
||||
SELECT GROUP_CONCAT(
|
||||
CONCAT(`type`, CHAR(61), `value`)
|
||||
ORDER BY `type`
|
||||
)
|
||||
FROM rank_data
|
||||
WHERE rank_data.general_id = general.no
|
||||
AND `type` IN %ls
|
||||
) AS `_rank_values`
|
||||
FROM `general` LEFT JOIN general_access_log
|
||||
ON general.no = general_access_log.general_id
|
||||
WHERE no = %i',
|
||||
Util::formatListOfBackticks($column),
|
||||
Util::formatListOfBackticks($accessLogColumn),
|
||||
$rankColumnValues,
|
||||
$generalID
|
||||
);
|
||||
} else {
|
||||
$rawGeneral = $db->queryFirstRow(
|
||||
'SELECT %l, %l FROM `general` LEFT JOIN general_access_log
|
||||
ON general.no = general_access_log.general_id WHERE no = %i',
|
||||
Util::formatListOfBackticks($column),
|
||||
Util::formatListOfBackticks($accessLogColumn),
|
||||
$generalID
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
if ($accessLogColumn) {
|
||||
$rawAccessLog = new Map();
|
||||
foreach ($accessLogColumn as $accessLogKey) {
|
||||
if (!key_exists($accessLogKey->value, $rawGeneral)) {
|
||||
@@ -1076,15 +1119,16 @@ class General extends GeneralBase implements iAction
|
||||
|
||||
$rawRankValues = new Map();
|
||||
if ($rankColumn) {
|
||||
$rawValue = $db->queryAllLists(
|
||||
'SELECT `type`, `value` FROM rank_data WHERE general_id = %i AND `type` IN %ls',
|
||||
$generalID,
|
||||
array_map(fn (\BackedEnum $e) => $e->value, $rankColumn)
|
||||
);
|
||||
foreach ($rawValue as [$rawRankType, $rankValue]) {
|
||||
$rankType = RankColumn::tryFrom($rawRankType);
|
||||
$rawRankValues->put($rankType, $rankValue);
|
||||
$rawRankPairs = $rawGeneral['_rank_values'];
|
||||
foreach ($rawRankPairs === null || $rawRankPairs === ''
|
||||
? []
|
||||
: explode(',', $rawRankPairs) as $rawRankPair
|
||||
) {
|
||||
[$rawRankType, $rankValue] = explode('=', $rawRankPair, 2);
|
||||
$rankType = RankColumn::from($rawRankType);
|
||||
$rawRankValues->put($rankType, (int) $rankValue);
|
||||
}
|
||||
unset($rawGeneral['_rank_values']);
|
||||
}
|
||||
|
||||
|
||||
|
||||
+13
-16
@@ -302,7 +302,7 @@ class GeneralAI
|
||||
$this->calcWarRoute();
|
||||
$troopCandidate = [];
|
||||
|
||||
$chiefTurn = cutTurn($this->general->getTurnTime(), $this->env['turnterm']);
|
||||
$chiefTurn = cutTurn($this->general->getTurnTick(), $this->env['turnterm']);
|
||||
$yearMonth = Util::joinYearMonth($this->env['year'], $this->env['month']);
|
||||
|
||||
foreach ($this->troopLeaders as $troopLeader) {
|
||||
@@ -319,7 +319,7 @@ class GeneralAI
|
||||
|
||||
$last발령 = $troopLeader->getAuxVar('last발령');
|
||||
if ($last발령) {
|
||||
$leaderTurn = cutTurn($troopLeader->getTurnTime(), $this->env['turnterm']);
|
||||
$leaderTurn = cutTurn($troopLeader->getTurnTick(), $this->env['turnterm']);
|
||||
$compYearMonth = $yearMonth;
|
||||
if ($chiefTurn < $leaderTurn) {
|
||||
$compYearMonth += 1;
|
||||
@@ -405,7 +405,7 @@ class GeneralAI
|
||||
return null;
|
||||
}
|
||||
|
||||
$chiefTurn = cutTurn($this->general->getTurnTime(), $this->env['turnterm']);
|
||||
$chiefTurn = cutTurn($this->general->getTurnTick(), $this->env['turnterm']);
|
||||
$yearMonth = Util::joinYearMonth($this->env['year'], $this->env['month']);
|
||||
|
||||
$troopCandidate = [];
|
||||
@@ -428,7 +428,7 @@ class GeneralAI
|
||||
|
||||
$last발령 = $troopLeader->getAuxVar('last발령');
|
||||
if ($last발령) {
|
||||
$leaderTurn = cutTurn($troopLeader->getTurnTime(), $this->env['turnterm']);
|
||||
$leaderTurn = cutTurn($troopLeader->getTurnTick(), $this->env['turnterm']);
|
||||
$compYearMonth = $yearMonth;
|
||||
if ($chiefTurn < $leaderTurn) {
|
||||
$compYearMonth += 1;
|
||||
@@ -586,8 +586,8 @@ class GeneralAI
|
||||
continue;
|
||||
}
|
||||
|
||||
$generalTurnTime = $userGeneral->getTurnTime();
|
||||
$troopTurnTime = $troopLeader->getTurnTime();
|
||||
$generalTurnTime = $userGeneral->getTurnTick();
|
||||
$troopTurnTime = $troopLeader->getTurnTick();
|
||||
|
||||
if ($generalTurnTime < $troopTurnTime) { //NOTE: 어차피 수뇌 턴이 제일 빠르다
|
||||
$generalCadidates[$generalID] = $userGeneral;
|
||||
@@ -782,7 +782,7 @@ class GeneralAI
|
||||
|
||||
if (
|
||||
key_exists($troopLeader->getCityID(), $this->supplyCities) &&
|
||||
$this->troopLeaders[$troopID]->getTurnTime() < $lostGeneral->getTurnTime()
|
||||
$this->troopLeaders[$troopID]->getTurnTick() < $lostGeneral->getTurnTick()
|
||||
) {
|
||||
//이미 탈출 가능한 부대를 탔다
|
||||
continue;
|
||||
@@ -1986,7 +1986,7 @@ class GeneralAI
|
||||
if ($lastTurn->getCommand() === '천도' && $lastTurn->getArg()['destCityID'] != $this->nation['capital']) {
|
||||
$cmd = buildNationCommandClass('che_천도', $this->general, $this->env, $lastTurn, $lastTurn->getArg());
|
||||
if ($cmd->hasFullConditionMet()) {
|
||||
$nationStor->last천도Trial = [$general->getVar('officer_level'), $general->getTurnTime()];
|
||||
$nationStor->last천도Trial = [$general->getVar('officer_level'), $general->getTurnTick()];
|
||||
$this->reqUpdateInstance = true;
|
||||
return $cmd;
|
||||
}
|
||||
@@ -1995,12 +1995,9 @@ class GeneralAI
|
||||
$lastTrial = $nationStor->last천도Trial;
|
||||
if ($lastTrial) {
|
||||
[$lastTrialLevel, $lastTrialTurnTime] = $lastTrial;
|
||||
$timeDiffSeconds = TimeUtil::DateIntervalToSeconds(
|
||||
date_create_immutable($lastTrialTurnTime)->diff(
|
||||
date_create_immutable($general->getTurnTime())
|
||||
)
|
||||
);
|
||||
if ($timeDiffSeconds < $turnTerm * 30 && $lastTrialLevel !== $general->getVar('officer_level')) { //0.5Turn
|
||||
$timeDiffTick = abs($general->getTurnTick() - Util::toInt($lastTrialTurnTime));
|
||||
if ($timeDiffTick < intdiv(GameClock::TICKS_PER_TURN, 2)
|
||||
&& $lastTrialLevel !== $general->getVar('officer_level')) { //0.5Turn
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -2109,7 +2106,7 @@ class GeneralAI
|
||||
}
|
||||
|
||||
|
||||
$nationStor->last천도Trial = [$general->getVar('officer_level'), $general->getTurnTime()];
|
||||
$nationStor->last천도Trial = [$general->getVar('officer_level'), $general->getTurnTick()];
|
||||
$this->reqUpdateInstance = true;
|
||||
return $cmd;
|
||||
}
|
||||
@@ -3730,7 +3727,7 @@ class GeneralAI
|
||||
$src,
|
||||
$src,
|
||||
$general->getVar('npcmsg'),
|
||||
new \DateTime(),
|
||||
Message::gameNow(),
|
||||
new \DateTime('9999-12-31'),
|
||||
[]
|
||||
);
|
||||
|
||||
+33
-10
@@ -54,14 +54,24 @@ abstract class GeneralBase
|
||||
);
|
||||
}
|
||||
|
||||
function getTurnTime(int $short = self::TURNTIME_FULL_MS): ?string
|
||||
{
|
||||
if(!key_exists('turntime', $this->raw)){
|
||||
return null;
|
||||
}
|
||||
|
||||
return [
|
||||
self::TURNTIME_FULL_MS => function ($turntime) {
|
||||
function getTurnTime(int $short = self::TURNTIME_FULL_MS): ?string
|
||||
{
|
||||
if(!key_exists('turntime', $this->raw)){
|
||||
return null;
|
||||
}
|
||||
|
||||
$rawTurnTime = $this->getVar('turntime');
|
||||
// 비교용 Dummy와 과거 fixture는 문자열을 잠시 허용하되 제품 DB는 tick만 사용합니다.
|
||||
if (is_string($rawTurnTime) && !ctype_digit(ltrim($rawTurnTime, '-'))) {
|
||||
$formattedTurnTime = $rawTurnTime;
|
||||
} else {
|
||||
$db = DB::db();
|
||||
$clock = GameClock::fromStorage(KVStorage::getStorage($db, 'game_env'));
|
||||
$formattedTurnTime = $clock->formatTick(Util::toInt($rawTurnTime), true);
|
||||
}
|
||||
|
||||
return [
|
||||
self::TURNTIME_FULL_MS => function ($turntime) {
|
||||
return $turntime;
|
||||
},
|
||||
self::TURNTIME_FULL => function ($turntime) {
|
||||
@@ -73,8 +83,21 @@ abstract class GeneralBase
|
||||
self::TURNTIME_HM => function ($turntime) {
|
||||
return substr($turntime, 11, 5);
|
||||
},
|
||||
][$short]($this->getVar('turntime'));
|
||||
}
|
||||
][$short]($formattedTurnTime);
|
||||
}
|
||||
|
||||
function getTurnTick(): ?int
|
||||
{
|
||||
if (!key_exists('turntime', $this->raw)) {
|
||||
return null;
|
||||
}
|
||||
$rawTurnTime = $this->getVar('turntime');
|
||||
if (is_string($rawTurnTime) && !ctype_digit(ltrim($rawTurnTime, '-'))) {
|
||||
$clock = GameClock::fromStorage(KVStorage::getStorage(DB::db(), 'game_env'));
|
||||
return $clock->dateTimeToTick(new \DateTimeImmutable($rawTurnTime));
|
||||
}
|
||||
return Util::toInt($rawTurnTime);
|
||||
}
|
||||
|
||||
function getNPCType(): int
|
||||
{
|
||||
|
||||
@@ -59,7 +59,7 @@ class RandomNameGeneral extends AbsGeneralPool{
|
||||
'generalName'=>$generalName,
|
||||
'imgsvr'=>0,
|
||||
'picture'=>null
|
||||
], '9999-12-31 12:00:00');
|
||||
], PHP_INT_MAX);
|
||||
}
|
||||
|
||||
static public function pickGeneralFromPool(MeekroDB $db, RandUtil $rng, int $owner, int $pickCnt, ?string $prefix = null): array
|
||||
@@ -68,26 +68,25 @@ class RandomNameGeneral extends AbsGeneralPool{
|
||||
$result = [];
|
||||
$dbInsert = [];
|
||||
|
||||
$oNow = new \DateTimeImmutable();
|
||||
|
||||
|
||||
for($i=0;$i<$pickCnt;$i++){
|
||||
$result[] = static::pickGeneral1FromPool($db, $rng, $owner, $prefix);
|
||||
}
|
||||
|
||||
if($owner){
|
||||
$now = $oNow->format('Y-m-d H:i:s');
|
||||
$gameStor = \sammo\KVStorage::getStorage($db, 'game_env');
|
||||
$clock = \sammo\GameClock::fromStorage($gameStor);
|
||||
$now = $clock->nowTick();
|
||||
$db->delete('select_pool', [
|
||||
'reserved_until'=>null,
|
||||
'owner'=>null,
|
||||
],'(reserved_until < %s OR reserved_until IS NULL) AND general_id IS null', $now);
|
||||
$validUntil = $oNow->add(new \DateInterval(sprintf('PT%dS', 30)));
|
||||
$validUntil = $now + $clock->ticksFromSeconds(30);
|
||||
foreach($result as $pickedGeneral){
|
||||
$dbInsert[] = [
|
||||
'owner'=>$owner,
|
||||
'uniqueName'=>$pickedGeneral->getUniqueName(),
|
||||
'info'=>$pickedGeneral->getInfo(),
|
||||
'reserved_until'=>$validUntil->format(('Y-m-d H:i:s'))
|
||||
'reserved_until'=>$validUntil
|
||||
];
|
||||
}
|
||||
$db->insert('select_pool', $dbInsert);
|
||||
@@ -99,4 +98,4 @@ class RandomNameGeneral extends AbsGeneralPool{
|
||||
public static function initPool(\MeekroDB $db){
|
||||
//do Nothing
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,7 +14,7 @@ class SPoolUnderU100 extends AbsFromUserPool
|
||||
private const STAT_BONUS_MAX_TOTAL = 190;
|
||||
private const STAT_BONUS_MAX_MULTIPLIER = 1.5;
|
||||
|
||||
public function __construct(\MeekroDB $db, RandUtil $rng, array $info, string $validUntil)
|
||||
public function __construct(\MeekroDB $db, RandUtil $rng, array $info, int $validUntil)
|
||||
{
|
||||
$targetInfo = $info;
|
||||
$initialInfo = $info;
|
||||
|
||||
+75
-18
@@ -15,6 +15,9 @@ class Message
|
||||
|
||||
protected $sendCnt = 0;
|
||||
|
||||
private ?int $sendTimeTick = null;
|
||||
private ?int $sendValidUntilTick = null;
|
||||
|
||||
public function __construct(
|
||||
public MessageType $msgType,
|
||||
public MessageTarget $src,
|
||||
@@ -26,6 +29,12 @@ class Message
|
||||
) {
|
||||
}
|
||||
|
||||
public static function gameNow(): \DateTime
|
||||
{
|
||||
$clock = GameClock::fromStorage(KVStorage::getStorage(DB::db(), 'game_env'));
|
||||
return \DateTime::createFromImmutable($clock->nowDateTime());
|
||||
}
|
||||
|
||||
public function setSentInfo(int $mailbox, int $messageID) : self
|
||||
{
|
||||
if(!Message::isValidMailBox($mailbox)){
|
||||
@@ -78,6 +87,15 @@ class Message
|
||||
}
|
||||
|
||||
public function toArray():array{
|
||||
$clock = GameClock::fromStorage(KVStorage::getStorage(DB::db(), 'game_env'));
|
||||
$messageTick = $clock->dateTimeToTick($this->date);
|
||||
$deleteUntilTick = GameClock::addTicks($messageTick, $clock->ticksFromMinutes(5));
|
||||
$deleteRemainingTicks = max(0, $deleteUntilTick - $clock->nowTick());
|
||||
$deleteRemainingTicks = min($deleteRemainingTicks, $clock->ticksFromSeconds(2_147_483));
|
||||
$deleteRemainingMilliseconds = intdiv(
|
||||
$deleteRemainingTicks * 1000,
|
||||
$clock->ticksPerSecond(),
|
||||
);
|
||||
if($this->msgType === MessageType::public){
|
||||
$src = $this->src->toArray();
|
||||
$dest = null;
|
||||
@@ -98,12 +116,15 @@ class Message
|
||||
'dest'=>$dest,
|
||||
'text'=>$this->msg,
|
||||
'option'=>$this->msgOption,
|
||||
'time'=>$this->date->format('Y-m-d H:i:s')
|
||||
'time'=>$this->date->format('Y-m-d H:i:s'),
|
||||
'deleteRemainingMilliseconds'=>$deleteRemainingMilliseconds,
|
||||
'clockMode'=>$clock->getMode(),
|
||||
];
|
||||
}
|
||||
|
||||
public static function buildFromArray(array $row) : Message
|
||||
{
|
||||
$clock = GameClock::fromStorage(KVStorage::getStorage(DB::db(), 'game_env'));
|
||||
$dbMessage = Json::decode($row['message']);
|
||||
|
||||
$msgType = MessageType::from($row['type']);
|
||||
@@ -116,8 +137,8 @@ class Message
|
||||
$src,
|
||||
$dest,
|
||||
$dbMessage['text'],
|
||||
new \DateTime($row['time']),
|
||||
new \DateTime($row['valid_until']),
|
||||
\DateTime::createFromImmutable($clock->tickToDateTime(Util::toInt($row['time']))),
|
||||
\DateTime::createFromImmutable($clock->tickToDateTime(Util::toInt($row['valid_until']))),
|
||||
$option
|
||||
];
|
||||
|
||||
@@ -151,9 +172,12 @@ class Message
|
||||
public static function getMessageByID(int $messageID) : ?Message
|
||||
{
|
||||
$db = DB::db();
|
||||
$now = new \DateTime();
|
||||
$row = $db->queryFirstRow('SELECT * FROM `message` WHERE `id` = %i AND valid_until', $messageID);
|
||||
//FIXME: $now가 들어가야 하는데 안 들어가있는데?
|
||||
$clock = GameClock::fromStorage(KVStorage::getStorage($db, 'game_env'));
|
||||
$row = $db->queryFirstRow(
|
||||
'SELECT * FROM `message` WHERE `id` = %i AND valid_until > %i',
|
||||
$messageID,
|
||||
$clock->nowTick(),
|
||||
);
|
||||
if (!$row) {
|
||||
return null;
|
||||
}
|
||||
@@ -171,12 +195,12 @@ class Message
|
||||
{
|
||||
$db = DB::db();
|
||||
|
||||
$date = (new \DateTime())->format('Y-m-d H:i:s');
|
||||
$date = GameClock::fromStorage(KVStorage::getStorage($db, 'game_env'))->nowTick();
|
||||
|
||||
$where = new \WhereClause('and');
|
||||
$where->add('mailbox = %i', $mailbox);
|
||||
$where->add('type = %s', $msgType->value);
|
||||
$where->add('valid_until > %s', $date);
|
||||
$where->add('valid_until > %i', $date);
|
||||
if ($fromSeq > 0) {
|
||||
$where->add('id >= %i', $fromSeq);
|
||||
}
|
||||
@@ -203,12 +227,12 @@ class Message
|
||||
{
|
||||
$db = DB::db();
|
||||
|
||||
$date = (new \DateTime())->format('Y-m-d H:i:s');
|
||||
$date = GameClock::fromStorage(KVStorage::getStorage($db, 'game_env'))->nowTick();
|
||||
|
||||
$where = new \WhereClause('and');
|
||||
$where->add('mailbox = %i', $mailbox);
|
||||
$where->add('type = %s', $msgType->value);
|
||||
$where->add('valid_until > %s', $date);
|
||||
$where->add('valid_until > %i', $date);
|
||||
$where->add('id < %i', $toSeq);
|
||||
|
||||
if ($limit > 0) {
|
||||
@@ -236,7 +260,8 @@ class Message
|
||||
return '시스템 외교 메시지는 삭제할 수 없습니다.';
|
||||
}
|
||||
|
||||
$prev5min = new \DateTime();
|
||||
$clock = GameClock::fromStorage(KVStorage::getStorage(DB::db(), 'game_env'));
|
||||
$prev5min = \DateTime::createFromImmutable($clock->tickToDateTime($clock->nowTick()));
|
||||
$prev5min->sub(new \DateInterval('PT5M'));
|
||||
|
||||
if($msgObj->date < $prev5min){
|
||||
@@ -265,14 +290,15 @@ class Message
|
||||
|
||||
}
|
||||
|
||||
$in1min = new \DateTime();
|
||||
$now = \DateTime::createFromImmutable($clock->tickToDateTime($clock->nowTick()));
|
||||
$in1min = clone $now;
|
||||
$in1min->add(new \DateInterval('PT1M'));
|
||||
$newMsg = new Message(
|
||||
$msgObj->msgType,
|
||||
$msgObj->src,
|
||||
$msgObj->dest,
|
||||
"req_del_msg",
|
||||
new \DateTime(),
|
||||
$now,
|
||||
$in1min,
|
||||
$msgOption
|
||||
);
|
||||
@@ -300,13 +326,15 @@ class Message
|
||||
|
||||
|
||||
$db = DB::db();
|
||||
$clock = GameClock::fromStorage(KVStorage::getStorage($db, 'game_env'));
|
||||
[$timeTick, $validUntilTick] = $this->resolveSendTicks($clock);
|
||||
$db->insert('message', [
|
||||
'mailbox' => $mailbox,
|
||||
'type' => $this->msgType->value,
|
||||
'src' => $src_id,
|
||||
'dest' => $dest_id,
|
||||
'time' => $this->date->format('Y-m-d H:i:s'),
|
||||
'valid_until' => $this->validUntil->format('Y-m-d H:i:s'),
|
||||
'time' => $timeTick,
|
||||
'valid_until' => $validUntilTick,
|
||||
'message' => Json::encode([
|
||||
'src'=>($this->src)?($this->src->toArray()):[],
|
||||
'dest'=>($this->dest)?($this->dest->toArray()):[],
|
||||
@@ -317,6 +345,32 @@ class Message
|
||||
return [$mailbox, $db->insertId()];
|
||||
}
|
||||
|
||||
/** @return array{0:int, 1:int} */
|
||||
protected function resolveSendTicks(GameClock $clock): array
|
||||
{
|
||||
if ($this->sendTimeTick !== null && $this->sendValidUntilTick !== null) {
|
||||
return [$this->sendTimeTick, $this->sendValidUntilTick];
|
||||
}
|
||||
|
||||
$timeTick = $clock->nowTick();
|
||||
if (Util::toInt($this->validUntil->format('Y')) >= 9000) {
|
||||
$validUntilTick = GameClock::MAX_SAFE_TICK;
|
||||
} else {
|
||||
$validitySeconds = $this->validUntil->getTimestamp() - $this->date->getTimestamp();
|
||||
$validUntilTick = GameClock::addTicks(
|
||||
$timeTick,
|
||||
$clock->ticksFromSeconds($validitySeconds),
|
||||
);
|
||||
}
|
||||
|
||||
$this->sendTimeTick = $timeTick;
|
||||
$this->sendValidUntilTick = $validUntilTick;
|
||||
$this->date = \DateTime::createFromImmutable($clock->tickToDateTime($timeTick));
|
||||
$this->validUntil = \DateTime::createFromImmutable($clock->tickToDateTime($validUntilTick));
|
||||
|
||||
return [$timeTick, $validUntilTick];
|
||||
}
|
||||
|
||||
private function sendToSender():array{
|
||||
if($this->sendCnt > 1){
|
||||
throw new \RuntimeException('이미 전송한 메일입니다.');
|
||||
@@ -430,7 +484,7 @@ class Message
|
||||
$src,
|
||||
$dest,
|
||||
$msg,
|
||||
new \DateTime(),
|
||||
self::gameNow(),
|
||||
new \DateTime('9999-12-31'),
|
||||
[]
|
||||
);
|
||||
@@ -464,6 +518,8 @@ class Message
|
||||
}
|
||||
|
||||
public function invalidate(?array $newMsgOption=null, bool $hideMsg=true){
|
||||
$clock = GameClock::fromStorage(KVStorage::getStorage(DB::db(), 'game_env'));
|
||||
$validUntilTick = $clock->dateTimeToTick($this->validUntil);
|
||||
if($newMsgOption !== null){
|
||||
$this->msgOption = $newMsgOption;
|
||||
}
|
||||
@@ -471,7 +527,8 @@ class Message
|
||||
$this->msgOption['invalid'] = true;
|
||||
|
||||
if($hideMsg){
|
||||
$this->validUntil = new \DateTime('2000-12-31');
|
||||
$validUntilTick = GameClock::addTicks($clock->nowTick(), -1);
|
||||
$this->validUntil = \DateTime::createFromImmutable($clock->tickToDateTime($validUntilTick));
|
||||
}
|
||||
else{
|
||||
if(key_exists('receiverMessageID', $this->msgOption)){
|
||||
@@ -489,7 +546,7 @@ class Message
|
||||
'text' => $this->msg,
|
||||
'option' => $this->msgOption
|
||||
]),
|
||||
'valid_until'=>$this->validUntil->format('Y-m-d H:i:s'),
|
||||
'valid_until'=>$validUntilTick,
|
||||
], 'id=%i', $this->id);
|
||||
|
||||
}
|
||||
|
||||
@@ -142,7 +142,7 @@ class RaiseInvaderMessage extends Message
|
||||
$srcTarget = MessageTarget::buildSystemTarget();
|
||||
$destTarget = MessageTarget::buildQuick($destGeneralID);
|
||||
if ($date === null) {
|
||||
$date = new \DateTime();
|
||||
$date = Message::gameNow();
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
+34
-16
@@ -245,21 +245,35 @@ class ResetHelper{
|
||||
true
|
||||
);
|
||||
|
||||
if($sync == 0) {
|
||||
// 현재 시간을 1월로 맞춤
|
||||
$starttime = cutTurn($turntime, $turnterm);
|
||||
$month = 1;
|
||||
$year = $startyear;
|
||||
} else {
|
||||
// 현재 시간과 동기화
|
||||
[$starttime, $yearPulled, $month] = cutDay($turntime, $turnterm);
|
||||
$requestedTime = new \DateTimeImmutable($turntime);
|
||||
if($sync == 0) {
|
||||
// 현재 시간을 1월로 맞춤
|
||||
$baseTime = new \DateTimeImmutable(cutTurnDateTime($turntime, $turnterm));
|
||||
$month = 1;
|
||||
$year = $startyear;
|
||||
} else {
|
||||
// 현재 시간과 동기화
|
||||
[$baseTimeString, $yearPulled, $month] = cutDay($turntime, $turnterm);
|
||||
$baseTime = new \DateTimeImmutable($baseTimeString);
|
||||
if($yearPulled){
|
||||
$year = $startyear-1;
|
||||
}
|
||||
else{
|
||||
$year = $startyear;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$wallNow = GameClock::readWallTime();
|
||||
$initialClock = new GameClock(
|
||||
$baseTime,
|
||||
$turnterm,
|
||||
0,
|
||||
GameClock::MODE_REALTIME,
|
||||
$wallNow,
|
||||
fn (): \DateTimeImmutable => $wallNow,
|
||||
);
|
||||
$requestedTick = $initialClock->dateTimeToTick($requestedTime);
|
||||
$currentTick = $initialClock->dateTimeToTick($wallNow);
|
||||
|
||||
$killturn = 4800 / $turnterm;
|
||||
if($npcmode == 1) { $killturn = intdiv($killturn, 3); }
|
||||
@@ -283,10 +297,14 @@ class ResetHelper{
|
||||
'maxnation'=>GameConst::$defaultMaxNation,
|
||||
'refreshLimit'=>30000,
|
||||
'develcost'=>$develcost,
|
||||
'turntime'=>$turntime,
|
||||
'starttime'=>$starttime,
|
||||
'opentime'=>$turntime,
|
||||
'turnterm'=>$turnterm,
|
||||
'turntime'=>$requestedTick,
|
||||
'starttime'=>0,
|
||||
'opentime'=>$requestedTick,
|
||||
'turnterm'=>$turnterm,
|
||||
'clock_base_time'=>TimeUtil::format($baseTime, true),
|
||||
'clock_tick'=>$currentTick,
|
||||
'clock_mode'=>GameClock::MODE_REALTIME,
|
||||
'clock_wall_anchor'=>TimeUtil::format($wallNow, true),
|
||||
'killturn'=>$killturn,
|
||||
'genius'=>GameConst::$defaultMaxGenius,
|
||||
'show_img_level'=>$show_img_level,
|
||||
@@ -308,7 +326,7 @@ class ResetHelper{
|
||||
'name'=>$admin['name'],
|
||||
'picture'=>$admin['picture'],
|
||||
'imgsvr'=>$admin['imgsvr'],
|
||||
'turntime'=>$turntime,
|
||||
'turntime'=>$requestedTick,
|
||||
'killturn'=>9999,
|
||||
'crewtype'=>GameUnitConst::DEFAULT_CREWTYPE
|
||||
]);
|
||||
@@ -344,7 +362,7 @@ class ResetHelper{
|
||||
|
||||
$db->insert('ng_games', [
|
||||
'server_id'=>$serverID,
|
||||
'date'=>$turntime,
|
||||
'date'=>TimeUtil::format($requestedTime, false),
|
||||
'winner_nation'=>null,
|
||||
'map'=>$scenarioObj->getMapTheme(),
|
||||
'season'=>$seasonIdx,
|
||||
@@ -368,4 +386,4 @@ class ResetHelper{
|
||||
'result'=>true
|
||||
];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -136,13 +136,13 @@ class GeneralBuilder{
|
||||
$this->specialWar = GameConst::$defaultSpecialWar;
|
||||
}
|
||||
try{
|
||||
$this->specialDomestic = SpecialityHelper::getDomesticClassByName($special);
|
||||
$this->specialWar = GameConst::$defaultSpecialWar;
|
||||
}
|
||||
catch (\Exception $e){
|
||||
$this->specialDomestic = GameConst::$defaultSpecialDomestic;
|
||||
$this->specialWar = SpecialityHelper::getWarClassByName($special);
|
||||
}
|
||||
catch (\Exception $e){
|
||||
$this->specialDomestic = SpecialityHelper::getDomesticClassByName($special);
|
||||
$this->specialWar = GameConst::$defaultSpecialWar;
|
||||
}
|
||||
return $this;
|
||||
}
|
||||
|
||||
@@ -653,7 +653,7 @@ class GeneralBuilder{
|
||||
$officerLevel = $nationID?1:0;
|
||||
}
|
||||
|
||||
$turntime = \sammo\getRandTurn($this->rng, $env['turnterm'], new \DateTimeImmutable($env['turntime']));
|
||||
$turntime = \sammo\getRandTurn($this->rng, $env['turnterm'], Util::toInt($env['turntime']));
|
||||
|
||||
if($this->killturn){
|
||||
$killturn = $this->killturn;
|
||||
@@ -735,4 +735,4 @@ class GeneralBuilder{
|
||||
|
||||
return true; //생성되었다.
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -35,7 +35,7 @@ class ScoutMessage extends Message
|
||||
$this->validScout = false;
|
||||
}
|
||||
|
||||
if ($this->validUntil <= new \DateTime()) {
|
||||
if ($this->validUntil <= $this->date) {
|
||||
$this->validScout = false;
|
||||
}
|
||||
}
|
||||
@@ -108,7 +108,7 @@ class ScoutMessage extends Message
|
||||
$this->src,
|
||||
$this->dest,
|
||||
"{$this->src->nationName}{$josaRo} 등용 제의 수락",
|
||||
new \DateTime(),
|
||||
Message::gameNow(),
|
||||
new \DateTime('9999-12-31'),
|
||||
[
|
||||
'delete' => $this->id
|
||||
@@ -122,11 +122,11 @@ class ScoutMessage extends Message
|
||||
public static function invalidateAll(int $generalID, ?int $exceptMsgID = null)
|
||||
{
|
||||
$db = DB::db();
|
||||
$now = TimeUtil::now();
|
||||
$now = GameClock::fromStorage(KVStorage::getStorage($db, 'game_env'))->nowTick();
|
||||
//XXX: 뭔가 기존 쿼리가 애매하다. invalid 관련해서 다른 옵션이 가능한가?
|
||||
$rawMsgList = Util::convertArrayToDict($db->query(
|
||||
'SELECT * FROM `message` WHERE
|
||||
`mailbox` = %i AND `type` = "private" AND `dest` = `mailbox` AND `valid_until` > %s AND
|
||||
`mailbox` = %i AND `type` = "private" AND `dest` = `mailbox` AND `valid_until` > %i AND
|
||||
JSON_VALUE(message, "$.option.action") = %s',
|
||||
$generalID,
|
||||
$now,
|
||||
@@ -156,7 +156,7 @@ class ScoutMessage extends Message
|
||||
$this->src,
|
||||
$this->dest,
|
||||
"{$this->src->nationName}{$josaRo} 등용 제의 거부",
|
||||
new \DateTime(),
|
||||
Message::gameNow(),
|
||||
new \DateTime('9999-12-31'),
|
||||
[
|
||||
'delete' => $this->id
|
||||
@@ -205,9 +205,9 @@ class ScoutMessage extends Message
|
||||
$db = DB::db();
|
||||
$srcGeneral = $db->queryFirstRow('SELECT `name`, nation FROM general WHERE `no`=%i', $srcGeneralID);
|
||||
$destGeneral = $db->queryFirstRow('SELECT `name`, nation, `officer_level` FROM general WHERE `no`=%i', $destGeneralID);
|
||||
if ($date === null) {
|
||||
$date = new \DateTime();
|
||||
}
|
||||
if ($date === null) {
|
||||
$date = Message::gameNow();
|
||||
}
|
||||
|
||||
if ($destGeneral['officer_level'] == 12) {
|
||||
if ($reason !== null) {
|
||||
|
||||
@@ -40,34 +40,22 @@ final class ServerTool
|
||||
$locked = tryLock();
|
||||
}
|
||||
|
||||
$oldunit = $admin['turnterm'] * 60;
|
||||
$unit = $turnterm * 60;
|
||||
|
||||
if($unit == $oldunit){
|
||||
if($turnterm == $admin['turnterm']){
|
||||
if($locked){
|
||||
unlock();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
$unitDiff = $unit / $oldunit;
|
||||
|
||||
$servTurnTime = new \DateTimeImmutable($admin['turntime']);
|
||||
foreach ($db->query('SELECT no,turntime FROM general') as $gen) {
|
||||
$genTurnTime = new \DateTimeImmutable($gen['turntime']);
|
||||
$timeDiff = TimeUtil::DateIntervalToSeconds($genTurnTime->diff($servTurnTime));
|
||||
$timeDiff *= $unitDiff;
|
||||
$newGenTurnTime = $servTurnTime->add(TimeUtil::secondsToDateInterval($timeDiff));
|
||||
|
||||
$db->update('general', [
|
||||
'turntime' => $newGenTurnTime->format('Y-m-d H:i:s.u')
|
||||
], 'no=%i', $gen['no']);
|
||||
}
|
||||
$turn = ($admin['year'] - $admin['startyear']) * 12 + $admin['month'] - 1;
|
||||
$starttime = $servTurnTime->sub(TimeUtil::secondsToDateInterval($turn * $unit))->format('Y-m-d H:i:s');
|
||||
$starttime = cutTurn($starttime, $turnterm, false);
|
||||
$oldClock = GameClock::fromStorage($gameStor);
|
||||
$currentTick = $oldClock->nowTick();
|
||||
$currentDisplay = $oldClock->tickToDateTime($currentTick);
|
||||
$oldClock->persistTick($gameStor, $currentTick);
|
||||
$gameStor->turnterm = $turnterm;
|
||||
$gameStor->starttime = $starttime;
|
||||
$gameStor->clock_base_time = TimeUtil::format(
|
||||
GameClock::baseTimeForProjection($currentDisplay, $currentTick, $turnterm),
|
||||
true,
|
||||
);
|
||||
pushGlobalHistoryLog(["<R>★</>턴시간이 <C>{$turnterm}분</>으로 변경됩니다."]);
|
||||
|
||||
if($locked){
|
||||
|
||||
@@ -6,15 +6,20 @@ use sammo\Enums\EventTarget;
|
||||
use sammo\Enums\InheritanceKey;
|
||||
use \Symfony\Component\Lock;
|
||||
|
||||
class TurnExecutionHelper
|
||||
{
|
||||
class TurnExecutionHelper
|
||||
{
|
||||
/** @var General*/
|
||||
protected $generalObj;
|
||||
|
||||
public function __construct(General $general)
|
||||
public function __construct(General $general)
|
||||
{
|
||||
$this->generalObj = $general;
|
||||
}
|
||||
}
|
||||
|
||||
public static function monotonicCompletionTick(int $completedTick, int $candidateTick): int
|
||||
{
|
||||
return max($completedTick, $candidateTick);
|
||||
}
|
||||
|
||||
public function __destruct()
|
||||
{
|
||||
@@ -215,14 +220,13 @@ class TurnExecutionHelper
|
||||
$general->rebirth();
|
||||
}
|
||||
|
||||
$turntime = addTurn($general->getTurnTime(), $gameStor->turnterm);
|
||||
$turntime = addTurn($general->getTurnTick(), $gameStor->turnterm);
|
||||
|
||||
$nextTurnTimeBase = $general->getAuxVar('nextTurnTimeBase');
|
||||
if($nextTurnTimeBase !== null){
|
||||
$turntime = cutTurn($turntime, $gameStor->turnterm);
|
||||
$turntimeObj = new \DateTimeImmutable($turntime);
|
||||
$turntimeObj = $turntimeObj->add(TimeUtil::secondsToDateInterval($nextTurnTimeBase));
|
||||
$turntime = TimeUtil::format($turntimeObj, true);
|
||||
$clock = GameClock::fromStorage($gameStor);
|
||||
$turntime += $clock->ticksFromSeconds($nextTurnTimeBase);
|
||||
$general->setAuxVar('nextTurnTimeBase', null);
|
||||
}
|
||||
|
||||
@@ -230,7 +234,7 @@ class TurnExecutionHelper
|
||||
}
|
||||
|
||||
|
||||
static public function executeGeneralCommandUntil(string $date, \DateTimeInterface $limitActionTime, int $year, int $month)
|
||||
static public function executeGeneralCommandUntil(int $date, \DateTimeInterface $limitActionTime, int $year, int $month)
|
||||
{
|
||||
$db = DB::db();
|
||||
$generalsTodo = $db->query(
|
||||
@@ -244,7 +248,7 @@ class TurnExecutionHelper
|
||||
$autorun_user = $gameStor->autorun_user;
|
||||
|
||||
foreach ($generalsTodo as $rawGeneral) {
|
||||
$currActionTime = new \DateTimeImmutable();
|
||||
$currActionTime = GameClock::readWallTime();
|
||||
if ($currActionTime > $limitActionTime) {
|
||||
return [true, $currentTurn];
|
||||
}
|
||||
@@ -350,7 +354,7 @@ class TurnExecutionHelper
|
||||
pullNationCommand($general->getVar('nation'), $general->getVar('officer_level'));
|
||||
pullGeneralCommand($general->getID());
|
||||
|
||||
$currentTurn = $general->getTurnTime();
|
||||
$currentTurn = $general->getTurnTick();
|
||||
$general->increaseVarWithLimit('myset', GameConst::$incDefSettingChange, null, GameConst::$maxDefSettingChange);
|
||||
|
||||
if (($autorun_user['limit_minutes'] ?? false) && $general->getNPCType() < 2 && $hasReservedTurn) {
|
||||
@@ -390,13 +394,14 @@ class TurnExecutionHelper
|
||||
return true;
|
||||
}
|
||||
|
||||
static public function executeAllCommand(&$executed = false, &$locked = false): string
|
||||
static public function executeAllCommand(&$executed = false, &$locked = false): int
|
||||
{
|
||||
$db = DB::db();
|
||||
|
||||
$gameStor = KVStorage::getStorage($db, 'game_env');
|
||||
|
||||
if (TimeUtil::now(true) < $gameStor->turntime) {
|
||||
$clock = GameClock::fromStorage($gameStor);
|
||||
if ($clock->nowTick() < $gameStor->turntime) {
|
||||
//턴 시각 이전이면 아무것도 하지 않음
|
||||
return $gameStor->turntime;
|
||||
}
|
||||
@@ -420,7 +425,7 @@ class TurnExecutionHelper
|
||||
//접속자 수 따라서 갱신제한 변경
|
||||
CheckOverhead();
|
||||
|
||||
$date = TimeUtil::now(true);
|
||||
$date = $clock->nowTick();
|
||||
// 최종 처리 월턴의 다음 월턴시간 구함
|
||||
//$lastExecuted = $gameStor->turntime;
|
||||
$prevTurn = cutTurn($gameStor->turntime, $gameStor->turnterm);
|
||||
@@ -433,7 +438,7 @@ class TurnExecutionHelper
|
||||
$maxActionTime = max($maxActionTime * 2 / 3, $maxActionTime - 10);
|
||||
}
|
||||
|
||||
$limitActionTime = (new \DateTimeImmutable())->add(TimeUtil::secondsToDateInterval($maxActionTime));
|
||||
$limitActionTime = GameClock::readWallTime()->add(TimeUtil::secondsToDateInterval($maxActionTime));
|
||||
|
||||
// 현재 턴 이전 월턴까지 모두처리.
|
||||
//최종 처리 이후 다음 월턴이 현재 시간보다 전이라면
|
||||
@@ -450,9 +455,12 @@ class TurnExecutionHelper
|
||||
updateTraffic();
|
||||
|
||||
if ($executionOver) {
|
||||
if ($currentTurn !== null) {
|
||||
$executed = true;
|
||||
$gameStor->turntime = $currentTurn;
|
||||
if ($currentTurn !== null) {
|
||||
$executed = true;
|
||||
$gameStor->turntime = self::monotonicCompletionTick(
|
||||
Util::toInt($gameStor->turntime),
|
||||
$currentTurn,
|
||||
);
|
||||
}
|
||||
unlock();
|
||||
return $gameStor->turntime;
|
||||
@@ -497,10 +505,16 @@ class TurnExecutionHelper
|
||||
$gameStor->month
|
||||
);
|
||||
|
||||
if ($currentTurn !== null) {
|
||||
$executed = true;
|
||||
$gameStor->turntime = $currentTurn;
|
||||
}
|
||||
if ($currentTurn !== null) {
|
||||
$executed = true;
|
||||
// A general's sub-tick can be just before the monthly boundary that
|
||||
// was completed above. Never move the global completion cursor back
|
||||
// behind an already-applied monthly event.
|
||||
$gameStor->turntime = self::monotonicCompletionTick(
|
||||
Util::toInt($gameStor->turntime),
|
||||
$currentTurn,
|
||||
);
|
||||
}
|
||||
|
||||
//토너먼트 처리
|
||||
processTournament();
|
||||
|
||||
@@ -55,7 +55,8 @@ class UserLogger
|
||||
}
|
||||
|
||||
$db = DB::db();
|
||||
$date = TimeUtil::now();
|
||||
$clock = GameClock::fromStorage(KVStorage::getStorage($db, 'game_env'));
|
||||
$date = $clock->formatTick($clock->nowTick());
|
||||
$serverID = UniqueConst::$serverID;
|
||||
$request = array_map(function ($textAndType) use ($date, $serverID) {
|
||||
[$text, $type] = $textAndType;
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user