Operator report: selecting a kit in the pre-match selector gives "This kit is
currently locked. To unlock and use it, please go to the football club
catalogue."
Root cause, from static RE of the UNPACKED CardsDLL. CardsDLL registers a kit
provider into the FIFA engine (singleton FUN_1800338f0, vtable 0x1801f1d68):
slot +0x08 FUN_180033770 enumerate kits for a team
slot +0x10 sub_180033430 describe one kit <- the lock gate
The describe function decodes a packed kit id into (teamid, year, slot) and
compares it against the club's ACTIVE HOME and ACTIVE AWAY triples. On a match
it writes NAME/TYPE (and, for historical kits, LOCKED). On no match it writes
NOTHING AT ALL and the descriptor falls through to the engine's own default,
which is where the locked-catalogue message comes from.
The active triple is 100% server-driven. FUN_1801c26d0 -> FUN_1800d73d0 scans
club items for cardtype 7 + cardsubtypeid 9 + itemState 101/102, then reads:
teamid <- item+0x94 (atom 0x306) we were sending this
year <- item+0xba (atom 0x389) WE WERE NOT SENDING THIS
slot <- item+0xb8 (category) WE WERE NOT SENDING THIS
category 2 -> slot 0 home, 3 -> slot 1 away, 5 -> slot 3 third
So we shipped kits carrying only teamid, and the triple could never match.
fifa17-recon/data/club_items.json already has category and year per kit
resourceId (1482 kits; category {2:740, 3:654, 5:88}; 85 historical years), so
this is carried through the catalog rather than invented: Fifa17CardIdentity
gains category/year, Fifa17KitIdentity carries them, and shape_club_item emits
them for KIT_SUBTYPE only. Badges and stadiums deliberately do not gain the
fields - the slot mapping is kit-specific, and sending a family a field its
resolver does not read is how this project previously froze the client.
Also corrects the Vault note: item+0xba is `year`, not `kittype`. The side comes
from itemState 101/102 and the slot from category.
Two things this does NOT fix, both client-owned and recorded rather than
guessed:
- the runtime teamkits clone into FUT club 130000 (the kit ART) is gated on
item+0x60 == 4, and +0x60 has no wire atom at all: the deserialiser
unconditionally zeroes it, the only CMP against 4 in the whole DLL is
0x1801c34f1, and a live probe measured it as 1 for players / 0 for staff,
never 4. The existing lib.rs claim that a server can never produce 4 is
CONFIRMED, though its stated reason was a live observation rather than the
real one (no wire atom exists).
- whether a year==0 kit needs an explicit LOCKED write is UNKNOWN: CardsDLL
only writes LOCKED for year != 0, and the engine's default for an untouched
descriptor is in Denuvo-packed FIFA17.exe.
OpenFUT
⚠️ Status — see
docs/PROJECT_STATE.md(canonical). The working, actively-developed target is FIFA 17, not FIFA 23. Everything below this banner describes the superseded FIFA 23bridgelineage and is kept for historical context.Run the server (canonical):
cd fifa17-recon/docker/fifa17-python && docker compose up -d— seefifa17-recon/FUT-RUNBOOK.md.openfut-coreis the shared offline backend (still used by the FIFA 17 path);openfut-bridgeis the retired FIFA 23 integration.
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.