10-31-2026, 03:59 PM
![[Image: hero-compressed.png]](https://github.com/0xd34db8/LF2-decomp/raw/main/assets/hero-compressed.png)
GitHub Repo: https://github.com/0xd34db8/LF2-decomp
Over the past 20+ years, this community has seen countless incredible fan projects: AngelScript dynamic memory hooks (LF2-Enchanted), DirectDraw ddraw wrappers, clean-room modern engine clones (OpenLF2, OriVered's rebuild), and Unity/Godot reimplementations.
While those projects are awesome, they all share one thing in common: they are approximations, external wrappers, or clean-room interpretations of how LF2 might work.
To date, nobody has ever completed a REAL, 1:1 binary decompilation of lf2.exe.
The only person who came close was xsoameix roughly 12 years ago when they began painstakingly mapping out assembly instructions into Ruby (xsoameix/lf2). But that project was abandoned before a working, compilable game engine could be finished.
We are actively working to finish that mission.
What Makes This Project Different?
We are not building an engine from scratch, and we are not guessing.
Using Ghidra and modern binary analysis, we are disassembling and decompiling the original compiled x86-32 MSVC++ executable (lf2.exe v1.9c / v2.0a) and lifting the exact, authentic C++ code directly from the binary.
- Zero Guesswork / 100% Math Fidelity: Hitbox collision formulas (itr_t / bdy_t), 3D velocity integration, gravity steps, frame wait timers, and damage calculations are mathematically identical to the original assembly.
- Pristine Ground Truth: We maintain an untouched archive of raw Ghidra decompiler exports (decompiled/RAW/) alongside a syntactically valid legacy C suite (decompiled/Compilable/).
- Liberation, Not Emulation: We extract that pure game logic into a modern, portable C++20 engine (src/), replacing deprecated Win32 message pumps and DirectDraw 6 surfaces with SDL2 so it compiles natively on modern 32-bit and 64-bit platforms.
Wild Secrets & Mysteries Uncovered Inside lf2.exe
Decompiling the binary instruction-by-instruction has finally answered questions and mysteries LF2 players and modders have debated for over two decades:
- The Anatomy of the Infamous "Synchronisation Error!" (0x0041C5F0):
LF2 network play runs on a compact 22-byte lockstep packet. Every tick, the host calculates a cumulative checksum of all active characters' HP (Σ HPᵢ). If client and host HP checksums differ by even 1 HP (due to a single floating-point jitter or projectile spawn timing deviation), the binary immediately aborts execution and shows the dreaded "Synchronisation Error!" modal dialog!
- Why Stage 5 Crashes to Desktop (g_objects[100]):
lf2.exe manages all world entities through a fixed, hardcoded array capped at exactly 100 slots (0x00450BE0). Davis, bandits, dropped baseball bats, flying energy balls, and transient blood splatter particles all compete for these same 100 slots. In chaotic Stage 5 battles, slot 101 returns NULL—which the game promptly attempts to dereference, causing an instant CTD.
- The No-Vtable Architecture:
Clean-room rebuilds often assume an object-oriented hierarchy (Character -> Entity -> Weapon). In the real binary, Marti Wong wrote a single, monolithic 880-byte object_t struct without a single virtual method or vtable pointer! Everything from Julian to a falling rock runs through the exact same struct layout and massive procedural state machines (like the 4,000-line combat dispatcher at 0x0042E100).
- Why Usernames in control.txt Had Backticks (`):
LF2 serialized control.txt with fscanf("%s"), which normally splits on spaces. Marti’s clever workaround in assembly (0x004233E0) was a loop that replaced every space character with a grave accent (`) before saving, and reverted them back on load!
- The Rudolf Void Glitch (0x00403270):
When Rudolf grabs an opponent at the edge of the screen, the game computes x₍dest₎ = x₍target₎ ± 40. The assembly completely forgot to clamp this destination against the stage boundaries—meaning grabbing someone near the edge of the screen teleports Rudolf into negative coordinates outside the map.
- Hardcoded Cheats & Secrets:
Looking at WindowProc (0x0043b3d0), keystroke state machines listen for:
- "lf2.net": Unlocks Julian, Firzen, LouisEX, and other enemy henchmen characters.
- "herofighter.com": A secret shoutout Marti added to LF2 v2.0 for his next game, which unlocks function keys in stage mode
- "ABC": Switches on the developer's internal frame/hitbox inspector.
- "lf2.net": Unlocks Julian, Firzen, LouisEX, and other enemy henchmen characters.
- The 3,000-Byte PRNG Table:
LF2 doesn't use the C standard library rand() because CRT implementations differ across compilers and desync multiplayer. Instead, embedded at 0x0044FF90 is a precomputed 3,000-byte lookup table that the engine simply cycles through circularly.
Project Status (Work in Progress!)
This is an active, ongoing effort. Here is what has been lifted, verified, and running so far:
- [x] Core Memory Maps: Struct layouts for bdy, itr, wpoint, cpoint, opoint, frame, file, and object verified with compile-time assertions.
- [x] Cipher & Data Loader: 100% authentic Vigenère decryptor (123-byte header skip + "SiuHungIsAGoodBearBecauseHeIsVeryGood" key) and full parser for data.txt and .dat character files.
- [x] Entity Physics & Movement: 3D velocity integration, gravity, jumping arcs, ground friction, and wait-counter state machines.
- [x] Combat & Collision Dispatcher: Full 1:1 lift of 0x0042E100 (damage calculations, flinch states, knockdown fall thresholds, rest timers).
- [x] Weapons & Grappling: Catch/throw anchoring (cpoint) and 3D weapon pickups/drops/throws (wpoint).
- [x] AI Decision Tree: Autonomous enemy threat targeting, approach synthesis, and combo execution (0x00406BA0).
- [x] Graphics & Audio: Software clipping, sprite sheet slicing (including the 1-pixel separator gutter), multi-layer parallax backgrounds, and zero-dependency SDL2 audio.
- [x] Automated Test Harnesses: Test suites ensuring mathematical parity against the raw disassembly.
What's Next?
We are continuing to lift the remaining high-level scene management, menu flows, stage phase progression, and modernizing the network layer so we can finally have a completely liberated, authentic LF2 engine that plays exactly like the 1999–2002 original.
If you are an LF2 veteran, modder, or reverse engineering enthusiast, we'd love to hear your thoughts, answer questions about the binary internals, and share findings with the community

Chat
