Modders' workshop · guide · 52 min read
RPFM, the guide: adding a unit, a faction and a lord to Total War: Warhammer III
RPFM (Rusted PackFile Manager) opens and builds Total War packs. This guide shows step by step how to use it, then walks through three complete procedures for Total War: Warhammer III: adding a unit, a faction, a legendary or playable lord. The pitfalls come from the community and from our own project.
Reviewed on 25 September 2026, update 9.0. Written against its sources, RPFM 5.0.6's code and manual (labels and locations), the game's data and the Assembly Kit on patch 8.1; what 9.0 changed on our project has been added, the rest has not been rechecked point by point. When in doubt, check, and tell us.
What RPFM does, and what a pack is§
A Total War mod is a .pack file, an archive the game reads from its data folder. RPFM (Rusted PackFile Manager, by Frodo45127, under the MIT licence) opens the game's packs read-only and builds yours. A pack holds tables (db/), texts (text/), Lua scripts (script/), images (ui/), model definitions (variantmeshes/) and, for a campaign, its start position (campaigns/).
This guide follows RPFM 5.0.6, the latest stable release as of 24 September 2026, and tables read on patch 8.1. For update 9.0, released the same day, RPFM's schemas were published that very day; the tables cited here have not been reread one by one since: when in doubt, check. Every change follows these six steps:
- Find
The closest game row.
View → Toggle Global Search Window (Ctrl+Shift+F)
- Copy
Into your table (
db/), under a key of your own (the same one to modify a game row).<table>_tables/ <file> right-click the pack → Create… → Create DB, then Paste as New Row
- Name
The texts shown to the player, in
text/.db/ <file>.loc right-click the pack → Create… → Create Loc
- Check
References, keys, empty fields.
Diagnostics panel → Check PackFile
- Try
The pack installed in
<game>\, in game.data\ right-click the pack's root → Install
- Publish
The optimised version.
right-click the pack's root → Save Pack For Release… (on a copy)
The words of the trade§
| Word | Meaning |
|---|---|
| Pack | a mod's archive, placed in the game's data folder |
| Table | a table of the game's database, stored in db/ |
| Key | what identifies a row, unique in its table (sometimes several columns) |
| Fragment | one table file; the game reads every fragment of a table, its own and the mods' |
| Datacore | a fragment named like the game's (data__), which replaces the whole table |
.loc | a text file: one key per displayed sentence |
| Schema | the description of the tables: columns, keys, links (RPFM's, or the kit's: TWaD_*.xml) |
| Dependencies cache | the game's data, prepared by RPFM for searching and checking |
| Assembly Kit | Creative Assembly's official kit (Steam → Library → Tools) |
| Subtype | a character's exact type (agent_subtypes) |
| Art set | a character's set of appearances (campaign_character_art_sets) |
| Startpos | startpos.esf, a campaign's turn-0 save |
| Pack root | the first line of the pack tree, bearing the pack's name; its right-click menu holds Install, Uninstall, Save Pack For Release… and Build Startpos |
| Palette | RPFM's search by name: Ctrl+Shift+P for an action, Ctrl+P for a file |
%APPDATA% | your Windows account's settings folder: type %APPDATA% into File Explorer's address bar |
| Military group | military_group, a faction's recruitment group: a unit allowed to a group is allowed to all its factions (in CA's data, Bretonnia's factions have wh_main_group_bretonnia) |
twad_key_deletes | the table that removes game rows at launch (Warhammer III, since patch 6.3): columns table_name and key |
| Mixer | MIXER – Mixu's Unlocker, a mod by Mixu: its startpos makes every faction of Immortal Empires and Realm of Chaos playable; according to the wiki, it is most players' only startpos mod |
| Error / Warning / Info | the three severities of the diagnostics: Error, a problem in game; Warning, a likely problem; Info, worth knowing. Aim for zero Error |
Installing and setting up RPFM 5.0.6§
Download RPFM from its releases, then, once and for all:
- PackFile → Settings. Game Paths: the Game Folder (the folder of the game's executable) and the Assembly Kit Folder. Extra Paths: the MyMod's Folder, outside Program Files, where Windows protects writing. Default Game: Warhammer 3.
- About → Check Updates, then, in the Update Manager, the button of the Schema Updates line: the schema tells RPFM how to read each table of the current patch (you can also tick Check Schema Updates on Start in the settings).
- Game Selected → Generate Dependencies Cache, a few minutes: RPFM prepares the game's data for its searches and checks. Without the Assembly Kit set up, it warns that its diagnostics will give false positives.
The basic moves§
RPFM 5.0.6's window, area by area:
- 1The menusPackFile, MyMod, View, Game Selected, Tools, About. Settings: PackFile → Settings (Ctrl+,); schemas: About → Check Updates; the cache: Game Selected → Generate Dependencies Cache.
- 2The tabsone per open file.
- 3Pack Contentsthe pack's tree; its first line, the root, bears the pack's name.
- 4The root's right-click menuSave Pack As…, Save Pack For Release…, Install, Uninstall, Change PackFile Type, Optimize PackFile, Build Startpos (and other actions): what concerns the whole pack.
- 5Dependenciesthe files of the game, of parent mods and of the Assembly Kit, read-only; right-click → Import brings one into your pack.
- 6The open tableyour row, highlighted; in red, an invalid reference: no land_units row bears this key yet. The atlas_main_units file has no @: it adds a new key.
- 7DiagnosticsCheck PackFile reads the pack through; each line has a severity: Error, Warning or Info. Aim for zero Error.
- 8Global Searchhidden at first: View → Toggle Global Search Window (Ctrl+Shift+F); sources Game Files or Assembly Kit Tables.
- 9The status barshort messages from the last operation.
Creating your mod§
MyMod → New MyMod. Pick the game (Warhammer 3) and a name with underscores, no spaces and no .pack (author_description). RPFM creates the pack <MyMod>\ and, next to it, the folder <MyMod>\ for your working files (plus a Git repository or a VSCode project if you tick them), then opens the pack. The MyMod folder must be set first, or RPFM refuses.
Finding game data§
View → Toggle Global Search Window (Ctrl+Shift+F): Game Files source (or Assembly Kit Tables), DB type (Loc for texts), then the key, underscores included; a click opens the table at the right row, read-only. Other ways: PackFile → Load All CA Packs (read-only; greyed out when the dependencies cache is loaded), or View → Toggle Dependencies Window, right-click → Import, which brings a game file into your pack: rename a table brought in this way at once (F2), as under the name data__ it would replace the game's.
Creating a table§
Right-click the pack → Create… → Create DB; pick the table (land_units_tables) and name the file with your prefix: db/. The name matters: when your file and the game's (data__) give the same key, the one whose name sorts first wins. To add rows (new keys), any name of your own will do; to modify a game row (same key), start the name with @ or !.
- Never rename or move a
_tablesfolder (“NEVER RENAME/MOVE THE TABLE FOLDERS”, RPFM writes): the folder is what tells the game which table this is. - No final digit and no space in a table file name: according to RPFM, a final digit makes the mod crash for everyone except its author, and a space sometimes keeps the table from loading.
Starting from a game row§
- In the game's table, select the model row (click its number): Copy… → Copy.
- In your table: Paste as New Row (Ctrl+Shift+V). To add a row, change the key first: otherwise your row adds nothing, it competes with the game's row.
- To duplicate one of your rows: Clone… → Clone and Append.
Following a key§
Right-click a cell → Go To… → Go To Definition (the row cited), Go To Loc Entry (its text) or Find References (everything that cites this key); Rename References renames a key everywhere (the manual calls it Cascade Edition). This is how you take a unit or a lord apart, table after table.
Writing texts§
- Right-click the pack → Create… → Create Loc, for example
text/.db/ atlas.loc - Three columns: key (the key), text (the displayed text) and tooltip, whose role is unknown according to RPFM's manual: do as CA's rows do.
- The key has the form
<table>_<column>_<row key>. Example: the name of unitatlas_chevaliers(columnonscreen_nameofland_units) has the keyland_units_onscreen_name_atlas_chevaliers. - Right-click the pack → Generate Loc Data produces two files.
zzz_…: the keys your tables are missing; rename it or copy its lines into your.loc, then fill them in.aaa_…: the game texts your tables cite; keep only what you change. Publish neither under its original name: RPFM rewrites them at every generation, and the optimiser removesaaa_…(andzzz_…if it is empty).
Checking, testing, publishing§
The diagnostics§
View → Toggle Diagnostics Window → Check PackFile, before every test: a fault caught here saves a pointless game launch. Each line has a severity: Error (a problem in game), Warning (a likely problem), Info (worth knowing); aim for zero Error. The figure follows a mod from the diagnostics to the game.
RPFM checks:
- tables: outdated version; invalid reference, one of the leading causes of crashes on launch according to RPFM; empty or duplicate key; empty row; empty mandatory field, which may crash the game (RPFM), often without an error message (Casualfield); file name ending in a digit or containing a space; table overwriting the game's (“datacoring”); banned table (Banned Table), which the game checks and which crashes it if altered;
- files: path cited but not found, missing text;
- portraits: undeclared art sets and variants;
- configuration: dependencies cache missing or outdated.
Trying it in game§
- Ctrl+S (saves the open packs), then right-click the pack's root (the first line of the tree, bearing its name) → Install: RPFM copies the pack into
<game>\.data\ - Tick the mod in Creative Assembly's launcher, or in a third-party manager (Kaedrin's Mod Manager, Runcher).
- Same menu → Uninstall: removes the copy.
Publishing§
Keep your working pack: copy it first (or Save Pack As… under another name), because Save Pack For Release… saves the optimised version in place of the open pack. Right-click the pack's root → Save Pack For Release…: the optimiser opens, then the pack is saved; Optimize PackFile, in the same menu, does the same work without saving, so you can review first. The optimiser only does what you tick:
- remove files and rows identical to the game, duplicates, empty files;
- compress the pack;
- remove unused art sets and variants from portraits (unticked by default);
- for Warhammer III, Import datacores into twad_key_deletes: it writes into a
twad_key_deletestable the rows a copied game table removed. Check that table, rename it (RPFM would rewrite it on the next run), then delete the copied table yourself.
After a game update§
- About → Check Updates, schemas button.
- Game Selected → Generate Dependencies Cache: otherwise RPFM compares your tables with an outdated game.
- On every table flagged Outdated table: right-click → Update Table.
- Read through the new columns: RPFM puts default values in them, not necessarily the right ones for your rows.
With 9.0, RPFM's schemas came out on the day of the update. If you also write to the Assembly Kit: Steam updates it after the game (for us, an hour later) and rewrites raw_data\; the rows you had added there disappear. Check and restore them before regenerating the dependencies cache and before building anything.
Pack rules: who wins over whom§
The game reads every fragment of a table, its own and every mod's: as long as the keys differ, the rows add up. When two fragments give the same key, the one whose name sorts first wins; and a fragment carrying the exact path of a game file replaces it entirely.
The figure below shows who wins when several fragments of the same table give the same key.
Example: the game's battle units table is the file db/. According to RPFM's manual, @my_mod comes before it, zmy_mod after it, and a fragment named data__ replaces it entirely: that is a “datacore”, which the diagnostics flag (“Leaving them named data__ will overwrite the base game files”, Casualfield warns).
Four rules that prevent the worst surprises§
- Names and keys of your own: your rows add up without replacing anything, and other campaigns and other mods stay untouched.
- Don't redefine a game text. The game loads a mod's
.locfiles whatever the player's language: a repeated game key replaces the official text in every language. Only add new keys. For a second language, a second pack: it holds only a.locthat repeats your keys, under a name starting with!so it takes priority over yours (wiki, Submodding page). - To remove a game row, don't copy its table (a datacore): a fragment removes nothing from the others. Since patch 6.3, Warhammer III reads a
twad_key_deletestable (columnstable_nameandkey) that removes the named rows at launch. In RPFM: createtwad_key_deletes_tablesonce in your pack (Create DB), open the game's table, select the rows, right-click → Add Selection to Key Deletes → your table. Beware: removing a row still cited by another table crashes the game, and the diagnostics do not check this yet. Only two tables also have amod_disabledbox (character_skill_node_set_items,faction_agent_permitted_subtypes), which CA's schema presents as the means given to modders since they could not remove rows. - In the
datafolder, a pack wins over loose files (seen in our workshop): a regenerated file (a startpos, for example) only counts once it is back in the pack.
Your first mod, in ten minutes§
Before the three procedures, a short test that also checks your setup: making a game unit dearer in custom battles. The wiki's RPFM For Dummies tutorial starts the same way, with a table edit found through the global search.
- MyMod → New MyMod: game Warhammer 3, name
my_first_mod. - View → Toggle Global Search Window (Ctrl+Shift+F): Game Files source, DB type; search for
wh_dlc07_brt_cav_knights_errant_0, then click themain_units_tablesresult: the game's table opens at the right row, read-only. - Click the row's number, then right-click → Copy… → Copy.
- Right-click your pack → Create… → Create DB: table
main_units_tables, name@my_main_units. The@makes your file sort before the game's (data__): so yours wins. - Right-click in the empty table → Paste as New Row (Ctrl+Shift+V). Keep the key: here, you modify the game's unit. Set
multiplayer_cost(its price in custom battles; 700 in CA's data) to 999. - Diagnostics panel → Check PackFile: no Error line.
- Ctrl+S, then right-click the pack's root → Install; tick the mod in the launcher. In a custom battle, Bretonnia's Knights Errant cost 999.
To add a unit instead of modifying one, you change the key: that is procedure 1.
Procedure 1: adding a unit§
The safe way: copy a game unit that looks like yours, then change what must change. Example followed: Bretonnia's Knights Errant, wh_dlc07_brt_cav_knights_errant_0.
Before you start: the model unit§
- A model unit with the same skeleton and the same animations as yours: otherwise, it renders deformed in game.
- A key prefix of your own, so you never compete with the game or another mod.
The next figure shows a unit's tables and the columns that link them.
The unit's steps§
- Global Search for the model's key: it appears in 24 tables of the kit; the table below gives the ones you need.
- For each: Create DB (a file with your prefix), Paste as New Row, then change what makes the unit and keep the rest (see “What changes, what stays”). Like CA, give
main_units.unitandland_units.keythe same key. - Set the stats, costs, appearance and card, then the recruitment, the custom battle and the texts.
- Check: right-click your key → Find References. RPFM's manual advises this check after adding a unit: it shows whether the unit is wired up everywhere it should be (costs, recruitment, factions).
- Diagnostics, Install, custom battle test.
| Table | What to set | Key | Links |
|---|---|---|---|
main_units | the copy; costs, caste, ui_unit_group_land | unit | land_unit → land_units.key |
land_units | the copy; stats, weapons | key | man_entity → battle_entities; primary_melee_weapon → melee_weapons; short_description_text → unit_description_short_texts; historical_description_text → unit_description_historical_texts |
unit_variants | name = your key (as CA does), faction empty (= every faction), variant, unit_card | faction + unit | unit → land_units.key; variant → variants.variant_name; the card: ui/ |
variants | only for a new model: variant_filename | variant_name | → variantmeshes/ |
units_to_groupings_military_permissions | the unit and the military group | both columns | military_group = factions.military_group (for example wh_main_group_bretonnia) |
building_units_allowed | building, unit, key (a unique number), faction empty | key | building → building_levels.level_name; unit → main_units |
units_custom_battle_permissions | the battle faction (CA uses wh_main_brt_bretonnia), general_unit = 0 | unit + faction + general_unit | → main_units, factions |
unit_description_short_texts, unit_description_historical_texts | only for a text specific to the unit | key | cited by land_units |
What changes, what stays§
- To change: the new key
atlas_chevalierswherever CA's appears (main_units.unit,main_units.land_unit,land_units.key,unit_variants.unitandunit_variants.name, theunitcolumns of the permissions and buildings), and a new number inbuilding_units_allowed.key(right-click → Generate Ids, from a starting number of your own, below 2³¹). The key ofunit_variantsspans two columns (faction+unit):unitis the one that changes;nameis not part of the key, but CA puts the unit's key in it andunit_variants_coloursrefers to it: change it too. - To keep for a first test: CA's
variantandunit_card(wh_dlc07_brt_knights_errant: same model, same card), the military group (wh_main_group_bretonnia), the battle faction (wh_main_brt_bretonnia, withgeneral_unit= 0) and the four stables (wh_main_brt_stables_2towh_main_brt_stables_5). - A CA key forgotten in one of your rows: that row competes with CA's instead of adding up.
RPFM also has a Unit Editor, experimental according to its manual; this guide follows the tables route.
The unit's optional tables§
According to Casualfield's guide, depending on what the unit must do:
land_units_to_unit_abilites_junctions, for its abilities (the misspelling is CA's);unit_attributes_groupsandunit_attributes_to_groups_junctions;unit_set_to_unit_junctions;ui_unit_bullet_point_unit_overrides;allied_recruitment_unit_permissions;armed_citizenry_unit_groupsandbuilding_level_armed_citizenry_junctions, for garrisons;cdir_military_generator_unit_qualities, for the AI;units_to_exclusive_faction_permissions;faction_rebellion_units_junctions, for rebel armies: CA's schema asks for the unit ofunits_to_groupings_military_permissionsto be repeated there, Casualfield calls it optional.
The unit's texts§
land_units_onscreen_name_<key>: the name (Casualfield givesunit_description_historical_texts_UNITKEY, but the kit's schema stores the name inland_units.onscreen_name);unit_description_short_texts_text_<short key>andunit_description_historical_texts_text_<long key>, if the unit has its own descriptions;land_units_concealed_name_<key>, optional.
The unit's minimum viable set§
- In custom battles:
main_units,land_units,unit_variants, the card (a 60 × 130 PNG according to the wiki's Unit Card Guide; not interlaced like CA's, read on patch 8.1),units_custom_battle_permissionsand the name in a.locfile. - In the campaign, as well:
units_to_groupings_military_permissionsandbuilding_units_allowed.
The unit's pitfalls§
- Every building level. CA lists the unit at every level that allows it, not just the one that unlocks it: its Knights Errant appear on the level 2, 3, 4 and 5 stables.
- The
enabledcolumn ofbuilding_units_allowedonly forbids recruitment when three conditions are met: the building-unit pair exists elsewhere,factionis filled in, the box is unticked. units_custom_battle_permissionsalso acts in the campaign (wiki, Units custom battle permissions tables page): a hero's card in the building browser comes from it, and the preview of the units affected by an effect takes it into account.- An empty mandatory field, a file named
data__: see the diagnostics and the pack rules.
What the unit needs from the startpos§
Nothing, except to exist from turn 0 (start_pos_land_units, start_pos_settlement_garrisons, mercenary pools); even then, a script spares you the startpos: cm:create_force_with_general places an army, cm:add_unit_to_faction_mercenary_pool stocks a pool.
Checking that the unit works§
- Diagnostics: no invalid reference, no missing text.
- Custom battle with the chosen battle faction: the unit is in the list, with its card and its name; in battle, the model is whole.
- New campaign: the unit can be recruited at every building level listed.
Procedure 2: adding a faction§
A faction fits in a few tables, but it only exists on the map through the startpos.
Before you start: what to gather§
A target campaign, an existing culture and subculture, the flags, and time to generate a startpos.
The figure shows a faction's tables, and the path from the start tables to the startpos.
The faction's steps§
factions: copy a neighbouring faction (wh_main_brt_bordeleaux) under a new key; setsubculture,name_group,military_group,flags_path=ui\and the colours (or Tools → Faction Painter).flags\ <key> - The flags: a
ui/folder like CA's:flags/ <key>/ mon_24.png,mon_64.png,mon_256.png(24, 64 and 256 pixels),mon_64_glow.png,mon_icon.png,mon_rotated.png,mon_banner.dds(CA's own file names, read on patch 8.1). Which ones are essential is not confirmed: supply the full set. faction_agent_permitted_subtypes: the model's rows, which say which lords and heroes the faction can have (Bordeleaux has 12: general, colonel, minister, champion, wizard).- The texts, then the start tables of the table below, in the kit (Dave) or in the pack (RPFM), plus
start_pos_character_to_settlementsfor a garrisoned leader andstart_pos_diplomacy. - The startpos, regenerated (see “What needs a new startpos”), stored in
campaigns/in the pack; then Diagnostics, Install (except for a pack opened from the<campaign>/ startpos.esf datafolder, which Install refuses), new campaign.
| Table | What to set | Key | Links |
|---|---|---|---|
factions | the faction | key | subculture → cultures_subcultures; name_group → names_groups; military_group → groupings_military |
faction_agent_permitted_subtypes | the lords and heroes allowed | faction + agent + subtype | → agent_subtypes |
start_pos_factions | ID (a new integer), faction, campaign, playable, is_major, cai_personality_group | ID | → factions, campaigns |
start_pos_regions | owning_faction = that ID, faction_capital | region + campaign | → start_pos_factions.ID |
start_pos_characters | the leader: Type = general, subtype, ministerial_position = faction_leader, portrait_id, startx and starty, Name and Surname | ID | faction → start_pos_factions.ID; Name → names.id; portrait_id → campaign_character_art_sets |
start_pos_land_units | the army: unit_type, general, soldiers | id | → main_units; → start_pos_characters.ID |
The faction's texts§
factions_screen_name_<key>, factions_screen_adjective_<key>, factions_screen_name_when_rebels_<key>, factions_attack_desc_<key> and factions_defend_desc_<key>; the leader's name comes from names_name_<id>.
The faction's minimum viable set§
factions, the flags, faction_agent_permitted_subtypes, the texts, start_pos_factions, a region or a leader with his army, and the regenerated startpos.
The faction's pitfalls§
- The AI group. Every faction must have an AI group (
cai_personality_group) containing a personality, or the game crashes. In our workshop: the group the faction has in Immortal Empires, failing that the one of its culture's minor factions. - The start tables' IDs: unique integers, below 2³¹ (the limit of a signed 32-bit integer), that no CA row already uses (CA's are scattered up to nearly 2³¹, patch 8.1).
- Keys change from one game to another (
wh_dlc05_brt_mini_bastonnein Warhammer I,wh_main_brt_bastonnein Warhammer III): when porting data, match them on the culture and the end of the key (the porting tutorial).
What the faction needs from the startpos§
Everything that makes it exist: the wiki lists playable factions, like those that appear during a game, among what needs a startpos. Once the faction is in the startpos, scripts take over: cm:transfer_region_to_faction(region, faction), cm:create_force_with_general(...), or CA's Campaign Custom Starts system (regions, armies, diplomacy, effects).
Checking that the faction works§
- Clean diagnostics;
campaigns/is really in the pack, dated from the generation.<campaign>/ startpos.esf - Start tables served through a mod pack:
%APPDATA%\names the faulty record, one at a time.The Creative Assembly\ Warhammer3\ crash_report\ bad_mods_report.txt - New campaign: the faction is on the map, in its region, with its flag and its name; its leader leads his army.
- If playable, it can be picked on the selection screen once procedure 3 is done for its leader.
Procedure 3: adding a legendary or playable lord§
Three stages: A, the lord exists in the database; B, a script makes him appear in an existing faction; C, he can be picked on the “New Campaign” screen, and only this stage needs a startpos. Prerequisites: his battle unit (procedure 1), his model, his portrait.
Stage A: the lord in the database§
agent_subtypes: copy a neighbouring lord (wh_dlc07_brt_alberic);auto_generateunticked for a unique character,associated_unit_override= his unit,recruitment_category=legendary_lords,recruitable= 1 andcap=-1(like Alberic). Leavemagic_loreempty: filled in, withlegendary_lords, it can hide the other legendary lords of the recruitment pool (wiki, Agent subtypes tables page).- The appearance:
campaign_character_art_sets→campaign_character_arts(a uniqueid) →agent_uniforms→variants. - The portrait: Warhammer III reads it from
ui/, arranged by art set (for Alberic,portraits/ portholes/ portrait_settings*.bin portrait_settings__3.bin, a 300 × 164 thumbnail: read on CA's files, patch 8.1). In RPFM: Create… → Create Portrait Settings, then its editor. In CA's rows,campaign_character_arts.portraitstays empty. - The skills:
character_skill_node_sets(columnagent_subtype_key),character_skill_node_set_items(set,item),character_skill_nodes(tier= the tree's column,indent= the row),character_skillsthencharacter_skill_level_to_effects_junctions,character_skill_node_linksfor the arrows. faction_agent_permitted_subtypes(the faction,general, the subtype) andnames(newidvalues for the forename and the surname). For custom battles:units_custom_battle_permissionswithgeneral_unit= 1,general_portraitandgeneral_uniform.
| Table | What to set | Key | Links |
|---|---|---|---|
agent_subtypes | the subtype | key | associated_unit_override → main_units |
campaign_character_art_sets | the art set | art_set_id | agent_subtype → agent_subtypes |
campaign_character_arts | the appearance, per level | id | uniform → agent_uniforms |
agent_uniforms | the campaign map and battle models | uniform_name | filename, battle_filename → variants |
character_skill_node_sets | the skill tree | key | agent_subtype_key → agent_subtypes |
character_skill_node_set_items | the tree's nodes | set + item | → character_skill_nodes |
character_skill_nodes | a skill's position | key | character_skill_key → character_skills |
frontend_faction_leaders | the selection screen record | key (free) | agent_subtype_record, faction |
start_pos_starting_general_options | the link from the character to his record | id | general → start_pos_characters.ID |
The lord's texts§
agent_subtypes_onscreen_name_override_<subtype>: the type's label (“Legendary Lord” for Alberic); his proper name comes fromnames_name_<id>;agent_subtypes_description_text_override_<subtype>;character_skills_localised_name_<key>,character_skills_localised_description_<key>andcharacter_skill_node_sets_enc_title_<key>;frontend_faction_leaders_frontend_description_<record>andfrontend_faction_leaders_localised_description_<record>; according to CA,localised_action_pointsandloading_screen_textare no longer used.
The lord's minimum viable set§
agent_subtypes, the battle unit, the art set, arts, uniform and variant, faction_agent_permitted_subtypes, names, the texts, and a script call.
Stage B: spawning him by script§
Without a startpos, a script can add the lord to a faction that already exists. This skeleton follows the signatures in CA's scripts, to be tested:
-- skeleton, to be tested: a lord in an existing faction's pool
cm:add_first_tick_callback(function()
if cm:is_new_game() then
cm:spawn_character_to_pool("wh_main_brt_bordeleaux", "names_name_<id>", "names_name_<id>",
"", "", 30, true, "general", "<subtype>", true, "<art set>")
end
end)- Parameter order of
cm:spawn_character_to_pool: faction, forename, surname, clan, other name, age, male, type, subtype, immortal, art set. Names are writtennames_name_<id>. cm:is_new_game(): the call only happens at the start of a new game, not at every load. According to CA's documentation, a game is “new” if it has been saved only once, during startpos generation: if a script failed during that generation, a new game may pass for a saved one.- With an army:
cm:create_force_with_general(faction, units, region, x, y, "general", subtype, forename, clan, surname, other name, faction_leader, callback), whose units are, according to CA's documentation,land_unitskeys (the same as themain_unitskeys in CA's data). - The script goes into
script/, which the game loads by itself (tw-modding, Lua/First Script), under a unique, prefixed file name: two files at the same path in two packs do not both load.campaign/ mod/
Stage C: picking him on the “New Campaign” screen§
start_pos_characters: the character (see procedure 2).start_pos_starting_general_options:general(the character) →frontend_faction_leader(his record). Without this table, no lord can be picked.- A
frontend_faction_leadersrecord, with a free key:character_image(an 85 × 115 portrait, read on CA's at patch 8.1),uniform(the.cscscene),video,loading_screen_image,agent_subtype_record,faction. start_pos_factions.playable= 1, then the regenerated startpos.
The lord's pitfalls§
- Warhammer II tutorials. “Custom Lords & Heroes”, on tw-modding, targets Warhammer II: check every table against Warhammer III's schema, where the link between a node and its tree goes through
character_skill_node_set_items. - The
tiercolumn stays below 48 (wiki, page oncharacter_skill_nodes). startpos_map: CA mostly putsdefaultor the record's own key there; for a new record, leavedefault. In our workshop, a new key in that field crashed the loading.- A garrisoned lord: left as is, his marker stays in the corner of the selection screen's Map tab; fill in his record's
override_force_location_xandoverride_force_location_y(wiki, Startpos page). They are fractions: the character's position in hexes, divided by the map's width for x and by its height for y, following the example in CA's schema;-1leaves the default position (in CA's data, Eltharion: 0.398 and 0.420).
Checking that the lord works§
- Diagnostics: no undeclared art set or variant, no invalid reference.
- Stage A: in a custom battle, he can be picked as his faction's general, with his portrait and his uniform.
- Stage B: in a new game with the faction, he is among the lords to recruit, or at the head of his army. If not, read the script log: a non-empty
script/file in a loaded pack makes the game writeenable_console_logging script_log_*.txtfiles. - Stage C: on the “New Campaign” screen, his record appears with his portrait and his description, his marker is in place on the Map tab, and the game starts with him.
What needs a new startpos§
The startpos is the turn-0 save: what it records only changes if you regenerate it. The Assembly Kit's schema marks with a flag, requires_startpos_reprocess, the columns that go into it: read it in TWaD_<table>.xml. On patch 8.1, 42 tables carry one:
- 25 of the 29
start_pos_*tables: factions, characters, traits, items, units, regions, settlements, garrisons, diplomacy, lord options, technologies, victory conditions…; campaigns,campaign_maps,campaign_map_playable_areas,campaign_map_regions,campaign_map_attritions,campaign_map_masks_to_excluded_regions,regions,region_to_province_junctions,climatesandcampaign_ground_types;- seven mercenary tables:
mercenary_pools,mercenary_unit_groups,mercenary_pool_modifiers,mercenary_pool_to_groups_junctions,mercenary_pool_type_enums,faction_to_mercenary_set_junctionsandprovince_to_mercenary_set_junctions.
Units, subtypes, appearances, skills, texts and the factions table change in the database alone. Three ways produce a startpos: RPFM's Build Startpos, BOB's Process start pos action, or a user.script.txt written by hand. In our workshop, only writing it by hand worked: the tools guide.
Build Startpos, in RPFM§
Right-click the pack's root → Build Startpos has the game itself generate the startpos (palette, Ctrl+Shift+P: “Build Startpos”). Version 5.0.6 no longer has a Special Stuff menu: the “Special Stuff → …” paths of older tutorials and of the wiki apply to version 4.
- Put the
start_pos_*andcampaignstables in the pack: create them, or import them from the Assembly Kit through the Dependencies panel. The instructions RPFM displays also ask fordb/, but not for Warhammer III (RPFM's code; changelog, version 4.3.11).victory_objectives.txt - The open pack must be saved in the game's
datafolder (Save Pack As…, or PackFile → Open From Data): otherwise RPFM refuses. - Right-click the pack's root → Build Startpos; pick the campaign (the list comes from your
campaignstable). Only tick Process HLP and SPD data (the AI's map data,hlp_data.esfandspd_data.esf) for a new map. The time varies a lot: 16 s for us (400 × 440 hexes); tw-modding's campaign map tutorial gives under a minute forspd, about five minutes forhlpon a medium map and well over an hour on a large one; RPFM announces 10 to 30 minutes. - Click Build Startpos: the game starts (Steam open; click Play in the launcher if needed), generates, then closes by itself. Don't close RPFM meanwhile.
- Once the game has closed, click Hit this when the game is closed: RPFM puts
campaigns/(and, if the option was ticked, the hlp and spd files) into the pack, and puts your<campaign>/ startpos.esf user.script.txtback as it was. - Save the pack (Ctrl+S), then start a new campaign.
One clarification: you write the start_pos_* tables in the kit (Dave) or in RPFM, but the game does not read the kit's XML files; for generation, they must therefore be in a loaded pack (for Build Startpos, the very pack it generates). Once the startpos is produced, remove them from the published pack: they are no longer used. In our workshop, the game validates a mod pack's start_pos_* tables at every launch, and %APPDATA%\ then names the faulty record.
RPFM for an AI: the MCP server§
Since version 5, RPFM has a server, rpfm_server.exe. It speaks MCP (Model Context Protocol), the standard plug for AI assistants: an AI connected to it opens packs, reads and writes tables, searches everywhere and runs diagnostics, in its own session, separate from RPFM's window.
- If RPFM's window is open, its server is already running: the window starts it itself. Otherwise, run
rpfm_server.exewithout arguments (it has no--helpoption: it starts at once). It listens on127.0.0.1:45127and stops when no session is left open. - Point your assistant at
http://(Streamable HTTP). With Claude Code:127.0.0.1:45127/ mcp claude mcp add --transport http rpfm http://. Any Streamable HTTP MCP client works.127.0.0.1:45127/ mcp - Ask it to read the server's “Initialization guide” resource first: it describes the order of calls (select the game, check the schema, open the pack).
set_game_selected (warhammer_3, rebuild_dependencies: true)
→ is_schema_loaded (otherwise update_schemas)
→ open_packfiles (returns the pack_key)
→ open_pack_info (the pack tree)
→ decode_packed_file (e.g. db/land_units_tables/<file>)
→ fields_processed (the rows' shape)
→ save_packed_file_from_view
→ diagnostics_check
→ save_packfile- One session = one state (selected game, open packs): do everything in the same session,
set_game_selectedfirst. Each connection has its own session: the AI does not see the packs open in your window. To be safe, don't edit the same pack from both sides. - Rows are written in “processed” format: call
fields_processedon the definition before building a row. For example, a region'sr,g,bcolumns become a singleColourRGBvalue at the end of the row; otherwise saving fails (“expected a row with 6 fields, but we got a row with 8”). - Complex arguments (
Definition,GlobalSearch,NewFile) are passed as JSON strings. A new table:new_packed_filewith{"DB": ["<file>", "land_units_tables", <version>]}. - Removing a game row:
add_keys_to_key_deleteswrites its keys into atwad_key_deletestable of the pack (see “Pack rules”). build_starpos(that is the tool's spelling; argumentspack_key,campaign_id,process_hlp_spd) answers “Success” in zero seconds: it means “game launched”, not “startpos built”. Wait for the game to close, then callbuild_starpos_postwith the same arguments: it putscampaigns/(and the hlp and spd files) into the pack and restores your<campaign>/ startpos.esf user.script.txt; thensave_packfile. To give up:build_starpos_cleanup. Without one of them,user.script.txtkeepsquit_after_campaign_processing;and the game will close on every launch.- As of 20 September 2026, the RPFM 5.0.6 server exposed about 150 tools, 11 prompts and 11 resources: packs, files, tables, dependencies and schemas, search, diagnostics, optimiser, translations, startpos.
- If CAIME (Campaign AI Map Editor), the Campaign Map Toolkit's editor, reads its database through RPFM, it needs
rpfm_cli.exe, the one from a version 4 of RPFM (in our workshop, 4.2.7): version 5 no longer ships it (the CAIME guide).
For an AI reading this page§
For an AI helping to mod Total War: Warhammer III with RPFM, the essentials as checkable facts, taken on RPFM 5.0.6 and patch 8.1 of the game (September 2026), reviewed for update 9.0: check them again after an update (schemas, dependencies cache; and, if the Assembly Kit is used too, the rows added to raw_data\, which Steam rewrites).
- RPFM 5.0.6: menus PackFile, MyMod, View, Game Selected, Tools, About (no more Special Stuff). PackFile → Settings; About → Check Updates (schemas button); Game Selected → Generate Dependencies Cache; MyMod → New MyMod (creates
<MyMod>\); Ctrl+Shift+F global search; Diagnostics panel → Check PackFile. Right-click the pack's root: Install, Uninstall, Save Pack For Release…, Optimize PackFile, Build Startpos. Palette: Ctrl+Shift+P (actions), Ctrl+P (files).warhammer_3\ <name>.pack - Table file:
db/, never<table>_tables/ <prefix>_<name> data__, no final digit or space. Add: new key. Modify a game row: same key, in a file whose name sorts beforedata__(@,!). Remove a game row:twad_key_deletes(Warhammer III ≥ 6.3; MCP tooladd_keys_to_key_deletes), never a copied table;mod_disabledonly exists in two tables. - Text key:
<table>_<column>_<key>; a mod's.locfiles apply to every language; never a game key. - Unit: same key in
main_units.unitandland_units.key;building_units_allowedat every building level,key= unique integer (Generate Ids). - Faction: unique
start_pos_factions.IDbelow 2³¹,cai_personality_grouprequired; one startpos per campaign; Immortal Empires and Realm of Chaos: Mixer. - Selectable lord:
start_pos_starting_general_options+frontend_faction_leaders(startpos_map=default) +playable= 1 + startpos; by script (to be tested):cm:spawn_character_to_pool, namesnames_name_<id>. - Startpos to regenerate: tables with a field flagged
requires_startpos_reprocess(readTWaD_<table>.xml); everything else, database alone. - MCP:
http://(Streamable HTTP), one session per connection, separate from the window; “Initialization guide” resource first;127.0.0.1:45127/ mcp set_game_selected(warhammer_3,rebuild_dependencies: true),is_schema_loaded(otherwiseupdate_schemas); rows followingfields_processed; complex arguments as JSON strings;build_starpos(“Success” = game launched) → game closes →build_starpos_post→save_packfile; to give up,build_starpos_cleanup. - Ask the human before launching the game, driving the screen or publishing; delete nothing: tidy away, only the human deletes.
- No reverse engineering and no workaround of a CA tool: when a tool gets stuck, a control case, then the community (CAIME's Discord, tw-modding).
Sources and links§
- RPFM manual, especially Datacores, Optimising a mod and MCP; RPFM's code at tag v5.0.6 (menu locations, Build Startpos, server); releases; RPFM 5.0.6 itself (labels, changelog).
- tw-modding wiki: RPFM For Dummies (written for RPFM 2.3.2, old menus), RPFM Post-Setup for Beginners, Localisation, Submodding, Startpos, Lua/First Script, Example Scripts.
- Startpos of Immortal Empires and Realm of Chaos: MIXER – Mixu's Unlocker, by Mixu.
- Units: Creating Custom Units for WH3, by Casualfield (linked from tw-modding), Unit Card Guide, Building units allowed tables, Units custom battle permissions tables.
- Lords: Custom Lords & Heroes (Warhammer II, by Nanu), Agent subtypes tables, Character skill nodes tables.
- Scripts, by Vandy: Campaign Custom Starts and campaign_manager.
- Game data read on patch 8.1: the Assembly Kit's schema (
TWaD_*.xml,TExc_LocalisableFields.xml), the CA rows used as models (Knights Errant, Alberic, Bordeleaux),lib_campaign_manager.lua. - Our other guides: the modder's tools, CAIME, Terry, BOB, modding with an AI; and the modders' workshop.
Frequently asked questions
Which RPFM version should I use for Warhammer III?
5.0.6, the latest stable release as of 24 September 2026, whose menus this guide follows. The online manual describes that same version, sometimes with labels that differ from the window: the palette (Ctrl+Shift+P) finds the action by name.
My mod crashes the game on launch: what should I check?
RPFM's diagnostics (Check PackFile). An invalid reference is one of the leading causes of crashes on launch, and an empty mandatory field may crash the game, often without an error message.
Do I need a new startpos to add a unit?
No. Only starting armies and garrisons and mercenary pools require one, and a script can handle them (cm:create_force_with_general, cm:add_unit_to_faction_mercenary_pool).
Can I add a faction without touching the startpos?
No: everything that makes it exist goes through the startpos, of which each campaign has only one, which a mod replaces entirely. Your mod will therefore be incompatible with any other startpos mod for that campaign. For Immortal Empires and Realm of Chaos, ask instead for your faction to be added to Mixer, most players' startpos mod, then do the rest by script.
Why doesn't my unit show up in custom battles?
It needs main_units, land_units, unit_variants, its card (a 60 × 130 PNG), its name in a .loc file and a units_custom_battle_permissions row for the battle faction, with general_unit set to 0.
How do I make a lord selectable on the new campaign screen?
The character in start_pos_characters, a start_pos_starting_general_options row linking him to a frontend_faction_leaders record (startpos_map set to default), start_pos_factions.playable set to 1, then a regenerated startpos.
Why do my texts replace the game's in every language?
The game loads a mod's .loc files whatever the player's language. Only add new keys, and make one pack per language.
How do I connect an AI to RPFM?
If RPFM's window is open, its server is already running; otherwise, run rpfm_server.exe (RPFM 5). Then add the MCP server http:// to your assistant; with Claude Code: claude mcp add --transport http rpfm http://.
Why doesn't my mod show up in the launcher?
Check that it is installed in the game's data folder and that its type is Mod: right-click the pack's root, Change PackFile Type, Mod. In the same submenu, the Index Includes Timestamp box must be unticked: according to RPFM, a pack with it ticked does not show up in the official launcher.
Why does my change to a game unit do nothing?
Your table file sorts after the game's (data__): so the game's row wins. Start your file's name with @ or !, then install the pack again.
Some tables are flagged Outdated after a game update: what should I do?
Update the schemas (About, Check Updates), then the cache (Game Selected, Generate Dependencies Cache). Then right-click each flagged table, Update Table, and read through the new columns: RPFM puts default values in them.
How do I remove a game row?
With the twad_key_deletes table (Warhammer III, since patch 6.3), never by copying the game's table: create twad_key_deletes_tables once in your pack, select the rows in the game's table, then right-click, Add Selection to Key Deletes. Don't remove a row still cited by another table: the game would crash.
Why does the game close as soon as it starts?
A quit_after_campaign_processing; line was left in user.script.txt (%APPDATA%\): a startpos generation was interrupted before its end. Remove the line or put back the previous file. With Build Startpos, always click Hit this when the game is closed, which puts it back.
This guide as plain text (Markdown), for AIs and offline reading
This is a community guide
A mistake, a pitfall you hit, a tip or a newer tool version: tell us, and every correction will be checked, then added with its source.
Suggest an idea