The tile's big number is `clubPlayers` (atom 0x90) in the body of GET ut/%s/hub, a
route we have answered with {} for the life of the project.
The chain, re-derived independently by two agents (one via Ghidra, one via raw PE plus
capstone with no decompiler) and checked by two reviewers:
clubPlayers(0x90) --INT getter 0x1801c79d0--> clamp FUN_1800d7b30 (<=0 becomes 0)
-> R+0x3c, where R = FUT data-manager slot +0x1f8 (FUN_18011a810 is literally
`lea rax,[rcx+0x1fd70]; ret`)
-> read by FUN_1800b0250, published as TEXT0 of TILE_ID 0x210
-> captions FUT_GH_TOTAL_PLAYERS_0/_1 at 0x18020a0f8 / 0x18020a110
auctionCount(0x33) -> R+0x38 -> TEXT0 of TILE_ID 0x1b0, the TRANSFERS tile
FUN_180139610 (the hub body parser, 14855 chars, censused in full: 18 atoms, none
missed) is the ONLY writer of +0x3c anywhere in the image, one write, guarded by
`if (iVar6 != 0x90)`. This is not a candidate, it is the field.
I SPENT A DAY ON THE WRONG SURFACE AND WROTE THE WRONG CONCLUSION. REBUILD_RESEARCH
S19 declared the counter "not server-fixable" with a mechanism that was internally
correct and completely beside the point: the tile never read the club-stat store.
Two things reinforced the error and both are now fixed in the docs:
* ENDPOINT_MAP said this response "uses C++ reflection / vtable dispatch, NOT an
inline atom ladder -- no static field ladder to read" and marked it a GAP. False.
There is an inline ladder, one indirection away.
* The eight-row MY CLUB panel was assumed to be FUN_180043b90 case 1, which
publishes six keys, and I treated the six-versus-eight mismatch as a puzzle rather
than as evidence. It is a DIFFERENT provider, FUN_180094ce0, using a different
string family (FUT_MYCLUB_*), reading neither the mode tag nor any type id we were
sending. Two providers; we were reading the wrong one.
That is the third negative claim of this shape to fail today, after "this deserializer
has no skip handler" and "the factory does not wipe the stat map".
auctionCount is included as a FREE CONTROL: different field, different tile, so if MY
CLUB moves and TRANSFERS does not, delivery is fine and something is specific to +0x3c.
Default ON. Freeze risk is low by construction rather than by belief: a flat object of
two integers, both read with the INT getter, so there is no array, no nested object and
no type-desync surface. FUT_HUBDATA=0 restores {}.
Contract guard added, and verified to bite rather than merely pass:
default 439 checks, 0 failed
FUT_HUBDATA=0 435 checks, 3 FAILED (clubPlayers missing / not a number)
A regression here would otherwise be silent: still 200, still valid JSON, tile quietly
back to 0.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VUT92pz6RWKih9dSr8ZpxW
OpenFUT
Offline Ultimate Team — like SPT, but for FIFA 23.
OpenFUT replaces EA's retired FUT servers with a fully offline, single-player backend. You own FIFA 23 legitimately. You just want to keep playing after EA shut down the servers.
Repositories
| Repo | Purpose |
|---|---|
openfut-core |
Game-independent offline FUT backend |
openfut-bridge |
FIFA 23 integration layer + reverse-engineering proxy |
Architecture
FIFA 23 client
│
▼
┌─────────────────┐
│ openfut-bridge │ ← intercepts FUT traffic, maps routes, logs unknown
└────────┬────────┘
│
▼
┌─────────────────┐
│ openfut-core │ ← offline FUT backend: profiles, packs, squads, SBCs
└─────────────────┘
│
▼
SQLite database
Core is game-independent. It speaks a clean REST API and knows nothing about FIFA 23 internals.
Bridge is FIFA-specific. It speaks FIFA 23's wire protocol and translates it into Core API calls. Bridge is where all reverse engineering work happens.
Current Status
| Feature | Status |
|---|---|
| Local profiles + clubs | ✅ Working |
| Coin system | ✅ Working |
| Pack generator | ✅ Working |
| Card collection | ✅ Working |
| Squad builder | ✅ Working |
| Objectives engine | ✅ Working |
| SBC engine | ✅ Working |
| Match rewards | ✅ Working |
| NPC transfer market | ✅ Working |
| Statistics | ✅ Working |
| FIFA 23 integration | 🔴 Reverse engineering in progress |
| Chemistry calculation | 🟡 In progress |
| Full Draft mode | 🟡 In progress |
| Squad Battles AI generator | 🟡 In progress |
| Objectives claim flow | 🟡 In progress |
Running
# Start the offline backend
cd openfut-core
cargo run
# Start the proxy (for traffic capture / FIFA integration)
cd openfut-bridge
cargo run
Core listens on http://127.0.0.1:8080 by default.
Bridge listens on http://127.0.0.1:8443 by default.
Design Principles
- Offline-first. No EA account required. No internet connection needed.
- Single-player only. This is not a multiplayer server emulator.
- Data-driven. All cards, packs, SBCs, and objectives are JSON files. Everything is moddable.
- Clean architecture. Core has zero knowledge of FIFA 23. Bridge has zero game logic.
- No copyrighted assets. No real player images, no EA trademarks in data files.
Disclaimer
This project is not affiliated with EA Sports. You must own FIFA 23 legitimately to use this software. This project does not bypass any ownership verification and is intended only to restore offline playability of a game whose online services have been retired.