docs: add FLE bridge direction pivot and squad-injection test tooling
Adds the app-centric FLE bridge direction (direction.md) replacing the Blaze-backend route as primary plan, plus a corrected foundational test procedure and snapshot/diff/apply tooling for reverse-engineering FLE's Freeze Lineup write mechanism. Also picks up prior untracked research docs (status-review, fut-integration-options, fifa23-startup-flow, track-c) and existing capture/export tooling that hadn't been committed yet.
This commit is contained in:
@@ -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.
|
||||
Reference in New Issue
Block a user