diff --git a/.gitignore b/.gitignore index 55b7a41..4360743 100644 --- a/.gitignore +++ b/.gitignore @@ -14,6 +14,10 @@ target/ # Captures (runtime data, not source) openfut-bridge/captures/ +# Python +__pycache__/ +*.pyc + # Editor .vscode/ .idea/ diff --git a/docs/direction.md b/docs/direction.md new file mode 100644 index 0000000..f1899d0 --- /dev/null +++ b/docs/direction.md @@ -0,0 +1,250 @@ +# OpenFUT — Direction Document +*The pivot: FUT lives in the app; FIFA 23 is the match renderer.* +*Supersedes the Blaze-backend approach as the primary plan. Last updated 2026-06-30.* + +--- + +## 1. Goal (revised) + +Deliver an **intuitive way to play a FUT-style experience with FIFA 23**, where: + +- The entire **FUT experience** — cards, squads, packs, SBCs, coins, chemistry, + progression — lives in a **custom app** (web UI or desktop) built on the + already-complete OpenFUT Core economy backend. +- **FIFA 23 is demoted to a match renderer.** Its only job is to play a + single-player match using the squad the app built. No FUT mode, no online, no + Blaze, no EA servers. + +This deliberately drops in-game FUT cards/UI (they live in the app) in exchange +for a project that **converges** instead of being gated behind months of +backend reverse-engineering. + +### Why this replaces the backend plan + +The status review confirmed the backend route (faking EA's online stack) is +blocked at an upstream in-process EbisuSDK gate, with Blaze/Fire2 unconfirmed +beyond it — realistically 3–6 months of expert RE that may not converge. The +app-centric route sidesteps **every** wall in that review by never making FIFA's +own FUT mode run. + +--- + +## 2. Base mode: Career, not Kick-Off + +**Career mode is the base.** Reasons: + +- FLE's live-editing API (`EditDBTableField`, Freeze Lineup) is **confirmed to + work in career mode** and explicitly does NOT work in FUT/online modes. +- Career already provides the FUT-shaped scaffolding we'd otherwise fake: + persistent club, a fixture schedule, recorded results, progression across a + season. +- **Match results are written into the career DB**, making result capture a DB + read rather than a fragile live-memory grab. + +**Kick-Off is the prototype sandbox.** Use it first to prove squad injection +works with nothing to corrupt (no save to break), then move the real loop onto +career. Run the foundational injection test in BOTH. + +--- + +## 3. Core architecture: the bidirectional FLE bridge + +The backbone is a **bidirectional channel between the app and a resident FLE Lua +script running inside the game.** Everything else is messages over this channel. + +``` + Custom App (FUT experience) + │ squad push ──────────────► ┌─────────────────────────────┐ + │ │ Resident FLE Lua script │ + │ ◄────────── game state │ (inside FIFA 23, career) │ + │ ◄────────── match result │ - reads game state │ + └────────────────────────────► │ - applies squad live │ + (file-watch or local socket) │ - reads results from DB │ + └─────────────────────────────┘ + │ + FIFA 23 plays the match +``` + +Three message types over the bridge: + +1. **App → Game: squad push.** The app's chosen XI + stats applied LIVE via + `EditDBTableField`, replicating whatever DB write FLE's "Freeze Lineup" + feature performs (see `docs/foundational-xi-injection-test.md` — the exact + field(s) are found by diffing, not assumed). No restart, no + file-copy-reload. (File-load remains a fallback.) + +2. **Game → App: game state.** The resident script polls the game's current + screen/menu state and reports "safe to apply" vs "not safe", driving a smart + Apply button in the app (see §5). + +3. **Game → App: match result.** After full-time, the script reads the result + from the career DB and pushes score/scorers to the app, which awards + coins/progression. (Manual entry is the baseline fallback.) + +The bridge transport can be a watched file the in-game Lua polls, or a local +socket — decided in build (see §7). Either way the *game keeps running*; a file, +if used, is just the message channel, not a reload. + +--- + +## 4. Tiered mod scope + +Build in tiers matched to risk. The core tier is all the SAME kind of DB write, +so it lands together once squad injection works. + +### Tier 1 — Core writes (ride the same live DB-edit mechanism) +- **Squad / custom XI** — the load-bearing primitive (Freeze Lineup's + underlying write, replicated via script — see §6). +- **Player stats as "cards"** — card tiers, in-form versions, SBC upgrades all + expressed as written attribute values. +- **Chemistry as stat adjustment** — app computes FUT chemistry, applies it as + small stat bumps when writing players in (no in-game chem UI; that's in the app). +- **Appearance / identity** — kits, names, team assignment, so the club looks + like your club on the pitch. +- **Formation / tactics** — squad structure carries the app's build onto the pitch. + +### Tier 2 — Confirm-then-add +- **Match difficulty per game** — to drive a Squad-Battles-style "this opponent is + World Class". Settable in-game trivially; programmatic drive needs confirming. +- **Match rules / modifiers** (half length, etc.) — for app-defined challenges. + +### Tier 3 — Result capture (manual baseline + automated stretch) +- **Manual:** user enters the score in the app after the match. Zero RE, ships + first. +- **Automated:** resident script reads the career-DB result (or, for Kick-Off, + reads the in-match score from memory at full-time — precedent exists: the + CM cheat table's `export_season_stats.lua` already reads goals/cards from + memory via known offsets). Push to app → auto-award progression. + +### Out of scope (stays in the app, by design) +- In-game FUT cards, FUT menus, pack-opening animation, chemistry board, FUT + presentation. The app is where it looks/feels like FUT. + +--- + +## 5. The smart Apply button (state-aware) + +Live DB edits only "stick" in safe menu states (the in-game "Edit Player" screen, +for example, overwrites edits). So the bridge reads game state and gates applying: + +- Resident Lua script polls the game's current-screen value (a few Hz), + classifies **safe / not safe**, reports to the app. +- App's **Apply button is enabled only when the script confirms a safe state** + (squad hub, main menu); greyed otherwise. +- **Safe-by-default-OFF:** unknown state → button greyed → never a risky write. + Expand the known-safe list incrementally as states are confirmed. +- **v2 (more seamless):** instead of greying, the app always lets you click and + the script **queues** the apply, executing the moment a safe state is entered, + then confirms back. Greying is v1; queue-and-apply is v2. + +`IsInCM()` is a confirmed state-read; the specific screen-state address + the +value→screen mapping is one-time reconnaissance (same technique as result reading). + +--- + +## 6. What's confirmed vs what needs validating + +**Confirmed (from FLE's own Lua API docs/wiki, checked 2026-06-30):** +- FLE live-edits the running career DB without restart, via `EditDBTableField` + (real signature: `EditDBTableField(cell)` where `cell = row["fieldname"]` + with `.value` mutated first — not the table/index/field/value form an + earlier draft of this doc assumed). +- FLE reads game state via `IsInCM()`. +- A `MEMORY` Lua class exists (`ReadInt`/`WriteInt`/`ReadMultilevelPointer`/ + etc.) for arbitrary process memory — confirms the result-reading fallback + in §4 Tier 3 is a real, documented capability, not just cheat-table analogy. +- `GetPlayersStats()` is a documented function returning per-player + goals/assists/cards/etc. — a better confirmed path for match-result capture + than raw memory offsets. +- **Freeze Lineup** (Formation Editor → arrange XI → tick "Freeze Lineup" → + `Data → Save`) is FLE's actual documented mechanism for forcing a starting + XI in career mode. This **replaces** "selection bias" below. +- OpenFUT Core (economy) is complete and tested. + +**Walked back — not actually confirmed:** +- "Selection bias forces specific players into the starting XI" — no such + field appears anywhere in FLE's documented Lua API or its own example + scripts. This was an unverified assumption carried over from general FIFA + modding precedent (other titles), not anything checked against FLE/FIFA 23. + See `docs/foundational-xi-injection-test.md` for the corrected plan, which + uses Freeze Lineup instead. + +**Needs validating (the foundational tests — see §7):** +- Whether Freeze Lineup actually holds into a played match (FLE's wiki + documents the feature but not a live-match test of it). +- What DB table/field Freeze Lineup's `Data → Save` actually writes — it's + GUI-only and undocumented at that level; finding it is part of the + foundational test. +- Whether that write can be replicated by a script (`EditDBTableField`) well + enough to drive it from an EXTERNAL trigger, not just the Formation Editor + UI — required for the app↔game bridge. +- The app↔game bridge transport (file-watch vs socket) works cleanly under the + run setup. +- The screen-state address + safe/not-safe classification (FLE's `Events` + API page exists in the wiki index but its content is currently empty/ + undocumented — this is more open than previously assumed). +- Result read-back from the career DB after a match. + +**Standing caveat:** the whole stack rides on **EAAC staying neutralized** +(FLE's fake-launcher bypass). If a game update re-enables it, hooks fail. Keep +game updates off; confirm neutralized state each session. + +--- + +## 7. Build order / next steps + +Each is a bounded, verifiable step. Do them in order; later ones depend on +earlier answers. + +1. **FOUNDATIONAL TEST — live custom XI in career.** Confirm Freeze Lineup + holds into a played match, reverse-engineer the DB write it makes, then + replicate that write from a script so it can be triggered externally + instead of through the Formation Editor UI. See + `docs/foundational-xi-injection-test.md` for the full procedure. *Done = + a script-driven write produces a match that fields the squad you + specified.* Everything rests on this. + +2. **Pick the bridge transport.** Decide file-watch vs local socket for app↔game + messaging; implement the minimal app→game squad push. *Done = app sends a + squad, the resident script receives and applies it.* + +3. **Game-state reader + smart Apply.** Find the screen-state address, classify + safe/not-safe, expose to the app, gate the Apply button. *Done = button greys + when you enter a match/edit screen, enables in the squad hub.* + +4. **Result read-back.** Read the career-DB match result post-game, push to app, + award progression. Manual entry ships alongside as the fallback. *Done = app + updates coins from a played match.* + +5. **Tier 1 breadth.** Extend the squad push to carry stats, appearance, + formation (same write mechanism). *Done = the club looks and plays like the + app's build.* + +6. **Tier 2 + economy loop polish.** Difficulty drive, challenges, and the full + pack → SBC → squad → match → reward loop closed end-to-end. + +### Decision still open +- **App form factor:** web UI vs desktop app. This affects the bridge transport + (a desktop app can hold a local socket more naturally; a web UI leans toward a + small local helper/file-watch). Decide before step 2. + +--- + +## 8. Provenance + +Clean-room throughout. This route relies on FLE's documented public API and the +game's own supported career mode — no EA backend, no Blaze, and nothing derived +from leaked EA source. The earlier backend RE remains clean-room and is preserved +as a spec artifact; it is simply no longer the primary path. + +--- + +## 9. One-paragraph summary + +OpenFUT becomes a **FUT companion app that uses FIFA 23 as a match engine.** The +app owns the entire FUT experience; a resident FLE Lua script in career mode +applies the app's squad live (no restart), reports game state to drive a safe +Apply button, and reads match results back to feed progression. This sidesteps +every backend wall, runs on confirmed FLE capabilities, builds on the finished +economy core, and delivers the intuitive, offline, FUT-flavored loop that is the +actual goal. diff --git a/docs/fifa23-startup-flow.md b/docs/fifa23-startup-flow.md new file mode 100644 index 0000000..16416ea --- /dev/null +++ b/docs/fifa23-startup-flow.md @@ -0,0 +1,108 @@ +# FIFA 23 PC Startup Flow (Offline / Proton) + +Observed via FLE log, hook log, and file inspection on 2026-06-26. + +## Launch chain + +``` +umu-run / Steam → FIFA23.exe (via Proton/Wine) + │ + ├─ DLL load order (before entry point) + │ ntdll.dll, kernel32.dll, ws2_32.dll … + │ version.dll ← our hook DLL slot (loads here) + │ FIFALiveEditor.DLL ← injected by FLE launcher after ~100 ms + │ + ├─ anadius / LSX emulator (anadius64.dll) + │ Fakes EA App / Origin session + │ Reads HKLM\SOFTWARE\Wow6432Node\Origin\ClientPath + │ Writes AppData\Local\anadius\LSX emu\achievement-*.xml + │ Provides fake PersonaId=1144668899 / UserId=1000200030000 + │ + ├─ EA Anti-Cheat (EAAntiCheat.GameServiceLauncher.exe) + │ Spawns as child; checks EAAntiCheat.cfg + │ Not active in offline/cracked builds (FakeEAACLauncher present) + │ + └─ FIFA23.exe entry point + Frostbite engine init (BuildDate 2023-07-05, changelist 5417699) + Reads Data\initfs_Win32 ← Frostbite package manifest + Reads Data\layout.toc ← file-system layout + Reads Patch\initfs_Win32 ← patches on top of base + Reads Documents\FIFA 23\fifasetup.ini ← display settings + Reads Data\locale.ini ← language table + Reads Data\db_meta.xml (via FLE) ← DB schema for all tables +``` + +## Phase timing (observed, single machine) + +| Phase | Time after launch | Trigger | +|------------------------------|-------------------|----------------------------------| +| DLL load + FLE injection | 0 – 0.3 s | OS loader | +| Engine + DirectX init | 0.3 – 5 s | FIFA23 entry point | +| "Press any key" splash | ~5 s | First rendered frame | +| Main menu | ~25 s | After key press | +| FUT mode entry (attempted) | user-driven | User selects FUT tile | +| Network calls to EA services | at FUT entry | DirtySDK / EAWebKit | + +## Files read at startup (observed) + +| File | Format | Purpose | +|------|--------|---------| +| `Data/initfs_Win32` | Frostbite pkg | Base asset manifest | +| `Data/layout.toc` | Frostbite TOC | File layout index | +| `Patch/initfs_Win32` | Frostbite pkg | Patch layer | +| `Data/locale.ini` | INI | String localisation | +| `Data/db_meta.xml` | XML | DB schema (loaded by FLE) | +| `Data/id_map.json` | JSON | Player/team ID→name map | +| `Data/char_conv.json` | JSON | Character conversion table | +| `Documents/FIFA 23/fifasetup.ini` | INI | Display/audio settings | +| `AppData/Local/Temp/FIFA 23/_replay0.bin` | binary | Replay buffer | +| `anadius.cfg` | VDF | Fake EA persona config | +| `AppData/Local/anadius/LSX emu/achievement-*.xml` | XML | Achievement state | + +## Files written during a session (observed) + +| File | When written | Content | +|------|-------------|---------| +| `Documents/FIFA 23/settings/Settings*` | Main menu reached | FBCHUNKS — controller/display prefs | +| `Documents/FIFA 23/settings/ProfileOptions` | Profile load | FBCHUNKS — 1.5 MB profile blob | +| `Documents/FIFA 23/filesystemcache/survey.state` | Startup | Empty state file | +| `Documents/FIFA 23/filesystemcache/atlPlayTimeJson/playtime_*.json` | Ongoing | Playtime tracking | +| `FIFA 23 Live Editor/config.json` | FLE ready | FLE settings (rewritten each session) | +| `Logs/log_DD-MM-YYYY.txt` | Throughout | FLE debug log | + +## Save file formats + +### FBCHUNKS (Frostbite chunk container) +- Magic: `46 42 43 48 55 4E 4B 53` (`FBCHUNKS`) +- Byte 8: version (01 seen) +- Offset 0x12: null-terminated label string (e.g. "Personal Settings 1", "Career - Player Progress 1") +- Remainder: compressed/binary chunk data — no public spec; requires Frostbite tooling to fully parse +- Tools: [Frosty Tool Suite](https://github.com/CadeEvs/FrostyToolSuite) can read/write these + +### fifasetup.ini +- Plain `KEY = VALUE` ini, fully human-readable +- Safe to edit (display resolution, locale, vsync) + +## Network calls at FUT entry (observed with iptables redirect) + +Traffic pattern captured before changing strategy: +- Multiple TLS connections to port 443 (destination: EA servers, resolved as various EA IPs) +- TLS 1.3, AES-256-GCM (DirtySDK's copy of ProtoSSL, inline in FIFA23.exe) +- No SNI sent (DirtySDK does not set `server_name` extension) +- Connections originate from Wine/Proton network stack via Linux kernel TCP + +Specific EA hostnames used (from openfut-bridge captures, not decoded from TLS): +- `fut.ea.com` (FUT API) +- `accounts.ea.com` (auth) +- `gateway.ea.com` (entitlements) +- `pin-river.data.ea.com` (telemetry) + +## Key FLE Lua API hooks + +FLE injects `FIFALiveEditor.DLL` and exposes a Lua engine that can: +- Read any in-memory DB table via `GetDBTableRows(tableName)` +- Write any cell via `EditDBTableField` +- Query career mode state via `IsInCM()` +- Get player/team names via `GetPlayerName`, `GetTeamName` + +This is the primary safe integration path (see `fut-integration-options.md`). diff --git a/docs/foundational-xi-injection-test.md b/docs/foundational-xi-injection-test.md new file mode 100644 index 0000000..422ac98 --- /dev/null +++ b/docs/foundational-xi-injection-test.md @@ -0,0 +1,191 @@ +# Foundational test — live custom XI via Freeze Lineup + +**Status: PENDING — test has not yet been run.** + +This is build-order step 1 from `docs/direction.md`: the test everything else +in the direction pivot depends on. + +## What changed since the first draft of this doc + +The first version of this test guessed at a "selection bias" DB field and a +candidate squad/lineup table name, based on general FIFA-modding precedent +that turned out not to hold for FLE's documented API — no such field appears +anywhere in FLE's actual Lua API docs or its own example scripts. While +researching an unrelated hotkey issue, a **confirmed, FLE-documented** +mechanism for forcing a starting XI turned up instead: the **Formation +Editor's "Freeze Lineup" feature** (FLE wiki, `Formation-Editor.md`): + +> This feature can be used in player career mode if you want to manage the +> starting lineup of your team. Can be also used in manager career mode to +> manually manage your next opponent's starting lineup. + +Steps (GUI, no scripting): open Formation Editor for a team → arrange players +on the pitch → tick **Freeze Lineup** → `Data → Save`. + +This is real and documented, but it's GUI-only — there is no Lua function for +it, and what DB write it actually performs under the hood is undocumented. +This test is now two phases: confirm the GUI feature works at all, then +reverse the DB write it makes so it can be replicated programmatically +(required for the app→game bridge in build-order step 2, which needs this +driven from outside the game, not from a person clicking checkboxes). + +Also fixed in this pass: `EditDBTableField`'s real signature, confirmed from +FLE's own docs and `lua/scripts/99ovr_99pot.lua`, is +`EditDBTableField(cell)` where `cell` is `row["fieldname"]` with `.value` +mutated in place — **not** `EditDBTableField(table, row_index, field, value)` +as originally (incorrectly) written into the first draft of the injector +script. + +## What this test settles + +Whether a *specific, externally-chosen* 11 players can be forced into a +career (or Kick-Off) match's starting lineup, live, with no restart — and +whether the mechanism that does it (Freeze Lineup's underlying DB write) can +be driven by a script instead of a person clicking through the Formation +Editor UI. + +If Freeze Lineup itself doesn't actually hold under match start (the wiki +doesn't show it being tested against a live match, only "you should be able +to see... when you play against them"), the whole bridge architecture in +`docs/direction.md` §3 needs rethinking — there is no other documented +mechanism for forcing a lineup. + +## Prerequisites + +- FIFA 23 launched normally (FLE injected, EAAC neutralized — same baseline + as `track-c-fut-table-test.md`) +- A career save loaded (Freeze Lineup is documented for career mode + specifically — confirm separately whether it does anything in Kick-Off, + don't assume it does) +- Note 11 player IDs from your club (`tools/squad-exporter/export_squad.lua` + output, `playerid` field) that are NOT currently your starting XI + +## Phase 1 — confirm Freeze Lineup actually holds into a match + +This has zero scripting and should be done first since everything else is +wasted effort if it fails. + +1. Open the Live Editor overlay (F9, or `Windows → Settings` from the + overlay's own menu bar if the hotkey isn't registering — see the umu/Wine + hotkey note below). +2. `Features → Teams` → find your team → `Edit`. +3. `Team → Formation` to open the Formation Editor. +4. Swap players around on the pitch so the XI differs from your current + actual starting XI in some checkable way (e.g. swap two outfield players' + positions, or bench/start a specific player). +5. Tick **Freeze Lineup**. +6. `Data → Save`. +7. Hide Live Editor (F9), save your career **on a new slot** (don't overwrite + your main save in case this corrupts something), exit to main menu, reload + that save, and check the team's lineup screen / play a match and watch who + starts. + +**Record in the Results table below whether the frozen lineup actually took +the pitch.** If not, stop here — Phase 2 is moot. + +## Phase 2 — find the underlying DB write + +Only proceed if Phase 1 confirmed Freeze Lineup works. + +1. In FLE's Lua Engine, run `tools/squad-injector/snapshot_lineup_tables.lua`. + This dumps every DB table whose name contains `squad`, `lineup`, + `formation`, `tactic`, `teamsheet`, `selection`, `players`, or `teams` to + `C:\FIFA 23 Live Editor\openfut_snapshot_.json`. Note this + filename — this is your **before** snapshot. +2. Without restarting or reloading, repeat the Formation Editor steps from + Phase 1 (steps 2–6 only — open Formation Editor, change the lineup, tick + Freeze Lineup, `Data → Save`). Don't save/reload the career between + snapshot and this step — keep it to a single live session so the diff + isn't polluted by other state changes. +3. Run `snapshot_lineup_tables.lua` again. This is your **after** snapshot. +4. Copy both JSON files out of the Wine prefix (same path pattern as + `track-c-fut-table-test.md`: `~/Games/umu/.../drive_c/FIFA 23 Live + Editor/`) and run: + + ```bash + python3 tools/squad-injector/diff_snapshots.py before.json after.json + ``` + +5. The output shows exactly which table(s) and field(s) changed. This is the + real, confirmed write Freeze Lineup performs — record it in the Results + table below. + +## Phase 3 — replicate the write via script + +1. Open `tools/squad-injector/apply_lineup_write.lua` and fill in + `TARGET_TABLE` and `TARGET_FIELDS` using Phase 2's diff output. +2. Edit `C:\FIFA 23 Live Editor\openfut_test_xi.json`: + + ```json + { + "team_id": 12345, + "xi": [ + { "player_id": 111111, "position": 0 }, + { "player_id": 222222, "position": 5 } + ] + } + ``` + + Use 11 entries. Position codes are **confirmed numeric 0–27** + (`GK=0, SW=1, RWB=2, RB=3, RCB=4, CB=5, LCB=6, LB=7, LWB=8, RDM=9, CDM=10, + LDM=11, RM=12, RCM=13, CM=14, LCM=15, LM=16, RAM=17, CAM=18, LAM=19, + RF=20, CF=21, LF=22, RW=23, RS=24, ST=25, LS=26, LW=27`) — from + `lua/scripts/export_season_stats.lua`'s `get_pos_name` table in FLE's own + repo, not a guess. +3. Run `apply_lineup_write.lua` from FLE's Lua Engine. +4. Repeat the save-to-new-slot / reload / check-lineup verification from + Phase 1, but this time without ever opening the Formation Editor — the + write was made entirely from the script. + +## Classification criteria + +### "Confirmed — full mechanism works" + +Phase 1 holds, Phase 2 finds a clean diff, Phase 3's scripted write produces +the same in-match result as the manual GUI path. + +**Verdict:** Build-order step 1 done. Proceed to step 2 (bridge transport) in +`docs/direction.md`. + +### "GUI works, script doesn't" + +Phase 1 holds but Phase 3's replicated write doesn't stick, even though the +diffed fields matched what changed in Phase 2. + +**Verdict:** Freeze Lineup likely does more than a single DB field write +(e.g. an internal engine call beyond `EditDBTableField`'s reach, or a second +write the diff missed because it happened in a table outside the `KEYWORDS` +filter in `snapshot_lineup_tables.lua` — widen the filter and redo Phase 2). + +### "Freeze Lineup doesn't hold at all" + +Phase 1 fails — the lineup reverts to the game's own AI-picked XI regardless. + +**Verdict:** No confirmed mechanism exists for forcing a lineup. This kills +the bridge architecture as designed in `direction.md` §3 and needs a return +to first principles — there is no fallback documented anywhere in FLE's wiki +for this specific case. + +## A note on the umu/Wine F9/F11 hotkey issue + +If FLE's F9 (hide/show) hotkey isn't registering under umu, this is plausibly +a Wine keyboard-hook limitation (FLE's global hotkey detection likely uses a +low-level hook that doesn't translate cleanly through Wine's input layer) — +not something documented anywhere in FLE's own troubleshooting docs, which +don't mention Linux/Wine at all. F11 specifically has **no documented FLE +function** — F9 is the only documented toggle. Workaround: click directly +into the FLE overlay window (it should still be visible/clickable even if the +hotkey doesn't fire) and use its own menu bar instead of relying on the +hotkey. + +## Results + +*(To be filled in after the test is run.)* + +| Field | Value | +|---|---| +| Date run | — | +| Phase 1: Freeze Lineup holds into a match? | — | +| Phase 2: table(s)/field(s) changed | — | +| Phase 3: scripted write reproduces Phase 1 result? | — | +| **Classification** | **PENDING** | diff --git a/docs/fut-integration-options.md b/docs/fut-integration-options.md new file mode 100644 index 0000000..1212996 --- /dev/null +++ b/docs/fut-integration-options.md @@ -0,0 +1,136 @@ +# FUT Integration Options + +How to connect FIFA 23 to the OpenFUT local simulator, ranked by safety and feasibility. + +## Option A — FLE Lua scripting (RECOMMENDED) + +**What it does:** Use FIFA Live Editor's in-memory Lua API to read and write the game's +database tables at runtime. FLE is already injected; no additional hooking needed. + +**Why it's the right path:** +- Fully offline, no EA servers touched +- FLE is already trusted by the user (it's the launch mechanism) +- `GetDBTableRows` / `EditDBTableField` expose the full Frostbite DB in memory +- Scripts run inside the game process; no IPC complexity +- Same mechanism used by modders for career mode edits today + +**Integration design:** + +``` +openfut-core (SQLite) + │ + │ HTTP REST (localhost) + ▼ +openfut-bridge (port 8080, plain HTTP, no TLS) + │ pulls club/squad/player data as JSON + ▼ +FLE Lua bridge script + │ calls GetDBTableRows, EditDBTableField + ▼ +FIFA 23 in-memory DB (Frostbite) +``` + +The Lua script polls openfut-core's REST API at intervals (or on FUT menu entry) +and writes simulator data (coins, items, squad) into the appropriate DB tables. + +**Tables likely involved (to verify with export_squad.lua):** + +| Table | Expected FUT content | +|-------|---------------------| +| `players` | Player attributes (OVR, potential, stats) | +| `teams` | Club identity, stadium, colors | +| `fut_clubs` | FUT club record (if in memory when FUT loads) | +| `fut_items` | Card inventory (if in memory) | +| `fut_squads` | Active squad (if in memory) | + +**Steps to implement:** +1. Run `tools/squad-exporter/export_squad.lua` from FLE Lua Engine while in FUT to discover which tables are live +2. Map openfut-core's data model to the discovered table fields +3. Write a Lua polling script that fetches `/api/v1/club`, `/api/v1/squad`, etc. from openfut-core and calls `EditDBTableField` to populate them +4. Optionally add a small HTTP client to the Lua script using LuaSocket (FLE ships with Lua 5.4) + +**Limitations:** +- Changes are in-memory only; they reset on game restart (acceptable for a simulator) +- Only works while FLE is running (always true in our setup) +- FUT tables may only be populated when the FUT hub is loaded; test with the exporter + +--- + +## Option B — Local save file injection (career mode proxy) + +**What it does:** Generate or modify offline career mode save files that contain FUT-like +squad/player data, using Frostbite's FBCHUNKS format. + +**Feasibility:** Medium +- FBCHUNKS format is not publicly documented but has been partially reverse-engineered by the Frosty Tool Suite project +- Career saves are 16 MB — large and complex +- Changes take effect only after a game restart + +**Best use:** Pre-populating a career club with the same players as the FUT simulator squad, so offline Squad Battles use "your" players. + +**Steps:** +1. Use Frosty Tool Suite to open a career save and map the schema +2. Build a Python exporter that writes a valid FBCHUNKS save with simulator squad data +3. Test: replace the career save, launch FIFA, verify squad is correct + +--- + +## Option C — Local companion web UI + +**What it does:** The user manages their FUT simulator entirely in a web browser (openfut-core already has this). A button exports the current squad/club state to a format that a Lua script or file injector can consume. + +**This is already implemented** — openfut-core serves the FUT simulator REST API. The missing piece is the Lua bridge script (Option A) that reads from it. + +--- + +## Option D — Local proxy for non-secured local calls only + +**What it does:** Intercept FIFA 23's calls to `localhost:*` or a known local endpoint (not EA servers) and respond with simulator data. + +**Feasibility:** Low value in isolation +- FIFA 23 does not make calls to localhost in normal operation (except EA App on port 10853) +- All FUT API calls go to EA's servers over TLS +- Intercepting those would require the approach we explicitly ruled out + +**Not recommended as a primary path.** Could be combined with Option A if the Lua script exposes a local socket that a coordinator process writes to. + +--- + +## Option E — Memory bridge (Cheat Engine / FLE offsets) + +**What it does:** Use known memory offsets (FLE's `offset_cache.json`) to read/write FUT state directly in FIFA23.exe's heap. + +**Feasibility:** Medium — FLE already does this for career mode +- FLE's `offset_cache.json` contains addresses for many game structures +- FUT in-memory structs are separate from career structs and may not be mapped yet +- This is fragile (offsets change with game updates) + +**Not recommended** unless Options A and B both fail — too brittle. + +--- + +## Recommendation + +**Start with Option A (FLE Lua scripting).** + +1. Run `tools/squad-exporter/export_squad.lua` in-game to discover which DB tables exist in FUT mode +2. Use `tools/file-watch-diff/watch.sh` to snapshot file state entering FUT and identify any new local files +3. Use `tools/network-metadata-logger/netlog.sh` to log which EA hosts FIFA contacts at FUT entry (metadata only, no decryption) +4. Map findings back to openfut-core's data model +5. Implement the Lua bridge script that calls openfut-core's REST API and writes to discovered tables + +If FUT tables are not exposed by FLE's DB API (they may not be — FUT data lives server-side in online mode), fall back to **Option B** (career save injection) to provide a squad that mirrors the simulator's club. + +--- + +## Safety boundary + +The following are out of scope and must not be implemented: + +- Decrypting or inspecting EA's TLS traffic +- Spoofing EA domain names or impersonating EA servers +- Sending modified clients to EA's production services +- Bypassing EA App login or account verification +- Anything that could constitute online cheating or violate EA's ToS for online play + +All integration must remain local/offline/single-player. diff --git a/docs/status-review.md b/docs/status-review.md new file mode 100644 index 0000000..76e69f7 --- /dev/null +++ b/docs/status-review.md @@ -0,0 +1,208 @@ +# OpenFUT Status Review +*Generated 2026-06-30 — read-only stocktake, no code changed.* + +--- + +## Executive Summary + +OpenFUT has a mature offline FUT economy backend (Core, 25 phases, fully functional in +isolation) and a sophisticated hook DLL that loads into FIFA 23, redirects EA hostnames +to loopback, and bypasses TLS certificate verification. The Blaze/ProtoSSL layer is +structurally ready: framing code exists, a TLS listener runs, cert-verify is patched. +However the project is currently blocked before any Blaze traffic is ever seen. +The fundamental problem is that FIFA 23 submits `GoOnline` to EbisuSDK and then +**waits for an asynchronous ONLINE_STATUS_EVENT push** from the EA-app LSX server — +a push that current code never sends. Every approach tried so far (flipping poll +return values, forcing the state flags, read-only probes) confirms the gate is +event-driven, not poll-driven. The Blaze captures directory contains six empty files. +No Fire2 frame from FIFA 23 has ever been decoded. Until the ONLINE_STATUS_EVENT push +is synthesized and delivered correctly, Milestones 2–7 are all waiting on the same +single wall. + +--- + +## 1. Proven vs Assumed + +| Claim | Status | Evidence | +|---|---|---| +| FIFA 23 uses DirtySDK / ProtoSSL | **Proven** | String scan hit `ProtoSSLSend`, `ProtoSSLRecv`, `gosredirector` in FIFA23.exe memory (Task 1) | +| `version.dll` loads and runs hook code | **Proven** | `hook.log` written at DLL_PROCESS_ATTACH | +| `getaddrinfo` IAT hook redirects EA domains to loopback | **Proven** | Hook log records every EA `getaddrinfo` call; connect_hook log confirms port redirects | +| ProtoSSL cert-verify prologue found and patched (FIFA23.exe) | **Proven** | ssl_patch.rs prologue confirmed at file offset 0xf0c850; hook log "ssl: main exe cert-verify patched" | +| ProtoSSL cert-verify patched in EAWebKit.dll | **Proven** (if loaded) | Lazy patch fires on first EA getaddrinfo call; hook log message confirms | +| Gate is upstream of DirtySDK — no DNS/connect fires on FUT entry | **Proven** | getaddrinfo, connect, WSASend/Recv hooks all show zero external traffic during "connecting to EA Servers" | +| `GoOnline` is called by the game | **Proven** | Read-only detour on `anadius64.dll+0x2BB90` confirmed hit | +| anadius returns GoOnline success | **Proven** | Handler observed returning successfully; game still retries every ~7 s | +| Gate is downstream of GoOnline | **Proven** | GoOnline called + returns success; no Blaze connect follows | +| Connection-state function: `GetInternetConnectedState @ anadius64.dll+0x27790` | **Proven** | Located via anadius LSX command-registration table; two-flag branch decoded (`+0xCAB1A`, `+0xCAB1B`) | +| Gate is event-driven (game waits for async push, not a poll return) | **Proven** | Forced both state flags AND GoOnline return to "1"; game kept retrying; worker-thread stack scan confirms handler runs on anadius IOCP thread, not FIFA's thread | +| GoOnline runs on anadius worker thread, not FIFA's call thread | **Proven** | Stack scan from inside detour found zero FIFA23.exe frames, sp ~2.4 KB from thread stack top | +| `protossl-scan` live toolkit is exhausted for finding GoOnline in FIFA23.exe | **Proven** | No `"GoOnline"` string in image; worker-thread call stack has no FIFA frames; jmpscan yields ~3875 hits (overwhelmingly data false positives) | +| FIFA 23 redirector config references `Authorization:` header (Nucleus token) | **Proven** | Found in FIFA23.exe .rdata pointer table @ `+0x83FC858` | +| openfut-core REST API complete and tested | **Proven** | 25 phases, 15 migrations, passing integration tests | +| Bridge LSX server starts and handles request-response | **Proven** (code) | `openfut-bridge/src/lsx.rs` + `main.rs` — server starts on 127.0.0.1:3216 | +| Bridge LSX server ACTUALLY receives FIFA's LSX connections | **UNCONFIRMED** | anadius may intercept the same calls in-process before the TCP connection reaches the bridge | +| Bridge LSX server `GetInternetConnectedState → connected="1"` unblocks the gate | **UNCONFIRMED (known to fail in-process)** | Flipping the value via anadius in-process failed; bridge path not yet confirmed working | +| ONLINE_STATUS_EVENT push XML format | **UNKNOWN** | No capture; format not derived | +| Fire2 framing is correct for FIFA 23 | **UNCONFIRMED** | Implemented based on post-2012 EA convention; all blaze captures are empty (0 bytes) | +| Blaze component / command IDs for FIFA 23 | **UNKNOWN** | Zero captures; dispatch table entirely empty placeholders | +| ProtoSSL recv-injection convention (non-blocking return values etc.) | **UNCONFIRMED** | Never reached M4; recv_hook module removed from active install path | +| FUT REST endpoint paths in mapper.rs | **SPECULATIVE** | Based on community knowledge of older FIFA titles; the one actual capture in `captures/` is an early GET from before the Blaze strategy | +| FLE Lua API exposes FUT DB tables in memory | **UNKNOWN** | `export_squad.lua` has never been run; FUT data may only exist server-side in online mode | + +--- + +## 2. Milestone Status + +| Milestone | Status | Blocker | Depends on unconfirmed assumption? | +|---|---|---|---| +| **M1** — Locate connection-state decision point | ✅ Done | — | No | +| **M2** — Flip gate, force "connected" | ⛔ Blocked | Game waits for async ONLINE_STATUS_EVENT push; no current code sends it | Yes — unknown event XML format | +| **M3** — First ProtoSSL plaintext on Blaze connection | 🔲 Not started | Depends on M2 | Yes — Fire2 framing unconfirmed | +| **M4** — Answer redirector + decode first Fire2 frame | 🔲 Not started | Hard wall: Fire2 framing, recv-injection convention, component/command IDs all unconfirmed | Yes — all three unknown | +| **M5** — Blaze preauth / login / postauth | 🔲 Not started | Depends on M4 | Yes — Blaze auth TDF body layout unknown | +| **M6** — FUT entry + hub load | 🔲 Not started | Depends on M5; also requires FUT REST response shapes confirmed | Yes — endpoint paths speculative | +| **M7** — Squad Battles (AI FUT) | 🔲 Not started | Depends on M6 | Yes | + +**Note on roadmap.md wording:** Under M2–M4, roadmap.md uses `**Done (observable):**` bullets. These describe the *success criterion* for each milestone, not an achieved state. The authoritative status is in `connection-gate-findings.md` (M2 attempts failed; M3/M4 never started). The roadmap has not been updated to reflect M2 failure. + +### M4 is the first hard wall in detail + +Even assuming M2 is solved, M4 requires three unconfirmed things simultaneously: +1. **Fire2 framing** — the 12-byte header layout is assumed; if FIFA 23 uses an older Fire variant or a custom delta, the codec will misparse every packet. +2. **ProtoSSL recv-injection** — delivering responses to the game via recv hook requires knowing what return values and buffer conventions ProtoSSL expects; recv_hook.rs exists but is not installed. +3. **Blaze component/command IDs** — the dispatch table is entirely empty; we cannot answer any request until IDs are known from captures. + +All three are resolved by getting one real captured frame. M4 is primarily a capture problem, not a decoding problem — once bytes exist, the framing and IDs are immediately readable. + +--- + +## 3. Blockers, Risks, Unknowns + +### Blockers (stop progress now) + +1. **ONLINE_STATUS_EVENT push not synthesized** *(M2 wall)* + The game calls GoOnline, gets success, then waits indefinitely for a push event on the LSX socket that never arrives. This is the single gate blocking all Blaze work. Options: (a) trace the event format via Ghidra on FIFA23.exe (xref `ONLINE_STATUS_EVENT` string + the game's EbisuSDK listener), (b) RE anadius's LSX event-send path (find what it would push in an "online" scenario), (c) brute-force push candidate event XMLs and observe whether the game advances. + +2. **Bridge LSX server delivery unconfirmed** *(architectural risk converted to blocker)* + The hook passes port 3216 connections through, assuming the bridge LSX server on the Linux host receives them. If anadius's in-process hooks intercept the winsock calls before they reach the TCP stack, the bridge server is never reached. This must be confirmed by checking `openfut_hook.log` for a getaddrinfo on the LSX host, or by observing the bridge server's accept logs. + +### Risks (could derail later) + +3. **Fire2 framing wrong** *(M4 risk)* + If FIFA 23 uses Fire (pre-2012) or a modified frame layout, the codec misparses. Mitigation: the server has a `Raw` fallback mode for capturing raw bytes when framing fails. + +4. **Secondary auth-token gate** *(M5 risk)* + `connection-gate-findings.md` noted the redirector request carries an `Authorization:` header. M1's final conclusion said `GetAuthCode` returns a fake token that appears accepted — but this was inferred, not confirmed by seeing the redirector request actually constructed with that token. + +5. **EAAC not fully neutralized** *(persistent risk)* + `FakeEAACLauncher` bypasses the anticheat launcher. The hook DLL is unsigned. If EAAC is ever active (e.g., after a game update re-enables it), all hooks fail silently. Marked as "not active in offline/cracked builds" — assumed, not confirmed on every launch. + +6. **FUT REST response shapes wrong** *(M6 risk)* + The 61 endpoint mappings in mapper.rs and the shaper stubs in shaper.rs are based on community guesses about older FIFA FUT APIs, not FIFA 23 captures. Response JSON shapes may differ enough to cause the client to fail silently or crash. + +### Unknowns (open questions) + +7. **ONLINE_STATUS_EVENT XML format** — exact tag names, field order, sender attribute, and any nonces/tokens required. +8. **GoOnline event sequence** — whether ONLINE_STATUS_EVENT alone is sufficient or a sequence of events (e.g., PROFILE_EVENT, LOGIN_EVENT, COMMERCE_EVENT) is expected. +9. **Whether FLE exposes FUT DB tables** — FUT card inventory and squad data likely live server-side in online mode; FLE may not surface them for in-process editing. +10. **Blaze component/command IDs for FIFA 23** — entirely unknown; no captures. +11. **openfut_hook.log current content** — we have the code but no log output in any document. Whether the current hook (with connect, ssl_patch, tls_bypass, WSAIoctl, origin_spy all installed) fires correctly and what it observes is unverified in this review. + +--- + +## 4. Track Comparison + +### Track A — Full EA-backend fake (M1–M7, playable FUT vs AI) + +**What it delivers:** The FIFA 23 FUT hub loads from OpenFUT Core; Squad Battles matches play and reward economy items. + +**Effort:** Research-grade. Minimum path: synthesize ONLINE_STATUS_EVENT (unknown format, 1–2 weeks of RE), then capture Fire2 frames (days once M2 is solved), then implement Blaze auth handlers (weeks), then implement FUT entry (weeks), then Squad Battles (weeks). Realistic minimum: 3–6 months of expert RE work. + +**Proven support:** Hook loads and redirects correctly. TLS bypass patched. Core economy backend complete. Blaze framing code and TLS listener exist. + +**Assumed:** Fire2 framing correct; component/command IDs discoverable from captures; FUT REST shapes close enough to community guesses; no additional undiscovered gates. + +**Evidence for:** Architecture is coherent. The M1 finding (gate precisely named and decoded) was achieved cleanly. The in-process hook approach is validated. + +**Evidence against:** M2 was attempted and failed with the in-process approach. The event-driven architecture adds a full EbisuSDK emulation layer before even one Blaze byte is seen. The live toolkit is exhausted (Path A verdict); Ghidra-level work on a 505 MB binary is required. Six capture files with zero bytes. + +--- + +### Track B — Clean-room spec deliverable (M1–M5 documented) + +**What it delivers:** A documented map of the connection gate, LSX event sequence, Blaze auth surface (transport, framing, gate conditions, component IDs, TDF schemas). Valuable as an archival/community artifact even if Track A stalls. + +**Effort:** Medium. M1 is done. M2–M5 documentation emerges as a by-product of engineering work. The spec itself (writing) is lightweight; the engineering to produce the captures is the cost. + +**Proven support:** M1 complete and documented. connection-gate-findings.md is already a high-quality spec artifact. + +**Assumed:** Same as Track A for the unconfirmed values, but the spec can mark them `TODO/CONFIRM` rather than needing to implement them. + +**Evidence for:** The clean-room constraint means a spec is the only artifact that can be safely published. connection-gate-findings.md shows this approach produces real value. B finishes even if A is never fully playable. + +**Evidence against:** Track B alone doesn't produce a playable FUT; it is a foundation, not an end-user product. + +--- + +### Track C — FLE Lua bridge (local-match path, skip the backend gate) + +**What it delivers:** FIFA 23 career mode or Kick-Off with an OpenFUT club's players and squad loaded via FLE's in-memory DB API. No online gate, no Blaze, no TLS. Fully offline from day one. + +**Effort:** Low-to-medium. FLE is already loaded in the normal launch path. Tools exist (`tools/squad-exporter/`, `tools/profile-exporter/`). Primary unknown is whether FUT-relevant DB tables are accessible. + +**Proven support:** FLE Lua API exposes `GetDBTableRows` / `EditDBTableField` for career mode. `fifa23-startup-flow.md` confirms FLE injects at load. `fut-integration-options.md` documents the integration path in detail and rates this as the recommended option. + +**Assumed:** FUT card/club/squad data has in-memory DB table representations that FLE can write. If FUT data is purely server-side (loaded from EA servers, not from the Frostbite DB layer), Track C produces no FUT simulation at all — only career mode player stats. + +**Evidence for:** Career mode already works with FLE edits (community precedent). Tools are present and designed for this path. No infrastructure work needed. + +**Evidence against:** FUT in FIFA 23 uses server-side data. The cards in a player's FUT club, the coins, the squad — these are fetched from `fut.ea.com` REST APIs, not from the Frostbite embedded DB. FLE's `GetDBTableRows` likely exposes base player stats tables but not FUT item tables. The crucial test (run `export_squad.lua` while in FUT mode) has never been done. + +--- + +### Recommendation + +**Start Track C immediately as a parallel, low-cost validation.** + +Run `export_squad.lua` in FLE while inside the FUT hub (or attempting to enter it). If FUT tables appear in the export, Track C is viable and is the fastest path to something a user can interact with. This test takes one session and costs nothing. + +Simultaneously, **continue Track A/B with the next concrete RE step:** synthesize the ONLINE_STATUS_EVENT push. The most actionable option is to run `origin_spy` logs from the current hook to see what LSX events fire during a session, then attempt to push candidate event XMLs via the bridge LSX server and watch whether the game advances. This is bounded, testable work that either unblocks M2 or produces the spec value for Track B. + +**Do not abandon Track A/B for Track C** — they are complementary. Core is already built; the bridge is mostly built. The gap is purely the RE wall at M2. + +--- + +## 5. Architecture and Provenance Sanity-Check + +### Hook + Brain coherence + +The CLAUDE.md bridge architecture diagram (hook intercepts ProtoSSL → plain localhost TCP → blaze_brain → Core) remains coherent. The M1/M2 findings revealed one additional layer (EbisuSDK LSX event) that must precede the Blaze connection. The bridge has been updated to handle LSX directly. The overall design is sound; the M2 blocker is an implementation gap (event synthesis), not an architectural flaw. + +**One inconsistency to flag:** The hook's `lsx.rs` contains a complete in-process LSX emulator (AES-128-ECB, CRandom, all response builders), but the recv/send hooks that activate it are explicitly removed (`lib.rs`: "recv/send hooks removed — LSX is now handled by the native openfut-bridge LSX server"). This is dead code. The bridge's LSX server is the current path. The in-process lsx.rs should either be deleted or documented as a fallback; its presence is confusing. + +### Clean-room status + +No evidence of EA leaked source anywhere in the tree. All RE work is derived from: +- Running the shipping binary and observing behavior (function return values, network traffic patterns) +- Memory scanning of the live process (string search, xref, disasm of observed addresses) +- Reading anadius's own compiled output (its exported symbols, its LSX XML format — which is anadius's own implementation, not EA's) +- Community FUT API knowledge (mapper.rs endpoint paths — plausible but speculative) + +The Blaze framing in `fifa-blaze/crates/blaze-proto/src/frame.rs` cites "Fire2 used by ME3, BF3, and most post-2012 titles" — this is sourced from public community documentation of those older titles, not from any leaked EA source. **Clean-room intact.** + +The `AES_KEY` in the hook's lsx.rs (`[0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15]`) is a placeholder key used for the LSX session encryption. The real session key is derived from the challenge seed via CRandom — this algorithm was RE'd from anadius's own binary. No EA source required. + +--- + +## 6. If You Read Only This + +- **The project is blocked at M2.** FIFA 23 submits `GoOnline`, gets success, then waits for an async `ONLINE_STATUS_EVENT` push on the LSX socket that no current code ever sends. All six Blaze capture files are empty (0 bytes). No Fire2 frame has ever been decoded. + +- **M1 is the only completed milestone.** The gate function (`GetInternetConnectedState @ anadius64.dll+0x27790`) is precisely named and its two-flag branch decoded. Everything after M1 is either blocked or not started. + +- **The next concrete action** is synthesizing the ONLINE_STATUS_EVENT push XML and testing whether the bridge's LSX server can deliver it to the game. This is the single thing that unblocks all Blaze work. + +- **Track C (FLE Lua) is untested but cheap to validate.** Run `export_squad.lua` while in FUT to find out if FUT DB tables are accessible. If yes, it is the fastest path to user-visible results. If no, it is ruled out with one session. + +- **openfut-core is complete and ready** — 25 phases, 15 migrations, full economy REST API, passing tests. It is not blocking anything; it is waiting for the bridge to connect to it. diff --git a/docs/track-c-fut-table-test.md b/docs/track-c-fut-table-test.md new file mode 100644 index 0000000..c8511de --- /dev/null +++ b/docs/track-c-fut-table-test.md @@ -0,0 +1,93 @@ +# Track C — FUT DB table viability test + +**Status: PENDING — test has not yet been run.** + +## What this test settles + +Track C ("FLE Lua bridge") would inject OpenFUT club data directly into FIFA 23's +in-memory Frostbite DB tables at runtime, bypassing the entire backend/Blaze stack. +It is only viable for FUT (not just career mode) if FUT-specific tables — card +inventory, squad composition with FUT fields, coins — are accessible in memory when +the game is in the FUT area. + +FUT data in online mode is fetched server-side from `fut.ea.com`. It is not known +whether FIFA 23 mirrors any of this into the Frostbite in-memory DB that FLE +can read/write. This test settles that question directly. + +## Test procedure + +**Prerequisites:** +- FIFA 23 launched normally via umu-run/Steam +- FLE (FIFA Live Editor) injected and active (normal launch path) +- EAAC in offline/neutralized state +- Game navigated as deep into FUT as possible (FUT hub if reachable; otherwise the + furthest FUT screen before the gate blocks it) + +**Run the exporter:** +1. In FLE's Lua Engine, open and run `tools/squad-exporter/export_squad.lua` + (full path on the Windows side: `C:\\openfut_squad_export.json`) +2. Wait for the MessageBox "Done! N players, M teams." or "ERROR writing..." +3. Retrieve the output file from the Wine prefix: + `~/Games/umu/fifa23-tools/drive_c/FIFA 23 Live Editor/openfut_squad_export.json` + (or wherever `C:\FIFA 23 Live Editor\` maps in the active prefix) + +**What to inspect in the output:** +- `all_db_tables` array — the complete list of table names visible to FLE right now +- `fut_tables` object — any table whose name contains `fut`, `club`, `pack`, `item`, or + `market` (the script auto-extracts these) +- `is_career_mode` — confirms whether FUT or career mode was active + +## Classification criteria + +### "FUT tables present" + +`fut_tables` is non-empty AND contains FUT-specific fields beyond base player stats: +- e.g., `fut_items` with card-type / rating / chemistry fields +- e.g., a squad table with FUT formation / chemistry / loan-flag fields +- e.g., a coins or points balance field + +**Verdict:** Track C is viable for FUT. Fastest path to user-visible results. + +### "only base player tables" + +`fut_tables` is empty (no `fut_*` / `club_*` / `item_*` / `market_*` table names found +in `all_db_tables`), OR those tables exist but contain only base player attributes +(OVR, potential, position, pace, …) — the same fields visible in career mode. + +**Verdict:** Track C cannot produce FUT. It could at most provide a custom Kick-Off or +career-mode match with players sourced from OpenFUT Core. FUT items and coins exist +only on EA's servers (not in the in-memory DB in offline mode). + +### "FUT area unreachable to test" + +The connection gate blocked entering FUT deeply enough for FUT tables to be populated. +Record which tables were visible and at what screen the test was run. + +**Verdict:** Retest after M2 is unblocked, OR test with `TLS_ENABLED=false` bridge +handling the entry check stub. + +## Results + +*(To be filled in after the test is run.)* + +| Field | Value | +|---|---| +| Date run | — | +| FIFA screen at test time | — | +| `is_career_mode` | — | +| Total tables in `all_db_tables` | — | +| FUT-specific table names found | — | +| Key FUT fields present | — | +| **Classification** | **PENDING** | + +## Honest prior + +`fut-integration-options.md` rates this as the recommended path and lists `fut_clubs`, +`fut_items`, `fut_squads` as "expected" tables. However those expectations are based on +analogy with career mode (which does store club/squad in the DB). FUT's data model is +architecturally different — it is account-bound server-side. The expectation may be +wrong. This test is the oracle. + +The `export_squad.lua` script checks `GetDBTablesNames()` exhaustively (not just +assumed names), so it will surface any FUT tables that actually exist, regardless of +what name they use. diff --git a/tools/file-watch-diff/snapshots/baseline.txt b/tools/file-watch-diff/snapshots/baseline.txt new file mode 100644 index 0000000..0db19d6 --- /dev/null +++ b/tools/file-watch-diff/snapshots/baseline.txt @@ -0,0 +1,115 @@ +# snapshot: baseline 2026-06-26T21:44:51Z +2023-06-02 22:13:13 280984156 /mnt/games/FIFA 23/Patch/Win32/superbundlelayout/fifa_commentaryfull_eng_us_ds/cas_02.cas +2023-06-02 22:13:13 52532092 /mnt/games/FIFA 23/Patch/Win32/superbundlelayout/fifa_commentaryfull_eng_us_ds/cas_03.cas +2023-06-02 22:20:08 768293618 /mnt/games/FIFA 23/Patch/Win32/superbundlelayout/fifa_installpackage_07/cas_02.cas +2023-06-02 22:20:18 728251988 /mnt/games/FIFA 23/Patch/Win32/superbundlelayout/fifa_installpackage_07/cas_03.cas +2023-06-02 22:20:37 1074835 /mnt/games/FIFA 23/Patch/Win32/superbundlelayout/fifa_commentarylaunch_spa_es/cas_01.cas +2023-06-02 22:20:37 1471597 /mnt/games/FIFA 23/Patch/Win32/superbundlelayout/fifa_commentarylaunch_ita_it/cas_01.cas +2023-06-02 22:20:37 1670951 /mnt/games/FIFA 23/Patch/Win32/superbundlelayout/fifa_commentarylaunch_spa_mx/cas_01.cas +2023-06-02 22:20:37 2184167 /mnt/games/FIFA 23/Patch/Win32/superbundlelayout/fifa_commentarylaunch_rus_ru/cas_01.cas +2023-06-02 22:20:37 2750298 /mnt/games/FIFA 23/Patch/Win32/superbundlelayout/fifa_commentarylaunch_ger_de/cas_01.cas +2023-06-02 22:20:37 275617825 /mnt/games/FIFA 23/Patch/Win32/superbundlelayout/fifa_commentaryfull_eng_us_ds/cas_01.cas +2023-06-02 22:20:37 34794805 /mnt/games/FIFA 23/Patch/Win32/superbundlelayout/fifa_commentarylaunch_jpn_jp/cas_01.cas +2023-06-02 22:20:37 5583406 /mnt/games/FIFA 23/Patch/Win32/superbundlelayout/fifa_commentarylaunch_eng_us_ds/cas_01.cas +2023-06-02 22:20:37 976736 /mnt/games/FIFA 23/Patch/Win32/superbundlelayout/fifa_commentarylaunch_chs_cn/cas_01.cas +2023-06-02 22:20:38 5481 /mnt/games/FIFA 23/Patch/Win32/superbundlelayout/fifa_installpackage_04/cas_01.cas +2023-06-03 00:25:53 11768 /mnt/games/FIFA 23/Patch/Win32/commentarywc_fre_fr.toc +2023-06-03 00:25:53 1224 /mnt/games/FIFA 23/Patch/Win32/chants_install.toc +2023-06-03 00:25:53 125583 /mnt/games/FIFA 23/Patch/initfs_Win32 +2023-06-03 00:25:53 12570 /mnt/games/FIFA 23/Patch/Win32/commentarywc_ita_it.toc +2023-06-03 00:25:53 12624 /mnt/games/FIFA 23/Patch/Win32/commentarywc_chs_cn.toc +2023-06-03 00:25:53 12624 /mnt/games/FIFA 23/Patch/Win32/commentarywc_dut_nl.toc +2023-06-03 00:25:53 12624 /mnt/games/FIFA 23/Patch/Win32/commentarywc_por_br.toc +2023-06-03 00:25:53 12624 /mnt/games/FIFA 23/Patch/Win32/commentarywc_rus_ru.toc +2023-06-03 00:25:53 12632 /mnt/games/FIFA 23/Patch/Win32/commentarywc_ger_de.toc +2023-06-03 00:25:53 12678 /mnt/games/FIFA 23/Patch/Win32/commentarywc_ara_sa.toc +2023-06-03 00:25:53 12678 /mnt/games/FIFA 23/Patch/Win32/commentarywc_pol_pl.toc +2023-06-03 00:25:53 12678 /mnt/games/FIFA 23/Patch/Win32/commentarywc_spa_es.toc +2023-06-03 00:25:53 12686 /mnt/games/FIFA 23/Patch/Win32/commentarywc_spa_mx.toc +2023-06-03 00:25:53 12796 /mnt/games/FIFA 23/Patch/Win32/commentarylaunch_chs_cn.toc +2023-06-03 00:25:53 14470 /mnt/games/FIFA 23/Patch/Win32/commentarylaunch_spa_es.toc +2023-06-03 00:25:53 16044 /mnt/games/FIFA 23/Patch/Win32/commentarylaunch_spa_mx.toc +2023-06-03 00:25:53 16440 /mnt/games/FIFA 23/Patch/Win32/commentarylaunch_ger_de.toc +2023-06-03 00:25:53 17494 /mnt/games/FIFA 23/Patch/Win32/commentarylaunch_ita_it.toc +2023-06-03 00:25:53 17890 /mnt/games/FIFA 23/Patch/Win32/commentarylaunch_rus_ru.toc +2023-06-03 00:25:53 22910 /mnt/games/FIFA 23/Patch/Win32/commentarylaunch_jpn_jp.toc +2023-06-03 00:25:53 24752 /mnt/games/FIFA 23/Patch/Win32/commentarylaunch_eng_us_ds.toc +2023-06-03 00:25:53 2966 /mnt/games/FIFA 23/Patch/Win32/commentarywc_eng_us_ds.toc +2023-06-03 00:25:53 45092 /mnt/games/FIFA 23/Patch/Win32/commentaryfull_fre_fr.toc +2023-06-03 00:25:53 46980 /mnt/games/FIFA 23/Patch/Win32/commentaryfull_eng_us_ds.toc +2023-06-03 00:25:53 49502 /mnt/games/FIFA 23/Patch/Win32/commentaryfull_pol_pl.toc +2023-06-03 00:25:53 53840 /mnt/games/FIFA 23/Patch/Win32/commentaryfull_ita_it.toc +2023-06-03 00:25:53 59752 /mnt/games/FIFA 23/Patch/Win32/commentaryfull_jpn_jp.toc +2023-06-03 00:25:53 59878 /mnt/games/FIFA 23/Patch/Win32/commentaryfull_ger_de.toc +2023-06-03 00:25:53 59878 /mnt/games/FIFA 23/Patch/Win32/commentaryfull_spa_mx.toc +2023-06-03 00:25:53 61238 /mnt/games/FIFA 23/Patch/Win32/commentaryfull_rus_ru.toc +2023-06-03 00:25:53 61940 /mnt/games/FIFA 23/Patch/Win32/commentaryfull_por_br.toc +2023-06-03 00:25:53 63236 /mnt/games/FIFA 23/Patch/Win32/commentaryfull_chs_cn.toc +2023-06-03 00:25:53 63236 /mnt/games/FIFA 23/Patch/Win32/commentaryfull_spa_es.toc +2023-06-03 00:25:53 64802 /mnt/games/FIFA 23/Patch/Win32/commentaryfull_ara_sa.toc +2023-06-03 00:25:53 65224 /mnt/games/FIFA 23/Patch/Win32/commentaryfull_dut_nl.toc +2023-06-03 00:25:53 928 /mnt/games/FIFA 23/Patch/Win32/commentarywc_jpn_jp.toc +2023-08-22 15:21:19 110383 /mnt/games/FIFA 23/Patch/layout.toc +2023-08-22 15:21:19 1818 /mnt/games/FIFA 23/Patch/Win32/chants_full.toc +2023-08-22 15:21:19 2321 /mnt/games/FIFA 23/Patch/Win32/matchcinematicssba.toc +2023-08-22 15:21:19 263983 /mnt/games/FIFA 23/Patch/Win32/storycharsb.toc +2023-08-22 15:21:20 129098 /mnt/games/FIFA 23/Patch/Win32/careermodestorysba.toc +2023-08-22 15:21:20 1459 /mnt/games/FIFA 23/Patch/Win32/storyingamesba.toc +2023-08-22 15:21:20 1520 /mnt/games/FIFA 23/Patch/Win32/streaminginstallcinematicsbundle.toc +2023-08-22 15:21:20 1695 /mnt/games/FIFA 23/Patch/Win32/globalswc.toc +2023-08-22 15:21:20 1894949 /mnt/games/FIFA 23/Patch/Win32/contentlaunchsb.toc +2023-08-22 15:21:20 191908 /mnt/games/FIFA 23/Patch/Win32/worldcupsb.toc +2023-08-22 15:21:20 3052093 /mnt/games/FIFA 23/Patch/Win32/worldssb.toc +2023-08-22 15:21:20 3788 /mnt/games/FIFA 23/Patch/Win32/futsb.toc +2023-08-22 15:21:20 440453 /mnt/games/FIFA 23/Patch/Win32/presprematchsba.toc +2023-08-22 15:21:20 4886 /mnt/games/FIFA 23/Patch/Win32/presentationsb.toc +2023-08-22 15:21:20 531911 /mnt/games/FIFA 23/Patch/Win32/globalsfull.toc +2023-08-22 15:21:20 548511 /mnt/games/FIFA 23/Patch/Win32/careersba.toc +2023-08-22 15:21:20 7271 /mnt/games/FIFA 23/Patch/Win32/marketingsba.toc +2023-08-22 15:21:20 7360676 /mnt/games/FIFA 23/Patch/Win32/contentsb.toc +2023-08-22 15:21:21 24476 /mnt/games/FIFA 23/Patch/Win32/choreosb.toc +2023-08-22 15:21:21 268514476 /mnt/games/FIFA 23/Patch/Win32/superbundlelayout/fifa_installpackage_06/cas_07.cas +2023-08-22 15:21:21 58624 /mnt/games/FIFA 23/Patch/Win32/storysba.toc +2023-08-22 15:21:21 6144 /mnt/games/FIFA 23/Patch/Win32/superbundlelayout/fifa_installpackage_01/cas_01.cas +2023-08-22 15:21:21 760492 /mnt/games/FIFA 23/Patch/Win32/globals.toc +2023-08-22 15:21:23 103085062 /mnt/games/FIFA 23/Patch/Win32/superbundlelayout/fifa_installpackage_06/cas_09.cas +2023-08-22 15:21:23 268483345 /mnt/games/FIFA 23/Patch/Win32/superbundlelayout/fifa_installpackage_06/cas_05.cas +2023-08-22 15:21:24 268448487 /mnt/games/FIFA 23/Patch/Win32/superbundlelayout/fifa_installpackage_06/cas_08.cas +2023-08-22 15:21:24 268563472 /mnt/games/FIFA 23/Patch/Win32/superbundlelayout/fifa_installpackage_06/cas_02.cas +2023-08-22 15:21:26 268663563 /mnt/games/FIFA 23/Patch/Win32/superbundlelayout/fifa_installpackage_06/cas_03.cas +2023-08-22 15:21:27 268440522 /mnt/games/FIFA 23/Patch/Win32/superbundlelayout/fifa_installpackage_06/cas_04.cas +2023-08-22 15:21:28 268597122 /mnt/games/FIFA 23/Patch/Win32/superbundlelayout/fifa_installpackage_06/cas_01.cas +2023-08-22 15:21:29 268587757 /mnt/games/FIFA 23/Patch/Win32/superbundlelayout/fifa_installpackage_06/cas_06.cas +2023-08-22 15:21:30 234374397 /mnt/games/FIFA 23/Patch/Win32/superbundlelayout/fifa_installpackage_02/cas_02.cas +2023-08-22 15:21:31 410809408 /mnt/games/FIFA 23/Patch/Win32/superbundlelayout/fifa_installpackage_02/cas_01.cas +2023-08-22 15:21:33 491728234 /mnt/games/FIFA 23/Patch/Win32/superbundlelayout/fifa_installpackage_08/cas_01.cas +2023-08-22 15:21:36 287271203 /mnt/games/FIFA 23/Patch/Win32/superbundlelayout/fifa_installpackage_05/cas_02.cas +2023-08-22 15:21:37 268438709 /mnt/games/FIFA 23/Patch/Win32/superbundlelayout/fifa_installpackage_05/cas_01.cas +2023-08-22 15:21:38 271000144 /mnt/games/FIFA 23/Patch/Win32/superbundlelayout/fifa_installpackage_05/cas_03.cas +2023-08-22 15:21:44 236583358 /mnt/games/FIFA 23/Patch/Win32/superbundlelayout/fifa_installpackage_05/cas_04.cas +2023-08-22 15:21:46 492908031 /mnt/games/FIFA 23/Patch/Win32/superbundlelayout/fifa_installpackage_07/cas_01.cas +2023-08-22 15:21:52 270993339 /mnt/games/FIFA 23/Patch/Win32/superbundlelayout/fifa_installpackage_00/cas_04.cas +2023-08-22 15:21:58 273177012 /mnt/games/FIFA 23/Patch/Win32/superbundlelayout/fifa_installpackage_00/cas_03.cas +2023-08-22 15:22:02 99254970 /mnt/games/FIFA 23/Patch/Win32/superbundlelayout/fifa_installpackage_00/cas_06.cas +2023-08-22 15:22:05 270041465 /mnt/games/FIFA 23/Patch/Win32/superbundlelayout/fifa_installpackage_00/cas_01.cas +2023-08-22 15:22:12 268490780 /mnt/games/FIFA 23/Patch/Win32/superbundlelayout/fifa_installpackage_00/cas_02.cas +2023-08-22 15:22:18 295744650 /mnt/games/FIFA 23/Patch/Win32/superbundlelayout/fifa_installpackage_00/cas_05.cas +2023-08-22 15:22:19 270176162 /mnt/games/FIFA 23/Patch/Win32/superbundlelayout/fifa_installpackage_03/cas_01.cas +2023-08-22 15:22:20 118305 /mnt/games/FIFA 23/Patch/Win32/fifa/fifagame/fifagame.toc +2023-08-22 15:22:20 180049441 /mnt/games/FIFA 23/Patch/Win32/superbundlelayout/fifa_installpackage_03/cas_02.cas +2026-06-23 15:41:54 1536026 /home/alex/.local/share/Steam/steamapps/compatdata/3887260930/pfx/drive_c/users/steamuser/Documents/FIFA 23/settings/ProfileOptions +2026-06-23 15:41:54 1 /home/alex/.local/share/Steam/steamapps/compatdata/3887260930/pfx/drive_c/users/steamuser/Documents/FIFA 23/settings/ProfileOptions_profile +2026-06-23 15:42:00 0 /home/alex/.local/share/Steam/steamapps/compatdata/3887260930/pfx/drive_c/users/steamuser/Documents/FIFA 23/filesystemcache/survey.state +2026-06-23 15:48:11 16272228 /home/alex/.local/share/Steam/steamapps/compatdata/3887260930/pfx/drive_c/users/steamuser/Documents/FIFA 23/settings/Career20260623154811 +2026-06-24 17:06:53 749 /home/alex/.local/share/Steam/steamapps/compatdata/3887260930/pfx/drive_c/users/steamuser/Documents/FIFA 23/settings/overrideAutodetect.lua +2026-06-24 17:07:05 304 /home/alex/.local/share/Steam/steamapps/compatdata/3887260930/pfx/drive_c/users/steamuser/Documents/FIFA 23/fifasetup.ini +2026-06-24 17:16:24 16272228 /home/alex/.local/share/Steam/steamapps/compatdata/3887260930/pfx/drive_c/users/steamuser/Documents/FIFA 23/settings/Career20260624171624A +2026-06-24 17:16:39 16272228 /home/alex/.local/share/Steam/steamapps/compatdata/3887260930/pfx/drive_c/users/steamuser/Documents/FIFA 23/settings/Career20260624171639A +2026-06-24 17:33:42 515334 /home/alex/.local/share/Steam/steamapps/compatdata/3887260930/pfx/drive_c/users/steamuser/Documents/FIFA 23/settings/Settings20260624173342 +2026-06-24 17:33:43 16272228 /home/alex/.local/share/Steam/steamapps/compatdata/3887260930/pfx/drive_c/users/steamuser/Documents/FIFA 23/settings/Career20260624173343A +2026-06-24 17:44:25 189 /home/alex/.local/share/Steam/steamapps/compatdata/3887260930/pfx/drive_c/users/steamuser/Documents/FIFA 23/filesystemcache/atlPlayTimeJson/playtime_2143594531.json +2026-06-24 19:35:05 8499 /mnt/games/FIFA 23/Logs/log_launcher_24-06-2026.txt +2026-06-25 19:26:02 45957 /mnt/games/FIFA 23/Logs/log_launcher_25-06-2026.txt +2026-06-25 19:26:24 49997 /mnt/games/FIFA 23/Logs/log_25-06-2026.txt +2026-06-26 14:38:44 251783 /mnt/games/FIFA 23/Logs/log_launcher_26-06-2026.txt +2026-06-26 14:38:59 281281 /mnt/games/FIFA 23/Logs/log_26-06-2026.txt diff --git a/tools/file-watch-diff/watch.sh b/tools/file-watch-diff/watch.sh new file mode 100755 index 0000000..28b0d4e --- /dev/null +++ b/tools/file-watch-diff/watch.sh @@ -0,0 +1,112 @@ +#!/usr/bin/env bash +# file-watch-diff/watch.sh +# Snapshots FIFA 23 local file state and diffs it between labelled game phases. +# Usage: watch.sh snapshot