Squad planner findings: 4 season runs of 27 position slots in the "humans" section

Open
#77 1 comment 0 reactions 0 assignees View on GitHub

Maintainers usually reply within 1 day

Nobody has claimed this yet.

Assessment

Difficulty
5/5
Estimated time
Over a week
Newbie friendliness
35/100
Issue type
Feature
Clarity
Mostly clear
Activity status
Active
Tech stack
python
Domain
data

Research direction

Start by reading the existing humans section reader and the save parsing entry points; the issue does not name their files. Use the documented run layout and controlled observations to decide whether and how to expose planner records in the parsed output. Done means the four runs and their 27 slots can be read without losing empty slot indices, with player IDs resolved safely; run 4 semantics and several slot mappings remain open.

Written by the indexing model from the issue text.

Description

What this is

Format findings for FM27's in-game squad planner (the per-position depth columns on the squad screen), collected from my own career saves by controlled in-game experiments and the planner UI - no decompilation, no third-party parsers. Inside fmsave, planner data is the one part of the humans section there is no reader for, so here is what my tooling observed, in case it is useful for a reader.

Checked on FM27 builds 27.0.0+2486695 and 27.0.0+2493426, macOS, single-player career. I can email a controlled save privately if useful.

Location and framing

Per human manager, the humans section holds four planner runs. Each run:

03 1b                       run header (constant across observed saves)
[ n u8 ][ id u32 x n ]      27 slot records, back to back, empties included
1b                          terminator

A record is [count u8][item_id u32 x count], item order = depth order (first item = top choice). An empty slot is a lone 00 byte: a record with count 0. This is not padding - emptying a slot in the planner UI kept the run at 27 records and wrote a 00 exactly at the emptied index, so slot indices stay stable.

The four runs are season sections

The planner UI shows three season sections (current / next / next-next). Controlled edits (game paused, only the planner screen changed, saves otherwise byte-comparable) mapped them:

  • run 1 = current season, the user's assignments (changed by every edit in the current-season view),
  • run 2 = next season: removing one player from the next-season view changed exactly one slot of run 2 (an 8-item list became 00) and nothing else,
  • run 3 = the season after: clearing every position of that view emptied seven run-3 slots,
  • run 4 = all 27 slots 00 in every save observed; semantics unknown.

Future-season runs are seeded by the game with auto depth lists (they include loaned-in and youth players), so they are not empty by default, and clearing the view does not remove the seeded lists - only the user-placed entries.

The 27 slots are a position grid

Enumerated from the keeper upward, right to left within each zone. Labels below are backed by the controlled experiments (GK, ST) and by planner position views whose depth-card lists match slot records exactly in depth order; the planner's position dropdown enumerates the current tactic's positions bottom-up, left to right, matching the save.

slots zone
1 GK
2 ? (always empty in observed saves)
3-7 DR, DC x3 (right/center/left center-backs unsplit), DL
8-12 DM: central trio 9-11; flank cells 8/12 held backup full-backs
13-17 MC: central trio 14-16; flank cells 13/17
18-22 AMR (18), AMC trio (19-21), AML (22)
23-27 ST trio 24-26 (25 = the drag target of the UI), 23/27 always empty

Item ids

item_id = person compact id + 1. A person record in game_db starts with [compact u32][uid u32][uid u32] where the uid pair is equal, so an item resolves to a person by scanning for [compact][uid][uid] and requiring the uid to exist in the players table.

Two traps, both hit in practice:

  • reverse lookup (find the uid pair, read 4 bytes back for the compact id) is not reliable: the same uid pair also appears in non-record positions;
  • the same compact id can prefix more than one person (observed: one compact matched a staff record and a player record) - disambiguate by requiring a player uid.

Open questions

  • slot 2, 23, 27 (always empty; 23/27 are presumably the wide-forward flank cells),
  • which exact cell of an identical trio the tactic's position maps to,
  • run 4's semantics,
  • what 03 in the header encodes (1b = 27 may be the run length).

Happy to share the experiment protocol, screenshots or a save privately.

Dominant language
Python
Stars
28
Forks
8
Avg merge
42m
Merged PRs (30d)
33

Getting set up

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

More from rhiever/fmsave

All issues in rhiever/fmsave

Similar issues

More Python issues

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.