A map viewer, spectator client and (skeleton) dedicated server for Call of Duty (2003), patch 1.1, written in Rust. It reads the game's own pk3 archives, renders maps with their lightmaps and props, lets you walk them with the original movement rules, and speaks the real 1.1 network protocol well enough to spectate a live multiplayer server with players, animations, HUD, sound and combat effects.
- Loads any stock or custom map from an installed copy of the game and renders it textured, lightmapped, props included. Skies, water, fences, foliage and terrain detail blends draw through their authored Q3-style shader scripts, with the sun disc and the map's fog. Fly around freely. The map's ambient loop plays in fly and walk mode.
--walkspawns you as a soldier with Quake 3 derived movement: gravity, stances, stepping, wall sliding, leaning, and the kar98k viewmodel playing the game's own xanim clips. Footsteps follow the retail cadence per surface, the weapon plays its file's fire/rechamber/reload sounds, and landings pick their alias from fall speed.--connect <ip:port>joins a CoD 1.1 server as a spectator. The client does the handshake, Huffman coding, netchan, delta snapshots and usercmds, follows the server's spectator camera, and renders every player as an assembled soldier playing the server-driven animations. Kill feed, chat, scoreboard, sounds, tracers, impacts and muzzle flashes come from the same events the retail client reads. It downloads every pak the server references and the install lacks, the way the retail client does, so mod paks arrive along with the map's own.vcod-serveranswers server browsers, accepts connections and hands out the gamestate, so a retail 1.1 client loads the map, then keeps it alive with delta-compressed snapshots against the client's last acked frame and flies it around as a spectator on the shared pmove.--test-entitiesadds entities that move on the wire to exercise the packet-entity path; they carry noeTypeor model, so a retail client draws nothing for them, and the server simulates no real gameplay yet.
The whole thing runs on wgpu and winit, so in principle it is cross-platform. I have only run it on Linux.
It is a Cargo workspace of four crates. crates/common holds the file
formats, collision, movement and the 1.1 protocol, shared by the client and
the server; nothing in it imports wgpu, winit or kira. crates/client is the
window, renderer, HUD, effects and audio; crates/server is the dedicated
server. crates/gsc is a virtual machine for CoD's own script language
(.gsc), so the dedicated server can eventually run Activision's shipped
gameplay scripts instead of hand-written rules; it depends on neither
vcod-common nor the client's rendering stack. AGENTS.md is
the contributor guide.
Mostly to see whether it could be done. Call of Duty 1 is an id Tech 3 descendant, and the Quake III Arena and Return to Castle Wolfenstein sources are public, but the 1.1 wire protocol has never been written down. Every field width, every enum order, every place where Infinity Ward diverged from RTCW had to be recovered from the binaries and confirmed against the retail server. That recovered protocol is documented in docs/protocol-1.1.md and is probably the most useful thing in here.
The other reason is that it is fun to watch a 2003 game come back to life in a window you built yourself.
Most of the code and documentation in this repository was written by an AI coding agent working under my direction. I decide what to build, review what comes back, run it against the real game and the retail server, and do the pixel-level and by-ear checks the agent cannot. The research docs record for each fact whether it was verified live or only inferred from a decompilation, so you can tell the two apart. Treat the code as a working prototype, not a reference implementation.
- A purchased, original copy of Call of Duty (2003) installed with patch 1.1.
This repository contains no game data. The 1.5 patch ships the same
pak0-4.pk3assets, so a 1.5 install also works as the asset source; the netcode and the reverse-engineering notes are about 1.1. - Rust 1.90 or newer; the dependency graph requires it.
- For the client, a GPU and driver with BC (DXT) texture compression. wgpu
picks whatever backend it finds (Vulkan, DX12, Metal, GL);
WGPU_BACKEND=vulkan|gl|dx12|metalnarrows the choice. The server needs no GPU. - I have only tested on Linux. Windows and macOS are unverified.
- Optional, for sound: a working default output device. Without one the client logs a warning and runs silent.
Prebuilt binaries for Linux amd64, Windows amd64 and macOS arm64 are on the
nightly release, rebuilt
from master on every push. It is a rolling tag: the assets are replaced in
place, so the download URLs never change and the previous build is gone.
Linux and macOS ship as .tar.zst, Windows as .zip.
To build it yourself:
cargo build --release
builds target/release/vcod (client) and target/release/vcod-server.
cargo build -p vcod or -p vcod-server builds one of them.
The binaries expect to sit inside the game install, next to CoDMP.exe, and
read the paks from its main/ subdirectory. Either copy them there, set
COD_DIR=/path/to/CallOfDuty, or pass --game-dir. --game-dir beats
COD_DIR, which beats the executable's own directory, with the working
directory as the last resort.
COD_DIR=/path/to/CallOfDuty cargo test
Without COD_DIR the tests that need game data return early and report ok,
so a green run on a machine without the game proves nothing about the
parsers. The net-protocol tests read committed captures and run anywhere.
CI runs the suite this way, since the game data cannot ship with it.
vcod mp_pavlov
vcod mp_pavlov --walk
vcod --list
vcod --connect <ip:port>
vcod mp_pavlov --game-dir /path/to/CallOfDuty
- The first positional argument is the map name (case-insensitive).
--listprints every.bspin the search path instead of opening a window.--mod-dirselects which subdirectory's pk3s to index:mainfor retail CoD1 (default),uofor United Offensive. Only one directory mounts at a time, so a UO map whose art ships inmain/shows missing textures; noville was flown this way and renders apart from that. Anything beyond noville is untested.--walkstarts at a player spawn point as a collidable soldier. Needs a map with a spawn entity and collidable geometry.--connect ip:portspectates a live server. To find a populated one, the master server atcodmaster.activision.com:20510still answersgetservers 1 full empty.--debug-overlay(or F3 at runtime) shows frame time, draw stats, net and audio counters.--no-audioruns silent;--volume <0..1>sets the master volume.--net-probe ip:portis a headless client that prints what it receives and dumps captures totmp/under the current directory. It is the netcode debugging tool; details in AGENTS.md.
vcod-server mp_carentan --port 28960 --hostname "my server"
vcod --connect 127.0.0.1:28960
The server binds 0.0.0.0 and, like the retail server, answers getstatus
from anyone and honours an out-of-band disconnect by source address. Run it
on a LAN or behind a firewall you control. --max-clients sets
sv_maxclients (default 8). --test-entities <n> adds n entities that
move on the wire, one of which cycles in and out, to exercise the
packet-entity path; they are not rendered by a retail client, only present
to drive the encoding. 0 (the default) is off. --game-dir, --mod-dir and
COD_DIR work the same way as for the client.
Click to capture the mouse, Esc to release it, mouse to look around.
| Input | Action |
|---|---|
| W / A / S / D | Move forward / left / back / right |
| Space | Move up |
| Ctrl | Move down |
| Shift | Speed boost |
| Scroll | Adjust fly speed |
In spectate mode the position comes from the server; the mouse drives the look angles. Hold Tab for the scoreboard. A map change on the server shows a loading screen (and downloads missing paks the way the connect does) and continues on the new map.
These work in every mode:
| Input | Action |
|---|---|
| F3 | Toggle the debug overlay |
| F4 | Culling: on, locked (freeze the visible set), off |
| Input | Action |
|---|---|
| W / A / S / D | Move forward / left / back / right |
| Space | Jump (re-press to jump again, no autohop) |
| Ctrl | Crouch (held) |
| Z | Toggle prone |
| Q / E | Lean left / right |
| Shift | Slow walk |
| LMB | Fire (hitscan, per-surface impact effect and tracer) |
| RMB | Aim down sights (held) |
| R | Reload |
| 1-6 | Weapon: colt, thompson, mp40, mp44, enfield, kar98k |
- Shadow-decal prop models (
shadow_tree_*,shadow_crateand similar) draw as coplanar, alpha-blended decals on the ground, depth-biased against z-fighting. - Props are lit by the compiler's per-entity
lightingPrecalctint, one colour for the whole model. The engine samples its light grid per vertex. - Shader scripts drive skies, water, blends, the
sunfilesun disc and the ocean'sdeformVertexes wave. What is left of the grammar: the otherdeformVertexesforms parse and stay inert, and NV/ATI hardware-path stages are dropped exactly as retail dropped them on machines without those extensions. The script fog keywords (fogvarsand friends) stay inert too; no stock MP map sets fog from a script. The fog every map shows is set by gsc and arrives on the wire in configstring 12, which vcod renders. Engine-generated$dlightbundle images and the ship's deckflag texture have no file to load, so a generated light blob and a white pixel stand in for them (neuville windows, mp_ship flag decks). Details in docs/research/cod11-shader-scripts.md. - Visibility follows the retail cells, portals, bevel planes and occluder volumes. Three deliberate divergences draw a little more than retail: clipped portal polygons narrower than a sliver epsilon are skipped, cells whose top is below the eye are marked with the camera frustum instead of a portal cone, and after the walk every cell sharing a portal with a visited cell is frustum-tested to a fixpoint. Retail assumes nobody looks over a cell's walls; the mp_ship decks prove otherwise. Outside every cell (fly mode above the map) only the frustum culls.
- Alpha-cutout surfaces without a clip bit (bushes, treelines, ground decals) no longer collide; masked wire and iron fences carry PLAYERCLIP in the BSP and still stop the player, but bullets pass them, as on a retail server.
- Submodels (doors, exploding walls) collide by their brush hulls, but only as static geometry: no entity-driven movers, so there is nothing to ride.
- Walk-mode bullet impacts resolve per surface through
fx/iw_impacts.csvlike spectate does, plus tracers. No penetration, grenades or projectiles. - Walk mode carries six weapons on keys 1-6 (colt, thompson, mp40, mp44, enfield, kar98k) with per-weapon viewmodel, anims, sounds and reserve ammo; sniper scope overlays are not drawn.
- No mantling - which retail 1.1 MP turns out not to have either; ledge hops are plain jumps and step-ups (docs/research/cod11-mantle.md).
- No doppler, matching retail: the 1.1 engine never sets a Miles velocity
(
docs/research/cod11-sound-system.md, section 11). Occlusion is a vcod addition the retail client does not have: a wall between the listener and an emitter quiets it to about -12 dB. - Voice pools and priority stealing follow the retail engine: at most 32 spatial, 32 flat and 8 streamed voices, and a full pool evicts a lower- priority victim instead of refusing the new sound.
- Quick chat (
vsay) is handled and inert on a stock install, exactly as retail is: thej/k/lcommands resolve against mod-provided.voicetables, which no stock pak ships. The speaker's head icon is not drawn and category strings display unlocalized. A sweep of three populated public servers sent noj/k/lat all, so the path is unobserved live (docs/research/cod11-quick-chat.md). - Audio fidelity is matched to the retail engine on paper (falloff, panning, channel replacement, ducking) but not yet confirmed by ear against the real game.
- The server deltas snapshots against the client's last acked frame and moves
spectators itself; it simulates no real gameplay.
--test-entitiesadds entities that move on the wire so the packet-entity path (baselines, moving deltas, removal and re-add) has something to exercise; they carry noeTypeor model, so a retail client renders nothing for them, and their encoding is round-trip tested, not pinned against a retail capture the way the rest of the snapshot writer is, since no entity in the captured frames ever moves.
- docs/protocol-1.1.md: the CoD 1.1 wire protocol, both directions, with the list of every divergence from RTCW/Q3 at the end.
- docs/research/: per-subsystem notes recovered from the binaries and confirmed live: the BSP, xmodel and xanim formats, the clientState stream, the player model and animation system, the event and effect tables, the efx grammar, the HUD protocol, the sound system, the retail server's handshake, and the shader scripts. Each claim cites the module and address it rests on and says whether it was verified live or inferred.
- tools/re/: the small scripts used to pull tables out of the binaries (event enum, netfield tables, xrefs, a Ghidra export script) and the disassembly notes for the Linux server.
- AGENTS.md: working notes for contributors and coding agents: layout, test setup, netcode debugging, the reverse-engineering workflow.
- Quake III Arena and Return to Castle Wolfenstein by id Software, GPL. CoD1 is an RTCW-MP descendant and its netcode, movement and animation code follow those sources closely. Where vcod ports a routine, the comment names the file it came from.
- ioquake3, for a cleaner reading of the same netcode.
- CoDExtended, a GPL server extension for CoD1 1.1 whose reverse-engineered struct layouts were the starting point for the netfield tables.
- cod-asset-importer, a GPL Blender add-on for CoD assets; the xmodel triangle-strip decoder is ported from it and the xmodel layout was cross-checked against it.
- wgpu, winit and kira for graphics, windowing and audio.
vcod is not affiliated with or endorsed by Activision or Infinity Ward. Call of Duty is a trademark of Activision Publishing, Inc. This repository contains no game assets, no game code and no binaries from the game; it reads the files of a copy you own. The reverse engineering was done to interoperate with the game's own files and servers. The research notes document file formats and the network protocol for that purpose: they contain layouts and addresses recovered from the binaries, and no copied code. The screenshots above show art owned by Activision.
Quake III Arena and Return to Castle Wolfenstein are trademarks of id Software. Their GPL sources, and the other ported code, are credited in NOTICE.
GPL-3.0-or-later; see LICENSE. The network code was written with the RTCW (GPLv3) and Quake 3 (GPLv2-or-later) sources as reference, so the project is GPL to stay compatible with them.


