Top-level server game loop.
More...
#include <ServerGame.hpp>
|
| bool | init (const char *addr, Uint16 port, int tickRateHz=128, int snapshotHz=32, const TransportConfig &transport={}) |
| | Bind to the given address and port, spawn test entities.
|
| void | run () |
| | Block on the game loop until shutdown() is called.
|
| void | shutdown () |
| | Signal the loop to stop and release all resources.
|
Top-level server game loop.
Owns the ECS registry and the network Server. Each tick it drains incoming messages, runs all ECS systems, and broadcasts state.
◆ attachServerAnimator()
| void ServerGame::attachServerAnimator |
( |
entt::entity | player | ) |
|
|
private |
Create and store a server-side animator for the given player entity.
◆ closeGroundTruthLog()
| void ServerGame::closeGroundTruthLog |
( |
| ) |
|
|
privatenoexcept |
Flush + close the CSV if open. Safe to call from dtor.
◆ deletePlayerEntity()
| void ServerGame::deletePlayerEntity |
( |
ClientId | clientId | ) |
|
|
private |
Remove player entity from ECS.
- Parameters
-
| clientId | Network client identifier for the player. |
◆ detachServerAnimator()
| void ServerGame::detachServerAnimator |
( |
entt::entity | player | ) |
|
|
private |
Remove the server-side animator for the given entity.
◆ eventHandler()
| void ServerGame::eventHandler |
( |
Event | event | ) |
|
|
private |
Apply a single event to the ECS registry.
- Parameters
-
| event | The event to process. |
◆ init()
| bool ServerGame::init |
( |
const char * | addr, |
|
|
Uint16 | port, |
|
|
int | tickRateHz = 128, |
|
|
int | snapshotHz = 32, |
|
|
const TransportConfig & | transport = {} ) |
Bind to the given address and port, spawn test entities.
- Parameters
-
| addr | Hostname or IP to bind to (e.g. "127.0.0.1"). |
| port | TCP port to listen on. |
| tickRateHz | Physics tick rate in Hz (default 128). |
| snapshotHz | Registry snapshot send rate in Hz (default 32). Must be ≤ tickRateHz; clamped if not. Phase 4 decouples snapshot rate from tick rate so the server can keep deterministic 128 Hz physics while only paying the serialization+broadcast cost a fraction as often. |
| transport | Phase 3d: UDP sidecar feature toggles. |
- Returns
- True on success, false on network or initialisation failure.
◆ initAnimation()
| void ServerGame::initAnimation |
( |
| ) |
|
|
private |
Initialise the server-side animation subsystem (skeleton, clips, hitboxes).
Called once during init() after map loading.
◆ initNewPlayerEntity()
| void ServerGame::initNewPlayerEntity |
( |
ClientId | clientId | ) |
|
|
private |
Create a new player entity and map it to the given client ID.
- Parameters
-
| clientId | Network client identifier for the new player. |
◆ openGroundTruthLog()
| void ServerGame::openGroundTruthLog |
( |
| ) |
|
|
private |
Open the ground-truth CSV from env var if set.
No-op when the env var is missing; load tests stay fast by default.
◆ run()
Block on the game loop until shutdown() is called.
Loop structure (each iteration = one tick at tickRateHz):
- server.poll() — accept new connections, read incoming packets, enqueue events (Connected / Disconnected / Input).
- tick(dt, nextTick) — process events and run all ECS systems.
- Sleep — hybrid sleep+spin-wait to maintain tick cadence.
- See also
- tick for the per-tick ECS system execution order.
◆ shutdown()
| void ServerGame::shutdown |
( |
| ) |
|
Signal the loop to stop and release all resources.
◆ tick()
| void ServerGame::tick |
( |
float | dt, |
|
|
Uint64 | nextTick ) |
|
private |
Advance one physics tick: drain events, run ECS systems, broadcast state.
Execution order each tick:
- Event drain — dequeue Connected/Disconnected/Input events from the network server until the queue is empty or the tick deadline is exceeded.
- Animation + hitboxes — updateAnimationAndHitboxes(dt) samples skeleton poses and recomputes bone-capsule hitboxes for all players.
- Weapon system — runWeapon() processes fire inputs, performs hitscan raycasts against hitbox capsules, applies damage, generates particle/kill events.
- Movement — runMovement() applies acceleration, friction, gravity, and special movement modes (wallrun, slide, grapple).
- Collision — runCollision() performs swept-AABB resolution against the world geometry (planes, boxes, brushes).
- Explosions — runExplosion() processes pending projectile detonations with radius damage.
- Player status — runPlayerStatus() handles respawn timers, death state transitions, and health regeneration.
- Weapon spawners — runWeaponSpawners() ticks pickup cooldowns and spawns weapon entities.
- Match controller — matchController.update() manages match phase transitions (warmup → countdown → in-progress → finished).
Broadcast — send updated registry snapshot, particle events, and kill events to all connected clients.
- Parameters
-
| dt | Fixed delta time in seconds (1 / tickRateHz). |
| nextTick | Performance counter deadline for the current tick. |
- See also
- Game::iterate for the client-side frame loop.
◆ updateAnimationAndHitboxes()
| void ServerGame::updateAnimationAndHitboxes |
( |
float | dt | ) |
|
|
private |
Update all server-side animators and recompute hitbox capsules.
Called once per tick before weapon/damage systems.
◆ updateLagCompTargets()
| void ServerGame::updateLagCompTargets |
( |
| ) |
|
|
private |
Phase 6: write LagCompTarget onto each connected player's entity from their connection's last-reported RTT.
Translates Connection::lastReportedRttMs (ms) into a targetServerTick = max(0, currentServerTick - rewindTicks), where rewindTicks = clamp(rttMs * tickRateHz / 2000, 0,
k_maxLagCompTicks). Players with no client connection (e.g. AI bots in a future expansion) keep their previous target, which on the next pushHitboxHistory will become a valid rewind anchor — but for now, only entities bound through clientEntities get a target.
Called once per tick between pushHitboxHistory and runWeapon.
◆ writeGroundTruthLogIfDue()
| void ServerGame::writeGroundTruthLogIfDue |
( |
| ) |
|
|
private |
Write one row per replicated player entity if the current tickCount aligns with truthHzDivider_.
Called at the end of each tick after the per-tick physics + broadcast settles.
◆ animationLoaded_
| bool ServerGame::animationLoaded_ = false |
|
private |
True if rig+clips loaded successfully.
◆ clientEntities
| std::unordered_map<ClientId, entt::entity> ServerGame::clientEntities |
|
private |
Maps client IDs to ECS entities.
◆ hitboxRig_
Shared hitbox capsule definitions.
◆ k_pendingShotIntentsMax
| std::size_t ServerGame::k_pendingShotIntentsMax = 256 |
|
staticconstexprprivate |
◆ mapCollision_
Map collision data — owns vectors backing activeWorld().
◆ matchController
Manages match flow and state.
◆ pendingKillEvents
Accumulates kill events waiting for network broadcast.
◆ pendingShotIntents_
◆ registry
ECS entity/component store.
◆ rigMeshMinY_
| float ServerGame::rigMeshMinY_ = 0.0f |
|
private |
Minimum Y of bind-pose mesh (for vertical offset).
◆ rigScale_
| float ServerGame::rigScale_ = 1.0f |
|
private |
Rig model-space → game-unit scale factor.
◆ running
| bool ServerGame::running = false |
|
private |
Loop continues while true.
◆ server
Owns the TCP socket and network I/O.
◆ serverAnimators_
| std::unordered_map<entt::entity, std::unique_ptr<CharacterAnimator> > ServerGame::serverAnimators_ |
|
private |
Per-entity server animators (not ECS components to avoid pulling animation headers into the component registry).
◆ serverAnimLibrary_
Animation clips for server-side sampling.
◆ serverRig_
Shared skeleton (loaded from same FBX as client).
◆ snapshotEveryNTicks
| int ServerGame::snapshotEveryNTicks = 4 |
|
private |
Send a registry snapshot every Nth tick.
Computed in init() as max(1, tickRateHz / snapshotHz) so the snapshot rate is roughly tickRateHz / snapshotEveryNTicks Hz. With the default 128 / 32 = 4 the server snapshots every 4th tick — 4× less serialization + broadcast work than pre-Phase-4.
◆ tickCount
| int ServerGame::tickCount = 0 |
|
private |
Total ticks since start, used for periodic logging.
◆ tickRateHz
| int ServerGame::tickRateHz = 128 |
|
private |
Physics ticks per second.
◆ truthCsv_
| std::FILE* ServerGame::truthCsv_ = nullptr |
|
private |
◆ truthHzDivider_
| int ServerGame::truthHzDivider_ = 4 |
|
private |
The documentation for this class was generated from the following files: