-
Notifications
You must be signed in to change notification settings - Fork 0
Multiplayer
Home · Gameplay · Characters · User-Interface
Multiplayer uses PeerJS peer-to-peer data connections. There is no dedicated authoritative game server for live combat. One peer is the host and owns the shared enemy simulation; Convex is used separately for accounts, persistent progression, and leaderboards.
The host creates a lobby and shares its lobby ID. A joining peer connects to that ID. The lobby supports:
- Co-op Survival and Last Man Standing labels.
- Host-selected map, difficulty, and
auto/ day / night atmosphere. - Optional time limit from 60 to 1,800 seconds in 30-second steps.
- Character choice with unique ownership, player color, avatar, rank badge, and mobile indicator.
- Host kick controls and duplicate-name rejection.
The implementation has eight class choices and eight predefined player colors, but no explicit MAX_PLAYERS enforcement was found. Do not treat “up to eight players” as a verified hard networking limit.
The host spawns enemies, runs enemy AI, resolves enemy health and death, advances waves, and sends enemy snapshots. Guests do not create or simulate independent waves; they mirror host entities and report their local bullet hits to the host as enemy_hit messages.
Guest input / bullet hit ──> Host validates and applies enemy damage
Host enemy simulation ─────> Guests receive enemy snapshots and kill credit
Host enemy attack ─────────> Target client receives player_damaged
This prevents guest wave drift and makes an enemy's position and death shared. Loot remains local-client presentation/state, while waves and enemy entities are shared. Weapon unlocks are score-local to each player.
| Stream | Behavior |
|---|---|
| Player movement | Position, rotation, health, weapon, crouch, profile metadata, sender timestamp, and sequence number. Sends at up to 20 Hz (50 ms interval). |
| Enemy state | Host sends compact position/yaw/HP/dead snapshots about 10 times per second. Full keyframes arrive about once per second; deltas carry changed enemies between keyframes. |
| Remote rendering | Timestamped snapshot buffers render slightly in the past. They interpolate between samples and extrapolate briefly on packet loss before holding. |
| Clock handling | Receivers estimate a sender-clock offset from the lowest-latency samples, discard out-of-order sequence numbers, and adjust render delay for jitter. |
Remote player interpolation starts around a 100 ms render delay and adapts between 60 and 280 ms. Enemy playback starts around 165 ms and adapts from observed host-stream jitter. Large teleport/respawn-like changes reset the interpolation buffer instead of flying an avatar across the map.
| Area | Owner |
|---|---|
| Enemy spawning, AI, HP, deaths, wave advancement | Match host |
| Guest bullet contacts | Guest reports; host resolves |
| Enemy damage to remote player | Host tells the target client to apply the hit |
| Player movement snapshot | Each player sends its own sanitized transform |
| Lobby, peer connection, heartbeat | PeerJS clients; host relays relevant messages |
| Account stats, skills, achievements, rank, daily claims | Convex mutations and queries |
Because the live session is peer-to-peer, the anti-cheat is best-effort rather than cheat-proof. The host sanitizes reported player fields and tracks repeated physically impossible movement before kicking a client. Progression submissions are also clamped and rate-limited by Convex.
When a multiplayer player reaches zero health, the client spectates. The host match manager ends Co-op Survival when all players are dead; Last Man Standing ends when one player remains alive in a match with more than one player. Match result UI can return players to the same lobby for another game.
- Text chat and quick emotes.
- Chat message cooldown of 500 ms and emote cooldown of 1.5 seconds.
- Floating nameplates and health bars on remote avatars.
- Live scoreboards and a tactical minimap with ally blips.
- Multiplayer game-over and spectator interfaces.
- Mobile indicators for touch players.
- Voice chat: no WebRTC media, microphone, or voice-channel implementation was found.
- Matchmaking: no queue, region, or automatic matchmaking service was found; joining is by lobby ID.
- Direct PvP: lobby text includes Last Man Standing and network message types exist for player shots, but direct player-versus-player combat is not connected from the gameplay loop. Only enemy-caused player damage is confirmed.
Implementation references: src/utils/MultiplayerManager.ts, src/utils/RemotePlayerManager.ts, src/utils/SnapshotInterpolator.ts, src/components/MultiplayerLobby.tsx, src/App.tsx.