An authoritative-server multiplayer FPS in Unity, built on FishNet. This repo is a source showcase of the game's original systems (networking, AI, and match flow), pulled out of a larger private project.
It's meant for reading, not building. The paid art and some third-party frameworks it depends on are left out (see Dependencies), so it won't compile as-is.
The core of the project: an authoritative server with client-side prediction, reconciliation, and lag compensation.
| File / folder | Role |
|---|---|
src/Player.cs |
The networked player core (NetworkBehaviour): ownership, observer/client component gating, and the hub other systems attach to. |
src/ClientSidePrediction/ |
PlayerInput runs the client loop: predict locally, cache input/state in ring buffers, and rewind-and-replay on a server correction. ServerSimulation is the authoritative server; it receives inputs, rate-limits them per connection (anti-cheat), simulates, and broadcasts state. ClientInputState and SimulationState are the wire payloads. |
src/LagCompensation/ |
Server-side rewind of hitboxes to the shooter's reported render tick, so hits are validated against what the shooter saw, with bounded rewind depth. Includes remote-entity and animation interpolation. |
src/Movement/Q3PlayerController.cs is a Quake-3-style movement controller (air-strafing, bunny-hopping) that I rewrote to be deterministic and network-predictable, which is what lets prediction and reconciliation work:
- It takes no direct input. It exposes
moveDirection,viewDirection,isJumping,isCrouching, andisSprintingfields that the netcode sets, and it's stepped byRunUpdate()on the fixed tick instead of inUpdate(). Client and server then simulate the same motion from the same inputs. - Collision runs through Fragsurf
TraceUtil/SurfPhysics(ResolveCollisions, capsule ground traces) rather than Unity'sCharacterController, andGetOrigin()/SetOrigin()let reconciliation rewind and replay the controller.
A MovementState machine (Ground, Air, Crouch, Sprint, Slide) drives per-state speed, acceleration, and friction:
- Crouch: lerped capsule height with its own speed and friction settings.
- Sprint: separate acceleration and max-speed profile.
- Slide: entered from a crouch above a speed threshold, with a directional speed burst that flips to match backwards momentum, reduced friction while sliding, a minimum speed to sustain it, once-per-crouch gating, and a cooldown before re-entry.
- Surfing: velocity reflection off steep ramps (
SurfPhysics.SimpleReflect) with slope-limit handling. - Double jump: one extra air jump per airtime, gated on a fresh jump press so holding the button can't spam it. Cancels upward external velocity first.
- Jump lurch: Titanfall/Apex-style mid-air direction change, applied only to inputs that changed since takeoff. Strength falls off over a grace period and costs horizontal speed.
- Step-up:
BoxCaststair climbing under a max step height. - External velocity:
m_ExternalVelocityfrom moving platforms and jump pads, layered on top of player velocity instead of mixed into it. - Runtime cvars:
SetSetting()exposessv_accelerateandsv_airacceleratefor console tuning.
Lineage: the starting point was IsaiahKelly/quake3-movement-for-unity, released under the Unlicense. That version is a single-player MonoBehaviour that reads input directly in Update() and moves a CharacterController. What survives here is the core Quake-3 CPM acceleration math (Accelerate, AirControl, friction). Everything listed above is new.
A self-contained bot AI that plays as networked players (src/Bot/):
BotBrain: a state machine (Roam,Fight,Chase,Retreat) that drives perception, navigation, and combat.BotPerception: tracks known enemies with last-known-position, visibility, distance, and a per-enemy threat level.BotNavigationandBotCombat: movement/pathing and target engagement.BotManager,BotCharacter,BotPlayer: spawning and wiring bots onto the sharedPlayercore.
| File / folder | Role |
|---|---|
src/Gameplay/MatchManager.cs |
Match state machine (WaitingForPlayers, Warmup, InProgress, PostMatch) with server-synced timers and player counts. |
src/Gameplay/GameModes/ and IGameMode.cs |
Pluggable game-mode interface (score/time limits, warmup, win conditions) with a FreeForAll implementation. |
src/Gameplay/ |
ScoreManager, PlayerStats, kill feed (KillFeedManager, KillMessageUI), scoreboard, match timer UI, moving platforms. |
src/Enemy/ |
NavMesh-driven PvE enemies with an IDamageable damage interface. |
src/Core/ |
Bootstrap and SceneLoader startup and scene management. |
- Client-side prediction: the owning client applies input immediately, without waiting for the server.
- Server reconciliation: past a position tolerance, the client snaps to server state and re-simulates its buffered inputs to catch up, so there's no rubber-banding.
- Lag compensation: the server rewinds hitboxes to the shooter's precise sub-tick. Rewind depth is capped so a spiking RTT can't be abused.
- Anti-cheat input gating: per-connection input-rate limiting.
- Fixed 64 Hz tick: client and server run the same deterministic simulation from a shared movement config.
Referenced but not included here:
- FishNet (required): transport, tick/
TimeManager - A third-party weapon and input layer, plus debug tooling (
LiveWatch,IngameDebugConsole), from the parent project.
Since those layers aren't bundled, the code here won't compile on its own. It's here to show the design and implementation.
The design draws on these:
- Gabriel Gambetta, Client-Side Prediction and Server Reconciliation, for the prediction and reconciliation model.
- Valve, Source Multiplayer Networking and Overwatch Gameplay Architecture and Netcode (GDC 2017), for the authoritative-server and lag-compensation model.
- J.M.P. van Waveren, The Quake III Arena Bot (TU Delft, 2001), the basis for the bot AI (goal-driven behavior and navigation).
Pulled from Project-Playground (private). Original systems by LostPizzaMan.