Files
core2026/docs/architecture/legacy-engine-execution.md
T

136 lines
6.2 KiB
Markdown

# Legacy Engine Execution Flow
This document summarizes how the legacy engine advances turns and executes
commands. It focuses on the execution pipeline, RNG seeding, and state writes
based on `legacy/hwe/sammo/API/Global/ExecuteEngine.php`,
`legacy/hwe/sammo/TurnExecutionHelper.php`, and `legacy/hwe/sammo/Command/BaseCommand.php`.
## Entry Point: ExecuteEngine API
- Endpoint: `legacy/hwe/sammo/API/Global/ExecuteEngine.php`
- Session: no session required (`NO_SESSION`)
- Optional `serverID` guard via `UniqueConst::$serverID`
- Calls `TurnExecutionHelper::executeAllCommand($updated, $locked)`
- Returns `{ updated, locked, lastExecuted }`
## Global Turn Loop (`TurnExecutionHelper::executeAllCommand`)
1. **Time gate**
- If `now < game_env.turntime`, return without executing.
2. **Locking**
- `tryLock()` on `plock` row (`type='GAME'`).
- If locked or `isunited` in `2|3`, return (frozen state).
3. **Pre-turn maintenance**
- Cache game env, `checkDelay()`, `updateOnline()`, `CheckOverhead()`.
4. **Catch-up monthly loop**
- Compute `prevTurn = cutTurn(turntime, turnterm)` and `nextTurn = addTurn(prevTurn)`.
- While `nextTurn <= now`:
- `executeGeneralCommandUntil(nextTurn, limitActionTime, year, month)`
- `updateTraffic()`
- Monthly pipeline:
- `runEventHandler(PreMonth)`
- `preUpdateMonthly()`
- `turnDate(nextTurn)`
- `checkStatistic()` (only if `month == 1`)
- `runEventHandler(Month)`
- `postUpdateMonthly($monthlyRng)`
- Advance `prevTurn`, `nextTurn`, update `game_env.turntime`.
5. **Current partial month**
- `turnDate(prevTurn)`
- `executeGeneralCommandUntil(now, limitActionTime, year, month)`
6. **Post-turn maintenance**
- `processTournament()`
- `processAuction()`
- Reset cache, `unlock()`.
`limitActionTime` is derived from `max_execution_time` (roughly 2/3 of the
configured limit). If time runs out mid-loop, it returns early and keeps
`game_env.turntime` at the most recent executed value.
## Per-General Execution (`executeGeneralCommandUntil`)
For each general with `turntime < targetDate` (ordered by `turntime, no`):
1. **Load state**
- `General::createObjFromDB()` and `KVStorage` for `game_env`.
2. **Nation command (if officer_level >= 5)**
- Pull `nation_turn` row for `turn_idx = 0`.
- Build `NationCommand` with `LastTurn` stored in `nation_env`.
3. **AI/autorun**
- NPCs (`npc >= 2`) or players past `autorun_limit` use `GeneralAI`.
- AI can replace both nation and general commands.
4. **Preprocess triggers**
- RNG seed: `hiddenSeed + 'preprocess' + year + month + generalID`.
- `preprocessCommand()` merges action triggers + `che_부상경감`, `che_병력군량소모`.
5. **Blocked users**
- `processBlocked()` consumes `killturn` and logs if `block >= 2`.
6. **Execute nation command**
- RNG seed: `hiddenSeed + 'nationCommand' + year + month + generalID + commandKey`.
- `processNationCommand()` checks conditions, term stack, `run()`.
- If `run()` fails and `getAlternativeCommand()` exists, it retries.
- Updates `nation_env` with `LastTurn` result.
7. **Execute general command**
- Load from `general_turn` (`turn_idx = 0`), default to `휴식`.
- RNG seed: `hiddenSeed + 'generalCommand' + year + month + generalID + commandKey`.
- `processCommand()` checks conditions, term stack, `run()`.
- Updates `killturn` based on NPC status, autorun, or `휴식`.
8. **Queue maintenance & turntime**
- `pullNationCommand()` / `pullGeneralCommand()` advance queues.
- `updateTurnTime()` handles deletion/retirement and sets next `turntime`.
- Persist via `General::applyDB()`.
9. **LastTurn persistence**
- General `LastTurn` lives in `general.last_turn` JSON.
- Nation `LastTurn` is stored in `nation_env` under `turn_last_{officer_level}`.
- `LastTurn.term` only advances when the same command + arg repeats across turns.
## Command Semantics (BaseCommand)
- **Constraints**: permission/min/full conditions are evaluated via
`Constraint::testAll()` with `general/city/nation/dest*` context.
- **Pre-turn requirement**: `getPreReqTurn()` uses `LastTurn` to accumulate
term stack (`addTermStack()`), logging "수행중" until the term completes.
- **Post-turn requirement**: `getPostReqTurn()` uses `next_execute` storage
(general: `next_execute`, nation: `nation_env`) to block early execution.
- **Run flow**: `run($rng)` returns `true` when completed; `false` can chain to
`getAlternativeCommand()`.
## Turntime & Lifecycle (`updateTurnTime`)
- **Inactivity**: if `killturn <= 0`:
- NPC-owned characters can detach (owner -> NPC) if `deadyear` not reached.
- Otherwise the general is deleted (`kill()`).
- **Retirement**: if `age >= retirementYear` and not NPC, `CheckHall()` and
`rebirth()` are invoked.
- **Scheduling**: next `turntime` is `addTurn(current, turnterm)` with
optional `nextTurnTimeBase` override (aux var).
## killturn, block, autorun
- `killturn` acts as an inactivity counter; it is reset to `game_env.killturn`
when a non-rest player action completes, and decremented for NPCs, autorun,
rest commands, or block states.
- `block >= 2` forces `killturn` decrement and logs a block message.
- When `killturn <= 0`, the general is converted to NPC (owner removed) or
deleted depending on NPC type and `deadyear`.
- `autorun_limit` is stored in general `aux` and used to decide AI takeover.
## Deterministic RNG Seeds
RNG uses `LiteHashDRBG` with `UniqueConst::$hiddenSeed`:
- Preprocess: `('preprocess', year, month, generalID)`
- Nation command: `('nationCommand', year, month, generalID, commandKey)`
- General command: `('generalCommand', year, month, generalID, commandKey)`
- Monthly: `('monthly', year, month)`
These seeds make command outcomes and monthly updates reproducible for
validation.
## Open Questions / Follow-ups
- `preUpdateMonthly()`, `postUpdateMonthly()`, `turnDate()`, `checkStatistic()`
are defined outside this flow; see `legacy/hwe/func_time_event.php` for
economic updates and population calculations.
- `updateTraffic()`, `checkDelay()`, `updateOnline()` logic lives in
`legacy/hwe/func.php` and related utility files.