IW5V gameplay: Team Deathmatch on Resistance with the PS3-style HUD
Dev Journal · Entry 01

Building IW5V: How I Used AI Agents to Bring MW3 Multiplayer Back

One human developer, 13 Claude Code sessions and about 284 agent runs, four days of work: what it took to get Modern Warfare 3 (2011) multiplayer on PC back to Find Game, friends and full lobbies.

9–12 October 2026open-iw5 · MW3 PC 1.9.388110~18 min read
4days, 9–12 Oct 2026
13Claude Code sessions
~284agent runs (239 inside 40 workflows)
84commits of mine in the game client
+72klines on top of open-iw5 (incl. a 37k-line bot AI port)
237automated tests on the online services
01

Why bring back MW3?

Modern Warfare 3 is the game I remember playing on PlayStation 3: the grey menus, the Find Game screen with its little population map, lobbies filling up one player at a time, Search and Destroy rounds that ran until two in the morning. The PC version still runs, but its online side died with the official servers, and the PC menus never looked or felt like the console game I played.

IW5V is my attempt to fix that. The goal I wrote down at the start was simple: download, launch, press Find Game, play with other people, and let bots fill the lobby until the community grows. It should look like the PS3 version, work with a controller or mouse and keyboard, and never ask anyone to type an IP address.

The base is open-iw5, an open-source client for MW3 PC (version 1.9.388110). Everything in this article sits on top of it as new modules and patches.

The IW5V online menu in the PS3 style: Find Game, Private Match, Create a Class, Callsign, Barracks
The online menu today. Built from the real PS3 menu data at runtime, with the PlayStation Network header, the party list on the right and the news ticker at the bottom. Screenshot from a test run on my PC.
02

One developer, a team of agents

I'm the only human on this project. The rest of the "team" was AI: Claude, running in Claude Code on my PC. I want to be exact about what that means, because "I used 20 agents" sounds better than it is true. Here are the real numbers, counted from the session records on my machine:

WhatCountWhat it did
Main session1The coordinator. Took my requests, planned the work, ran builds and tests, merged results, wrote releases. Ran from 9 Oct to 12 Oct.
Side sessions12Separate sessions, each with its own job and usually its own git worktree, so two of them never edited the same files.
Workflow runs40Scripted fan-outs: many agents at once on research, implementation, review and live testing, with the results collected and checked.
Agents inside workflows239Each one a separate Claude instance with a narrow brief and a structured result.
Single helper agents45One-off searches, code reviews and investigations outside workflows.

So it was never a fixed team of 20. It was closer to a small studio that grew and shrank by the hour: one coordinator, a handful of specialists working in parallel, and short bursts where dozens of agents researched or reviewed one problem at the same time.

How the work was split

The side sessions map cleanly to areas of the game. These are their real titles from the records:

AreaSide sessions
ResearchDump the real Xbox 360 menus
Menus and UIPS3 / Xbox button switch · Fix the in-match Choose Class
BotsKeep bot teams balanced · Bot gameplay polish (S&D) · Fix controller weapon defs (started by the bot session itself)
ServersTest the IW5V dedicated server · Make the dedicated server work (started by the test session)
OnlineUnique player ID per install · Let friends join a player-hosted match · Let friends join your party in the menu

The bigger jobs, like the matchmaking service, the relay network, the VPS setup, the anticheat and the bot AI port, went through workflows instead. A typical workflow had four stages: agents research the problem in the game binary and the code, other agents build it, a separate set of agents reviews the result and tries to break it, and a last stage tests it in the real game.

Keeping parallel work from colliding

Parallel agents are only useful if their work fits together. Three rules did most of the work:

  • One branch per area, one worktree per writer. The client grew on separate branches (ps3style, dedi-bots, p2p-matchmaking, master-server, relay-only), each checked out in its own folder. Merges happened in one place, the main session.
  • Notes instead of memory. Sessions left findings in a shared notes folder: addresses, pitfalls, what was tested and what wasn't. A new session read those first.
  • Nothing counts until it runs. A build that compiles is not a result. Results were live tests in the real game, with screenshots and logs, or automated tests on the server side.

It still went wrong sometimes. Two separate pieces of work both hooked the same function in the game, at 0x574F60, one for joining friends and one for bots. Each worked alone; together they broke Search and Destroy lobby bots. The fix was a single hook with one owner, and a rule I kept from then on: one owner per patch site.

03

Reverse engineering a 2011 game

There is no source code for MW3. Every feature started with finding the right place in iw5mp.exe: which function draws a menu item, where the party data lives, which call registers a setting. The agents did this with small Python tools around the Capstone disassembler, reading the binary and the running game's memory, and they wrote every finding down with its address so the next session didn't have to find it again.

The PS3 version was research material too. The menu definitions came from the PS3 game's memory while it ran in the RPCS3 emulator, read-only, and were turned into a JSON file the PC game loads at startup. The Xbox 360 version gave us its button glyphs, and the bot mod that runs on Xbox MW3 in the Xenia emulator turned out to be driven by a large C++ bot AI, which became the base for our bots.

Xbox 360 MW3 in the Xenia emulator with a bot mod running, Kill Confirmed scoreboard
Starting point for the bots: Xbox 360 MW3 with a bot mod in Xenia. Player names blurred.
The in-game console showing DemonWare network log lines
The in-game console (added on day one), showing the game's own DemonWare network log. Most investigations started here.

Some findings were small and painful. For example, a menu statement structure on PC is 0x50 bytes, not the size the PS3 layout suggested; getting it wrong corrupted memory far away from the menus. And an agent once recorded a weapon table address that was "two slots off". Another agent repeated that claim, and only a live test with a real weapon showed it was wrong. That is why every finding in the notes says whether it was verified in the game.

05

Controller, mouse and keyboard

A PS3-style game has to play like one with a pad. The controller module uses XInput with the PS3 button layouts, and the aim uses the PS3's own constants for turn rate, stick curve, slowdown and lock-on, taken from the PS3 game. Rumble plays the PS3 rumble files. The button icons switch between PlayStation and Xbox 360 glyphs.

In-game HUD in PS3 style on Seatown
PS3 HUD in a match on Seatown.
Sniper scope with the hint: Press and hold L3 to steady
Controller hints use the pad's buttons: "Press and hold L3 to steady".
Button layout menu: Default Flipped, Tactical Flipped, Lefty Flipped
Button layouts from the PS3 menu, working on PC.

Mouse players got their own work: raw mouse input, handling for 8 kHz polling mice (the game's window message loop couldn't keep up with that many messages per frame), and a MOUSE & KEYBOARD page with sensitivity and key bindings. One bug here was not ours. Steam's desktop controller configuration also drives the pad as arrow keys, which made the view shake. The fix drops that mapped input while a real pad is in use.

06

Bots that play like people

Empty lobbies kill a revival. The bot AI comes from the Xbox bot mod mentioned above: about 37,000 lines of C++ bot logic, ported to MW3 PC on the first evening (commit be8aff3). Porting meant fixing every structure that differs between Xbox and PC: player state offsets, config strings, perk bits, weapon tables.

Search and Destroy scoreboard, 6 versus 6, my player plus eleven bots
A 6v6 Search and Destroy test: me and eleven bots. Bot names are blurred (they use real-looking PSN-style names).

Getting bots to work in a menu test is easy. Getting them through a full Search and Destroy match was not. Some of the problems that needed more than one attempt:

  • The third team. In Find Game the game takes each player's team from the party. Bots aren't party members, so after every S&D round they landed on team 0: a yellow third list on the scoreboard and bots nobody could kill. Fixed by keeping the bot's team at the spot where the game assigns it.
  • Stuck bots. The waypoint graphs come from the Xbox mod, and some nodes sit inside crates or next to walls. Fixing this took several rounds of live tests on the worst maps with 11 bots, stuck logs, and changes to arrival checks and rescue logic. We also built an overlay that draws the waypoint graph in-game, which made the bad nodes visible.
  • The bomb. A mod setting quietly stopped bots from picking up any carried object, including the S&D bomb.
Search and Destroy on a shipyard map with a bot teammate ahead
A bot teammate pushing in a Search and Destroy round. Names blurred.
Gameplay on Seatown during a GSC script test
GSC scripts running on PC: the script loader compiles mods at startup, which the bot mod's script side needs.

Bots also fill Find Game lobbies. They join one by one or as small parties, like players would, and they leave to make room when a real player arrives. The dedicated server runs the same bot AI.

07

Getting people into the same match

This was the hardest part, and the plan changed on the way. It went through four steps:

  1. Join by address. A friend types connect and the host's address, and joins through the game's own invite code. Worked, but nobody should have to share an IP address.
  2. Dedicated server. Players join a dedicated server over plain UDP, without the old DemonWare backend. It now runs in Docker with bots.
  3. Matchmaking service. Find Game asks an IW5V service for player-hosted lobbies, joins the best one or hosts its own, and bots make room.
  4. Relay-only networking. Every player packet goes through an IW5V relay. Players never see each other's IP addresses, and there's no direct peer-to-peer path in public builds.

I chose relay-only on purpose. A peer-to-peer design would have been cheaper to run, but it exposes every player's IP address to everyone in the lobby. Protecting players mattered more.

Friends by number

Every install gets its own IW5V number and an identity key made on first start. You add friends by number, see who's online and in which lobby, and invite or join from MW3's own Friends screen. Logins are signed by the service, and the traffic between game and service is encrypted. When a host's game accepts a join, the joiner gets a ticket for the host's relay session, never an address:

server/iw5-matchmaking/friends.pyexcerpt
    def introduce_relayed(self, s, m, p, joiner):
        """the host's game said yes to a friend's join: the joiner gets a member ticket for the host's relay session"""
        op = UP_JOIN_ANSWER
        grant = self.live_grant(s.number)
        problem = lobby_blob_problem(m["blob"])
        code = R_OK
        if grant is None:
            code, j = R_NOT_JOINABLE, J_NOT_JOINABLE        # the game asks RELAY_HOST (kind 2) before it answers
        elif problem:
            code, j = R_BLOB_ADDRESS, J_NOT_JOINABLE
            self.log("relay_blob_refused", number=format_number(s.number), why=problem)
        elif grant.build != joiner.build:
            code, j = R_OTHER_BUILD, J_OTHER_BUILD

The first real test, and the bug it found

Everything above passed on one PC, with two copies of the game and local services. That proves less than it seems: it says nothing about two real internet connections. The first real test was with a friend on his own connection, early on 12 October. His game logged in from across the internet with a 78 ms round trip. Then Join failed: "they run another IW5V build".

Both of us had the same IW5V zip. The cause was the build check: it hashed iw5mp.exe too, and genuine copies of MW3 1.9.388110 differ byte for byte between installs. The fix was a one-line idea with a comment explaining why:

src/module/matchmaking.cppcommit b10bab9
// IW5V's own files only: iw5mp.exe differs byte for byte between genuine 1.9.388110 installs (players with the
// same IW5V zip got "another IW5V build" and couldn't join each other), and open-iw5 only runs on 1.9.388110
for (const auto& file : {std::string(exe), folder + "\\ps3style\\playlists.aggr"})

Ten minutes after the new build, I joined his lobby through the relay and we played a full 12-player Team Deathmatch on Resistance, the two of us plus bots.

Pre-match lobby screen for Team Deathmatch on Resistance
Team Deathmatch on Resistance, the pre-match intel screen.
Face Off playlists screen
Face Off playlists: small-team modes on the Face Off maps.

The same evening's logs turned up two more problems, both fixed or in progress: friends couldn't join someone sitting alone in the party menu (MW3 PC doesn't make a lone player the party host), and a friend's game crashed loading a DLC map his install doesn't have.

08

Servers, carefully

The online services first ran on a small Ubuntu box at home, then moved to a rented VPS in North America. For the move I gave the agents written rules, because an agent with shell access to a production server can do real damage:

  • Keep the existing server running and unchanged.
  • Use separate branches and staging environments.
  • Make backups before migrating data.
  • Test each stage and report before going on.
  • Stop and ask before anything destructive, a production cutover, or anything that could lock me out.
  • Never expose credentials, and never enable direct peer-to-peer connections.

The work then went in stages, each one reported and approved: hardening the server (firewall, SSH key-only login, brute-force protection), Docker, the matchmaking and friends service, then the relay. Every service runs in its own container with host networking, log limits and a health watch that restarts anything that stops answering. Opening the public ports was its own approval step.

A small admin site lets me see lobbies and matches and manage bans. It's only reachable from my own connection, which is why there is no screenshot of it here: it would show addresses I don't want on a public page.

Not pictured on purpose

Server addresses, ports, keys and the admin panel are left out of this article. The architecture diagram above shows how the pieces connect without them.

09

Security and stability

  • A host crash from a crafted packet. A party ticket with a bad length could crash the host. The length is now clamped. An older open-iw5 patch for the same spot turned out to be broken itself.
  • Anticheat. Ported from another community project: code integrity checks that know about our own patches, cheat-loader detection and macro detection. It currently logs instead of kicking, until the logs show no false alarms in normal play.
  • Bans by IW5V number. A banned number can't log in to Find Game or Friends, and the game shows the reason and the end date.
  • Private Match is off in public builds. The public game has no private lobbies; my developer build keeps them for testing.
  • Stats are saved after every match. The emulated backend only kept the first save of each session; now every save sticks.
10

How it was tested

There are two kinds of tests in IW5V. The online services have 237 automated tests (friends, matchmaking, relay mode, relay, bans) that run before anything is deployed. The game itself is tested live: an agent starts a copy of the game, drives the menus with a simulated controller (gpad_sim tap commands written to a file the game reads), takes screenshots and reads the logs. Most screenshots in this article come from those runs. Some ran overnight; one of them played seven Search and Destroy rounds and a Demolition match with halftime and overtime to check bot teams.

The live tests had their own lessons:

  • Several test games at once overloaded my graphics card and crashed my own game with a driver timeout. Rule since then: one light test game at a time.
  • A test window that pops up while I'm using the PC is a problem. Overnight tests ran hidden and muted.
  • Test copies multiplied until I had nineteen game folders and no idea which was which. Now there are exactly two: a developer copy and the release copy.
git log --oneline (excerpt, newest first, messages shortened)open-iw5 · relay-only
914d975 Friends join: one ask per Join press, and two friends who asked to join each other no longer both wait
90cc1a6 Big monitors get their own resolution, FOV scale and cl_maxpackets are saved
3c19809 com_maxfps up to 1000 and saved: the game registers it 0 - 100, not archived …
ebf373b Friends can join a player sitting alone in the party menu …
b10bab9 Matchmaking build id covers IW5V's own files only (open-iw5.exe, playlists.aggr) …
f2a3cb9 PS3 style survives vid_restart: the PS3 images, materials and fonts are made again …
34fc39e IW5V bans: a banned number gets no Find Game …
b04b80e IW5V relay-only networking (public builds): every player packet goes through the IW5V relay
680c1ce IW5V friends, the game side: add friends by IW5V number, requests, presence, invites and joins …
8fad9df Find Game through the IW5V matchmaking service: search player-hosted lobbies, join the best or host …
…
be8aff3 Bots: CoD Xe's C++ bot AI on MW3 PC (src/module/cbots)
bd1cafc Controller support (XInput) with the PS3 layouts
e3571a3 PS3 style: menus from the MW3 PS3 dump built at runtime
11

Timeline

All dates are 2026; times are taken from the commit history.

  1. 9 Oct · evening

    PS3 menus built from the PS3 dump, PS3 fonts and controller prompts, XInput controller with PS3 aim and rumble, in-game console, GSC script loader, and the C++ bot AI running on PC, all on the first evening.

  2. 10 Oct

    Xbox 360 button icons. Security fix for the party-ticket crash, anticheat, voice chat, stats saving. Dedicated server joins over plain UDP. A unique ID per install. Joining a friend's match without Steam. Find Game lobbies filled by bots. Discord presence. Input for 8 kHz mice.

  3. 11 Oct

    Bots on the dedicated server, fewer stuck bots after long live tests, a master server for a server browser (paused), Find Game through the IW5V matchmaking service, the friends system, and relay-only networking late that night.

  4. 12 Oct · early hours

    Private Match locked in public builds, bans, the services moved to the VPS in stages, the first test with a friend on another connection, the build check fix, and our first full match together through the relay.

  5. 12 Oct · night

    PC SETTINGS with real refresh rates and max FPS up to 1000, and joining a friend sitting in the party menu.

12

What works today, and what doesn't yet

Working

  • PS3-style menus and HUD, PlayStation or Xbox icons
  • Controller with PS3 aim and rumble; mouse and keyboard settings; PC video settings
  • Bots in Find Game lobbies, matches and on the dedicated server
  • GSC scripts and mods
  • Friends by IW5V number, invites, joining through the relay
  • Find Game through the IW5V service
  • Bans, stats saving, Discord presence
  • Anticheat in log-only mode

Not done yet

  • Skipping DLC maps a player doesn't have (crashes today)
  • Party-menu joins: built, not yet tested with two players
  • Host migration when the host leaves
  • Regions and lobby merging at scale
  • Anticheat that kicks instead of only logging
  • Bot-filled dedicated servers on the VPS
  • Voice chat tested with a real second player
13

What I learned managing AI agents

Agents are fast, and they're confidently wrong sometimes. The wrong weapon table address is the clearest example: it was written down, repeated, and only a live test caught it. Separate review agents whose job is to break the result help a lot, but the game itself is the final reviewer.

Say exactly what "done" means. When I said I wanted something fast, some agents stopped early and reported partial work as finished. Briefs that name the files, the test and the expected result worked much better than urgency.

Ownership beats parallelism. The double hook at 0x574F60 taught me that two correct pieces of work can still break each other. One owner per area, one writer per set of files, and merges in one place.

Local tests lie about networks. A whole online stack passed on one PC and failed on the first real two-connection test, because of a build check nobody had thought of. Real players on real connections are part of the test plan now.

Write the rules before giving access. The server rules above kept the old server untouched and every risky step behind my approval. The agents followed them, and when a step needed something only I could do, like a password, they stopped and asked.

I still made every decision about what IW5V should be. The agents did a huge amount of the research, code and testing, much faster than I could have alone. The result is a game I can actually play again with my friends, and I'll keep writing these entries as it grows.