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.
8.4 KiB
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.luaoutput,playeridfield) 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.
- Open the Live Editor overlay (F9, or
Windows → Settingsfrom the overlay's own menu bar if the hotkey isn't registering — see the umu/Wine hotkey note below). Features → Teams→ find your team →Edit.Team → Formationto open the Formation Editor.- 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).
- Tick Freeze Lineup.
Data → Save.- 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.
-
In FLE's Lua Engine, run
tools/squad-injector/snapshot_lineup_tables.lua. This dumps every DB table whose name containssquad,lineup,formation,tactic,teamsheet,selection,players, orteamstoC:\FIFA 23 Live Editor\openfut_snapshot_<timestamp>.json. Note this filename — this is your before snapshot. -
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. -
Run
snapshot_lineup_tables.luaagain. This is your after snapshot. -
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:python3 tools/squad-injector/diff_snapshots.py before.json after.json -
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
-
Open
tools/squad-injector/apply_lineup_write.luaand fill inTARGET_TABLEandTARGET_FIELDSusing Phase 2's diff output. -
Edit
C:\FIFA 23 Live Editor\openfut_test_xi.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) — fromlua/scripts/export_season_stats.lua'sget_pos_nametable in FLE's own repo, not a guess. -
Run
apply_lineup_write.luafrom FLE's Lua Engine. -
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 |