Separating state out of the location

This commit is contained in:
Vladislav Khorev committed 2026-10-30 14:56:24 +06:00
1 parent 5e9a663812
commit 297bd7377f
45 files changed
+2114 -778

No files matched your search

+57 -31
View File
@@ -157,23 +157,30 @@ Loading and persistence restoration clear pending events and remain silent.
`InternalGameServer` is the current `IGameServer` implementation. It:
- Exclusively owns the aggregate `GameState`.
- Privately stores loaded runtime `Location` objects.
- Executes typed commands against authoritative state.
- Advances the active location simulation through `update(deltaMs)`.
- Synchronizes non-bound auxiliary state such as dialogue, Lua globals, triggers, and teleports.
- Builds and caches immutable snapshots.
- Delegates save/load serialization to the aggregate state model.
`Game` remains a privileged lifecycle host, but it no longer holds or receives a
mutable `GameState` reference. It uses private, focused internal-server operations
for campaign loading and location construction. Those operations publish revisions
themselves and are not exposed by `IGameServer`.
`LocalGameServerHost` is the graphical client's integration adapter. It owns loaded
runtime `Location` objects, forwards simulation events to them, and synchronizes
dialogue, Lua, trigger, and teleport auxiliary state. `Game` uses the explicit
`IGameServerHost` lifecycle interface and is no longer a friend of
`InternalGameServer`. The standalone server does not compile this adapter.
Location loading has two phases. `LocationContentLoader` parses renderer-free
`LocationDefinition` data, and `LocationGameState::setup()` creates/reconciles
authoritative NPC, interactive-object, navigation, taxi, trigger, teleport, and
animation state. The graphical `Location::setup()` runs afterward and only builds
presentation objects from that definition and the prepared state. Lua and dialogue
runtime behavior remains client-side.
### Animation and combat
Logical animation frame clocks live in `CharacterState`. Animation frame counts are
copied from the loaded clip metadata during runtime construction, after which state
transitions and frame-19 combat impacts are deterministic authoritative simulation.
Logical animation frame clocks live in `CharacterState`. The renderer-free content
loader reads animation frame metadata before authoritative entities are created.
Runtime `Character` construction only loads models for presentation and does not
submit metadata mutations back to the server.
`CharacterState::update()` returns value-only events containing arrival Lua function
names, attack impacts, navigation requests, and death-animation completion. `LocationGameState` applies
@@ -224,9 +231,9 @@ editor obstacles, and taxi reset. No whole-location commit command is exposed.
Navigation target selection, replanning, stopping, facing, death reset, health
assignment, and attack-combo clock changes are implemented by `CharacterState`.
`Character` no longer exposes gameplay mutation helpers or a generic state mutation
callback. Its only state-facing setup responsibility is reporting frame ranges from
loaded animation assets through `SetCharacterAnimationMetadataCommand`; otherwise it
focuses on model posing, rendering, audio, particles, and runtime callbacks.
callback. Character construction is presentation-only; frame ranges are already
present in `CharacterState` after content setup. It focuses on model posing,
rendering, audio, particles, and runtime callbacks.
Death-animation and health-change callbacks remain runtime-only on `Character`.
Arrival behavior is represented solely by the serialized Lua function name in
@@ -242,10 +249,10 @@ by `Game`.
`GameObjectLoader` now:
1. Loads static creation data from location configuration.
2. Creates or reuses server-owned state objects.
3. Applies saved runtime fields over the configuration defaults.
4. Constructs visual objects using stable IDs and state-backed creation data.
1. Receives immutable object/NPC definitions parsed by `LocationContentLoader`.
2. Resolves already-prepared authoritative entities by stable ID.
3. Constructs meshes, textures, VBOs, `InteractiveObject`, and `Character`
presentation wrappers without creating or overwriting authoritative state.
Configuration remains the source of visual assets, animation paths, meshes, textures, and fixed tuning data.
@@ -256,7 +263,8 @@ The normal frame flow is:
1. SDL input is processed.
2. UI code submits semantic commands through `IGameServer`.
3. The internal server freezes location character observations and calls
`CharacterState::update()` for the player and each NPC.
`CharacterState::update()` for every present player and NPC. An empty player
collection is valid.
4. Attack impacts are queued, then damage is applied after all characters advance.
5. The runtime location consumes value-only events. Navigation requests are sent
back as semantic destination commands, whose server handler calls
@@ -283,21 +291,28 @@ When a campaign starts:
- Existing campaign state and runtime locations are cleared.
- Quest definitions are loaded.
- A campaign-level player state is created under the `"player"` ID.
- The visual player is created with its stable ID and resolves that state through snapshots.
- The graphical single-player host requests a campaign-level `"player"` state and
creates its visual wrapper.
- A standalone host may deliberately create no players; locations continue to tick.
- The battle-zone test bot is an explicit host option rather than an unconditional
campaign side effect.
### Location loading
When a location is loaded:
- A `LocationGameState` record is created or reused.
- Static configuration is loaded.
- NPC and interactive-object visuals are created against state owned by the location record.
- `LocationContentLoader` parses a renderer-free `LocationDefinition`.
- `LocationGameState::setup()` creates or reconciles navigation, taxi, NPC,
interactive-object, trigger, teleport, and animation state.
- Saved mutable fields are overlaid on configuration defaults by stable ID.
- `Location::setup()` builds static and entity visuals from the prepared definition
without mutating authoritative state.
- The shared campaign player is attached.
- Runtime visuals are created for other player IDs currently present in the
snapshot and are subsequently spawned or removed as snapshots change.
- Dialogue, Lua, navigation, trigger, teleport, and presentation callbacks are initialized.
- The runtime `Location` is registered privately with `InternalGameServer`.
- Dialogue, Lua, trigger/teleport visuals, and presentation callbacks are initialized.
- The runtime `Location` is owned and registered by `LocalGameServerHost`;
`InternalGameServer` remains headless.
### Location unloading
@@ -387,7 +402,6 @@ Still required for real multiplayer:
- Network transport and command serialization.
- Authentication and player/session assignment.
- Server tick scheduling independent of rendering.
- Snapshot delta generation or other replication strategy.
- Latency handling, interpolation, reconciliation, and prediction.
- Command validation, authorization, and anti-cheat rules.
@@ -407,6 +421,12 @@ The new state and server files are registered in:
The refactor uses portable C++17 and introduces no Windows-only gameplay code.
The standalone target lives under `server/`. It links the authoritative state,
campaign, content-definition, and portable resource sources only; SDL, OpenGL,
audio, Lua, dialogue presentation, and rendering sources are absent. It can prepare
a selected campaign/location with zero players and run the 50 ms fixed-step loop.
Networking remains outside this milestone.
The Windows Debug target was verified with:
```powershell
@@ -422,18 +442,24 @@ cmake --build proj-windows/build --config Debug --target ShadowOverBishkekDemo -
location-local NPC ID).
- Some top-level values remain mirrors for compatibility, notably player health used by the HUD and scripts.
- Dialogue and Lua are synchronized as auxiliary location state rather than fully networked subsystems.
- `Game` uses focused privileged internal-server APIs for local content
construction, but cannot access the aggregate or its state maps directly. The
private location-construction path still supplies `LocationGameState` to the
local object loader. A remote client implementation will need a client-side
runtime-location factory driven by configuration and snapshots.
- `IGameServerLifecycle` is the graphics-free campaign/location administration
boundary. `LocalGameServerHost` adds client-only runtime construction and
auxiliary-state synchronization without making `Game` a server friend.
- Empty player maps are valid. Player-specific interactions remain inactive until
a player entity is added.
- A remote client still needs a client-side runtime-location factory driven by
configuration/definitions and replicated snapshots.
## Main Files
- `src/GameState.h` / `src/GameState.cpp` — aggregate state and top-level persistence.
- `src/LocationGameState.h` / `src/LocationGameState.cpp` — typed location state, simulation, and ID-keyed persistence.
- `src/content/LocationDefinition.h` / `.cpp` — renderer-free content definitions,
parsing, and animation metadata loading.
- `src/game_server/IGameServer.h` — public snapshot and command contract.
- `src/game_server/IGameServerLifecycle.h` — graphics-free campaign/location lifecycle.
- `src/game_server/InternalGameServer.h` / `.cpp` — in-process authoritative implementation.
- `src/game_server/LocalGameServerHost.h` / `.cpp` — graphical-client runtime adapter.
- `src/Game.h` / `src/Game.cpp` — application host, campaign lifecycle, and runtime wiring.
- `src/Location.h` / `src/Location.cpp` — loaded location runtime, command routing,
interactions, collisions, scripts, and presentation-event consumption.
@@ -442,5 +468,5 @@ cmake --build proj-windows/build --config Debug --target ShadowOverBishkekDemo -
- `src/CharacterState.h` / `src/CharacterState.cpp` — deterministic character
simulation, navigation operations, combat state, and logical animation clock.
- `src/items/InteractiveObject.h` / `.cpp` — visual object runtime bound to central object state.
- `src/items/GameObjectLoader.h` / `.cpp` — configuration/state overlay and runtime construction.
- `src/items/GameObjectLoader.h` / `.cpp` — presentation builders for prepared definitions.
- `src/MenuManager.h` / `src/MenuManager.cpp` — snapshot-driven UI and command submission.