test: add aggregate monthly boundary trace
This commit is contained in:
@@ -0,0 +1,226 @@
|
||||
{
|
||||
"action": "MonthlyBoundary",
|
||||
"compactOutput": true,
|
||||
"environment": {
|
||||
"year": 190,
|
||||
"month": 12,
|
||||
"startyear": 190,
|
||||
"turnterm": 10,
|
||||
"starttime": "2026-07-25 00:00:00",
|
||||
"turntime": "2026-07-25 02:00:00"
|
||||
},
|
||||
"setup": {
|
||||
"syncEnvironment": true,
|
||||
"world": {
|
||||
"hiddenSeed": "monthly-boundary-core-catalog"
|
||||
},
|
||||
"gameEnvironment": {
|
||||
"isunited": 1,
|
||||
"refreshLimit": 3,
|
||||
"block_change_scout": false
|
||||
},
|
||||
"resetCities": true,
|
||||
"deleteOtherCities": true,
|
||||
"keepCityIds": [1, 2],
|
||||
"city": [
|
||||
{
|
||||
"id": 1,
|
||||
"values": {
|
||||
"name": "경계도시",
|
||||
"level": 1,
|
||||
"nation": 1,
|
||||
"pop": 10000,
|
||||
"pop_max": 20000,
|
||||
"agri": 1000,
|
||||
"agri_max": 2000,
|
||||
"comm": 1000,
|
||||
"comm_max": 2000,
|
||||
"secu": 1000,
|
||||
"secu_max": 2000,
|
||||
"trust": 50,
|
||||
"trade": 100,
|
||||
"def": 1000,
|
||||
"def_max": 2000,
|
||||
"wall": 1000,
|
||||
"wall_max": 2000,
|
||||
"officer_set": 1,
|
||||
"state": 31,
|
||||
"term": 1,
|
||||
"supply": 1,
|
||||
"front": 2,
|
||||
"conflict": {},
|
||||
"dead": 0
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": 2,
|
||||
"values": {
|
||||
"name": "중립도시",
|
||||
"level": 8,
|
||||
"nation": 0,
|
||||
"pop": 12000,
|
||||
"pop_max": 22000,
|
||||
"agri": 1200,
|
||||
"agri_max": 2200,
|
||||
"comm": 1200,
|
||||
"comm_max": 2200,
|
||||
"secu": 1200,
|
||||
"secu_max": 2200,
|
||||
"trust": 55,
|
||||
"trade": 100,
|
||||
"def": 1200,
|
||||
"def_max": 2200,
|
||||
"wall": 1200,
|
||||
"wall_max": 2200,
|
||||
"officer_set": 1,
|
||||
"state": 0,
|
||||
"term": 0,
|
||||
"supply": 0,
|
||||
"front": 0,
|
||||
"conflict": {},
|
||||
"dead": 0
|
||||
}
|
||||
}
|
||||
],
|
||||
"resetGenerals": true,
|
||||
"deleteOtherGenerals": true,
|
||||
"keepGeneralIds": [1, 2],
|
||||
"general": [
|
||||
{
|
||||
"id": 1,
|
||||
"values": {
|
||||
"name": "경계군주",
|
||||
"nation": 1,
|
||||
"city": 1,
|
||||
"officer_level": 12,
|
||||
"npc": 0,
|
||||
"age": 30,
|
||||
"belong": 3,
|
||||
"makelimit": 2,
|
||||
"gold": 1000,
|
||||
"rice": 1000,
|
||||
"crew": 100,
|
||||
"train": 80,
|
||||
"atmos": 70,
|
||||
"leadership": 50,
|
||||
"strength": 50,
|
||||
"intel": 50,
|
||||
"experience": 0,
|
||||
"dedication": 0,
|
||||
"dex1": 0,
|
||||
"dex2": 0,
|
||||
"dex3": 0,
|
||||
"dex4": 0,
|
||||
"dex5": 0,
|
||||
"personal": "None",
|
||||
"special": "None",
|
||||
"specage": 0,
|
||||
"special2": "None",
|
||||
"specage2": 0,
|
||||
"betray": 0,
|
||||
"bornyear": 160,
|
||||
"deadyear": 250
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": 2,
|
||||
"values": {
|
||||
"name": "경계재야",
|
||||
"nation": 0,
|
||||
"city": 2,
|
||||
"officer_level": 0,
|
||||
"npc": 0,
|
||||
"age": 25,
|
||||
"belong": 4,
|
||||
"makelimit": 0,
|
||||
"gold": 500,
|
||||
"rice": 500,
|
||||
"crew": 50,
|
||||
"train": 60,
|
||||
"atmos": 50,
|
||||
"leadership": 40,
|
||||
"strength": 40,
|
||||
"intel": 40,
|
||||
"experience": 0,
|
||||
"dedication": 0,
|
||||
"dex1": 0,
|
||||
"dex2": 0,
|
||||
"dex3": 0,
|
||||
"dex4": 0,
|
||||
"dex5": 0,
|
||||
"personal": "None",
|
||||
"special": "None",
|
||||
"specage": 0,
|
||||
"special2": "None",
|
||||
"specage2": 0,
|
||||
"betray": 0,
|
||||
"bornyear": 165,
|
||||
"deadyear": 250
|
||||
}
|
||||
}
|
||||
],
|
||||
"resetNations": true,
|
||||
"deleteOtherNations": true,
|
||||
"keepNationIds": [1],
|
||||
"nation": [
|
||||
{
|
||||
"id": 1,
|
||||
"values": {
|
||||
"name": "경계국",
|
||||
"color": "#123456",
|
||||
"capital": 1,
|
||||
"gennum": 1,
|
||||
"gold": 10000,
|
||||
"rice": 20000,
|
||||
"tech": 100,
|
||||
"power": 10,
|
||||
"level": 2,
|
||||
"type": "che_유가",
|
||||
"bill": 100,
|
||||
"rate": 20,
|
||||
"rate_tmp": 10,
|
||||
"scout": 1,
|
||||
"chief_set": 1,
|
||||
"strategic_cmd_limit": 2,
|
||||
"surlimit": 1,
|
||||
"spy": "{}"
|
||||
}
|
||||
}
|
||||
],
|
||||
"resetDiplomacy": true,
|
||||
"resetEvents": true,
|
||||
"event": [
|
||||
{
|
||||
"id": 991001,
|
||||
"target": "PRE_MONTH",
|
||||
"priority": 1000,
|
||||
"condition": true,
|
||||
"action": [
|
||||
["NoticeToHistoryLog", "aggregate-pre", 6]
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 991002,
|
||||
"target": "MONTH",
|
||||
"priority": 1000,
|
||||
"condition": true,
|
||||
"action": [
|
||||
["ProcessIncome", "gold"],
|
||||
["NewYear"],
|
||||
["ResetOfficerLock"],
|
||||
["RandomizeCityTradeRate"],
|
||||
["ChangeCity", "all", {"pop": "+10", "trust": 60}],
|
||||
["NoticeToHistoryLog", "aggregate-month", 6],
|
||||
["DeleteEvent"]
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"observe": {
|
||||
"generalIds": [1, 2],
|
||||
"nationIds": [1],
|
||||
"cityIds": [1, 2],
|
||||
"eventIds": [991001, 991002],
|
||||
"accessGeneralIds": [1, 2]
|
||||
}
|
||||
}
|
||||
@@ -33,7 +33,7 @@ function comparisonMonthlyPatch(string $table, int $id, array $values): void
|
||||
'idColumn' => 'nation',
|
||||
'allowed' => [
|
||||
'name', 'color', 'capital', 'gennum', 'gold', 'rice', 'tech',
|
||||
'power', 'level', 'type', 'rate_tmp', 'scout', 'chief_set', 'aux',
|
||||
'power', 'level', 'type', 'bill', 'rate_tmp', 'scout', 'chief_set', 'aux',
|
||||
'rate', 'strategic_cmd_limit', 'surlimit', 'spy',
|
||||
],
|
||||
],
|
||||
@@ -299,6 +299,7 @@ function comparisonMonthlyEventTraceMain(): void
|
||||
'ResetOfficerLock',
|
||||
'PreUpdateMonthly',
|
||||
'PostUpdateMonthly',
|
||||
'MonthlyBoundary',
|
||||
];
|
||||
if (!in_array($actionName, $supportedActions, true)) {
|
||||
throw new \InvalidArgumentException('unsupported monthly action');
|
||||
@@ -325,6 +326,13 @@ function comparisonMonthlyEventTraceMain(): void
|
||||
comparisonMonthlyPatch('city', $row['id'], $row['values']);
|
||||
}
|
||||
}
|
||||
if (($setup['deleteOtherCities'] ?? false) === true) {
|
||||
$keepCityIds = comparisonIntegerList($setup['keepCityIds'] ?? [], 'keepCityIds');
|
||||
if ($keepCityIds === []) {
|
||||
throw new \InvalidArgumentException('deleteOtherCities requires keepCityIds');
|
||||
}
|
||||
DB::db()->query('DELETE FROM city WHERE city NOT IN %li', $keepCityIds);
|
||||
}
|
||||
if (($setup['resetGenerals'] ?? false) === true) {
|
||||
DB::db()->query(
|
||||
'UPDATE general SET nation = 0, officer_level = 1, npc = 2, killturn = 0, horse = %s, weapon = %s, book = %s, item = %s',
|
||||
@@ -509,6 +517,9 @@ function comparisonMonthlyEventTraceMain(): void
|
||||
];
|
||||
DB::db()->insertUpdate('diplomacy', $diplomacyPatch, $diplomacyPatch);
|
||||
}
|
||||
if (($setup['resetEvents'] ?? false) === true) {
|
||||
DB::db()->query('DELETE FROM event');
|
||||
}
|
||||
foreach ($setup['event'] ?? [] as $row) {
|
||||
if (!is_array($row) || !is_int($row['id'] ?? null) || !is_array($row['action'] ?? null)) {
|
||||
throw new \InvalidArgumentException('invalid setup.event row');
|
||||
@@ -587,19 +598,30 @@ function comparisonMonthlyEventTraceMain(): void
|
||||
}
|
||||
if (($setup['syncEnvironment'] ?? false) === true) {
|
||||
$gameStorage = KVStorage::getStorage(DB::db(), 'game_env');
|
||||
foreach ([
|
||||
$environmentValues = [
|
||||
'year' => $year,
|
||||
'month' => $month,
|
||||
'startyear' => $startYear,
|
||||
'killturn' => $environment['killturn'] ?? $gameStorage->killturn,
|
||||
'turnterm' => $environment['turnterm'] ?? $gameStorage->turnterm,
|
||||
] as $key => $value) {
|
||||
];
|
||||
if (isset($environment['starttime'])) {
|
||||
if (!is_string($environment['starttime']) || $environment['starttime'] === '') {
|
||||
throw new \InvalidArgumentException('environment.starttime must be a non-empty string');
|
||||
}
|
||||
$environmentValues['starttime'] = $environment['starttime'];
|
||||
}
|
||||
foreach ($environmentValues as $key => $value) {
|
||||
$gameStorage->setValue($key, $value);
|
||||
}
|
||||
if ($actionName === 'MonthlyBoundary') {
|
||||
$before = comparisonTurnStateSnapshot($snapshotRequest);
|
||||
$beforeDetails = comparisonMonthlyDetails($snapshotRequest['observe'], $worldHistoryAfterId);
|
||||
}
|
||||
}
|
||||
|
||||
$actionClass = "\\sammo\\Event\\Action\\{$actionName}";
|
||||
if (in_array($actionName, ['PreUpdateMonthly', 'PostUpdateMonthly'], true)) {
|
||||
if (in_array($actionName, ['PreUpdateMonthly', 'PostUpdateMonthly', 'MonthlyBoundary'], true)) {
|
||||
$action = null;
|
||||
} elseif ($actionName === 'ProcessSemiAnnual') {
|
||||
$resource = $request['resource'] ?? null;
|
||||
@@ -707,6 +729,30 @@ function comparisonMonthlyEventTraceMain(): void
|
||||
$seedYear,
|
||||
$seedMonth,
|
||||
))));
|
||||
} elseif ($actionName === 'MonthlyBoundary') {
|
||||
$turntime = $environment['turntime'] ?? null;
|
||||
if (!is_string($turntime) || $turntime === '') {
|
||||
throw new \InvalidArgumentException('MonthlyBoundary requires turntime');
|
||||
}
|
||||
$gameStorage = KVStorage::getStorage($db, 'game_env');
|
||||
$seedYear = (int)$gameStorage->year;
|
||||
$seedMonth = (int)$gameStorage->month;
|
||||
TurnExecutionHelper::runEventHandler($db, $gameStorage, Enums\EventTarget::PreMonth);
|
||||
if (!preUpdateMonthly()) {
|
||||
throw new \RuntimeException('preUpdateMonthly failed');
|
||||
}
|
||||
turnDate($turntime);
|
||||
$gameStorage->resetCache();
|
||||
if ((int)$gameStorage->month === 1) {
|
||||
checkStatistic();
|
||||
}
|
||||
TurnExecutionHelper::runEventHandler($db, $gameStorage, Enums\EventTarget::Month);
|
||||
postUpdateMonthly(new RandUtil(new LiteHashDRBG(Util::simpleSerialize(
|
||||
UniqueConst::$hiddenSeed,
|
||||
'monthly',
|
||||
$seedYear,
|
||||
$seedMonth,
|
||||
))));
|
||||
} else {
|
||||
$action->run($actionEnvironment);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user