Ships the club-item subtype correction and the tradeable plumbing, and records two
refutations of claims made earlier in the same session. Nothing here is a working fix
for trading; the honest state is that the gate is still closed and we now know more
about why.
REFUTED 1: "the Blaze client-config store opens the trading gate". It does not, and the
flag is inert. IS_TRADING_ENABLED is an OUTPUT NAME. FUN_18006cc60 is a publisher: at
0x18006ccc6 it calls [rax+0x270] to READ gate byte 0x1fd2e, then lea rdx,[
IS_TRADING_ENABLED] and hands the value out under that name. The only rip-relative
reference to the literal 0x1801fc118 in all of .text is that lea; there is no comparison
against it anywhere, so no client-config key of that name can be read as an input. That
also undermines the IS_* store keys shipped beside it: their apparent success was never
actually attributed to them.
REFUTED 2: "the gate byte flipped to 1". It reads 0. It was measured as 1 shortly after
CardsDLL mapped and that was over-claimed as a success; a thorough re-measurement read 0
on the SAME pid and model pointer, and a fresh session reads 0 with an unambiguous raw
dump (model+0x1fd18.. = 01000000 00000000 00000000 00000000 3c000000 01 01 00 01, the 00
being 0x1fd2e). Either the first read was transient or something clears it after login.
The only writer is FUN_18011dc50 at 0x18011dc91, so a 0 means something RAN and wrote it.
AND THE "/settings IS DEAD" CLAIM FALLS TOO. FUN_18011dc50 is not unreachable: it is a
VIRTUAL method at model vtable slot +0x988 (absolute pointer 0x18021cc28). A direct-call
search found no callers because Ghidra does not resolve virtual calls, which is the same
dispatch-form trap that has now produced seven wrong verdicts here. The real chain is
settings response -> FUN_180174630 -> FUN_18013c6d0 (deser)
-> completion callback FUN_180173e00 -> vt+0x988 and vt+0x998 -> gate bytes
and FUN_180173e00 bails before applying anything unless the int at response+0x1c is
zero. Which atom writes +0x1c is unknown and is the thing worth chasing.
The measurement behind that claim also had a gap: it checked +0x1fd14, +0x1fd4c and
+0x1fd54 for the maximumTradePileSize=77 probe but NOT +0x1fd1c, which is the actual
TRADE_PILE_SIZE (read via vt+0xa58 = FUN_18011bf30). So the probe never tested the field
it needed to. Serving 77 and reading +0x1fd1c is the clean falsifier and is still open.
Recovered and worth keeping: an authoritative slot-to-name table from the publisher.
vt+0x270 IS_TRADING_ENABLED -> +0x1fd2e vt+0x2b0 IS_FRIENDLY_SEASON_ENABLED -> +0x1fd3a
vt+0x2b8 IS_TOURNAMENT_QUIT_ENABLED -> +0x1fd3b vt+0x2c0 IS_PROCESSING_STATE_ENABLED -> +0x1fd3c
vt+0x2c8 IS_DRAFT_MODE_ENABLED -> +0x1fd3d vt+0x2d8 IS_STORY_MODE_REWARD_ENABLED -> +0x1fd3f
vt+0x2f0 IS_RETURNING_USER_REWARDS_SCREEN -> +0x1fd40 vt+0xa58 TRADE_PILE_SIZE -> +0x1fd1c
That also locates the red TRANSFER LIST 0/0: it is +0x1fd1c, currently 0.
WHAT IS ACTUALLY SHIPPED HERE, all default off:
* FUT_TRADEABLE sends untradeable=false. Verified landing at item+0x49 (stored
INVERTED by case 0x361) on a live club record. Applied on every READ path, not only
in _item(), because the save holds 246 items minted before the flag existed and the
club route serves them straight from the save. That gap was caught by reading the
served JSON, not by unit-testing the factory.
* FUT_TRADING adds tradingEnabled and IS_TRADING_ENABLED to the Blaze config. Kept
only as a record of the refutation, with the reasoning inline so nobody retries it.
* fut_clubitems FAMILIES subtypes corrected: kit 9, stadium 10, badge 11 (cardtype 7,
not 9), ball 30, league logo 31. Every previous value sat in the 0x91..0x96 TROPHY
block. probe_shelf's candidate set lacked 9, 10 and 11, so the probe route the docs
preferred could never have answered this for three of five families.
* Club kits and badges now carry teamid, reintroduced ALONE after the 2026-08-05 crash
(which was never bisected; value is the established suspect and that response also
carried 30 items across five wrong subtypes). itemType dropped: it was unobserved and
never copied into the record.
Live: 439 contract checks, 414 card-family checks, market suite, all pass. The transfer
market still refuses with zero requests and the menu entries are still greyed.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
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.