SalastilandClaude Opus 5.5 b12db08ce5 Spawn lookup by ID (0x401b28), inline EQString dtor
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]>
2026-10-20 23:32:09 -04:00

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

  1. Pick a function: python3 tools/eq.py todo lists unmatched game functions, smallest first. build/decomp/<addr>.c has Ghidra's pseudo-C for it (tools/ghidra/ExportDecomp.java), and python3 tools/eq.py diff 0x00401050 shows the disassembly.
  2. Write C++ under src/, with an annotation directly above each definition:
    // FUNCTION: EQGAME 0x00401050
    void CList::Append(CListNode* node) { ... }
    
    // GLOBAL: EQGAME 0x0079c100
    CSpellPointManager* g_pSpellPointManager;
    
    Annotations on declarations (extern globals, called functions) tell the checker where referenced symbols live. // LIBRARY: EQGAME 0xADDR mangled names CRT helpers (see include/crt_symbols.h). Add NONMATCHING after the address for code that is functionally right but not yet byte-exact.
  3. 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 edit symbols.txt by hand.
  4. Iterate with diff until check says MATCH.
  5. python3 tools/eq.py link rebuilds build/eqgame.exe from 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 lib and excluded from progress.
  • Names are placeholders until identified from the binary itself (its own log strings and code structure); see config/eqgame/NAMES.md.
S
Description
No description provided
Readme
698 KiB
0 Stars 1 Watchers 0 Forks
Languages
C++ 48.8%
Python 46.5%
Java 2.7%
Shell 1.4%
C 0.6%