0x401b28 returns EQPlayer* from the 3000-entry spawn table (callers in EQPlayer::Die etc. use it as a spawn). ~EQString is an inline header function; 0x4482fb is its out-of-line copy, which compiler-generated destructors call instead of inlining. Co-Authored-By: Claude Opus 5.5 <[email protected]>
EverQuest Decomp/Recomp
A byte-for-byte matching decompilation of the EverQuest Titanium client
(eqgame.exe, linked 2005-10-31 18:36:26 UTC). The goal is C++ source that
recompiles with the original toolchain to the exact same machine code, which
can then be ported, fixed and recompiled freely.
This repository contains no original binaries or game assets, only decompiled source and tools. You need your own copy of the client; the tools check it against the expected hash.
| Target | eqgame.exe, SHA1 e8fdc68b46df69dde0094d57fd7ba2cb33aef1c5 |
| Compiler | MSVC 7.1 (Visual Studio .NET 2003), cl 13.10.3077, run under Wine |
| Flags so far | /O1 /GX /GS (size-optimised, EH, stack cookies; confirmed by matching code) |
| Functions | ~15.3k found by Ghidra: ~8.4k game code, ~6.9k CRT/STL/library |
Setup
Requirements: Linux (or WSL/macOS) with wine, python3 + PyYAML, ninja,
i686-w64-mingw32-objdump (binutils for mingw), and optionally Ghidra.
tools/setup.sh /path/to/EverQuest/eqgame.exe # links orig/, fetches MSVC 7.1, verifies both
python3 tools/eq.py build # compile src/ -> build/obj/
python3 tools/eq.py check # compare against the original
python3 tools/eq.py progress
Workflow
- Pick a function:
python3 tools/eq.py todolists unmatched game functions, smallest first.build/decomp/<addr>.chas Ghidra's pseudo-C for it (tools/ghidra/ExportDecomp.java), andpython3 tools/eq.py diff 0x00401050shows the disassembly. - Write C++ under
src/, with an annotation directly above each definition:Annotations on declarations (// FUNCTION: EQGAME 0x00401050 void CList::Append(CListNode* node) { ... } // GLOBAL: EQGAME 0x0079c100 CSpellPointManager* g_pSpellPointManager;externglobals, called functions) tell the checker where referenced symbols live.// LIBRARY: EQGAME 0xADDR manglednames CRT helpers (seeinclude/crt_symbols.h). AddNONMATCHINGafter the address for code that is functionally right but not yet byte-exact. python3 tools/eq.py build && python3 tools/eq.py check. The tools pair each annotation with the compiled (mangled) symbol, so there's no need to editsymbols.txtby hand.- Iterate with
diffuntilchecksaysMATCH. python3 tools/eq.py linkrebuildsbuild/eqgame.exefrom the compiled objects and checks its SHA1 against the original. It also prints how much of the binary now comes from source. See docs/ROADMAP.md.
Check statuses
| Status | Meaning |
|---|---|
MATCH |
every byte equal, every relocation points at the right symbol |
MATCH? |
bytes equal, but some referenced symbols have no address yet (annotate them, or check --learn) |
NONMAT |
marked NONMATCHING, still differs |
BADREF |
bytes equal, but a call/global resolves to a different address than the map says |
DIFF |
code differs |
Relocated fields (calls, globals, string literals) are masked when comparing bytes and then verified separately: against the symbol map for named symbols, and by content for string literals and float constants.
Layout
config/eqgame/config.yaml target hash, compiler flags
config/eqgame/symbols.txt ADDR SIZE KIND NAME for every known function/global
src/ decompiled source (one .cpp per original translation unit, eventually)
include/ shared headers
tools/eq.py build / check / diff / progress / map
tools/binfmt.py PE + COFF readers
tools/cl.sh MSVC 7.1 under Wine
tools/ghidra/ headless export used to seed symbols.txt
orig/ your eqgame.exe (git-ignored)
Per-file compiler flags: put // CFLAGS: /O2 (etc.) near the top of a source file.
Re-seeding the symbol map from Ghidra
/opt/ghidra/support/analyzeHeadless build/ghidra eqgame -import orig/eqgame.exe \
-scriptPath tools/ghidra -postScript ExportFunctions.java "$PWD/build/ghidra_functions.txt"
python3 tools/eq.py import-ghidra build/ghidra_functions.txt # keeps existing names
Notes
- The Rich header shows ~640 C++ objects from cl 13.10.3077, plus libraries built
with VC6 (build 8447/9178), likely Miles Sound System, DirectX helpers, etc.
Those are classified as
liband excluded from progress. - Names are placeholders until identified from the binary itself (its own log
strings and code structure); see
config/eqgame/NAMES.md.