A from-scratch reimplementation of bits of Call of Duty (2003), patch 1.1, in Rust. A map viewer, a client that spectates and plays on real 1.1 servers, and a dedicated server a retail 1.1 client can join. It reads the game's own pk3s and speaks the original 1.1 wire protocol, which nobody ever wrote down, so I dug it out of the binaries.
vcod is a hobby project. I work on it while poking at a 2003 engine is fun, and I stop when it isn't.
- It is not a playable game. You can run around, shoot people and plant a bomb, and some evenings it almost feels like Call of Duty. It is still a research rig with a renderer bolted on. Expect missing pieces and the occasional soldier living inside a wall.
- Retail parity is not a goal. No roadmap, no "1.0". If it ever becomes fully playable, that's an accident and I'll take the credit anyway.
- It doesn't replace your copy of the game. It needs that copy to run.
- Don't host real players on it. No anti-cheat, an rcon that knows a couple of dozen commands, and strong opinions about tick order. Your regulars deserve a server that was tested on someone other than bots.
If you want to play Call of Duty, play Call of Duty. If you want to watch a 2003 game boot in a window someone rebuilt from the bytes up, stick around.
- Draws any stock or custom map with textures, lightmaps and props. Skies,
water, fences, foliage and terrain blends run through the maps' own
Q3-style shader scripts, sun disc and fog included. Lamp glows face the
camera (
autosprite), flags flap, and a.sunfile's flare, glare and blind follow the sun's visibility. The map'scoronaentities glow around their lamps when seen from below, as retail draws them. - Culls with retail's cells, portals and occluders. F4 freezes or disables culling so you can fly out and see what the camera was drawing.
- Props, players and every other model switch to their coarser LODs with distance, zoom and Model Detail, by retail's rule.
- Plays the map's ambient loop.
- Spawns a soldier on a spawn point with retail movement: gravity, crouch, prone, stepping, leaning, wall sliding.
- Seven weapons with their own viewmodels, animations, sounds and reserve ammo. Hitscan shots with per-surface impacts and tracers.
- Footsteps on retail's cadence per surface; the landing sound scales with fall speed.
- Opens on the stock main menu and server browser, drawn from the game's own
ui_mp/*.menufiles. The browser's three sources are retail's: Local (agetinfobroadcast to ports 28960-28963), Internet (whatcodmaster.activision.comknows) and Favorites (kept inservercache.datbesideCoDMP.exe, the file retail uses). It pings, filters (by game type too), shows when each source was last refreshed, sorts by column, joins on double-click, and runs the stock password, server info, filter and favourite popups. Losing the server drops you back on the menu with the localized reason in the stock error popup. In a game, Esc opens the script menu and its Main Menu tab the stock in-game main menu (Back to Game, Disconnect). The stock Mods menu lists the mod directories besidemain/and switches to one, in a game too (not while a server you started with Dedicated No runs, as retail refuses), and the menus load from the mod's ownui_mp/menus.txtandui_mp/ingame.txt, each file tried undercl_language's directory first (latched, as retail: a change waits forvid_restart). - Start New Server runs the stock create server menus (game type, the maps
mp/*.arenalists for it, server and game type settings), then startsvcod-serverfrom the same directory asvcodwith those settings and the Mods menu's mod. The server logs tovcod-server.logbesidevcod_mp.cfg. Dedicated No joins it once it answers and stops it when the client disconnects; LAN and Internet leave the client in the menus. The client kills any server it started when it exits. - The stock Options and Multiplayer Options screens: rebind keys, mouse
sensitivity and invert, player name, rate, master volume, video mode and
full screen, brightness, texture detail, filter and quality, dynamic
lights, sync, blood and sound quality, applied at the restarts retail
applies them at. Choices land in the console's binds and cvars and persist in
vcod_mp.cfg; settings vcod has no use for are kept but do nothing. - Joins a 1.1 server (
--connector the browser): handshake, Huffman, netchan, delta snapshots, and pak downloads for whatever the server has and you don't, matched by checksum as retail does; a 1.5 or UO server'ssv_wwwBaseURLredirect is fetched over plainhttp://, as retail's libwww fetches it (cod15-protocol-diff.md 14). A downloaded pak whose checksum is not the one the server lists is deleted before anything loads it. Pure servers take its pak checksums. Modded servers work too: a server'sfs_gamelayers its mod directory overmain/and swaps in the mod's menus, itscl_allowDownloaddecides whether to download, and a mod's script menus andhud.menutext show up. - Watches a United Offensive 1.51 server (protocol 22) with
--mod-dir uo: it switches protocol when the server refuses the 1.1 connect, loads the UO map and models fromuo/over the 1.5main/, and draws the players, items, script models, the stock UO script menus, the kill feed and the events UO shares with 1.1. Tanks and jeeps draw posed as UO's cgame poses them (hull tilt, turret and barrel, the gunner's gun, the jeep's steering and front wheels), their treads and tyres scrolling with the vehicle's travel, and a seated player rides its seat (coduo-diff.md section 18). UO's own events play their effects and sounds (bullet impacts by ammo type, artillery, smoke and tank explodes, deploy, fatigue, overheating, the gunner's fire, the MG fire loop), vehicle engines and MG loops crossfade as UO's sound blend entities do, tank shells whizz in flight, a vehicle MG's rounds draw the impacts and tracers UO's cgame traces itself and stop on vehicles, tracers follow UO's length gate andsv_nightwidth, the flamethrower streams flame, leaves burning residue and reports its burns on you to the server (fdc), efx camera shakes shake the view, and the HUD adds the sprint and fatigue icon, the vehicle status icons and crosshair and vehicles on the compass (section 19). - Plays on a United Offensive server on foot:
+sprint(ALT, rebindable from the controls screen) sprints with UO's gun pose, breaths and footsteps, an LMG's sight deploys its bipod on sandbags, at atrigger_mountor prone, and the sight cooks a pulled grenade. Prediction runs UO's movement, 1.5's plus the sprint, the fatigue bar, the bipod's locks and yaw cap, the cook and automatic fire, replayed against retail captures (coduo-movement.md). - Drives, rides and fires United Offensive vehicles: the use key gets in and out, the weapon wheel changes seats, the stock keys drive, turn a tank's hull to the view (SPACE) and fire the main and alternate guns, and the camera sits where UO's does (a tank driver's chase camera and gunsight, the gunner on its gun with its sway and firing shake, a jeep's riders turning with it), with your own body drawn in the seat where retail draws it. Prediction holds a seat's view clamps and sight, replayed against retail captures (coduo-vehicles.md).
- Draws the server's script menus (team, weapon, view map, call vote,
quick messages) from their stock
.menufiles with their layout, pictures and sounds, driven by mouse and keys as CoD's UI drives them, or answers the team and weapon menus straight from--teamand--weapon. - The stock quick message menu (
V): commands, statements and responses go to the gametype script, which plays the voice line and sends the team chat line. - Spectates. Every player is an assembled, animated soldier. Kill feed,
chat, scoreboard, sounds, tracers, impacts, muzzle flashes, ejected
brass and script effects (the S&D bomb, the bombzone exploders, mines,
playLoopedFx,playFxOnTag) come off the same events retail reads. - Plays. Move, jump, crouch, prone, lean, fire, aim down the sight,
reload, melee, use, switch weapons, on retail's default binds. A usercmd
is built every 8 ms, like a 125 fps retail client, and they go out at
retail's
cl_maxpackets30 withcl_packetdup1 off the LAN. - Keeps its own weapon selection as retail's
cg_weaponSelectdoes: it answers the server's switch and pickup commands, swaps off a dry weapon, takesweapaltandweapon <name>, and keeps asking for the gun a ladder took out of your hands. A select shows retail's weapon-slot strip. - Predicts your movement by replaying unacknowledged cmds through the same step the server runs. A correction eases out over 100 ms.
- A script's
shellShockplays retail's effect from its.shockfile: the view trails and shakes, the mouse damps, the walk slows to 0.4, the mix ducks under the shellshock loop.cg_shellshock <secs> [file]tries one locally. - Draws and stamps cmds on retail's client clock, which slews a millisecond
or two per snapshot instead of stepping on jitter;
cl_timeNudgeworks. - First-person weapon with your team's hands, sight zoom at the weapon's FOV, sniper scope overlay that follows the sway and the hit kick, and your own fire, reload and footstep sounds played off the prediction. The gun bobs, breathes, lags a turn and shifts with speed and stance off the weapon file's keys, as retail's cgame draws it, and the eye bobs with the walk.
- Fire recoil off the weapon file's view and gun kick keys: the view kick rides your cmd angles, as retail's does, rolls the view with it, springs back to centre and clears on a respawn.
- A hit kicks the view along its direction, a landing dips it, and a script
earthquakeor a mounted MG's fire shakes it, with retail's curves. - Mounted MG42s with their fire anim and flash; on the gun the view rides
tag_playerand the crosshair turns into the gun's reticle. - The HUD the stock
hud.menulays out: crosshair that opens with spread, health, ammo, stance, compass with objectives and teammates, use hints, hit direction, chat and announcements. Also the gametype script's own HUD elements (S&D clock, bomb icons, progress bar) in retail's fonts, and head icons over players. A spectator following someone sees their HUD, weapon and scope. - Shows a running vote as retail's cgame does (what it's for, the seconds left, the yes and no counts with the keys to press) and plays its sound; F1 and F2 vote yes and no, and the call vote menu's restart, next map, map, type-and-map and kick picks call one.
- Follows the server through a map change: loading screen, downloads, new map. Open menus close, as in CoD.
- Retail's drop-down console on
`. It takes the commands under Console; binds and archived cvars persist inmain/vcod_mp.cfg. vc_bicubic 1(archived, live, default 0) filters lightmaps with a cubic B-spline instead of retail's bilinear, so low-res shadow edges stop stepping. A deliberate divergence from retail's look.vc_bloom(archived, default 0) adds a glow around bright pixels, which retail never had: the value is the strength (1 is subtle) andvc_bloomThreshold(default 0.8) the on-screen brightness where it starts. The HUD doesn't glow. Off by default to keep the retail look.- Beyond retail, off by default:
vc_ssao(archived, live) adds screen-space ambient occlusion to the lightmapped and ambient-lit surfaces, its value the strength (1 is subtle, 2 heavier). Retail has none; the blends, effects, sky, weapon and HUD are left alone. vc_shadows 1(off by default, live): players, corpses, entity models, moved brush models and waving flags cast soft sun shadows on the world and on each other, glass and water included; foliage, fences and grilles cast and block through their alpha, blended glass and water do not. A deliberate divergence: retail draws none. The baked lightmap shadows stay as they are, so a point the map already shadows is not darkened again, and a cast shadow is as dark as the map's own baked ones measure, per 1024-unit square where the lightmaps say enough (cod11-light-grid-and-leaf-lights.md, section 12).vc_sunShafts(archived, live, default 0): light shafts radiate from the sun through gaps in whatever stands in front of the sky, the value their strength (1 is moderate). Only maps whose.sunfile gives the sun a flare cast them; they fade as the sun leaves the screen, feedvc_bloom, and never cover the HUD. Retail has none.vc_softParticles(archived, live, default 0): smoke, dust, fire and explosion sprites fade out where they meet walls and ground instead of cutting a hard line into them. The value scales the fade distance (1 is half a sprite's size, at most 32 units). Retail has none; impact marks, world shader stages and the HUD are unchanged (cod11-gamma.md, section 8).vc_hdr 1(archived, takes effect onvid_restart, default 0) draws the world into a float target, so stacked effects, flares and the sun go past white and a tonemap rolls them off instead of clipping; ordinary surfaces keep retail's look, and bright overbright ones lose some of their clip. With bloom on, only those over-white pixels glow.vc_grade,vc_vignetteandvc_grain(archived, live, default 0, value is the strength) add a period-film colour grade, a vignette and film grain. None of them touch the HUD. All are divergences from retail's look (cod11-gamma.md, section 9).
I have played it against my own server and the retail Linux 1.1d server, and spectated public servers with it. I haven't joined a public server as a player, and neither should you. Those people signed up for Call of Duty, not for my test suite.
- Answers server browsers, accepts retail 1.1 clients, sends the gamestate and delta snapshots. Run from a patch 1.5 install it speaks 1.5 instead (protocol 6): 1.5's queries, cvars, menus and gametype scripts, with the configstring table 1.5b builds on mp_carentan (cod15-protocol-diff.md 13).
- Hosts United Offensive 1.51 (protocol 22) from a UO install with
--mod-dir uo: UO's queries, cvars, configstring layout, 63 weapons, means of death and event numbering, and UO's stockdm,tdm,sd,ctf,dom,hqandbasscripts. Players sprint, tire, deploy the bipod and cook grenades by UO's rules. The join, a spawned player's playerstate and a kar98k's shots and reload match the retail 1.51b server (coduo-diff.md 20). Artillery strikes, smoke grenades, satchel charges, the flamethrower's reported damage and mounted MG overheat run UO's rules too; the strike, the smoke, the bipod MG, the satchel and the overheat match retail's captures, and a satchel can be shot or blasted off (same doc, 21). The four UO modes' configstrings match retail's, and so do a flag pickup and capture inctf, a flag taken and retaken indom, a radio captured and neutralized inhqand a base breach inbas, HUD, compass and scoreboard included. So do the endings:ctf's flag drop and 20 s return,dom's domination bonus,hq's wave scoring,bas's bomb plant, defuse and blast, and in all four the round end, the score or round limit, intermission and the restartexitLevelfalls back to (same doc, 22). - Hosts United Offensive's tanks and jeeps: they spawn with retail's
entity numbers and configstrings, the use key boards the one you look
at,
nextvehslot/prevvehslotchange seats, and they drive, aim, fire shells and MGs, overheat, sound, take damage and run players over by the 1.51 game module's rules, a tank's driver shut against every round but his own tank's. A Panzer IV's and a Willys's drives replay on ours as retail's to the field, and so do the seat changes (coduo-vehicles.md 10-14). - Runs Activision's own gametype and map scripts on
vcod-gsc, a VM for CoD's.gsclanguage that lives in this repo. Menus, spawns, scoring, rounds and limits all come from the stock scripts, not from Rust. All five stock gametypes are checked against retail:dm,tdmandsdend to end,reandbelthrough their key events (cod11-gametypes-re-bel.md). - Shared pmove with capsule players that block and push each other. Falls stun and hurt.
- Bullets trace the world, players and static props, through the stock damage callback with per-bone hit locations. Rifle rounds go through players, every round goes through glass. Melee works. Grenades are real missiles that bounce, rest and explode with retail's falloff, and a blast walks its victims in retail's area-tree order, so the guy in front still eats it for the guy behind.
- Corpses in the eight-slot body queue, dropped weapons, pickups by touch or use key, items that fly retail's arc and respawn on its timer.
- Search & Destroy end to end: plant, defuse, progress bar, compass objectives.
- Mounted MG42s: mount, aim inside the arc, fire, dismount.
- Map triggers, script movers that carry and shove players and items, and
linkToon script models, brush models, items, turrets and player tags. - Intermission,
map_restartandsv_mapRotationthe way retail runs them. - Spectator follow and the killcam, replayed from a ring of archived frames.
- rcon with retail's commands and replies, bans, the master heartbeat, zombie slots and retail-measured pings.
- Votes (
callvote,vote) with retail's kinds, refusals, configstrings, pass rule, 30 s timeout and 3 s delay before the command runs: 1.1's seven kinds underg_allowVote, 1.5's twelve under their owng_allowVote*gates, measured against both retail servers. Bots are not counted as voters, and a map vote needs the map on the server on 1.1 too. A script'sallowComplaintopens retail's teamkill complaint, whichvoteanswers and the client prompts for. - Publishes retail's pak lists and checksums in the systeminfo, serves the
paks it lists to clients that lack them at retail's pace (on 1.5 and UO,
sv_wwwDownloadsends them tosv_wwwBaseURLinstead, connected or disconnected), and with--set sv_pure=1checks each client's pak checksums the way a pure retail server does.sv_minPing/sv_maxPingrefuse off-LAN clients by challenge ping, and an off-LAN client's messages wait out its rate andsnaps. Big messages, the gamestate included, go one fragment per frame, and a client not yet in the world gets retail's bare keepalive (every frame on a LAN, a second apart off it). --botsadds bots that join through the stock menus and roam a nav graph built from pmove runs, ladders and jumps. They play the objectives: S&D plants and defuses, Retrieval carries and escorts, Behind Enemy Lines hunts. With--bots-shootthey fight back, with a reaction delay, a turn cap and aim that settles on target. They are still bad at it. So am I. On a 1.5 or UO server the graph is proven under that patch's movement. UO bots sprint long straight legs while they have the breath, pick from UO's weapon menus (never a light machine gun: they don't deploy bipods), cook their frags and playdm,tdmandsd; they ignore vehicles.
The retail 1.1d Linux server is the oracle. When vcod and retail disagree, retail wins and the disagreement goes into a research doc.
- A headless probe client (
vcod --net-probe) joins a server and records what it sees, with a few dozen scripted modes: shoot someone, throw a grenade, plant the bomb, crawl prone up a hill, get stuck inside another player. - The retail recordings are committed as fixtures. A/B tests replay the same inputs on vcod's server and diff the result snapshot by snapshot.
- Small
.gscprobes run on retail and onvcod-gsc, and the suite compares their output.
This catches a lot. Anything about how it looks or sounds still needs a human squinting at a screen.
Retail does a lot more than this list. These are the gaps you'll hit first.
Front end. Main menu, browser and its popups, options, quit and error
popups work. The options screens' texture detail, filter and quality,
model detail, dynamic lights, sync, blood, wall marks, ejecting brass and
sound quality take effect as retail applies them; the sound provider and
NVIDIA fog are stored but ignored, and the language picker stays hidden.
Show Compass and Team Overlay do nothing, as in retail 1.1. CD key prints
"not in vcod yet".
There is no listen server: Start New Server always runs a separate
vcod-server, Dedicated No joins it as an ordinary client (it needs the
password too), and LAN or Internet does not turn the window into a server
console.
Client
- Patch 1.5 servers (protocol 6) are joined by switching protocol when
one refuses the 1.1 connect. A pure 1.5 server wants a 1.5 install as
COD_DIR(cod15-protocol-diff.md). Prediction runs 1.5's movement there (jump penalty, no prone dive, the stepped stance, the prone body's swing search, the footstep changes,disableWeapon), and the bobs take the server's bob cvars (cod15-movement.md). PunkBuster servers refuse it (vcod runs no PunkBuster), andcg_autodemoandcg_autoscreenshotdo nothing (no demos or screenshots). - On a United Offensive server vehicles kick up no wheel dust or tread effects, a seated player keeps the server's anim without UO's steering blend, and a gunner you follow aims its gun off the wire, not the followed view. The flamethrower's burning residue stays where it lands instead of drifting (coduo-diff.md sections 16-19).
- Prediction carries you on a moving brush model and turns your view with its yaw, as retail's does, but never turns your position about it. Neither does retail's.
- A mod's UI DLL is ignored; only its menu files count (cod11-front-end.md sections 16-17). Switching mods in a game keeps the loaded map's geometry.
playFxOnTagon the body the view rides (your own, or the player you follow) draws nothing; on any other entity it plays on the tag.
Server
- The server and the client pose a moving body as retail does
(ground-speed rate, phase, blend times, torso over legs). A tag on an
attached model can't take a link. - A brush model that turned and turned back keeps a sliver of yaw on retail and drifts its riders about 0.02 units a frame. vcod's comes back to zero. Yes, I'm calling that a bug in retail.
sv_puredefaults to 0 where retail's default is 1, and a client may download only the paks the server lists. Retail serves any file under its directories,..included, so I'm keeping that one on purpose.- rcon runs
map,devmap,map_restart,map_rotate,status,clientkick,kick,banUser,banClient,dumpuser,serverinfo,systeminfo,say,set,seta,cvarlist, cvar queries,heartbeat,killserverandquit, and on 1.5tempBanUser,tempBanClient,setdrawfriend,setfriendlyfireandsetkillcam. A temporary ban refuses an off-LAN client forsv_kickBanTimeseconds by address, where retail's keys it on the authorize server's guid; a LAN client is only kicked, as on retail. NotgameCompleteStatus,scriptUsageorstringUsage. Bans live in vcod (--ban-filekeeps them across runs) where retail hands them to Activision's authorize server. Like retail's, a ban refuses an address off the LAN and leaves the banned player connected until they leave on their own. Afterkillserverthe process sits there deaf, since there is no stdin console. - A heartbeat reaches the master, which probes back. I haven't seen vcod listed yet.
- On a UO server bullets pass through vehicles (so a tank's gunner and a
jeep's riders take far more hits than on retail), a shell's direct hit on
one deals only its splash, vehicles don't push each other, a body
dismounts 32 units higher than retail's where the ground is uneven, and
the compass shows no tanks out of view
(coduo-vehicles.md 14). Script
mounts (
spawnTriggerMount) are not done (coduo-diff.md 20). - A server speaks one patch, 1.1, 1.5 or UO, as each retail binary does. On 1.5
everyone, bots too, moves by 1.5's rules (as far as the client's
prediction models them), and so do the bots' nav graph's walks.
A 1.5 server runs the match timeout, 1.5's chat (
g_deadChat,say_squad) and refuses PunkBuster as the Linux 1.5b server does.
Rendering and sound
- Props are lit per vertex from the map's lights and its light-visibility grid at load, as retail does. Dynamic lights add on top with retail's falloff instead of competing for a prop's eight light slots. Players, other entity models and the viewmodel pick their eight lights from the grid every frame, fx lights and the panzerfaust's black rocket light among them (cod11-light-grid-and-leaf-lights.md).
- The frame holds retail's framebuffer bytes and the gamma ramp doubles it once at the end, as retail's hardware ramp did; windowed it draws as retail's windowed mode does, with no doubling and lightmaps shifted at load (cod11-gamma.md). Entity models and the viewmodel draw every stage of their material (pickup glow, objective pulse, the grenades' environment map) and sort among the world's surfaces by material sort, as retail's draw list does. The world draws its shaders in retail's sorted order (sort, then first-stage images), each shader's stages together, with no depth sorting; effects join the same list by sort.
- Impact marks (bullet holes, scorches) clip onto the world's triangles on
the CPU, take the surface's lightmap, fade over the second half of their
life and draw at their shader's sort and polygon offset, 1024 pieces at
most, as the retail cgame and renderer do. A
map_restartclears them with every live effect and sound.cg_shadows 1(a cheat, off by default as in retail) drops themarkShadowblob under players 250 to 1024 units away. Brush models and props take none, as in retail; the dlight pass skips them (cod11-events-and-fx.md, section 9). deformVertexesdrawswave,flap,autospriteandautosprite2;bulge,move,normalandtext(no stock user) parse and do nothing. Entity models and the viewmodel takeskins/script blocks but run no vertex deform (no stock MP entity has one). NV/ATI hardware-path stages are dropped, as retail did on cards without them. Dynamic lights (muzzle flashes, blasts) light the world through retail's dlight pass: the projected dlight image over each opaque surface a light reaches, through itsperLightstages, the copy of its texture ordlightshader. The ship's deckflag has no file behind it, so a stand-in draws (cod11-shader-scripts.md).- Visibility draws a bit more than retail on purpose. Retail assumes nobody looks over a cell's walls, and the mp_ship decks disagree.
- Audio follows the engine on paper (falloff, panning, voice pools, stealing, ducking) but hasn't been checked by ear against the real game. Wall occlusion is a vcod addition.
Things that look like gaps and aren't
- No mantling, no swimming. Retail 1.1 MP has neither (cod11-mantle.md).
- No grenade cooking. The fuse runs in full from the release, however long you clutched it.
- No doppler. The 1.1 engine never gives a sound a velocity.
- Quick chat (
vsay) does nothing on a stock install, same as retail: its.voicetables only ship in mods. - Asphalt footsteps are silent in retail because the engine asks for
asphaltand the sound table spells itasphault. vcod uses the table's spelling, so you can hear asphalt. Twenty-three years late, Infinity Ward, you're welcome.
- A purchased copy of Call of Duty (2003) with patch 1.1. This repo has no
game data. Patch 1.5 ships the same
pak1-4.pk3and a differentpak0.pk3; a 1.5 install works as the asset source, but itspak0is not on a pure 1.1 server's list, and a pure 1.5 server refuses a 1.1 install's. The client speaks 1.1 and 1.5 and plays United Offensive 1.51 (that install'suo/and 1.5main/); the server speaks whichever patch its install is, UO with--mod-dir uo. - Rust 1.90 or newer.
- For the client, a GPU with BC (DXT) texture compression. wgpu picks a
backend;
WGPU_BACKEND=vulkan|gl|dx12|metalnarrows it. The server needs no GPU. - Linux is the only platform I run. Windows and macOS builds exist and are untested, so godspeed.
- An audio device if you want sound. Without one the client warns and runs silent.
Prebuilt Linux amd64, Windows amd64 and macOS arm64 binaries are on the
nightly release,
rebuilt from master on every push that touches code. It's a rolling tag:
the assets are replaced in place and the previous build is gone.
cargo build --release
gives target/release/vcod and target/release/vcod-server. Both expect to
sit next to CoDMP.exe and read the paks from main/. Copy them there, set
COD_DIR=/path/to/CallOfDuty, or pass --game-dir. --game-dir beats
COD_DIR, which beats the executable's directory.
COD_DIR=/path/to/CallOfDuty cargo test
Without COD_DIR the tests that need game data return early and pass, so a
green run without the game proves nothing about the parsers. CI runs that
way, because it can't ship the game either.
vcod-server mp_carentan --bots 4 --bots-shoot
vcod --connect 127.0.0.1:28960
Pick a team, pick a weapon, go get shot by a bot.
vcod # main menu and server browser
vcod mp_pavlov # fly
vcod mp_pavlov --walk # walk, offline
vcod --list # every .bsp in the search path
vcod --connect <ip:port> --team axis --weapon kar98k_mp
- The map name is case-insensitive.
--team <allies|axis|autoassign|spectator>and--weapon <file>answer the menus without showing them, for--connectand every consoleconnect. If the menu refuses the weapon, you pick by hand.--mod-dir uosearches United Offensive'suo/over themain/beside it, as UO itself does, sovcod --game-dir <UO install> --mod-dir uo --connect <ip:port> --team spectatorwatches a UO server andvcod mp_cassino --game-dir <UO install> --mod-dir uoflies its maps.--debug-overlay(or F3) shows frame, draw, vis, net and audio counters.--rtx-onturns on every beyond-retail extra for one run (vc_bicubic,vc_bloom,vc_shadows,vc_ssao,vc_sunShafts,vc_softParticles,vc_hdr,vc_grade,vc_vignette,vc_grain) without saving them to the config. Despite the name, no rays were harmed.--no-audioruns silent;--volume <0..1>sets the master volume (mss_volume, default 0.8, also on the Sound screen).--net-probe <ip:port>is the headless probe client;vcod --helpdocuments its modes.
vcod-server mp_carentan --port 28960 --hostname "my server" --gametype tdm
- Binds
0.0.0.0and answersgetstatusfrom anyone, like retail. Keep it on a LAN or behind a firewall you control. --gametypepicks the script undermaps/mp/gametypes/(defaultdm);--max-clientssetssv_maxclients(default 8).--set NAME=VALUEis retail's+set, repeatable:--set scr_friendlyfire=1,--set sv_mapRotation="...".--set fs_game=<dir>runs a mod: its directory's paks go overmain/, and clients are told to load it, as retail's+set fs_game.--set rconPassword=<pw>turns rcon on.--set g_password=<pw>makes the server private, checked as retail does at connect,map_restartand map change.--set sv_privateClients=N --set sv_privatePassword=<pw>reserves the first N slots for clients that send that password, as retail does.dedicateddefaults to 1, not retail's 2, so dev runs stay off the master list.--set dedicated=2heartbeatscodmaster.activision.comevery three minutes and sends a flatline on Ctrl-C orquit.--bots <n>addsnbots in real client slots. The nav graph builds on its own thread on the first tick (a second or two on big maps); bots wander until it's ready.--bots-shootlets them fight.- On a patch 1.5 install the server speaks 1.5 (protocol 6) and takes only
1.5 clients; with
--mod-dir uoon a UO install it speaks UO (protocol 22).--set protocol=1,6or22overrides the install. --gametype-script <file>runs a gametype from disk instead of the paks.--test-entities <n>adds invisible entities that move on the wire, to exercise the entity encoding.--tracelogs every snapshot per client, and once a second the slowest tick and how far the loop fell behind its 20 Hz schedule.
Click to capture the mouse, Esc to release it.
| Input | Action |
|---|---|
| W / A / S / D | Move |
| Space / Ctrl | Up / down |
| Shift | Speed boost |
| Scroll | Fly speed |
The stock config_mp.cfg binds, with the sight on the right mouse button as
+speed. bind MOUSE2 "toggle cl_run" makes the sight a toggle.
| Input | Action |
|---|---|
| W / A / S / D | Move |
| Space | Stand up; jump when standing |
| C / Ctrl | Crouch / prone |
| Q / E | Lean (held) |
| LMB | Fire (semi-autos fire once per click) |
| RMB | Aim down the sight (held) |
| R | Reload |
| Shift | Melee |
| F | Use: pick up, mount an MG, plant, defuse, respawn |
| 1 / 2 / 3 / 4 | Primary, second primary, pistol, grenade |
| Scroll | Next / previous weapon |
| Tab | Scoreboard (held) |
| T / Y | Chat to everyone / your team |
| V | Quick message menu |
| M | Script menu: team, or weapon once you have a team |
| Esc | Script menu, as retail; its Main Menu tab opens the main menu (Back to Game, Disconnect, Quit) |
A script menu works as in CoD: the cursor shows, the item under it takes the focus, a click or its digit picks it, Tab and the arrows step the focus, Esc closes every script menu, and the stock menu sounds play. A menu keeps the mouse captured and moves its cursor by the mouse's motion, as CoD does; in a window the console lets the pointer go. The quick message menus leave the mouse and every key but their digits on the game. The main menu takes the mouse; Esc or Back to Game returns to the game. As a spectator, Space rises and C sinks; as on retail, E (lean right) sinks at 512 and Q (lean left) rises at 256.
| Input | Action |
|---|---|
| W / A / S / D | Move |
| Space | Jump (no autohop) |
| Ctrl | Crouch (held) |
| Z | Toggle prone |
| Q / E | Lean |
| Shift | Slow walk |
| LMB / RMB | Fire / aim down sights |
| R | Reload |
| 1-7 | colt, thompson, mp40, mp44, enfield, kar98k, scoped kar98k |
` or ~ toggles it; while it's down the game gets no keys. Up / Down
walk history, Tab completes, Page Up / Page Down scroll. In game, a line
without a leading / or \ is chat, as in retail. ; separates commands.
| Command | Does |
|---|---|
connect <ip:port>, disconnect, reconnect, quit |
What they say |
say, say_team |
Chat |
cmd <text> |
Send a raw client command |
bind, unbind, unbindall, bindlist |
Binds |
set, seta, toggle, <cvar> [value] |
Cvars; seta also saves |
cvarlist, cmdlist, echo, clear |
The usual |
Anything else goes to the server while connected (callvote, kill,
follownext). Bindable commands and key names are retail's (+attack,
+speed, weaponslot pistol, MOUSE1, MWHEELUP). The client cvars are
name, cl_run, sensitivity, m_yaw, m_pitch, cg_fov
(cheat-protected, so 80 unless the server runs sv_cheats 1), rate
(25000; retail's first-run 5000 starves snapshots), snaps,
scr_conspeed, mss_volume, r_mode / r_fullscreen (applied at start
and by vid_restart, which also reloads the menus closed),
password and the browser's ui_netSource,
ui_joinGametype and ui_browserShow*. exec <file> runs a config from the paks or main/,
and ui_load reloads the menus off the list ui_menuFiles names.
Binds only act while connected.
Mouse to pick, double-click or Enter to join, the arrows, Home, End and Page Up / Down with the cursor over the list to move the selection, the wheel or the scroll bar to scroll, Esc to go back. The wheel scrolling a list is vcod's; CoD's wheel scrolls none. Tab and the arrows no list takes move the menu's focus for as long as the key is down, as CoD's do. Held keys do not repeat in a menu, except typing and Backspace in a text field. Enter and the middle button act on the item under the cursor, as CoD's do. Click Source to cycle Local, Internet and Favorites, and Game Type to cycle All and the installed game types; right-click steps either back. On a bind, click or Enter, then press the new key (Esc cancels, Backspace clears); a third key replaces both of the old ones. Click a text field to type into it; Enter or Esc finishes, Tab and the up and down arrows move to the next field. In Start New Server, click Game Type to cycle it (right-click goes back); the map list scrolls with its bar, and with the cursor over it the arrows, Home, End and Page Up / Down move the selection. The Mods list works the same way.
| Input | Action |
|---|---|
` / ~ |
Console |
| F3 | Debug overlay |
| F4 | Culling: on, locked, off |
- docs/protocol-1.1.md: the 1.1 wire protocol, both directions, with every divergence from RTCW/Q3 at the end.
- docs/research/: about thirty documents on file formats, movement, combat, items, turrets, movers, HUD, sound, script semantics, the console, the front end, bots and more. Every claim names the module and address it rests on and says whether it was verified against a binary or capture, or inferred. I'd call this the most useful part of the repo.
- tools/re/: the scripts that pull tables out of the binaries, and the Linux server disassembly notes.
- AGENTS.md: the contributor guide. Layout, measuring against retail, and the traps I already paid for.
The code is four crates: vcod-common (formats, collision, movement,
protocol; no GPU or audio), vcod (client), vcod-server and vcod-gsc
(the script VM, which depends on nothing else here).
As of October 2026:
- about 173,000 lines of Rust,
- about 2,200 tests,
- about 270,000 words of protocol and research notes, longer than most novels and with a worse plot, except the twist where grenade cooking turned out not to exist,
- one asphalt footstep restored.
Mostly to see whether it could be done. CoD 1 descends from id Tech 3, and the Quake III and RTCW sources are public, but the 1.1 wire protocol was never documented. Every field width, enum order and place Infinity Ward wandered off from RTCW had to come out of the binaries and be confirmed against the retail server. Also, watching a 2003 game come back to life in a window you built yourself is a lot of fun.
An AI coding agent wrote most of the code and docs here, 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 and by-ear checks the agent can't. The research docs label each fact verified or inferred so you can tell them apart. Treat the code as a working prototype, not a reference implementation.
- Quake III Arena and Return to Castle Wolfenstein by id Software, GPL. CoD1 descends from RTCW-MP, 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 struct layouts were the starting point for the netfield tables.
- cod-asset-importer, a GPL Blender add-on. The xmodel triangle-strip decoder is ported from 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, game code or binaries; 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: layouts and addresses recovered from the binaries, no copied code. The screenshots 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.


