test: add monthly city supply trace
This commit is contained in:
@@ -0,0 +1,140 @@
|
||||
{
|
||||
"action": "UpdateCitySupply",
|
||||
"environment": {
|
||||
"year": 193,
|
||||
"month": 1,
|
||||
"startyear": 190
|
||||
},
|
||||
"setup": {
|
||||
"nation": [
|
||||
{
|
||||
"id": 99,
|
||||
"values": {
|
||||
"name": "보급검증국",
|
||||
"color": "#777777",
|
||||
"capital": 1,
|
||||
"level": 1,
|
||||
"type": "che_중립"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": 98,
|
||||
"values": {
|
||||
"name": "불일치수도국",
|
||||
"color": "#888888",
|
||||
"capital": 2,
|
||||
"level": 1,
|
||||
"type": "che_중립"
|
||||
}
|
||||
}
|
||||
],
|
||||
"city": [
|
||||
{
|
||||
"id": 1,
|
||||
"values": {
|
||||
"nation": 99,
|
||||
"supply": 0,
|
||||
"front": 2,
|
||||
"pop": 1001,
|
||||
"agri": 501,
|
||||
"comm": 499,
|
||||
"secu": 99,
|
||||
"trust": 50,
|
||||
"def": 101,
|
||||
"wall": 50,
|
||||
"officer_set": 7,
|
||||
"term": 2,
|
||||
"conflict": {"98": 3}
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": 9,
|
||||
"values": {
|
||||
"nation": 99,
|
||||
"supply": 0,
|
||||
"front": 2,
|
||||
"pop": 1001,
|
||||
"agri": 501,
|
||||
"comm": 499,
|
||||
"secu": 99,
|
||||
"trust": 50,
|
||||
"def": 101,
|
||||
"wall": 50,
|
||||
"officer_set": 7,
|
||||
"term": 2,
|
||||
"conflict": {"98": 3}
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": 2,
|
||||
"values": {
|
||||
"nation": 99,
|
||||
"supply": 1,
|
||||
"front": 2,
|
||||
"pop": 1001,
|
||||
"agri": 501,
|
||||
"comm": 499,
|
||||
"secu": 99,
|
||||
"trust": 33,
|
||||
"def": 101,
|
||||
"wall": 50,
|
||||
"officer_set": 7,
|
||||
"term": 2,
|
||||
"conflict": {"98": 3}
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": 3,
|
||||
"values": {
|
||||
"nation": 0,
|
||||
"supply": 0,
|
||||
"front": 0,
|
||||
"trust": 50
|
||||
}
|
||||
}
|
||||
],
|
||||
"general": [
|
||||
{
|
||||
"id": 1,
|
||||
"values": {
|
||||
"nation": 99,
|
||||
"city": 2,
|
||||
"officer_level": 4,
|
||||
"officer_city": 2,
|
||||
"crew": 101,
|
||||
"train": 51,
|
||||
"atmos": 99
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": 2,
|
||||
"values": {
|
||||
"nation": 99,
|
||||
"city": 1,
|
||||
"officer_level": 4,
|
||||
"officer_city": 2,
|
||||
"crew": 101,
|
||||
"train": 51,
|
||||
"atmos": 99
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": 3,
|
||||
"values": {
|
||||
"nation": 98,
|
||||
"city": 2,
|
||||
"officer_level": 3,
|
||||
"officer_city": 1,
|
||||
"crew": 101,
|
||||
"train": 51,
|
||||
"atmos": 99
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"observe": {
|
||||
"generalIds": [1, 2, 3],
|
||||
"cityIds": [1, 2, 3, 9],
|
||||
"nationIds": [98, 99]
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,212 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace sammo;
|
||||
|
||||
if (PHP_SAPI !== 'cli' || getenv('TURN_DIFFERENTIAL_ENABLED') !== '1') {
|
||||
http_response_code(404);
|
||||
exit;
|
||||
}
|
||||
|
||||
chdir(dirname(__DIR__));
|
||||
$_SERVER['REMOTE_ADDR'] ??= '127.0.0.1';
|
||||
error_reporting(E_ALL & ~E_DEPRECATED);
|
||||
require_once 'lib.php';
|
||||
require_once 'func.php';
|
||||
require_once __DIR__ . '/turn_state_snapshot.php';
|
||||
|
||||
/** @param array<string, mixed> $values */
|
||||
function comparisonMonthlyPatch(string $table, int $id, array $values): void
|
||||
{
|
||||
$definitions = [
|
||||
'city' => [
|
||||
'idColumn' => 'city',
|
||||
'allowed' => [
|
||||
'name', 'level', 'nation', 'supply', 'front', 'pop', 'pop_max',
|
||||
'agri', 'agri_max', 'comm', 'comm_max', 'secu', 'secu_max',
|
||||
'trust', 'trade', 'def', 'def_max', 'wall', 'wall_max',
|
||||
'officer_set', 'state', 'region', 'term', 'conflict',
|
||||
],
|
||||
],
|
||||
'nation' => [
|
||||
'idColumn' => 'nation',
|
||||
'allowed' => ['name', 'color', 'capital', 'gold', 'rice', 'level', 'type'],
|
||||
],
|
||||
'general' => [
|
||||
'idColumn' => 'no',
|
||||
'allowed' => [
|
||||
'name', 'nation', 'city', 'officer_level', 'officer_city',
|
||||
'crew', 'train', 'atmos',
|
||||
],
|
||||
],
|
||||
];
|
||||
$definition = $definitions[$table] ?? null;
|
||||
if ($definition === null) {
|
||||
throw new \InvalidArgumentException("unsupported setup table: {$table}");
|
||||
}
|
||||
$patch = [];
|
||||
foreach ($values as $key => $value) {
|
||||
if (!is_string($key) || !in_array($key, $definition['allowed'], true)) {
|
||||
throw new \InvalidArgumentException("unsupported {$table} setup field");
|
||||
}
|
||||
if (in_array($key, ['conflict'], true) && is_array($value)) {
|
||||
$value = json_encode($value, JSON_THROW_ON_ERROR | JSON_UNESCAPED_UNICODE);
|
||||
}
|
||||
$patch[$key] = $value;
|
||||
}
|
||||
if ($table === 'nation') {
|
||||
$patch += [
|
||||
'nation' => $id,
|
||||
'name' => "fixture-nation-{$id}",
|
||||
'color' => '#777777',
|
||||
'capital' => 0,
|
||||
'gold' => 0,
|
||||
'rice' => 0,
|
||||
'level' => 1,
|
||||
'type' => 'che_중립',
|
||||
'aux' => '{}',
|
||||
];
|
||||
DB::db()->insertUpdate('nation', $patch, $patch);
|
||||
} elseif ($patch !== []) {
|
||||
DB::db()->update($table, $patch, "`{$definition['idColumn']}` = %i", $id);
|
||||
}
|
||||
}
|
||||
|
||||
/** @param array<string, mixed> $observe */
|
||||
function comparisonMonthlyDetails(array $observe, int $worldHistoryAfterId): array
|
||||
{
|
||||
$db = DB::db();
|
||||
$generals = array_map(
|
||||
static fn(array $row): array => comparisonPickRow(
|
||||
$row,
|
||||
[
|
||||
'id' => 'no',
|
||||
'nationId' => 'nation',
|
||||
'cityId' => 'city',
|
||||
'officerLevel' => 'officer_level',
|
||||
'officerCityId' => 'officer_city',
|
||||
'crew' => 'crew',
|
||||
'train' => 'train',
|
||||
'atmos' => 'atmos',
|
||||
],
|
||||
),
|
||||
comparisonRowsById('general', 'no', comparisonIntegerList($observe['generalIds'] ?? [], 'generalIds')),
|
||||
);
|
||||
$cities = array_map(
|
||||
static fn(array $row): array => comparisonPickRow(
|
||||
$row,
|
||||
[
|
||||
'id' => 'city',
|
||||
'nationId' => 'nation',
|
||||
'supplyState' => 'supply',
|
||||
'frontState' => 'front',
|
||||
'officerSet' => 'officer_set',
|
||||
'term' => 'term',
|
||||
'conflict' => 'conflict',
|
||||
],
|
||||
['conflict'],
|
||||
),
|
||||
comparisonRowsById('city', 'city', comparisonIntegerList($observe['cityIds'] ?? [], 'cityIds')),
|
||||
);
|
||||
$worldHistory = array_map(
|
||||
static fn(array $row): array => comparisonPickRow(
|
||||
$row,
|
||||
[
|
||||
'id' => 'id',
|
||||
'nationId' => 'nation_id',
|
||||
'year' => 'year',
|
||||
'month' => 'month',
|
||||
'text' => 'text',
|
||||
],
|
||||
),
|
||||
$db->query(
|
||||
'SELECT id, nation_id, year, month, text FROM world_history WHERE id > %i ORDER BY id',
|
||||
$worldHistoryAfterId,
|
||||
),
|
||||
);
|
||||
return [
|
||||
'generals' => $generals,
|
||||
'cities' => $cities,
|
||||
'worldHistory' => $worldHistory,
|
||||
];
|
||||
}
|
||||
|
||||
function comparisonMonthlyEventTraceMain(): void
|
||||
{
|
||||
try {
|
||||
$input = stream_get_contents(STDIN);
|
||||
$request = json_decode($input === '' ? '{}' : $input, true, flags: JSON_THROW_ON_ERROR);
|
||||
if (!is_array($request)) {
|
||||
throw new \InvalidArgumentException('request must be an object');
|
||||
}
|
||||
if (($request['action'] ?? null) !== 'UpdateCitySupply') {
|
||||
throw new \InvalidArgumentException('unsupported monthly action');
|
||||
}
|
||||
$setup = $request['setup'] ?? [];
|
||||
if (!is_array($setup)) {
|
||||
throw new \InvalidArgumentException('setup must be an object');
|
||||
}
|
||||
foreach (['city', 'nation', 'general'] as $table) {
|
||||
$rows = $setup[$table] ?? [];
|
||||
if (!is_array($rows)) {
|
||||
throw new \InvalidArgumentException("setup.{$table} must be an array");
|
||||
}
|
||||
foreach ($rows as $row) {
|
||||
if (!is_array($row) || !is_int($row['id'] ?? null) || !is_array($row['values'] ?? null)) {
|
||||
throw new \InvalidArgumentException("invalid setup.{$table} row");
|
||||
}
|
||||
comparisonMonthlyPatch($table, $row['id'], $row['values']);
|
||||
}
|
||||
}
|
||||
|
||||
$db = DB::db();
|
||||
$snapshotRequest = ['observe' => $request['observe'] ?? []];
|
||||
$snapshotRequest['observe']['logAfterId'] =
|
||||
(int)($db->queryFirstField('SELECT COALESCE(MAX(id), 0) FROM general_record') ?? 0);
|
||||
$worldHistoryAfterId =
|
||||
(int)($db->queryFirstField('SELECT COALESCE(MAX(id), 0) FROM world_history') ?? 0);
|
||||
$before = comparisonTurnStateSnapshot($snapshotRequest);
|
||||
$beforeDetails = comparisonMonthlyDetails($snapshotRequest['observe'], $worldHistoryAfterId);
|
||||
|
||||
$environment = $request['environment'] ?? [];
|
||||
if (!is_array($environment)) {
|
||||
throw new \InvalidArgumentException('environment must be an object');
|
||||
}
|
||||
$year = $environment['year'] ?? null;
|
||||
$month = $environment['month'] ?? null;
|
||||
$startYear = $environment['startyear'] ?? null;
|
||||
if (!is_int($year) || !is_int($month) || !is_int($startYear)) {
|
||||
throw new \InvalidArgumentException('environment year, month, and startyear must be integers');
|
||||
}
|
||||
|
||||
$action = new Event\Action\UpdateCitySupply();
|
||||
$action->run([
|
||||
'year' => $year,
|
||||
'month' => $month,
|
||||
'startyear' => $startYear,
|
||||
]);
|
||||
unset($action);
|
||||
gc_collect_cycles();
|
||||
|
||||
$after = comparisonTurnStateSnapshot($snapshotRequest);
|
||||
$afterDetails = comparisonMonthlyDetails($snapshotRequest['observe'], $worldHistoryAfterId);
|
||||
echo json_encode(
|
||||
[
|
||||
'schemaVersion' => 1,
|
||||
'engine' => 'ref',
|
||||
'action' => 'UpdateCitySupply',
|
||||
'before' => $before,
|
||||
'beforeDetails' => $beforeDetails,
|
||||
'after' => $after,
|
||||
'afterDetails' => $afterDetails,
|
||||
],
|
||||
JSON_THROW_ON_ERROR | JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES | JSON_PRESERVE_ZERO_FRACTION,
|
||||
), PHP_EOL;
|
||||
} catch (\Throwable $throwable) {
|
||||
fwrite(STDERR, $throwable::class . ': ' . $throwable->getMessage() . PHP_EOL);
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
comparisonMonthlyEventTraceMain();
|
||||
Reference in New Issue
Block a user