213 lines
7.5 KiB
PHP
213 lines
7.5 KiB
PHP
<?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();
|