Football Manager internals
How the game stores its data, what its files are, and what its numbers mean. Every app in this documentation links here instead of explaining the game again.
Compiled from the repos in /home/rob/code on 2026-10-14. Most facts come from reverse engineering, not from official documentation, so each one is marked.
How to read this page
Every fact is tagged with how sure we are and which repo found it:
- Confirmed: checked against the game's own source code (we have the FM22 source), against the game's own export, or by testing in the game.
- Likely: fits all the files we have, but nobody has proved it.
- Guess: an inference. Treat it as a lead, not a fact.
"SI" means Sports Interactive, the studio that makes the game. "The FM22 source" is a read-only copy of SI's FM22 code kept at /home/rob/fm/sifiles/dev/fm2022/main. There is no source for any other version, so anything about FM24 or FM26 is deduced from files and from the game's program files.
Game versions
The game is released once a year and named after the year it starts in: FM24 starts in 2023/24 but is named for 2024, and FM26 is the 2026 edition. The repos cover FM18 to FM26, plus an experimental FM27. Files from different versions look similar but are not interchangeable.
Version numbers
Three different numbers are in use and they are easy to mix up.
| Number | Example | Meaning | Source |
|---|---|---|---|
| Build | 2620 | First two digits are the game year, then a major and minor number. 2620 = 26.2.0, 2430 = 24.3.0. It also names the folder of the data shipped with that build. | fm-xml, fm-reader-data (Confirmed) |
| Database version ("DBV") | 3569 (FM24), 3729 / 3733 (FM26 editor files) | A counter that goes up whenever the database layout changes. Editor files carry it as version. | fm-xml (Confirmed for the meaning, values observed in sample files) |
Save db_version | 3569 (FM24), 4000 (FM26) | The same idea, read from inside a .fm save. | fm-reader (Confirmed as observed) |
svvs) to tell games apart, not the database version. FM22 is also given as 2962 to 3006 (fm-xml) and 3035 (fm-reader, a save), which is another unexplained gap.What changes between versions
| Game | Archive version | Compression | Notes |
|---|---|---|---|
| FM18 to FM20 | 7 | zlib | fm-reader, fm-re (Confirmed) |
| FM21 to FM23 | 8 | zstd (a newer, faster compressor) | Each block has a length in front of it. |
| FM24 to FM26 | 8 | zstd | Plain blocks. FM24 and FM26 have the same list of 77 database parts. |
| FM26 | 8 | zstd | The screens are built with Unity (a game toolkit); the match and database engine is still native code. About 4,000 fewer engine classes than FM24 (fm-re, Confirmed). |
| FM27 | - | - | Experimental. Build 2700. Internal research only; the web and desktop readers reject it (fm-reader, Confirmed). |
Platform differences: the Windows game program is heavily protected from FM17 on, so it cannot be inspected. The Mac builds of FM10 to FM19 contain readable function names and are the most useful reference (fm-re, Confirmed). FM26 is a Unity IL2CPP build, which exposes the names and values of every screen-level setting but not the engine's code (fm-re, Confirmed).
Working out which game a file is for
For editor files the best clue is the svvs field, the build the file was last saved in. The order of checks used by fm-xml (Confirmed as a method):
svvssuch as2620: game is FM26.- Otherwise
orvs, the build the file was first made in. - Otherwise
verf, the versions the rules were checked against. - Otherwise guess from the database version.
A file first made in FM24 and re-saved in FM26 has orvs=2430 and svvs=2620. It counts as FM26, because FM26 is the game that loads it.
grep -m3 -E 'id="(svvs|orvs|version)"' "{{FILE}}"
That only works on the XML form of the file. For a .fmf, unpack it first (see The FMF archive format).
File locations
Game data lives in two places: the install folder (read-only, ships with the game) and the user's documents folder (saves, editor files, tactics).
User folders
| What | Windows and Linux (Proton) | Mac |
|---|---|---|
| Saves | Documents/Sports Interactive/Football Manager 2024/games/ | ~/Library/Application Support/Sports Interactive/Football Manager 26/games/ |
| Editor data (updates) | Documents/Sports Interactive/Football Manager 2024/editor data/ | ~/Library/Application Support/Sports Interactive/Football Manager 26/editor data/ |
| Languages | - | .../Football Manager 26/languages/ |
The folder name changed style: FM24 and earlier use the full year ("Football Manager 2024"), the notes for FM26 use "Football Manager 26". Likely (the repos show both spellings and do not state the rule). Tactics also live in the user folder; see Tactics files.
Install folder and the data layers
The game ships its database as numbered layers (fm-reader, database-layering.md, Confirmed for the layout, Likely for loader behaviour in FM24+):
data/database/db/
2600/ base release (26.0.0)
2600_fm/ the .dat database files + 2600_fm.xml manifest
dbc/ binary configuration (licensing, kits, names)
edt/ .edt / .ddt directive files
lnc/ .lnc language and name-change files
2620/ update release (26.2.0)
2620_fm/ full replacements of the .dat files
dbc/ edt/ lnc/
An update layer replaces whole database files; it is not a patch. The base layer carries lang_db.dat (text such as names of competitions); update layers carry lang_update_db.dat instead. Folders ending _fm, _fmc, _fmm are different editions of the same build (Likely: full, classic and mobile; the repos do not spell this out).
Where this server keeps game files
| Path | What |
|---|---|
/home/rob/code/fm-reader-data/games/ | Game installs FM10 to FM26, Windows and Mac. Read-only. |
/home/rob/code/fm-reader-data/dat/ | Just the database files, per game and build. Large files use Git LFS. |
/home/rob/code/fm-reader-data/saves/ | Example saves per version. A validation-json folder holds the game's own JSON export, used only to check our readers, never as an input. |
/home/rob/fm/sifiles/dev/fm2022/main | The FM22 source code (read-only). |
/home/rob/fm/sifiles/mdb/ | 118 old research databases, 2001 to FM2021. See Research databases. |
Save games (.fm)
A save game is a file ending .fm. It is an FMF archive (a container, like a zip) holding several files. The important one is game_db.dat, the whole game world at the moment of saving: about 98 MB (FM18) to 154 MB (FM24) once unpacked (fm-reader, Confirmed).
How a save is read
- Open the FMF archive and read its directory.
- Decompress
game_db.dat. - Read its header to learn the database version.
- Walk the tables one after another (there is no index; each table follows the last) and decode each record.
Fresh and played saves both work, from FM18 to FM26. Everything is checked against the game's JSON export: player and staff ability, reputation, height, weight and all attributes match 100%, club names 99.4% across 26,268 clubs (fm-reader, Confirmed for FM24).
What is and is not in a save
- The save does not contain
lang_db.dat, so the display names of competitions, nations, cities and continents are not in it. They have to come from the base game's database (fm-reader, Confirmed). - The save stores attributes as raw 0 to 100 numbers; the base database stores them already as 1 to 20. See Attributes.
- Saves made by different game versions have different table layouts; the first table (Awards) can only be found automatically in FM24 and FM26 so far (fm-reader, Confirmed).
Size and format by version
| Version | game_db.dat size | Archive | Compression |
|---|---|---|---|
| FM18 | 98.5 MB | 7 | zlib, one block |
| FM19 | 107 MB | 7 | zlib, one block |
| FM20 | 113 MB | 7 | zlib, one block |
| FM21 | 116 MB | 8 | zstd, chunked |
| FM22 | 130 MB | 8 | zstd, chunked |
| FM23 | 137 MB | 8 | zstd, chunked |
| FM24 | 154 MB | 8 | zstd, one block |
| FM26 | 122 MB | 8 | zstd, one block |
Source: fm-reader docs/formats/fm-save/README.md (Confirmed).
Example: list the parts of a save
python3 -I /home/rob/code/fm-re/scripts/fmf_dir.py "$HOME/Documents/Sports Interactive/Football Manager 20{{FM_YEAR}}/games/{{SAVE}}" --counts
The path template is only an example; use your own save location (see File locations).
Reading a running game
fm-reader can also read the game's live memory using a table of offsets per version (fm24.toml and similar). This is the only source for data that has not been saved yet. It is deliberately kept separate from the save and database readers: each reader reports its own gaps and never fills them from another source (fm-reader, Confirmed as project policy).
Editor and update files
The game's Pre-Game Editor lets people change the database before starting a career (move players, change clubs, rewrite competitions). The result is an editor file. Community data updates (for example sortitoutsi.net's yearly updates) are editor files. Three shapes exist and all hold the same content:
| Extension | What it is |
|---|---|
.fmf | An archive holding a .dbc, a thumbnail and a small details file. This is what players download and install. See FMF format. |
.dbc | The compact binary form of the changes ("database content"). |
.xml | The same content as readable text. Lossless both ways. |
Source: fm-xml docs/01 and 07, fmf-archiver docs/src/dbc.md (Confirmed).
What is inside an editor file
One outer record with two kinds of content (fm-xml, Confirmed):
- Header fields: version, author, description, save counter.
- Database changes (
db_changes): a long list; each entry sets one value on one record. Real files hold up to 1.5 million of them. - Sometimes advanced rules (
rule_group): competition and nation rules. See Nation rules.
| Header field | Meaning |
|---|---|
svvs | Build the file was last saved in, e.g. 2620. |
orvs | Build it was first created in. May be empty. |
version | Database version. Only read it at the top level; rule groups inside have their own unrelated version fields. |
verf | Builds the advanced rules were verified against. |
XSvC | Save counter: higher means a newer copy of the same file. |
EdDt, EdBr | Last save date and editor branch (a hint only). |
description, author | Shown in the game. |
Field order differs between files, so tools must look fields up by name. The list of changes can appear anywhere, even after tens of thousands of lines of rules.
A database change
Each change names a table, a record, a property and a new value. The game applies them in list order and a later change to the same field wins. If the record is missing or the value is refused, the change fails silently (written to a log only), so a file alone cannot prove a change worked (fm-xml, Confirmed from FM22 source).
<record>
<integer id="database_table_type" value="1"/> table 1 = person
<integer id="version" value="3729"/>
<large id="db_unique_id" value="421030296890625235"/> person 98028755
<unsigned id="property" value="1348695145"/> 'Pcti' = contracted club
<record id="new_value">
<large id="Ttea" value="1879"/> team 1879 = Trabzonspor
</record>
</record>
That change moves Mohamed Salah to Trabzonspor (fm-xml sample). Special properties ADDR, COPY and DELE create, copy and delete records.
Table types
The table number in each change comes from SI's list of database tables. New types are only added at the end, so numbers stay stable (fm-xml, Confirmed from FM22 source; FM26 files use the same numbers for every type seen).
| No. | Table | No. | Table |
|---|---|---|---|
| 0 | Award | 18 | Derby |
| 1 | Person (player, staff, official) | 19 | Region |
| 2 | City | 21 | Stadium |
| 3 | Club | 23 | Stage name |
| 5 | Continent | 24 | Team |
| 6 | Injury type | 25 | Competition |
| 7 | Media source | 41 | Currency |
| 8 | Language | 47 | Local region |
| 9 | Nation | 12 | Award history row |
.dat files is different and changes by version; see The database.Property codes
A property is named by four letters stored as a number: 1348695145 is the letters P c t i. The first letter usually hints at the owner (P person, C club, S stadium, T team, lower-case c competition, N nation), but a code only has a meaning together with its table. Cnam is "Name" for both clubs and cities (fm-xml, Confirmed).
python3 -c "import sys;n=int(sys.argv[1]);print(n.to_bytes(4,'big').decode())" 1348695145
The FM22 source declares about 13,860 codes; a newer CSV export adds 45 codes FM22 lacks (fm-xml: data_update_fields.csv, 2,667 fields). Human-readable names come from those two sources.
Changing lists
Some properties are lists of rows (a club's league history, a person's second nationalities, kits). A change to these carries an operator (fm-xml docs/05, Confirmed from FM22 source):
lsop | Operation |
|---|---|
| 0 | Add a blank row |
| 1 | Edit one field of a matching row |
| 2 | Delete a matching row |
| 3 | Clear the whole list |
Which file wins
When several editor files change the same field, the one the game applies last wins. How the game orders them (fm-xml docs/10; confirmed from FM22 source and checked in FM26 in game, September 2026):
- It collects loose
.xmlthen.dbcfiles fromeditor data(subfolders included), then from the shared editor data folder, then.fmfarchives (top level of the folder only; each needs a_data/details.aom). - It sorts them by file name without extension, ignoring case, comparing numbers as text (
10sorts before2). For an.fmfthe name that counts is the.dbcinside it, not the.fmfname. Renaming the archive changes nothing. - Files with equal names keep the order they were found in.
To make a file load last, rename the .dbc inside it, not the archive. The skip thresholds for files with too few changes are only known for FM22 (Likely the same later).
Making a smaller copy
A modified copy of an editor file is made by dropping whole change records and copying everything else byte for byte, never by editing values (fm-xml docs/11). Example with fm-xml's command line:
fmx cut "{{FILE}}" --remove 3:Tcap,3:Tvcp -o "smaller.xml"
The pair 3:Tcap means table 3 (club), property Tcap.
The FMF archive format
FMF ("Football Manager File") is SI's own container, like a zip. It is used for editor updates, graphics packs, saves, tactics and the game's own database files. Sources: fmf-archiver docs/src/fmf.md, fm-tactic-reader research/fmf-spec.md (Confirmed from FM22 source and 1,500+ real files), fm-re (Confirmed).
Layout
offset 0 9-byte header format 2, byte order 1 (little-endian), magic "fmf." (or "afe." if encrypted), version 7 or 8
offset 9 17-byte prologue: where the directory is, where file data starts, compression type
offset 26 file data, one block per file
... second header (always "fmf.") then the directory, compressed with zstd (v8) or zip (v7)
- All numbers are little-endian. Strings are a 4-byte length followed by UTF-8 text.
- All offsets are measured from the end of the first header (byte 9), not from the start of the file.
- Compression type: 0 none, 1 zip, 2 lz4, 3 zstd (fm-tactic-reader). fmf-archiver lists a fifth value, a second zstd that may be a stronger level (Guess).
- The directory is compressed according to the archive version, not the compression byte. An archive with "none" still has a zstd directory.
- Database
.datfiles have the same container, with an extra small header in front. Their directory names every part (see Database).
What an editor archive contains
My Update.fmf
Title.dbc the changes (the part you want)
data update.jpg thumbnail
_data/details.aom title, description, tags, owner (add-on metadata)
A saved game contains game_db.dat among others.
The DBC inner format
8-byte header: format 3, little-endian, magic "cbd.", version 6
1 byte: encrypted flag (then a key block if set)
compressed stream (zstd):
summary record (change count, versions, author, description)
rules record (everything except the changes)
change count
one record per change
Every value is typed (null, int, bool, colour, date, list, string and so on) and has a four-letter name. The XML form is a straight text rendering. Reading is supported for format 2 version 5, FM18's version 9998 and format 3 version 6; version 9999 is not supported (fmf-archiver, Confirmed). Writing always produces version 6. A comps.dbc file is a DBC header followed by an embedded FMF archive of about 1,158 smaller rule files (fm-reader, Confirmed).
Packing and unpacking
The tool is fmf_archiver (fmf-archiver repo). Its release build on this server is /home/rob/code/fmf-archiver/target/release/fmf_archiver.
# Unpack an .fmf; each .dbc inside is turned into .xml
/home/rob/code/fmf-archiver/target/release/fmf_archiver unpack "{{FILE}}" "{{OUT}}"
# Convert one .dbc to .xml
/home/rob/code/fmf-archiver/target/release/fmf_archiver unpack changes.dbc "{{OUT}}"
# Pack a folder (or one XML file) into a mod
/home/rob/code/fmf-archiver/target/release/fmf_archiver pack -i ./my_mod -o my_mod.fmf -t "{{TITLE}}" -a "{{AUTHOR}}"
Tips (fm-xml, Confirmed): the tool reads a config.json from the folder you run it in, so run it in an empty folder. An 8 MB .fmf can become a 397 MB XML file, and the whole XML is built in memory. The XML it writes is byte-for-byte what sortitoutsi publishes next to their .fmf files.
Encryption
The only encryption in these formats is AES-128 in counter mode, and it protects nothing from us: the key and the starting value are stored in plain sight in front of each encrypted file (fmf-archiver fmf.md, fm-xml docs/07, fm-tactic-reader fmf-spec.md; Confirmed).
- An encrypted archive has the magic
afe.instead offmf.. That one marker is the only flag; encryption applies to the whole archive, never to single members. - Each encrypted file starts with: key length (always 16), the key, IV length (always 16), the IV, then the data.
- The directory is never encrypted, and its second header still says
fmf.. - FM26 editor saves are encrypted version 8 archives. Encrypted archives are normally not also compressed.
- A
.dbccan have its own encryption flag. The envelope is key length, IV length, key, IV, data (fmf-archiverdbc.md). - FM18
.dbcfiles (version 9998) contain a plain copy of the database followed by an encrypted duplicate of it; the reader checks that the two match (fmf-archiver, Confirmed on 47 shipped files).
The database
The installed game keeps its starting world in several .dat files per build (fm-reader-data README; fm-re fm-dat-archive.md; Confirmed):
| File | Holds |
|---|---|
server_db.dat | The main tables: clubs, competitions, nations, stadiums, cities and many smaller lists. |
people_db.dat | People: names, personality, the 69 playing attributes, 52 staff attributes, contracts. |
basic_people_db.dat | A compact summary per person: ability, wage, value, reputation, nation, club and the id used for linking. |
client_db.dat | Data the game's screens need. |
lang_db.dat / lang_update_db.dat | Text and names (base layer / update layer). |
pl_hist_*, non_pl_hist_* | Playing and non-playing career history. |
summary.dat | Summary information. |
Each is an FMF archive with a directory at the end naming every sub-file (table_<type>, name_table_0, ...). That lets a reader find a table by name instead of guessing its position. Works for FM18 to FM26; all 587 sub-files across eight versions decompress to the size the directory says (fm-re, Confirmed).
python3 -I /home/rob/code/fm-re/scripts/fmf_dir.py /home/rob/code/fm-reader-data/dat/fm{{FM_YEAR}}/{{BUILD}}/{{BUILD}}_fm/server_db.dat --counts
How the table list changed
| Change | First version |
|---|---|
elections sub-file (FM18 and FM19 only) | gone from FM20 |
Newgen parameter tables (table_65 to table_70) | FM20 |
| Old-save copies of competition and stage-name tables | FM21 |
| Table 40 (starting international friendly) dropped | FM23 |
table_10 added, before table_9; table_1 dropped; table_71 to table_73 added | FM24 |
FM24 and FM26 have an identical list of 77 sub-files. Source: fm-re.
Nation versus national team
From FM24, table_10 is Nation (251 records) and table_9 is the national-team container (one per nation in FM24; men's and women's in FM26, so 502). Before FM24 table_9 was the nation. Confirmed by the FM26 enum names (fm-re) and the internal class names, and agrees with fm-reader's own "FM24 split" notes.
Table families
fm-reader exports 143 tables as CSV or MySQL; the generated catalogue is /home/rob/code/fm-reader/DAT_SCHEMA.md. thefmdb and fm-xml read the MySQL copies, one database per game release, named like fm26_update, fm26_release, fm24_release, fm23_release, fm22_release (fm-xml docs/08). Notes:
- There is no
fm24_updatedatabase on this machine, although one note mentions it (fm-xml). - Each database has an
export_metatable recording which game and export it came from. - Core tables:
person,player,staff,person_club_contract,club,club_team,nation,continent,competition,competition_type,stadium,city, and many small lookup lists (position,job_type,contract_status, ...).
Research databases (mdb)
Before the modern files, SI's research tooling used Microsoft Access databases. There are 118 of them (38 MB to 2.1 GB, from Championship Manager 3 in 2001 to FM2021) with 22,875 tables. mdb-reader exports them to CSV with mdbtools version 0.7.1 (chosen over 1.0.0 so new output matches the 12,675 CSVs already on disk; the difference is float formatting). Run scripts/run_all.sh 8, which skips tables that already exist, and check scripts/audit.sh for coverage. The CSV tree is in /home/rob/fm/sifiles/csvs/. Source: mdb-reader (Confirmed).
IDs
Every record in the database (person, club, stadium...) has numeric ids. Rules that hold across all the repos:
Unique id and random id
Each record has two 32-bit numbers (fm-xml docs/03, Confirmed from FM22 source):
unique_id(uid): its id within its table. This is the "FM ID" used by fmref, sortitoutsi and our MySQL databases.random_id: a disambiguator. For records shipped with the game it equals the uid. Records created in an editor get a random value.
When a reference is written as a single 64-bit number the two are packed:
packed = (random_id * 4294967296) + unique_id
unique_id = packed & 0xFFFFFFFF
random_id = packed >> 32
For shipped records packed = uid x 4294967297 ("fermat form", because 4294967297 is 232+1). Always decode with bit operations, never division, because division only works when both halves are equal. Three forms appear in real files, sometimes together: fermat, short (random half 0) and editor-random.
python3 -c "p={{PACKED}};print('uid',p&0xFFFFFFFF,'random',p>>32)"
That prints uid 98028755 random 98028755 for the default: Mohamed Salah.
When two ids mean the same record
- If the random halves are non-zero and equal: same record.
- Otherwise, if the uids are equal and either random half is 0: same record.
- Otherwise different.
This matters for references to records created in an editor. Uids from 2,000,000,000 upwards are editor-created in the files seen (Likely). A reference can carry both a packed id and a plain DBID uid.
Ids are only unique within a table
uid 680 is a club (Manchester United), a stadium (Old Trafford) and a city (Mobile, Alabama) at once. Anything that stores an id must also store the table type (fm-xml, Confirmed).
Club versus team
A club is the organisation. A team is one side: first team, reserves, youth, or a national team. A person's contract points at a team, not a club (fm-xml, Confirmed in the FM26 reference data).
- A club's first team has the same uid as the club (94,518 cases).
- Other club sides (reserves, B teams, youth) have their own uid and a link to the club (1,788).
- National teams have no club, a nation, and a "national" flag (502).
So team 1879 is club 1879, Trabzonspor. Search for a club should also match its teams.
Reference keys in editor files
| Key | Points at | Key | Points at |
|---|---|---|---|
Pers | person | Nnat | nation |
Cclu | club | Ttea | team |
city | city | comp | competition |
stad | stadium | cont | continent |
Other id facts
- Sentinel values such as -1 mean "none" in several tables (fm-reader, Confirmed).
- Record counts depend on the build; for example the FM27 build 2700 export holds 687,249 people (fm-reader).
Attributes
Attributes are the numbers that describe a person. Players have 69 stored values in a fixed order; 15 of them are position ratings, leaving 54 true attributes. Staff have 52 non-playing attributes (fm-reader people-and-attributes.md, Confirmed).
Scale
- Display scale: 1 to 20, what you see in the game.
- Internal scale: 0 to 100 in saves. Conversion:
display = clamp((raw + 2) / 5, 1, 20)with the division rounded down. Confirmed against 341,120 values from the game's own export. An older note used(raw + 3) / 5, which is wrong when raw is 2 more than a multiple of five. - The base
.datfiles already store 1 to 20. - 0 means "not stored", for example goalkeeper attributes on outfield players.
python3 -c "r={{RAW}};print(max(1,min(20,(r+2)//5)))"
The 69 slots in order
| Slots | Meaning |
|---|---|
| 0 to 14 | Position ratings: goalkeeper, sweeper (unused), defender left/central/right, defensive midfielder, midfielders left/central/right, attacking midfielders left/central/right, striker, wing-backs left/right. A score of 20 means natural. |
| 15 to 25 | Crossing, dribbling, finishing, heading, long shots, marking, off the ball, passing, penalty taking, tackling, vision |
| 26 to 31, 34, 36, 46 to 48 | Goalkeeper: handling, aerial reach, command of area, communication, kicking, throwing, one on ones, reflexes, eccentricity, rushing out, tendency to punch |
| 32 to 33, 35, 37 to 45 | Anticipation, decisions, positioning, first touch, technique, left foot, right foot, flair, corners, teamwork, work rate, long throws |
| 49 to 68 | Acceleration, free kicks, strength, stamina, pace, jumping, leadership, dirtiness, balance, bravery, consistency, aggression, agility, important matches, injury proneness, versatility, natural fitness, determination, composure, concentration |
The full slot-by-slot enum is in /home/rob/code/fm-reader/docs/formats/dat/people-and-attributes.md section 4.5.
people_db.dat the 69 attributes start a fixed distance after the current-ability number, and that distance depends on the version: 18 bytes (FM18), 19 (FM19 to FM22), 23 (FM23 and FM24), 24 (FM26). Using the wrong one shifts or garbles every attribute (fm-reader, Confirmed). Names, in the same record, are written after the playing data.Current and potential ability
Current ability (CA) and potential ability (PA) are a single 0 to 200 number each, hidden from players in the game. A negative PA or CA from -1 to -10 is not a value but a range the editor uses for "unknown" (fm-reader, Confirmed):
| Code | Range | Code | Range |
|---|---|---|---|
| -1 | 0 to 20 | -6 | 90 to 120 |
| -2 | 10 to 40 | -7 | 110 to 140 |
| -3 | 30 to 60 | -8 | 130 to 160 |
| -4 | 50 to 80 | -9 | 150 to 180 |
| -5 | 70 to 100 | -10 | 170 to 200 |
The base database also holds a second family of codes (-15, -25 ... -95) that fm-reader passes through raw; their meaning is not documented (Guess: scaled ranges). Reputation, height, weight and the personality (eight small numbers) also sit in the person record.
Numbers the game does not store
thefmdb's six-axis summary (pace, physical, technical, mental, defending, shooting) is an average computed by the app from the stored attributes, not a game value. Its exact grouping is on the thefmdb page.
Positions and roles
Positions
FM26 tactic files store each player slot as a position mask: a base bit plus an optional side marker (fm-tactic-reader research/fm26/positions.md, Confirmed from 28 controlled test files).
| Bit | Position | Bit | Position |
|---|---|---|---|
| 0 | GK | 8 | MR |
| 2 | DR | 9 | ML |
| 3 | DL | 10 | MC (CM) |
| 4 | DC | 11 | AMR |
| 5 | WBR | 12 | AML |
| 6 | WBL | 13 | AMC |
| 7 | DM | 14 | STC (ST) |
Adding 0x100000 to a mask marks the left half (for example DCL = 0x00100010) and 0x200000 the right half (DCR = 0x00200010). That is how a two-centre-back line is told apart. Names such as DMC and CM are aliases of DM and MC.
Roles and duties
A role (such as Poacher or Ball-Playing Centre-Back) is a bit number in a 64-bit field; the duty (Defend, Support, Attack) is another bit in the same field. Roles are separate in possession and out of possession. Both were checked two ways and agree: from 187 controlled test tactics (fm-tactic-reader) and from FM26's own program metadata (fm-re fm26-il2cpp.md). All 40 in-possession and 39 out-of-possession roles match, with 0 conflicts (Confirmed).
| Duty | Bit |
|---|---|
| Defend | 21 |
| Support | 22 |
| Attack | 23 |
| Defend (Stopper) | 25 |
| Defend (Covering) | 26 |
| Float | 34 |
Examples of role bits (in possession): 0 Goalkeeper, 1 Centre-Back, 2 Full-Back, 3 Wing-Back, 4 Defensive Midfielder, 5 Central Midfielder, 7 Winger, 9 Attacking Midfielder, 19 Poacher, 27 Inside Forward, 40 False Nine. The full table is /home/rob/code/fm-tactic-reader/research/fm26/roles.md.
Ten in-possession bits exist in the game's list but in no test file (20, 28, 30, 33, 36, 37, 39, 42, 47, 50: Complete Forward, Anchor Man, Regista, Mezzala and others). They were roles of FM24. Probably FM26 retired them (Guess; fm-re). Out-of-possession bit 24 does not exist at all.
Player instructions
Each player instruction is a numbered bit. All 31 bits seen in test files match the game's own enum (fm-re). Five exist in the game's list but in no sample (5 Cross Often, 6 Cross Less Often, 20 Be More Expressive, 21 Be More Disciplined, 28 Switch Position), probably FM24 leftovers (Guess). There are 15 setting groups (attacking width ... marking target).
Tactics files
A tactic is saved as a .tac file, or inside an .fmf archive when shared. A shared tactic is just an archive that happens to contain a .tac (fm-tactic-reader, Confirmed).
FM24 layout
Fully deterministic from byte 0 (validated on 423 files, 13,775 role slots; fm-tactic-reader research/tac-spec.md):
- 8-byte header: format 3, little-endian, magic
cat., version 34. - Body: tactics version (58), match version, name, description, author, password.
- Team instructions: fluidity, mentality, three 32-bit instruction words, goalkeeper distribution target, style name.
- Exactly 11 player slots: position mask, role and duty, enabled flag, player-instruction slots (24 bytes each), exclusions.
- A tail that is kept unchanged.
Mentality (1 to 7): Very Defensive, Defensive, Cautious, Balanced, Positive, Attacking, Very Attacking. Fluidity (0 to 4): Very Rigid ... Very Fluid. The game derives fluidity from duties, so keep what is stored.
FM26 layout
Schema version 66 (FM24 is 58). Verified on 839 shared tactics, all reading to the end of file (fm-tactic-reader). Each player has separate in-possession and out-of-possession records. The 72 controlled team-instruction files define a table of numbered bits (for example bit 1 to 4 are passing directness from "much more direct" to "much shorter"). Preset tactics also set six bits (25, 33, 34, 60, 74, 75) whose meaning is not known.
Rules a tactic editor must follow
- Parse then write without change must give identical bytes.
- Edit only the bytes the change needs. Keep unknown fields and trailing bytes.
- Some role and position combinations were seen in real saves but not in the test files, so editors treat "proved" combinations as allowed and refuse others (for example Attacking Midfielder at MC is proved; at MCL it is not).
Nation rules
Each nation has a set of rules that describe how its competitions run and when its season starts: league structure, cup draws, transfer windows, qualification slots, registration limits and start dates. They are authored as XML and compiled into comps.dbc; the running game reads the compiled form, never the loose XML (fm-reader docs/formats/comps/README.md, Confirmed from FM22 source). The database itself does not contain authored rules.
loose XML -> editor / compiler -> comps.dbc -> rule objects in the game
Where they are
- FM22 source:
data/sicomps/<region>/<country>/*.xml, with names likecomp_eng_prem.dbcornation_eng_rules.dbcinside the packed form. - FM24 and later: nation rules exported by the Pre-Game Editor into editor files as
rule_grouprecords (for exampledefault_rules.xml). The rules layout has its own version number,rule_group_version: 1536 in FM24, 1639 in FM26. - FM26 editor exports are converted by fmf-archiver the way the editor itself stores them (some words become numbers). See fmf-archiver
pge-fm26-rules.md.
Parts of a nation file
| Part | What it controls |
|---|---|
start_date_rules | Choices in the career start-date dropdown. See Start dates. |
generated_start_date_rules | Dates generated by the editor's "Test Rules"; not what the game uses (see Start dates). |
season_windows | Season-start dates per division range. |
Competition records (file_type="comp") | One per competition; a direct-child start_year controls whether it is active. |
preseason_preparation_days, late_preseason_preparation_days | Days before the season start for early and late preseason (typically 28 and 14). |
The nation-editor app edits these files in the browser. It labels property numbers by decoding the four-letter codes, and its tree edits are not checked against the schema as you type; run the saved file through the validator in the start-dates project (validate.mjs).
generated_start_date_rules yourself. The editor computes it from the rules and it cannot be derived from the XML (start-dates, Confirmed).Shifting rules a year forward
start-dates documents the recipe used to move older rule files to a new start year (Confirmed in file structure, in-game results noted per nation):
- Set
base_year_offsetto 3 for FM24 files or 1 for FM26 files in every start-date rule. - Insert early and late preseason rules before each start-of-season rule, cloning the competition block.
- Set the direct-child
start_yearof each competition record. Leave deeper nested ones (history) alone.
Start dates
When a new career begins, the game offers start options such as "Start of season", "Early preseason", "Late preseason". How it picks the actual date is documented in /home/rob/code/start-dates/docs/start-date-methods.md, re-verified 2026-08-26 against FM22 source, FM24 and FM26 files and recorded in-game results for Denmark and Portugal.
How a date is resolved
- Use the rule's own date if valid.
- If invalid and the rule is preseason or training camp, find the matching season rule and subtract the preparation days.
- If still invalid, use the nation's season-window fallback.
- If adjustment is requested and the date was not imported, subtract three days for season and competition types (one day for first game), then move back to Monday.
- Finally move back to Monday and zero the time.
When several invalid rules fall to the same fallback, their small adjustments can land on the same Monday, which collapses the dropdown into fewer options (Confirmed, FM22 source).
Things that surprise people
- Encoded dates are offsets. Weekday dates are stored relative to a base date: 1 January 2000 for the year 2000, otherwise the last Saturday before the target year. Example: Sun 6 Aug 2000 becomes Sun 2 Aug 2026 (Confirmed).
- An explicit date is rarely usable. FM22 accepts one only between 1 December of the game-start year minus 1 and 1 June of the year after, so a literal July 2026 date in an FM26 file was discarded in game (Confirmed, Denmark).
- The last season window wins in FM26. In a Denmark test the date followed the final window in the file. FM22 source always asks for level 0. So FM26 differs from FM22 here; whether that is true for every nation is unproved (Likely).
- Preparation days are a local fix. Raising early preparation from 20 to 34 moved the Denmark early option from 13 July to 29 June, but a blind change everywhere would change other nations (Confirmed locally).
- The 21 September "Sunday + 1" claim was corrected by the 23 September Portugal audit. Changing Portugal's final window to 9 August is predicted to give 3 August but is not yet tested in game.
- Static checks do not prove it works in game. Always say whether a result was confirmed in the editor or a real save.
Earlier start years
fm-re shows FM26 can start in 1995: a patched database was built and a headless start on 3 July 1995 runs, using England's nation rules repacked for build 26.9.0. Real birth dates for people and other nations' rules files are still to do (Confirmed for England only; fm-re docs/start-year-1995/).
The match engine
Football Manager plays a match as a series of tiny time slices. Facts below come from the FM22 source and from two projects that use it.
Basics (FM22 source)
- One slice is 0.25 seconds (4 per second). Distances are metres; speeds are metres per second. The pitch origin is the centre spot, with Z as height (2d-me docs, from FM22 source; Confirmed).
- The maths uses a wrapped single-precision float so that results are identical on every machine. A match with the same seed and inputs gives the same result (Confirmed).
- Ball and players have positions, speed and direction; tackles, passes, shots and saves are resolved with an error model. The player's attributes feed it directly on the 1 to 20 scale.
Running the real engine here
me-harness builds FM22's engine, and has FM24 and FM26 running headless from the Mac builds. It plays a match in about 2 to 3.5 seconds, about 10 matches a second on 64 workers, and is exactly repeatable. Typical output is 2.55 goals a match across 1,000 seeds (me-harness, Confirmed). A worker takes JSON lines:
echo '{"id":1,"pkm":"{{PKM}}","seed":{{SEED}},"edits":{"synthetic":true,"neutral":true,"freeze":true,"tactics":[{"tac":"{{TAC}}"}]}}' | /home/rob/code/me-harness-claude/scripts/me-worker.sh --workers 1
"Synthetic" makes every player identical; "neutral" removes home advantage and weather; "freeze" stops AI substitutions. Results include goals, expected goals, shots, possession and a checksum.
What has been learned about tactics
- Role, instruction and mentality tweaks did not measurably improve the best community tactics in the engine (me-harness validation, 2026-10-09/10; Confirmed for the search tried).
- In league back-tests over 8 leagues and 141 clubs, simulated team strength correlates with real goal difference at about 0.61 to 0.67, about the same as the average ability of the best eleven (0.64). The engine ranks clubs about as well as their squad strength does.
FM26 positional engine
FM26 projects each player's pitch area using a temporary match simulation. fm-re recovered the cross-phase positional warning table (118 rows) and part of the grid scoring, but the full role-by-role table is still missing. Do not substitute FM22 weights for FM26 (fm-re, Likely/in progress).
Updates
Two different things are called updates.
Official updates
SI ships a new build as an extra database layer (for example 2620 on top of 2600). The layer has full replacements of the .dat files, so the newest layer is the whole current world (fm-reader, Confirmed). The MySQL database fm26_update comes from the 26.2.0 layer; fm26_release comes from the base layer. Use the update database first and fall back to release (fm-xml).
Community data updates
Groups such as sortitoutsi.net publish editor files (.fmf plus the equivalent .xml) that change players, contracts, clubs and competitions. They are split by topic: Player Attributes, Contracts, New People, England, and so on. Sizes vary enormously: a Player Attributes file has 1.57 million changes (397 MB as XML). Typical uses of the changes: release then re-sign contracts, create and delete people (ADDR/DELE), rewrite club league histories. Load order matters when several are installed (see Which file wins).
Glossary
- afe.
- Magic text at the start of an encrypted FMF archive. A normal one starts
fmf.. - AOM
- Add-on metadata: the small
_data/details.aomfile inside an.fmfwith title, description, tags and owner. - Attribute
- A rated skill of a person, 1 to 20 on screen. See Attributes.
- Build
- A numbered release such as 2620 (26.2.0).
- CA / PA
- Current ability and potential ability, hidden 0 to 200 numbers.
- .dat
- A database file shipped with the game; an FMF archive of tables.
- .dbc
- "Database content": binary form of editor changes or configuration. Header magic
cbd.. - DBV
- Database version, a counter for the database layout.
- Editor / Pre-Game Editor / PGE
- SI's tool for changing the database before a career. Makes editor files.
- Fermat form
- A packed id where both halves equal the uid: uid x 4294967297.
- FMF
- SI's archive format (like zip). See The FMF archive format.
- FourCC
- Four letters stored as one number, used to name properties and file types.
- IL2CPP
- Unity's way of turning C# into native code; FM26's screens are built this way.
- Layer
- One release folder of the shipped database (2600, 2620 ...). Later layers replace earlier files.
- .lnc / .edt / .ddt
- Language and name-change files / directive files that the game applies on top of the database.
- Nation rules
- The competition and calendar rules for one country. See Nation rules.
- PI / TI
- Player instruction / team instruction, stored as numbered bits in a tactic.
- Sample
- The word used in these repos for test data; "fixture" is reserved for football matches.
- svvs / orvs / verf
- Header fields giving the build last saved in, first created in, and verified against.
- .tac
- A tactic file, magic
cat.. - Team
- One side of a club (or a national side). Distinct from the club.
- uid / random id
- A record's id within its table, and its disambiguator. See IDs.
- zstd
- A fast compression method used from archive version 8.
Open questions
- Why editor-file database versions (3729 to 3733) differ from the save value for FM26 (4000), and what FM27's 3750 means.
- Meaning of the second PA code family (-15 to -95) and of six preset team-instruction bits.
- Whether the FM26 "last season window wins" rule holds for every nation.
- Which of the ten retired in-possession roles and five retired instructions the game really dropped.
- Exact table numbers for sub-files 71 to 73 (identified by content, not by name).
- Whether the folder-name rule ("2024" versus "26") is a rule or a coincidence.
Changelog
- Initial version.