# NHL 14 Recomp **NHL 14 (Xbox 360), statically recompiled into a native PC executable.** It boots, it renders, it plays a full game of hockey at well over 60 fps, and it runs a Be a GM franchise from the entry draft through to re-signing your goalie. There is a save editor, an injector that replaces EA's randomly generated draft classes with the real 2014–2025 drafts, and a pipeline that puts actual player photographs on the cards. **If you read one document, read [getting to playable](docs/port/getting-to-playable.md).** It is the story of how a 360 executable that had never run a single instruction on a PC became a full sixty minutes of hockey: the boot chain, why the graphics backend decision was made one way and then flipped, a crash that took four rounds of retracted mechanisms to pin on one line of our own configuration, and a frame-rate problem whose fix was a single word after a week of being sure it was a CPU ceiling. The other half of this repository is the reverse-engineering work that the port made possible. NHL 14's franchise mode has never been documented. What follows is the first account of how it actually decides who develops, who gets drafted, and what a player will sign for, measured out of the game's own code and its own save files. ## No game data is in this repository **None of NHL 14 ships here. Not the disc image, not `default.xex`, not the `.big` archives, not the `.db` databases, not a font, not a frame of video, not a portrait.** The `.gitignore` excludes all of it. The recompiled C++ is also absent. It is generated on your machine, from your own dump, and lands in `generated/`, which is likewise ignored. Nothing derived from the game binary is published here beyond a few hundred function addresses in `nhl14_functions.toml` — the hand-pinned entries the recompiler's scanner missed. To use any of this you need **your own legally obtained copy of NHL 14** and your own dump of it. Where a dump goes is described in the docs; how to make one is not, and won't be. ## What "statically recompiled" means An emulator reads the console's PowerPC instructions and interprets them, or translates them, while the game runs. A static recompiler does the translation once, ahead of time: every function in the Xbox 360 executable is turned into a C++ function, and the result is compiled for x86 like any other program. There is no PowerPC left at runtime. It is the same approach the Zelda 64 and Mario 64 recompilation projects use. This port is built on the [ReXGlue SDK](https://github.com/rexglue/rexglue-sdk), which supplies the runtime — the guest memory model, the kernel imports, the Xenos GPU translation layer — and the code generator that emits the C++. ## What works | | state | |---|---| | Boot to the frontend menu | on the **stock** runtime, where a missing function is fatal rather than quietly no-oped | | Controller | a wired Xbox pad drives it with zero code changes and zero flags | | On-ice 3D gameplay | full games, start to finish, median **153 fps** | | Be a GM | franchise creation, the calendar, simming, trades, scouting, the entry draft, free agency, re-signings | | Roster editing, live | an in-game ImGui overlay on F1 | | Roster editing, offline | spreadsheet round trip against the shipped roster database | | Save editing | a desktop editor for a franchise already under way | | Real draft classes | twelve classes, 2014–2025, injected over EA's generated prospects | | Player portraits | fetched from public sources, encoded and patched into the archives | Still not goals: audio polish, and gameplay fidelity beyond "it plays". There are two builds and the split is deliberate. **D3D12** carries the menus and the franchise sim; **Vulkan** is the only backend that draws the 3D scene, because D3D12 reaches a face-off and renders it black. `docs/port/` explains why, and why the prebuilt SDK cannot do it at all. ## Start here - **[getting to playable](docs/port/getting-to-playable.md)** — the whole port in one document: boot, the backend decision, the crash, the frame rate, the green video. - **[the crash before puck drop](docs/port/postmortem-crash-before-puck-drop.md)** and **[the stuttering screen](docs/port/postmortem-stuttering-screen.md)** — the two bugs that cost days, written up properly: the false leads, the instruments, the retractions. - **[how players develop](docs/research/how-players-develop.md)** — the best of the franchise research, and the one to read if you came for Be a GM rather than for the port. - **[docs/README.md](docs/README.md)** — the map. The port, the formats, and the research. ## Layout ``` src/ the port itself — host code, the ImGui roster overlay, the write path scripts/ build, run and verify sdk/ our changes to the ReXGlue SDK, as patches tools/save/ the save editor: a desktop UI and a spreadsheet route tools/roster/ roster round trip: game database out to a spreadsheet, edits back in tools/draftclass/ replace a generated draft class with a real one tools/big/ EA archive surgery — unpack, patch one member, rebuild tools/portraits/ the portrait pipeline tools/research/ the probes that produced docs/ tools/begm/ the franchise-mode analysis scripts data/draftclass/ the real 2014-2025 classes, 1,335 players docs/ how all of it works. This is the bulk of the project. ``` ## The save editor `tools/save/` edits a Be a GM save directly. Two front ends over the same code: - **A browser UI** (`python tools/save/editor_server.py`) that binds `127.0.0.1` on an ephemeral port, with a token minted at startup. Pick a save, pick a player, change the numbers. - **A spreadsheet round trip** (`python tools/save/save_sheet.py dump --all`, edit the `.xlsx`, then `apply --latest`) for changing a lot at once. It backs up before it writes, re-verifies every checksum afterwards, and refuses to emit a save that does not audit clean — a corrupt write rolls back rather than reporting success. `test_editor.py` covers that with a large suite including negative controls that deliberately sabotage the writer to prove the failure path actually fires. It needs to find your extracted `nhlng-meta.xml` and `nhlng.db` for the schema and the team names. It searches for them; if your data lives somewhere unusual, set `NHL14_DATA` and `NHL14_DUMPS` to point at it. Close the game before writing. It rewrites the save when it exits and will throw your edits away. ## Real draft classes EA's Be a GM generates its own prospects. `data/draftclass/` replaces them with the players who were actually drafted, 2014 through 2025 — 1,335 of them, built from public career statistics, with ratings derived from what each player went on to do rather than from any EA source. `tools/draftclass/` writes a class into a save in place, overwriting generated prospects without adding a row. Getting this right took longer than getting it working, and the reasons are in [docs/research/draft-classes.md](docs/research/draft-classes.md). The short version: a prospect's authored rating is only half the job. The other half is a single field called `growthspeed`, and for a long time every class we shipped had it wrong in a way that made every prospect permanently inert. ## Building You need Clang 18+, CMake 3.25+, Ninja, and the ReXGlue SDK. Versions known to work are in [docs/port/toolchain.md](docs/port/toolchain.md). The 3D build additionally needs an SDK compiled from source with Vulkan enabled — the published SDK zips ship Vulkan off, and `sdk/BUILDING-3D.txt` is the procedure. The Python tools want 3.11+ and `openpyxl`; the desktop shell additionally wants `pywebview`, and building the standalone `.exe` wants `pyinstaller`. ## A note on how the documentation is written Most of these documents carry their own evidence — a ratio like `134/134` or `27/27`, a correlation with an n beside it, or an explicit note that something is an interpretation rather than a measurement. Where a claim was wrong, the retraction is written in beside it instead of being quietly edited out, because several of these findings were confidently wrong first and the record of how they broke is more useful than a clean list of facts. [docs/research/what-we-got-wrong.md](docs/research/what-we-got-wrong.md) collects them. The work ran as several parallel tracks, and their names survive in the raw logs — RENDERER, DRAFT, EDITOR, PORTRAITS, and an "internal" track doing the code reading. Where two tracks disagreed, the disagreement is usually still in the text. ## Credit where it's due [`puckhead73/nhl-legacy-recomp`](https://github.com/puckhead73/nhl-legacy-recomp) is a working recompilation of NHL Legacy Edition, which is the same engine — Legacy is the last-gen NHL 15, built on NHL 14. That is not an analogous example to reason from, it is a shipped port of this exact engine, and several problems here were solved by reading what it already did. Two lines of their app configuration account for most of one day's progress on both crashing and frame rate. `docs/port/reference-pins.md` records the commits referenced. The [ReXGlue SDK](https://github.com/rexglue/rexglue-sdk) is what makes any of this possible, and [`sp00nznet/360tools`](https://github.com/sp00nznet/360tools) documented the container formats. ## Licence MIT, for the original code and documentation in this repository — see `LICENSE`. That covers our work only. NHL 14 is EA's, the Xbox 360 platform is Microsoft's, and nothing here grants you any rights to either.