Real-Time Multiplayer • Netcode for GameObjects (NGO) • Windows
Arena Protocol is a real-time 2-player co-op survival arena built with Unity Netcode for GameObjects (NGO). Two players fight through wave-based enemies together, using a modular ability kit — dash, projectile, and heal — while the server maintains full authority over combat, AI, and scoring.
The project was built to deeply understand host-client networking fundamentals: NetworkVariable-driven state replication, server-authoritative combat validation, and — the hardest part — building a session system robust enough to survive a real disconnect and reconnect without losing player progress.
BaseAbility) supporting Dash, Projectile, and Heal with independent networked cooldownsThe host acts as both server and Player 1; all authoritative gameplay logic runs on the host. The client sends input to the server and renders the resulting replicated state.
Every ability extends an abstract BaseAbility (itself a NetworkBehaviour)
with a server-authoritative cooldown tick and a shared TryActivate() pattern. New abilities
only need to extend the base class and implement Activate() — no changes required elsewhere.
Enemy behavior runs exclusively on the server as a Patrol → Chase → Attack state machine, eliminating any possibility of enemy desync between clients. Positions replicate to clients via NetworkTransform interpolation.
Challenge: Reconnection with a shifting clientId
NGO assigns a new clientId to a client on every reconnect, so any session state
keyed directly on clientId breaks the moment a player rejoins.
Solution: Built a SessionManager using a static, slot-based dictionary
instead of a clientId-keyed one. Health and ability cooldown state are saved on disconnect and
restored once the player object respawns after rejoin — regardless of the new clientId assigned.
Challenge: Bridging scene UI to dynamically spawned player prefabs
Prefab Inspector references can't point at scene objects directly, but health bars and ability UI needed to react to a player prefab that only exists at runtime.
Solution: A one-time GameObject.Find() wiring step on player spawn bridges
the scene UI to the spawned prefab, with zero runtime performance cost since it only fires once.