🪲 onno of brusque-abstruss🐾 (@ongestalte) on X

X (formerly Twitter) ·

14 min read Original article ↗

I love videogames. I can scarcely remember an age at which I wasn't gaming. Throughout my childhood, videogames filled my mind with awe as their tiny worlds thrust upon the screen, seemingly reaching out beyond view, every virtual stone unturned yet to spur an unbounded set of discoveries. Once I turned teenage, it was videogames that brought me online, and even though the limits of games themselves were somewhat demystified as my comprehension grew, I in turn gained a deep appreciation for the enormity of multidisciplinary work and creative efforts that make up their development. Of course, like many gamers who recognize the feeling, I too dreamt of making a (great) videogame of my own someday.

Now is a more opportune time than ever to make videogames, as the power that creatives can wield with agentic AI is incredible. To provide a glimpse into the possibilities, I'll share my preservation efforts of a preexisting great game, World of Warcraft, using Codex to decompile and reverse engineer its game client of an old 2010 version --one that needs no introduction to those familiar with the game's history. My goal is to untangle and decipher the game's programming, to then reproduce it faithfully as an open-source client that you can run on Windows, Mac and Linux, working with your own original game installation. I want to peer into the core of the collective creative effort that made WoW, and preserve it as a piece of gaming history. Most of all, independently of this goal, I want to show you how agentic AI enables me to do it. Nobody has ever fully reverse engineered a WoW client before, and it isn't strange to fathom why, given the effort required. I wouldn't have ever dreamed of achieving my current rate of progress without agentic AI, and it amounts to the most staggering degree of productivity acceleration that I've personally experienced so far.

What it takes to preserve videogames

Videogames are strange pieces of media to preserve. Books, when they go out of print, can be acquired secondhand, and so long as they do not get physically destroyed will retain their information legibly for decades, if not centuries. Physical media such as cassettes and CDs are more prone to data loss, through demagnetization and disc rot respectively, yet when carefully stored can be preserved suitably as well. Digital preservation has been a great blessing to this respect: books can be scanned, and media like CDs can have their data readily transferred onto an arbitrary number of redundant, fully digital copies. Videogames however, even though they come contained in forms of physical media (like cartridges and discs) and directly as digital applications both, are complex pieces of software and graphics programming, and require equally complex pieces of hardware in order to work and to be experienced as intended. The data does not speak for itself: preserving a videogame means preserving the computer architecture upon which it is built.

Enthusiasts know the problem all too well: even if you can make digital copies of the physical videogames you own -- in case they ever break -- what will you do once your gaming system burns out? We're not running short on PlayStation 2s for now, but it will become increasingly inconvenient to keep them functional over time; you cannot expect the hardware to be made available in perpetuity, and especially for old and obscure systems whose parent companies have long-since dissolved, maintenance and repair is nothing short of computer archaeology. Some might think that this is a 'physical' problem, but make no mistake: even personal computer applications eventually lose platform support. Remember Amiga? Motorola 68K? PowerPC? 32-bit on macOS? It will go on.

To meet demands of game preservation, talented programmers have built emulators: software that tries to approach the full behavior of the respective system hardware, that can run on modern systems, usually personal computers. Emulators take years if not decades to develop, with most of them under continuous development to this day, in their striving to reach full functional parity with their respective systems' entire games library.

Yet, there are cases where emulators' broad capabilities are insufficient. What if the game has a bug that causes it to sometimes crash through unavoidable conditions in normal gameplay? What if the game has secret content that was only unlocked through an in-person event that happened decades ago? What if you want to add subtitles to the game in languages that never were made available for it originally? What if you want to bring native performance and high-resolution video output to the game, beyond the emulator's capabilities? Or worse, what if the game has such a complex or oddball graphics pipeline and system orchestration that it is effectively unplayable through the emulator? This is where we turn to decompilation and reverse engineering.

To technical people reading this, allow me to gloss over some nuances with what I'll discuss next: most software exists in a compiled form, meaning it is packaged in applications that carry machine instructions, essentially binary. This is done for performance and portability, but it also means that to the human, it is nigh-inscrutable. Games are no exception, and due to their common nature of commercial products, their source code -- i.e. the human-legible, original code -- is typically not made available to the public, for reasons that are left to the reader's common sense (there is plenty of commercial software that is open-source, anyway). When one decompiles software, they are painstakingly puzzling together what the source code would have resembled in order to produce the application's features and behavior. Reverse engineering is when one independently reproduces (parts of) the software, typically heavily assisted by decompilation efforts. Most of videogame mods and patches are grounded in decompilation; sometimes even entire games get reimplemented, like Morrowind and Zelda, fully playable using one's own, original copy of the game data. Such open-source reverse engineering projects are incredibly impressive, and like emulators themselves take a gargantuan development effort from the individuals that devote themselves to preservation of the games in question.

In summary, games are hard to digitally preserve because decompiling them -- which is needed to fully understand how they work and to keep them working in the future -- is slow, arduous, requires high technical knowledge and experience and an excruciating amount of trial and error. In other words, perfect for AI agents.

Why the WoW client?

Extending from my love of videogames, World of Warcraft holds a special place in my heart. It is the game that made up a large part of my early online social experiences, and is one that still continues to amaze me with its expansiveness, attention to detail, overall style and level of gameplay. It is a very, very good game, one that I want to exist forever. WoW itself is long-lived and has underwent many changes over its live-service tenure. Wrath of the Lich King -- the game's second expansion, originally released in 2008 and lasting up until 2010 -- is the version of the game I have the fondest memories of myself. As such, I will be targeting the final patch of WotLK, version 3.3.5a, for decompilation and reverse engineering efforts.

Before moving into detail on my process of decompiling the WoW client with Codex, I will pose and answer some questions in advance:

"Doesn't this exist already? How does this differ from a private server?"

> WoW server emulation projects have existed since the game itself has been live, but this is materially different from the client. The server is authoritative for world state, combat, NPCs, inventory, validation, et cetera. The client does graphical rendering, UI, asset loading, protocol state, movement and a variety of miscellaneous game systems. If this is still too abstract, think of the server the same way you would of a Minecraft server. Nobody has ever fully reverse engineered a client.

"Why would you decompile something that works? The client works on PC."

> It works, for now. Because 3.3.5a is a heavily outdated version of the game, it is only playable through the original Windows and Mac 32-bit clients from 2010, with the latter already incompatible with modern macOS. While you can run Windows applications on Mac and Linux through e.g. Wine, it is ultimately a compromise; and who knows what is going to happen to Windows support in the future.

"Can't you just play WoW Classic?"

> Yes! And you should, if you want to experience old WoW expansions on live servers! However, the WoW Classic client is not, in fact, the original WotLK client: it features old content but rebuilt on a modern engine. That being said, there will come a day when WoW Classic too will go offline.

Reverse engineering with Codex

It is perfectly...possible to tell Codex to "decompile this game, make no mistakes" immediately, but it would be a waste of time without first attaching it to reverse engineering software, to amplify its capabilities. I chose Ghidra for this, as it has a very flexible extension API, as well as Python integration and the benefit of being free and open source, where I reckoned that especially the latter part would become useful for tooling development. I asked GPT Pro (5.2, at the time) to do broad research into all available agentic AI tooling for Ghidra online, and, giving it broad context into my intents, to create an initial Ghidra extension for Codex to commandeer and iterate on.

The reason why I chose to have Codex develop its own tooling was to set another goal of experiential improvement: if the agent can't deliver the task at hand, it should build around the points of failure until it can. After a session of decompilation work, I would ask the agent whether it experienced any friction, or if it skipped over items that it could not adequately handle within the task scope, to then have it build out a plan for a tooling refactor, expansion or realignment. Once done, I would ask it to tackle the same task again until no friction remained, whereupon we could continue. You need to be careful when doing this, so that the agent does not overcorrect into solving that very one thing only, at the detriment of everything else. Codex is usually honest and pragmatic, and even though everyone that has worked with agents can relate to awkward moments of 'reward hacking', where the solution is self-justifying and not at all useful, you can mitigate such instances with a good workflow and AGENTS.md. What 'good' entails here is highly dependent on how you personally prompt and orchestrate tasks for your agent, but I will say that generally, you want your agent to minimize implicit state and to not scaffold defensive fallbacks.

Some more pointers on how to keep your agent effective for decompilation efforts:

Verify implementation against game assets before doing runtime comparisons. The game data is generally structurally consistent in how it wants to be parsed.

Do not overzealously move into implementation work immediately, as your agent needs a lot of decompiled material before it can work without making assumptions. Often, those assumptions will be quite workable, as agents are good at programming, but they hurt long term as the code diverges and eventually will run into novel bugs of its own making.

Prefer fail-fast behavior, and don't inline your tests. Tests are great, because they alert the agent when it cuts over dependent code, but agents are always eager to create a lot of them, with most tests being of throwaway quality.

Be very careful when having the agent compare screenshots. Screenshots can corroborate the things you see, but it is more important for you to put your findings in writing than to let the agent compare by itself.

Another aspect of decompilation is that one needs to keep a lot of notes. If you do not provide organizational structure for Codex, it will spit out notes on its ongoing decompilation process, which quickly becomes difficult to manage once conflicting or corrective evidence is found between functions. The 3.3.5a WoW client has roughly 28K named functions, which is rather substantial, and a reverse engineering effort of this scale is as much about programming as it is about management of information and evidence. If Codex is left to manage this through scattered notes and chat history alone, the project eventually will collapse under its own evidence before it has any chance to approach completion. The solution I came up with was to have Codex index the Ghidra project state into a SQLite database, wherein Codex can query decompiled functions, symbols, cross-references, comments, signatures, and evidence ledgers. Notes still exist, but they are tied back to aforementioned items and their addresses, as well as historical rename evidence and specs broadly. Regarding specs, once Codex had enough context of game systems (which was greatly assisted by WoW having over two decades of community modding efforts associated with it already), I tasked it with creating specs on a subsystem basis, as behavioral contracts anchored to decompiled functions. The specs serve a dual purpose: the specs pointing to our estimation of how the subsystem is constructed and how it functions, they can also guide reimplementation work.

Because a videogame evidently depends on graphics programming, and working with AI agents sometimes feels like sculpting marble from the inside-out, I figured it would be appropriate to choose a memory-safe language for the WoW client reimplementation, for which Rust (with wgpu as adapter) seemed like a comfortable choice. I soon realized that this would open up some extra challenges for Codex to handle, given that the original client is mostly C++, namely external libraries:

The client uses FreeType as its font renderer. The original game manual credited 'FreeType 2.0' but given that FreeType has multiple minor versions (and the exact version slug could not be found in the decompiled corpus), I had to match decompiled functions against their sources. Once it was nailed down to FreeType 2.0.0, I then asked Codex to create a pure-Rust port of the subset WoW uses, aiming for byte-faithful behavior. With a bit of iteration, it managed splendidly.

The client uses Lua, version 5.1.1, for interface and UI broadly. Bindings for this version of Lua do exist for Rust, but given the FreeType port went so well and that I cared about retaining native client code shape -- to ease reimplementation, WoW concerns itself heavily with its UI -- I figured that I might have Codex port that as well. With Lua of course being open source, and me having a good set of test vectors inferred from decompiled UI functions, it once again went smoothly.

The client uses Expat as its XML parser, working together with Lua for UI. Through a process of elimination, comparing decompiled functions with their sources, in similar fashion to FreeType, I had Codex narrow it down to version 1.95.5. Codex duly pointed out that older versions of Expat have a known security vulnerability, so it was ported in turn, WITHOUT that vulnerability!

The client uses FMOD for digital signal processing and sound, version 4.09.07 (parsed with facility from the embedded version). FMOD is a commercial, closed-source product, meaning had to be decompiled and reimplemented for the surfaces that WoW exercises, i.e. the ones we need. This is the only external library that Codex has struggled with so far.

Shaders! The client ships its shader assets in formats meant for its own era: D3D9 bytecode on Windows and OpenGL shader paths on macOS. Neither maps cleanly onto the modern cross-platform graphics stack that I landed on, wgpu with WGSL. To facilitate shaders, Codex had to decode the game shader file data, build interpreters for them, and then transpile the relevant shader families into WGSL. The terrain shader path is the clearest example so far: its vertex and pixel shaders are decoded from the original game data, translated into WGSL, validated against the original shader behavior with byte-level parity checks and have been implemented into the live renderer. Other shader families are still a work in progress.

What's left? A lot of work for Codex. At this point, I am convinced that with the rigor invested into my reimplementation process, as well as the months of ongoing decompilation efforts, Codex will be able to reimplement the WoW client fully and faithfully, requiring only the human in the loop as project manager. So far, I've managed to recreate login, server authentication, character select, world runtime, objects and creatures, with partial successes on shaders and physics. I retain my amazement at agentic AI's proficiency for reverse engineering, and I will continue unabatedly alongside it until the work is finished.