Files
OpenFUT/docs/foundational-xi-injection-test.md
funman300 1fb664710a 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.
2026-06-30 13:19:27 -07:00

8.4 KiB
Raw Permalink Blame History

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 LineupData → 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_<timestamp>.json. Note this filename — this is your before snapshot.

  2. Without restarting or reloading, repeat the Formation Editor steps from Phase 1 (steps 26 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:

    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:

    {
      "team_id": 12345,
      "xi": [
        { "player_id": 111111, "position": 0 },
        { "player_id": 222222, "position": 5 }
      ]
    }
    

    Use 11 entries. Position codes are confirmed numeric 027 (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