group2 0.1.0
CSE 125 Group 2
Loading...
Searching...
No Matches
ServerGame Class Reference

Top-level server game loop. More...

#include <ServerGame.hpp>

Collaboration diagram for ServerGame:
[legend]

Classes

struct  ShotIntentKey
struct  ShotIntentKeyHash

Public Member Functions

bool init (Server &server, int tickRateHz=128, int snapshotHz=32, bool skipLobby=false)
 Attach to an already-bound Server and initialise game state.
void run ()
 Block on the game loop until shutdown() is called.
void shutdown ()
 Signal the loop to stop and release all resources.
bool isHost (ClientId clientId) const
 True if the given client currently owns host-only lobby/server controls.
void onMatchConfigUpdated (std::function< void(const MatchConfig &)> fn)
 Register a callback fired after the host updates match settings.
void onDiscoverySettingsUpdated (std::function< void(const DiscoverySettings &)> fn)
 Register a callback fired after the host updates discovery visibility.
bool setMatchConfig (const MatchConfig &config)
 Apply a complete match config to the authoritative match controller.
bool setKillsToWin (int kills)
 Update only the kill threshold in the authoritative match config.
bool setMaxPlayers (int maxPlayers)
 Update only the maximum accepted player count in the authoritative match config.
bool setIdleShutdownMinutes (int minutes)
 Configure idle shutdown timeout in minutes; non-positive values disable it.

Private Member Functions

void eventHandler (const Event &event)
 Apply a single event to the ECS registry.
void applyInputEvent (ClientId clientId, const InputSnapshot &inputSnapshot)
void tick (float dt, Uint64 nextTick)
 Advance one physics tick: drain events, run ECS systems, broadcast state.
void initNewPlayerEntity (ClientId clientId)
 Create a new player entity and map it to the given client ID.
void deletePlayerEntity (ClientId clientId)
 Remove player entity from ECS.
void initAnimation ()
 Initialise the server-side animation subsystem (skeleton, clips, hitboxes).
void attachServerAnimator (entt::entity player)
 Create and store a server-side animator for the given player entity.
void detachServerAnimator (entt::entity player)
 Remove the server-side animator for the given entity.
void updateAnimationAndHitboxes (float dt)
 Update all server-side animators and recompute hitbox capsules.
void updateLagCompTargets ()
 Phase 6: write LagCompTarget onto each connected player's entity from their connection's last-reported RTT.
void selectMatchAbilityPool ()
 Select the subset of abilities for new match.
void applyMatchAbilityChoices (AbilityState &state) const
void openGroundTruthLog ()
 Open the ground-truth CSV from env var if set.
void writeGroundTruthLogIfDue ()
 Write one row per replicated player entity if the current tickCount aligns with truthHzDivider_.
void closeGroundTruthLog () noexcept
 Flush + close the CSV if open. Safe to call from dtor.
void resetPlayersForCountdown ()
 Reset live players to spawn points for countdown.
bool isGameplayInputAllowed (MatchPhase phase) const
 Determine if server should allow input based on phase.
bool isLobbyPhase (MatchPhase phase) const
 Return true when roster changes should use lobby updates instead of in-match popups.

Private Attributes

physics::MapCollisionData mapCollision_
 Map collision data — owns vectors backing activeWorld().
Serverserver = nullptr
 Non-owning pointer; main() owns and shuts down the socket.
Registry registry
 ECS entity/component store.
AbilityRegistry abilityRegistry
 Registry of abilities via type idx.
std::vector< AbilityTypematchPrimaryAbilities
 list of abilities available during the match
std::vector< AbilityTypematchSecondaryAbilities
LobbyManager lobbyManager
 Owns lobby roster and validates host-initiated match starts.
MatchController matchController
 Manages match flow and state.
std::function< void(const MatchConfig &)> matchConfigUpdatedFn_
 Mirrors match updates to networking/discovery.
std::function< void(const DiscoverySettings &)> discoverySettingsUpdatedFn_
 Mirrors discovery visibility changes.
bool lobbyStartCountdownActive = false
 True while lobby is counting down before entering match countdown.
float lobbyStartCountdownTimer = 0.0f
 Seconds remaining in the lobby staging countdown.
ClientId lobbyStartRequester {-1}
 Host that requested the active lobby staging countdown.
std::unordered_map< ClientId, entt::entity > clientEntities
 Maps client IDs to ECS entities.
std::vector< NetKillEventpendingKillEvents
 Accumulates kill events waiting for network broadcast.
std::array< int, player_colors::k_paletteSizecolorSlotUseCounts_ {}
 Use-count per palette slot for least-used color reservation.
std::array< int, player_nicknames::k_nicknameCountnicknameSlotUseCounts_ {}
 Use-count per nickname slot — same selection scheme as colors.
bool running = false
 Loop continues while true.
int tickRateHz = 128
 Physics ticks per second.
int tickCount = 0
 Total ticks since start, used for periodic logging.
int snapshotEveryNTicks = 4
 Send a registry snapshot every Nth tick.
bool shotDebugEnabled_ = false
 Opt-in lag-comp shot visualizer capture/send path.
physics::ContactCache contactCache_
 Persistent contact-manifold cache for warm-starting the PGS solver across ticks.
CharacterRig serverRig_
 Shared skeleton (loaded from same FBX as client).
AnimationLibrary serverAnimLibrary_
 Animation clips for server-side sampling.
HitboxRig hitboxRig_
 Shared hitbox capsule definitions.
float rigScale_ = 1.0f
 Rig model-space → game-unit scale factor.
float rigMeshMinY_ = 0.0f
 Minimum Y of bind-pose mesh (for vertical offset).
bool animationLoaded_ = false
 True if rig+clips loaded successfully.
std::unordered_map< entt::entity, std::unique_ptr< CharacterAnimator > > serverAnimators_
 Per-entity server animators (not ECS components to avoid pulling animation headers into the component registry).
std::FILE * truthCsv_ = nullptr
int truthHzDivider_ = 4
std::unordered_map< ShotIntentKey, ShotIntentPayload, ShotIntentKeyHashpendingShotIntents_
bool idleShutdownEnabled_ = false
 True if idle shutdown is enabled via env var.
uint64_t idleShutdownMs_ = 0
 Idle shutdown timeout in ms, from env var. 0 = no timeout.
uint64_t lastNonEmptyMs_ = 0
 Timestamp of the last player activity, for idle shutdown.

Static Private Attributes

static constexpr std::size_t k_pendingShotIntentsMax = 256

Detailed Description

Top-level server game loop.

Borrows an already-bound Server from the caller (main owns the socket). Each tick it drains incoming messages, runs all ECS systems, and broadcasts state.

Member Function Documentation

◆ applyInputEvent()

void ServerGame::applyInputEvent ( ClientId clientId,
const InputSnapshot & inputSnapshot )
private
Here is the caller graph for this function:

◆ applyMatchAbilityChoices()

void ServerGame::applyMatchAbilityChoices ( AbilityState & state) const
private
Here is the caller graph for this function:

◆ attachServerAnimator()

void ServerGame::attachServerAnimator ( entt::entity player)
private

Create and store a server-side animator for the given player entity.

Here is the caller graph for this function:

◆ closeGroundTruthLog()

void ServerGame::closeGroundTruthLog ( )
privatenoexcept

Flush + close the CSV if open. Safe to call from dtor.

Here is the caller graph for this function:

◆ deletePlayerEntity()

void ServerGame::deletePlayerEntity ( ClientId clientId)
private

Remove player entity from ECS.

Parameters
clientIdNetwork client identifier for the player.
Here is the call graph for this function:
Here is the caller graph for this function:

◆ detachServerAnimator()

void ServerGame::detachServerAnimator ( entt::entity player)
private

Remove the server-side animator for the given entity.

Here is the caller graph for this function:

◆ eventHandler()

void ServerGame::eventHandler ( const Event & event)
private

Apply a single event to the ECS registry.

Parameters
eventThe event to process.
Here is the call graph for this function:
Here is the caller graph for this function:

◆ init()

bool ServerGame::init ( Server & server,
int tickRateHz = 128,
int snapshotHz = 32,
bool skipLobby = false )

Attach to an already-bound Server and initialise game state.

Parameters
serverExternally-owned, already-initialised Server.
tickRateHzPhysics tick rate in Hz (default 128).
snapshotHzRegistry snapshot send rate in Hz (default 32). Must be ≤ tickRateHz; clamped if not.
skipLobbyTrue to bypass lobby and enter countdown automatically.
Returns
True on success, false on initialisation failure.
Here is the call graph for this function:
Here is the caller graph for this function:

◆ initAnimation()

void ServerGame::initAnimation ( )
private

Initialise the server-side animation subsystem (skeleton, clips, hitboxes).

Called once during init() after map loading.

Here is the call graph for this function:
Here is the caller graph for this function:

◆ initNewPlayerEntity()

void ServerGame::initNewPlayerEntity ( ClientId clientId)
private

Create a new player entity and map it to the given client ID.

Parameters
clientIdNetwork client identifier for the new player.
Here is the call graph for this function:
Here is the caller graph for this function:

◆ isGameplayInputAllowed()

bool ServerGame::isGameplayInputAllowed ( MatchPhase phase) const
nodiscardprivate

Determine if server should allow input based on phase.

Here is the caller graph for this function:

◆ isHost()

bool ServerGame::isHost ( ClientId clientId) const
nodiscard

True if the given client currently owns host-only lobby/server controls.

Here is the caller graph for this function:

◆ isLobbyPhase()

bool ServerGame::isLobbyPhase ( MatchPhase phase) const
nodiscardprivate

Return true when roster changes should use lobby updates instead of in-match popups.

Here is the caller graph for this function:

◆ onDiscoverySettingsUpdated()

void ServerGame::onDiscoverySettingsUpdated ( std::function< void(const DiscoverySettings &)> fn)
inline

Register a callback fired after the host updates discovery visibility.

Here is the caller graph for this function:

◆ onMatchConfigUpdated()

void ServerGame::onMatchConfigUpdated ( std::function< void(const MatchConfig &)> fn)
inline

Register a callback fired after the host updates match settings.

Here is the caller graph for this function:

◆ 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.

Here is the caller graph for this function:

◆ resetPlayersForCountdown()

void ServerGame::resetPlayersForCountdown ( )
private

Reset live players to spawn points for countdown.

Here is the call graph for this function:
Here is the caller graph for this function:

◆ run()

void ServerGame::run ( )

Block on the game loop until shutdown() is called.

Loop structure (each iteration = one tick at tickRateHz):

  1. server.poll() — accept new connections, read incoming packets, enqueue events (Connected / Disconnected / Input).
  2. tick(dt, nextTick) — process events and run all ECS systems.
  3. Sleep — hybrid sleep+spin-wait to maintain tick cadence.
See also
tick for the per-tick ECS system execution order.
Here is the call graph for this function:
Here is the caller graph for this function:

◆ selectMatchAbilityPool()

void ServerGame::selectMatchAbilityPool ( )
private

Select the subset of abilities for new match.

Here is the call graph for this function:
Here is the caller graph for this function:

◆ setIdleShutdownMinutes()

bool ServerGame::setIdleShutdownMinutes ( int minutes)

Configure idle shutdown timeout in minutes; non-positive values disable it.

Here is the caller graph for this function:

◆ setKillsToWin()

bool ServerGame::setKillsToWin ( int kills)

Update only the kill threshold in the authoritative match config.

◆ setMatchConfig()

bool ServerGame::setMatchConfig ( const MatchConfig & config)

Apply a complete match config to the authoritative match controller.

Here is the call graph for this function:
Here is the caller graph for this function:

◆ setMaxPlayers()

bool ServerGame::setMaxPlayers ( int maxPlayers)

Update only the maximum accepted player count in the authoritative match config.

◆ shutdown()

void ServerGame::shutdown ( )

Signal the loop to stop and release all resources.

Here is the call graph for this function:
Here is the caller graph for this function:

◆ tick()

void ServerGame::tick ( float dt,
Uint64 nextTick )
private

Advance one physics tick: drain events, run ECS systems, broadcast state.

Execution order each tick:

  1. Event drain — dequeue Connected/Disconnected/Input events from the network server until the queue is empty or the tick deadline is exceeded.
  2. Animation + hitboxesupdateAnimationAndHitboxes(dt) samples skeleton poses and recomputes bone-capsule hitboxes for all players.
  3. Weapon systemrunWeapon() processes fire inputs, performs hitscan raycasts against hitbox capsules, applies damage, generates particle/kill events.
  4. MovementrunMovement() applies acceleration, friction, gravity, and special movement modes (wallrun, slide, grapple).
  5. CollisionrunCollision() performs swept-AABB resolution against the world geometry (planes, boxes, brushes).
  6. ExplosionsrunExplosion() processes pending projectile detonations with radius damage.
  7. Player statusrunPlayerStatus() handles respawn timers, death state transitions, and health regeneration.
  8. Weapon spawnersrunWeaponSpawners() ticks pickup cooldowns and spawns weapon entities. 8b. Dropped weaponsrunDroppedWeapons() handles pickup and despawn for player-dropped weapons.
  9. Match controllermatchController.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
dtFixed delta time in seconds (1 / tickRateHz).
nextTickPerformance counter deadline for the current tick.
See also
Game::iterate for the client-side frame loop.
Here is the call graph for this function:
Here is the caller graph for this function:

◆ updateAnimationAndHitboxes()

void ServerGame::updateAnimationAndHitboxes ( float dt)
private

Update all server-side animators and recompute hitbox capsules.

Called once per tick before weapon/damage systems.

Here is the call graph for this function:
Here is the caller graph for this function:

◆ 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.

Here is the call graph for this function:
Here is the caller graph for this function:

◆ 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.

Here is the caller graph for this function:

Member Data Documentation

◆ abilityRegistry

AbilityRegistry ServerGame::abilityRegistry
private

Registry of abilities via type idx.

◆ 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.

◆ colorSlotUseCounts_

std::array<int, player_colors::k_paletteSize> ServerGame::colorSlotUseCounts_ {}
private

Use-count per palette slot for least-used color reservation.

Sized to player_colors::k_paletteSize. Incremented when a player connects (assigns the smallest-count slot, ties broken by lowest index for determinism); decremented on disconnect.

◆ contactCache_

physics::ContactCache ServerGame::contactCache_
private

Persistent contact-manifold cache for warm-starting the PGS solver across ticks.

Cleared on map load; trimmed each tick by runDynamics.

◆ discoverySettingsUpdatedFn_

std::function<void(const DiscoverySettings&)> ServerGame::discoverySettingsUpdatedFn_
private

Mirrors discovery visibility changes.

◆ hitboxRig_

HitboxRig ServerGame::hitboxRig_
private

Shared hitbox capsule definitions.

◆ idleShutdownEnabled_

bool ServerGame::idleShutdownEnabled_ = false
private

True if idle shutdown is enabled via env var.

◆ idleShutdownMs_

uint64_t ServerGame::idleShutdownMs_ = 0
private

Idle shutdown timeout in ms, from env var. 0 = no timeout.

◆ k_pendingShotIntentsMax

std::size_t ServerGame::k_pendingShotIntentsMax = 256
staticconstexprprivate

◆ lastNonEmptyMs_

uint64_t ServerGame::lastNonEmptyMs_ = 0
private

Timestamp of the last player activity, for idle shutdown.

◆ lobbyManager

LobbyManager ServerGame::lobbyManager
private

Owns lobby roster and validates host-initiated match starts.

◆ lobbyStartCountdownActive

bool ServerGame::lobbyStartCountdownActive = false
private

True while lobby is counting down before entering match countdown.

◆ lobbyStartCountdownTimer

float ServerGame::lobbyStartCountdownTimer = 0.0f
private

Seconds remaining in the lobby staging countdown.

◆ lobbyStartRequester

ClientId ServerGame::lobbyStartRequester {-1}
private

Host that requested the active lobby staging countdown.

◆ mapCollision_

physics::MapCollisionData ServerGame::mapCollision_
private

Map collision data — owns vectors backing activeWorld().

◆ matchConfigUpdatedFn_

std::function<void(const MatchConfig&)> ServerGame::matchConfigUpdatedFn_
private

Mirrors match updates to networking/discovery.

◆ matchController

MatchController ServerGame::matchController
private

Manages match flow and state.

◆ matchPrimaryAbilities

std::vector<AbilityType> ServerGame::matchPrimaryAbilities
private

list of abilities available during the match

◆ matchSecondaryAbilities

std::vector<AbilityType> ServerGame::matchSecondaryAbilities
private

◆ nicknameSlotUseCounts_

std::array<int, player_nicknames::k_nicknameCount> ServerGame::nicknameSlotUseCounts_ {}
private

Use-count per nickname slot — same selection scheme as colors.

Decrements when an auto-assigned nickname is released; custom nicknames don't touch the count, since they don't reserve a slot.

◆ pendingKillEvents

std::vector<NetKillEvent> ServerGame::pendingKillEvents
private

Accumulates kill events waiting for network broadcast.

◆ pendingShotIntents_

std::unordered_map<ShotIntentKey, ShotIntentPayload, ShotIntentKeyHash> ServerGame::pendingShotIntents_
private

◆ registry

Registry ServerGame::registry
private

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

Server* ServerGame::server = nullptr
private

Non-owning pointer; main() owns and shuts down the socket.

◆ 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_

AnimationLibrary ServerGame::serverAnimLibrary_
private

Animation clips for server-side sampling.

◆ serverRig_

CharacterRig ServerGame::serverRig_
private

Shared skeleton (loaded from same FBX as client).

◆ shotDebugEnabled_

bool ServerGame::shotDebugEnabled_ = false
private

Opt-in lag-comp shot visualizer capture/send path.

◆ 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: