Modders' workshop · guide · 41 min read
The campaign modder's tools: overview, startpos, crashes and tests
Where do you start when you want to mod a Total War: Warhammer III campaign map? This page is the overview: each tool, what it is for and its guide; the words of the trade; then what depends on no tool in particular: the start position, crashes, automated test games. Written during the first week of a project: porting a complete map from Warhammer I to Warhammer III.
Reviewed on 25 September 2026, update 9.0. Checked against CAIME 1.0.1, RPFM 5.0.6, the Assembly Kit and the game on patch 8.1. The 9.0 changes that affect our project are included; the rest has not been rechecked. Corrected on 5 October 2026: facts proven since on the game's 9.0.2, and versions released since (CAIME 1.1.0, RPFM 5.1.1). When in doubt, check, and tell us.
The toolbox at a glance§
A campaign goes through eight families of tools. None does everything, each has its own domain, and almost all have a trap. The first four have their own guide.
- CAIME (Campaign AI Map Editor)
The Campaign Map Toolkit's editor, for the logical half of the map: regions, ground, climates, roads, towns, and its exports (Map Data, pathfinding, borders).
- RPFM (Rusted PackFile Manager)
Open, create and edit packs: tables, texts, scripts, images; add a unit, a faction, a lord; be driven by an AI (MCP server).
- Terry
The Assembly Kit's 3D terrain editor: relief, textures, vegetation, props, logical zones.
- BOB
The Assembly Kit's builder: it turns sources into game files and packs, following
rules.bobfiles. - Dave and Tweak
Dave (CA writes it “DaVE”:
DaVE.retail.x64.exe; the Steam launcher says Database Editor: Dave) edits the Assembly Kit's XML tables (the database CAIME and BOB read); Tweak is the editor of which Terry is a mode.Steam → Library → Tools
- A scripting language
Python for us: everything repetitive, declaring tables, producing layers, checking a pack, running tests.
- WinDbg (cdb)
Reading the game's crash dumps.
cdb.exelives in the package'samd64subfolder, outside the PATH.winget install Microsoft.WinDbg --scope user - The game's logs
Knowing what the game really did: loading, scripts, rejected data.
See “When the game crashes” below
The words of the trade§
| Word | What it means |
|---|---|
| Pack | a mod's archive (.pack), placed in the game's data folder; to play, you tick it in the launcher |
| Table, key | a table of the game's database; each row has a unique key, and a mod adds fragments (pieces of a table) to it |
.loc | the displayed texts: one key per sentence |
| Startpos, ESF | a campaign's turn-0 save (startpos.esf), in Total War's binary format |
| Generation pack | a pack loaded only while the startpos is generated: it serves the start_pos_* tables to the game |
raw_data / working_data | what the Assembly Kit's tools read / what they produce |
| Campaign playable area | the campaign_map_playable_areas row that describes a campaign's map |
| Control case | a case known to be good, rerun identically next to yours |
Dump (.mdmp) | a snapshot of the game's memory at the moment of the crash |
| Null pointer | a read at address 0 (or very close to it): often, not always, the game looked for some data and did not find it |
%APPDATA% | your Windows account's settings folder (type it into Explorer) |
<game> | the game folder, the one holding Warhammer3.exe (Steam: right-click the game → Manage → Browse local files) |
| Lua | the game's scripting language (.lua), which the game loads from the packs |
| Event, listener | an event: what the game announces to scripts (a turn start, a battle…); a listener: a script function the game calls when that event happens |
| MCP | a protocol that lets an AI drive a tool; RPFM has a server for it |
Words specific to the map (hex, layer, swatch, lookup…) are in the CAIME guide.
Who does what, from database to game§
The whole chain of a new map, with each step's tool and the files it produces:
- The database: the Assembly Kit's tables (Dave, or the XML files by script), or a pack's (RPFM).
- The logical half: CAIME, then its exports: the CAIME guide.
- The visual half, meanwhile: Terry, then BOB: Terry, BOB. This is where a new map hits a wall: for a map the game's database does not know, BOB runs only 6 actions instead of a dozen, and we know of no official way past it; our method, outside the official routes and owned as such: BOB run under a debugger (“Campaign map terrain in brief”, below).
- The pack: RPFM gathers everything: the RPFM guide.
- Turn 0: the game itself generates the startpos from that pack (below); the files it produces go back into the pack, which you rebuild.
The Assembly Kit in brief§
The Assembly Kit is Creative Assembly's official kit (Steam → Library → Tools). Three folders matter: binaries (its programs), raw_data (what the tools read: XML tables, terrain, maps) and working_data (what they produce); alongside them, dave (Dave) and documentation. Back up before writing to raw_data\ (timestamped copies): it is the database CAIME and BOB read.
- Dave edits the
raw_data\tables; they can also be written by script.db\ *.xml - Tweak (
binaries\) is CA's editor. During CAIME's Map Data and Dynamic Resources exports, Tweak and Terry must be closed (Terry is a mode of Tweak). Don't rely on CAIME's warning: it looks for a program namedtweak.modder.x64.exe Tweak.AssemblyKit, while Warhammer III's kit shipstweak.modder.x64.exe. - Terry, a mode of Tweak: CA's page, written for the Warhammer I kit, presents it as the tool for campaign maps and battlefields, and states that the kit only lets you create battle tiles; we see the same in the Warhammer III kit, whose
raw_data\folder only holds battle data. While open, Terry locksterrain working_data: the Terry guide. - BOB turns sources into game files and packs, following
rules.bobfiles. BOB opens from the Assembly Kit's Steam launcher (Exporter: BOB), from its executablebob.modder.x64.exe, or from Terry (Process with BOB, Ctrl+P), which hands it the job. BOB has no command-line help; two official command lines are known, those of its launchers (box below): the BOB guide.
RPFM and packs in brief§
A Total War mod is a .pack file: an archive of tables, texts (.loc), Lua scripts, images and models. RPFM opens the game's packs read-only and builds yours; since version 5, its MCP server lets an AI drive it. Everything is in the RPFM guide, with three complete procedures: adding a unit, a faction, a legendary lord.
- Don't overwrite a game table: give your fragments your own name. When two fragments give the same key, the game keeps the one whose name sorts first; a fragment named like the game's file (
data__) replaces it entirely. - Don't redefine a game text: a mod's
.locfiles apply to every language. For a second language, for us: a second pack holding only its.loc, at the same path, which wins (a!at the start of its name). - In
data, a pack wins over loose files: a regenerated file (a startpos) only counts once it is back in the pack.
Campaign map terrain in brief§
Neither the Warhammer III kit nor the Warhammer I kit ships raw campaign terrain data. Yet Terry can open a campaign-type project: ChaosRobie proved it. For Immortal Empires Expanded, a mod he made with the CAIME team, he rebuilt the Immortal Empires map as a Terry project, and shared that project with the community. The project folder, its raster sizes, conventions and limits are in the Terry guide; the order of BOB's runs in the BOB guide.
A full successful run on a campaign terrain has 12 actions (15 if camera_heightmap.png is requested, and the added action crashes BOB; for us, about a minute once the relief is compressed, 25 minutes the first time). For a map that the game's database (the one in CA's packs) does not know, BOB runs only 6 of them, without a message; adding the map to the kit's database or to a mod pack changes nothing. We know of no official way to lift this limit: make a control case, then ask the community. The control case: a project known to be good, copied under another name; if it also stops at 6 actions, your files are not to blame.
Our method, owned as such: our new maps got their 12 actions through a tool of ours, outside the official routes. It starts BOB with the exact command Terry passes to it, under the cdb debugger, and hands it the map's limits that its database does not know; nothing is changed on disk beyond BOB's normal outputs. It is the only route we know for a new map's terrain; we say so plainly, and the details are in the BOB guide.
The start position (startpos)§
The startpos (startpos.esf) is the turn-0 save: factions, regions, characters, armies, diplomacy. Each campaign has a single start file, and a mod cannot add to it: it replaces it entirely (“there can be only one startpos”, says the modding wiki). Two mods touching the same campaign's startpos therefore do not combine.
The start_pos_* tables are written in the Assembly Kit (Dave), but the game does not read its XML files. For generation, they are served to it in a separate pack, loaded only while the startpos is generated; they never go into the pack you play. Only the generated files do.
The game builds the startpos itself, in a special mode driven by the file %APPDATA%\, which it reads at launch. Ours, for a new map: one mod line per pack, the generation, the AI's data, then the game's closing.
mod my_mod.pack;
mod my_start_tables.pack;
process_campaign_startpos my_campaign;
process_campaign_ai_map_data;
quit_after_campaign_processing;Three routes lead to this mode: RPFM's Build Startpos, BOB's Process start pos action, or a user.script.txt written by hand. For us, only writing it by hand worked. RPFM (right-click on the pack's root → Build Startpos) writes the generation's user.script.txt itself, but puts only one mod line in it: the open pack's. Our generation reads two packs (the mod and the start-table pack), so we write the script by hand. An add_working_directory line, which we had tried for the generation, made the game exit within nine seconds without producing anything; for playing, it does load a mod: it is the generation it breaks.
Generating it§
In brief, the five stages of generation:
- The start tables
The
start_pos_*tables, in the game's format, in a generation pack; next to it, the up-to-date mod pack.trap: the game does not read the kit's XML files
- The game's script
user.script.txtloads the packs, asks for the generation, then for the game to close.trap: restore it afterwards
- The game, in a special mode
It creates the campaign world, saves it, then closes. Steam must be running.
trap: closed does not mean done: check the file's date
- Turn 0
The startpos and, for a new map, the AI pathfinding data, written as loose files in
data.startpos.esf,hlp_data.esf,spd_data.esf - Into the pack
The three files join the mod's pack, which you rebuild.
trap: the pack wins over loose files
Step by step, as we do it; order matters: the mod pack first, then the generation, then the rebuilt pack.
- The mod pack, built and placed in the game's
datafolder, up to date (scripts included): the generation reads its tables (campaigns, the map…) and runs its scripts. - The generation pack, also placed in
data: it holds thestart_pos_*tables (see “The generation pack” below). - The script: keep a copy of
user.script.txtif it exists, then write the lines given above into it: onemodline per pack, the generation, the closing. - The AI data folder, for a new map: create the empty folder
<game>\before starting the game. Without it, neitherdata\ campaign_maps\ <map>\ hlp_data.esfnorspd_data.esfis written, without a message, and the campaign crashes while setting up the player. RPFM's Build Startpos creates it itself. - The generation: with Steam open and the game closed, start the game's executable directly (
Warhammer3.exe), then wait for it to close by itself, without touching its window. For us, asteam_appid.txtfile holding1142710(the game's Steam number), next to the executable, keeps the game, started directly, from going back through Steam; RPFM, for its part, starts the game through Steam. - The produced files: the game writes
<game>\; withdata\ campaigns\ <campaign>\ startpos.esf process_campaign_ai_map_data, for us,hlp_data.esfandspd_data.esfin<game>\. Check their date and time.data\ campaign_maps\ <map>\ - The rebuilt pack: copy these files into the mod's sources, rebuild the pack, then remove the loose copies from
data: the pack wins over them. - The clean-up: restore
user.script.txt; left as is,quit_after_campaign_processing;closes the game on every launch. Also move the generation pack out ofdatauntil the next generation: otherwise it shows in the launcher, where someone could tick it.
process_campaign_startpostakes a single argument, the campaign key.- With
process_campaign_ai_map_data, the game also writes the AI pathfinding data (hlp_data.esf,spd_data.esf), essential for a new map: without them, the game crashes while setting up the player. The game only writes them if the<game>\folder already exists. The time varies a lot: 16 to 22 s for us (400 × 440 and 560 × 905 hexes); tw-modding's campaign map tutorial gives under a minute fordata\ campaign_maps\ <map>\ spd, about five minutes forhlpon a medium map and well over an hour on a large one; RPFM estimates 10 to 30 minutes. - To our knowledge, these commands are not publicly documented: we checked them on patch 8.1 of the game, then with updates 9.0 and 9.0.2 (September and October 2026). Check them again after an update.
- Loading a mod: to play, you tick the mod in the launcher; to generate a startpos by hand, one
mod <pack>;line per pack inuser.script.txt. Started directly, the executable only loads the packs named this way. - The three files go into the pack:
campaigns/,<campaign>/ startpos.esf campaign_maps/and<map>/ hlp_data.esf campaign_maps/.<map>/ spd_data.esf - With RPFM (right-click on the pack's root → Build Startpos): the pack must be in the
datafolder, the campaign declared in the pack (campaigns_tables), and the game closed; everything the generation reads must be in that one pack. Through its MCP server,build_starposanswers “Success” in zero seconds: that means “game launched”, not “startpos built”; wait for the game to close, then callbuild_starpos_postandbuild_starpos_cleanup. With RPFM 5.1 or later, an MCP session idle for 5 minutes is closed: during a long generation, send a light command every 2 to 3 minutes (list_open_packs) or reopen the pack beforebuild_starpos_post(deduced from RPFM's code, not yet tried). Details: the RPFM guide.
The generation pack§
It is an ordinary mod pack, created with RPFM, used only for generation. It holds the start_pos_* tables in the game's format: pack tables, not the kit's XML files. For us, the campaign's campaigns row and the other tables the generation reads stay in the mod pack, loaded at the same time; with RPFM's Build Startpos, which loads a single pack, everything must be in that one.
- For us, it was built once from the start tables that BOB's database export writes, in the game's format, for each campaign (
raw_data\), without the XML files orEmpireDesignData\ campaigns\ <campaign>\ campaigns(the BOB guide describes that export). Then every row added to the kit was copied into it by script, through RPFM's MCP server. - Reread what BOB writes: it had set
defaultas the subtype of some of our characters, a value the game rejects in a mod pack; we put back the kit's values. - By hand, in RPFM's window: creating a pack, adding a table to it and pasting rows are in the RPFM guide.
- Check before launching the game: every value that points to another table (a faction, a subtype, an AI group) must exist there. Otherwise, the game's validator names the faulty record (box below).
What a startpos requires: the crashes we went through§
- Every settlement has a
primaryslot (start_pos_region_slot_templates): without it the startpos still generates, and the game crashes on loading. - Every faction has an AI group containing a personality: otherwise, a crash.
- Without
start_pos_starting_general_options, no lord can be picked on the selection screen. - In
start_pos_regions,rebel_faction_nameandlong_descriptionstay empty: any text (the kit's “PLACEHOLDER”) crashes world creation, with no dump and no crash report: the log stops right after the mods load. - The slot template comes from CA, for the owner's subculture: a settlement's trio (
primarytemplate fromstart_pos_region_slot_templates,primary_building,port_building) exists as is at CA for the same subculture; never a*_porttemplate on a region without a port. Otherwise the generation passes, and loading crashes (9.0.2). A region that changes owner takes templates AND buildings from the new owner's culture. - A faction that CA starts as a horde, without a region, gets no settlement at the start: same crash on loading (9.0.2).
- A port settlement keeps 16 + 3 hexes (16 main, 3 port): in 19 + 3, or in 16 + 1 and 16 + 2, loading crashes while CAIME validates the map (the CAIME guide, “Towns”).
campaigns.maskstays empty, as in every campaign in the kit: a non-empty mask crashes the generation (9.0.2). Copy a workingcampaignsrow, field by field.- The map preview on the selection screen (
preview_width×preview_heightincampaign_map_playable_areas) has the world's aspect ratio, height 600 (CA: 750 × 600); otherwise the map looks distorted there. Regenerate the startpos after any change to that row. - Never a
*_ownership_content_pack_junctionstable for a key of yours (faction, playable area, battle…): the game closes within 9 to 13 s, with no report and nomp_log(seen during the startpos generation, 9.0.2). A DLC lock is done by script. - A starting character placed at (0, 0) joins, as a garrison, the settlement that
start_pos_character_to_settlementsgives it; without that link, it appears in the corner of the map, on cell (1, 1). - A scripted campaign is generated AFTER its scripts: during generation, the scripts move the save counter (
__save_counter) from 0 to 1;cm:is_new_game()reads it. With a startpos older than the scripts, every new game is taken for a saved game: no intro, no missions, and thescript_logsays “reconstructing markers and listeners from saved data”. If your scripts error during generation, the counter also stays at 0: read the generation'sscript_log(seen on patch 8.1, on 23.09.2026). - Check before playing: compare the new startpos's structure with that of a startpos that loads (same blocks, same children).
When the game crashes: reading the clues§
Five questions, in order; each “yes” tells you which file to open:
%APPDATA%\: rejected data. TheThe Creative Assembly\ Warhammer3\ crash_report\ bad_mods_report.txt .mdmpdumps are in the same folder; the*.stack.txtsays almost nothing, the dump does.%APPDATA%\: how far loading got (database read, checksum, campaign environment created).The Creative Assembly\ Warhammer3\ logs\ mp_log.txt - The script log: a non-empty
script/file in a loaded pack, and the game writesenable_console_logging script_log_DDMMYY_HHMM.txtin its folder (an empty file is ignored). Clicks, even simulated ones, are logged there with the component's path. - The dump in the debugger: install WinDbg (
winget install Microsoft.WinDbg --scope user).cdb.exeis not on the PATH: PowerShell gives the package folder with(Get-AppxPackage Microsoft.WinDbg*).InstallLocation, andcdb.exeis in itsamd64subfolder. Then, in PowerShell,$cdb = "<folder>\(amd64\ cdb.exe" <folder>: that package folder), and& $cdb -z <dump.mdmp> -c ".ecxr; k 40; q". Without.ecxr, you are looking at the crash reporter's thread, not the faulting one. - Reading the verdict: code
0xC0000005with a read at a null or near-null address is a null pointer: often, not always, some expected data is missing. Look first in your tables for what the game did not find. - File crashes by test case and address: the address depends on the campaign and on the game version; note the game version next to each address. After an update, old addresses no longer compare.
- A crash that comes and goes: judge on a series. For us (update 9.0, 25.09.2026), the game crashed while rendering the map, at random, even in a normal game, and RPFM's server (
rpfm_server, version 5.0.6) kept the memory of every pack it built: nearly 70 GB after a night; with the server restarted, three tests passed. That was not the cause: the same crash came back on a restarted PC, with the server off. Three successful tests prove nothing: at least ten per variant. The cause named since (game on 9.0.2): mountains and cliffs placed as props with the terrain tiles' material 49, whereas CA only uses materials 68, 86 or 97 for its mountain props; an encouraging lead, not yet a proof (the Terry guide). rpfm_server's memory leak is real (5.0.6: each MCP connection creates a session that is never freed, 2 to 10 GB; 5.1.0 fixes it): restarting the server before a test is still good hygiene. Measure its private memory ((Get-Process rpfm_server).PrivateMemorySize64, or “Committed memory”), not the working set: for us, 91 MB of working set for 9.4 GB of private memory. Beyond 8 GB, restart it.- The game closes within seconds without writing anything (no report, no
mp_log): a*_ownership_content_pack_junctionstable for a key of yours? Remove it. Otherwise, remove one table at a time, on a copy of the pack, until you find the culprit. - Steam must be running: otherwise the game closes within seconds, and it looks like a crash.
Testing without playing: automated games§
To know whether a campaign holds for thirty turns, you don't have to play them. Our method:
- A separate test pack (created for the test, removed afterwards) holds a Lua script that clicks through the interface like a player: menu, campaign, lord, game start, end turn. Components are addressed by their path in the interface.
all_players_ai;inuser.script.txtmoves the player's turns on, but their faction does not play (for us: no recruit, no building): this mode tests the other factions and stability, not the player's faction. To our knowledge, this command is not publicly documented: checked on patch 8.1 and updates 9.0 and 9.0.2.
- At the end: a turn report, the
script_logread through, the dumps if any. Thenuser.script.txtrestored and the test pack removed, even after a forced stop. - The limits: in “AI plays everything” mode, no mission is issued to an AI. This mode tests stability (AI, invasions, dilemmas); a lord's story and mechanics are tested in player mode.
- An event that never arrives: on our map,
FactionTurnStartreached no script, underall_players_aias in player mode, whileFactionBeginTurnPhaseNormalarrived every turn. The cause: in the released game, the conditions of all of an event's listeners are evaluated in a single loop, without protection; a condition that errors cancels the event for every script, CA's and yours alike, without writing anything to the log. A callback that errors does the same (update 9.0). - Catching these errors: for us, a protected version of the
core:event_callbackmethod of CA's library, which names each faulty listener in the log, once. That library'sevt_callbackvariable is local to its file: replacing it from another script has no effect. And a test only proves a listener through a log line written by that listener. - The culprits, for us: three CA listeners (
wh3_campaign_bonus_values.lua), two for Mother Ostankya and one for Yuan Bo, whose condition failed at every turn start: they expect Kislev and Cathay systems that our campaign does not load. With their errors caught, the event came back. - The chosen remedy: remove these listeners by name when the campaign starts (
core:remove_listener), rather than create dummy variables. It has since been confirmed in three three-turn automated games, the AI playing everything (25.09.2026, update 9.0): listeners removed,FactionTurnStartreceived every turn; not yet in player mode. - The menu, in detail: the lord list only shows the lords of the chosen race (
campaign_select_new > culture_list); the screen opens on the last campaign chosen; a menu script only launches once per session (for us, a flag kept withcore:svr_save_bool), otherwise, back at the menu, it relaunches in a loop. Our clicks go throughfind_uicomponent,GetPropertyandSimulateLClick, retried every two seconds withcore:get_tm():real_callback. - The end of turn only goes through after closing the notifications one by one: every turn in player mode, only on turn 1 under
all_players_ai(later turns play by themselves). - The camera at playing height, set on the leader from the first turn: a test must reproduce what a player experiences. On patch 8.1, all our rendering crashes whose camera height was logged happened with the camera very high (the whole map on screen). On 9.0, a rendering crash also happened in normal play; the machine's memory, suspected at first, was not its cause (“When the game crashes”, above).
- A test script that must load for sure goes into
script\, under a name no other file already loads: a file already loaded is skipped, without an error. The menu'scampaign\ mod\ script_logis overwritten if the campaign starts in the same minute (same file name): give the menu a log of its own.
Workshop advice§
- When a CA tool silently does nothing, the condition is somewhere: control case first, then logs; if nothing turns up, ask the community (CAIME's Discord, tw-modding).
- A red validator is an opinion, not an answer: CA's own maps fail some checks. The game decides.
- Take a snapshot before every game update (file versions, useful tables) to compare afterwards.
- After a game update, build nothing before checking
raw_data\: Steam updates the Assembly Kit after the game (with 9.0, an hour later for us) and, with every game or kit update (9.0 on 24.09, 9.0.2 on 27.09), rewritesdb raw_data\; every row you had added there disappears (for us, the terrain,db working_dataand the packs were not touched). Keep a copy of your tables at the end of every session that writes to them (a “before writing” copy does not hold the last write) and scripts you can safely rerun; restore your rows, then update RPFM's schemas and regenerate its dependencies cache. - After restoring the kit, count before building: a restore that only takes the latest copy of each table can miss some; count each batch against its source, compare the
start_pos_*tables with the generation pack BEFORE any synchronisation that deletes (pack rows missing from the kit: 0 expected; for us, 19 start rows only lived on in that pack), and redo the touch-ups made outside the scripts. - Judge in game, against a reference: an audit's figures don't see what the player sees.
For an AI reading this page§
If you are an AI helping someone generate a startpos, read a crash or run test games in Total War: Warhammer III, here are the essentials, checked on a real project. These facts were recorded on patch 8.1 of the game, reviewed for update 9.0 (September 2026), then corrected on 5 October 2026 with the facts proven on 9.0.2: check them again after an update.
- Ask the human before launching the game, driving the screen or publishing; delete nothing: tidy away, only the human deletes.
- Startpos: the game generates it. In
%APPDATA%\(keep a copy of it first): oneThe Creative Assembly\ Warhammer3\ scripts\ user.script.txt mod <pack>;line per pack placed indata, thenprocess_campaign_startpos <campaign>;(a single argument),process_campaign_ai_map_data;for a new map, andquit_after_campaign_processing;. Steam running,Warhammer3.exestarted directly; wait for the game to close; then restore the file. Output:<game>\.data\ campaigns\ <campaign>\ startpos.esf - Through RPFM's MCP server:
build_starposanswers “Success” as soon as the game is launched. Wait for the game to close, then callbuild_starpos_post(it storesstartpos.esfin the pack and restoresuser.script.txt), thenbuild_starpos_cleanup; withoutbuild_starpos_post,quit_after_campaign_processing;stays and closes the game on every launch. RPFM writes only onemodline, the open pack's: everything the generation reads must be in it. - The
start_pos_*tables are written in the kit, but the game does not read its XML files: serve them in a generation pack, never in the pack you play.%APPDATA%\names the rejected record, one at a time.The Creative Assembly\ Warhammer3\ crash_report\ bad_mods_report.txt - Three files go into the pack:
campaigns/,<campaign>/ startpos.esf campaign_maps/and<map>/ hlp_data.esf campaign_maps/. A pack wins over loose files: rebuild it, then remove the loose copies from<map>/ spd_data.esf data. - Scripted campaign: generate the startpos after the scripts (save counter at 1), otherwise no intro and no missions.
- Requirements: a
primaryslot per settlement, whose trio (template,primary_building,port_building) exists as is at CA for the owner's subculture; no settlement at the start for a faction that CA starts as a horde; ports in 16 + 3; an AI group with a personality per faction;start_pos_starting_general_optionsfor the selection screen;rebel_faction_nameandlong_descriptionempty instart_pos_regions;campaigns.maskempty; no*_ownership_content_pack_junctionstable for a key of yours; for a new map,<game>\created before the generation.data\ campaign_maps\ <map>\ - Crash: follow the diagnostic tree;
0xC0000005with a read at address 0 often, not always, means some expected data is missing; the address depends on the campaign and on the game version. - Test games: a separate test pack, removed afterwards (and, after any forced stop,
user.script.txtcleaned); launch through the interface; notifications dismissed one by one (every turn in player mode, on turn 1 underall_players_ai); camera at playing height; nobody touches the PC; a control case; at least ten runs per variant for a random crash. - Intermittent crash: judge on a series (at least ten tests per variant), never on three successes.
rpfm_server's memory leak (5.0.6, fixed in 5.1.0) is real, but was not the cause of our rendering crash; measure its private memory and restart it beyond 8 GB. Cause named (9.0.2, a lead, not a proof): mountains placed as props with the tiles' material 49. - Game closing without writing anything: think of
bad_mods_report.txt's blind spots (DLC ownership junction on a key of yours, non-emptycampaigns.mask); remove one table at a time on a copy of the pack. - A script event that never arrives: a listener condition that errors cancels it for every script, without a log line. For us,
FactionTurnStartwas missing in player mode as underall_players_ai, because of three CA listeners (Mother Ostankya, Yuan Bo) loaded without their systems; with them removed by name when the campaign starts, the event arrives every turn (checked underall_players_ai, 9.0). Catch and name the listeners' errors; a listener is only proven by its own log line. - After every game or kit update (9.0, then 9.0.2): Steam updates the Assembly Kit later and rewrites
raw_data\, added rows lost; check it before building anything, restore the rows, count each batch against its source, compare thedb start_pos_*tables with the generation pack before any synchronisation that deletes, then RPFM's schemas and dependencies cache. - Never guess a tool's options (BOB, Terry, Tweak); a backup before writing to
raw_data\; a red validator is an opinion, the game decides.db - Reading and documenting a file format, as RPFM and CAIME do: yes. Altering CA's programs or working around their limits: no, with one exception the workshop owns, stated plainly in the BOB guide: BOB run under a debugger for a new map's terrain. When a tool gets stuck, a control case, then the community (CAIME's Discord, tw-modding).
Sources and links§
- RPFM manual and RPFM For Dummies (tw-modding wiki).
- Campaign Map Making for Warhammer III and Startpos (tw-modding wiki).
- Script documentation, maintained by Vandy.
- Terry introduction (written for the Warhammer I kit) and Rules.bob (Creative Assembly wiki).
- CAIME documentation.
- Our guides: CAIME, RPFM, Terry, BOB, modding with an AI.
Frequently asked questions
Do I need the Assembly Kit to mod Warhammer III?
For tables and scripts, RPFM is enough. For a campaign map, yes: CAIME reads its database, Terry and BOB build the terrain, and the startpos tables are written there.
Which guide should I start with?
For a map: the CAIME guide. For units, factions or lords: the RPFM guide. For 3D terrain: Terry, then BOB. For working with an AI: the AI guide.
Where does the game write the startpos it has just generated?
In <game>\; for us, hlp_data.esf and spd_data.esf in <game>\. Copy them into the mod, rebuild the pack, then remove these loose copies from the data folder.
Why does my new startpos change nothing in game?
Because the pack wins over loose files: put the startpos back into the pack, rebuild it and remove the loose copy from the data folder.
The campaign starts without its intro or missions: why?
Often the startpos is older than the scripts: regenerate it with the up-to-date pack (the save counter, __save_counter, must be 1). In all_players_ai mode, no mission is issued: that is normal.
My FactionTurnStart listener never fires: why?
Perhaps not because of it: a listener condition that errors, even in a CA script, cancels the event for everyone, without writing anything to the log. For us, three listeners for Mother Ostankya and Yuan Bo, deprived of their systems on our map, cut it off in player mode as under all_players_ai. Catch and name the listeners' errors to find the culprit; for us, removing the three listeners by name when the campaign starts brought the event back (checked under all_players_ai, update 9.0). FactionBeginTurnPhaseNormal, for its part, arrived every turn: our turn-start listeners moved to it.
My Assembly Kit rows disappeared after an update: why?
Steam updates the Assembly Kit after the game (for us, an hour later, with 9.0) and, with every game or kit update (9.0, then 9.0.2), rewrites raw_data\: added rows disappear; the terrain, working_data and the packs were not touched. Restore your rows from your copies, or rerun the scripts that write them, before building anything; count each batch against its source and compare the start tables with the generation pack; then update RPFM's schemas and regenerate its dependencies cache.
No lord shows on the selection screen: why?
The start_pos_starting_general_options rows are missing: they link a startpos character to a lord card (frontend_faction_leaders). Add them, then regenerate the startpos.
My startpos generates, but the campaign crashes on loading: what should I check?
A primary slot for every settlement, with a template and buildings that CA uses for the owner's subculture; no settlement at the start for a faction that CA starts as a horde; ports in 16 + 3; an AI group with a personality for every faction; hlp_data.esf and spd_data.esf in the pack for a new map; and the %APPDATA%\ file, which does not see these settlement mistakes.
Why does the game close by itself on launch?
Often a user.script.txt left over from a startpos generation (quit_after_campaign_processing;), or Steam not running. If it closes within seconds with no report and no mp_log: a *_ownership_content_pack_junctions table for a key of yours? Remove it; otherwise, remove one table at a time on a copy of the pack.
Why do my texts replace the game's in every language?
The game loads a mod's .loc files whatever the language. Only add new keys. For a second language, for us: a second pack holding only its .loc, at the same path, which wins (a ! at the start of its name).
Where are the logs?
%APPDATA%\ (with the .mdmp dumps next to it), %APPDATA%\, the script log (script_log_*.txt) in the game folder, and BOB's logs in the kit's binaries folder.
How do I turn on Warhammer III's script log?
Put a non-empty script/ file in a loaded pack: the game then writes script_log_*.txt files in its folder.
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.