wheybags' blog: Parsing Crusader Kings III data files to generate mods

Parsing Crusader Kings III data files to generate mods

- 21st September 2025

TL;DR: I wrote a system for parsing and modifying CK3 data files. This allows me to make mods which work with any version of the game, and are compatible with any other mods. I then used this system to create two mods: NoMore and Eurocentric.

I love CK3. But sometimes, the UX drives me a bit mad.

What is Crusader Kings III?
Crusader Kings III is a medieval grand strategy game, where you control a dynasty over multiple generations. Imagine something a bit like a slow paced Age of Empires, crossed with The Sims. You marry, have children, wage wars, plot and scheme in medieval Europe. It's fun!

One of the worst UX offenders is the context menu that opens when you right click on another character. It does this super annoying thing where it hides many interactions behind a "more" button, meaning it takes two clicks to do what would otherwise take only one. If there was no space to show all interactions I would understand, but that is not the case at all:

THERE'S SO MUCH EMPTY SPACE HOW DARE YOU BURGER MENU ME

Well, ok I suppose it's not that bad. But I wanted to fix it. Luckily, the game is moddable! Interactions are defined in text files, with data in a proprietary almost-json format that looks like this:

seduce_interaction = {     icon = icon_scheme_seduce     category = interaction_category_friendly     interface_priority = 45     scheme = seduce     common_interaction = no # foreshadowing     send_name = START_SCHEME     ignores_pending_interaction_block = yes     ai_targets = {         ai_recipients = family         max = 2     }     # ... etc for 600 lines }

The game determines which interactions to hide behind a "More" with the common_interaction flag. So to show everything, all we need to do is change every common_interaction = no to common_interaction = yes and, as the field is optional and defaults to no, also add it to every interaction that is missing the flag entirely.

Cool, so job's done right? Well, no. The way the modding system works is file-based. If I want to edit, for example game/​common/​character_interactions/​00_scheme_interactions.txt, what I need to do is copy that file from the base game into my mod, and edit it there. The game will then detect that the mod contains an override of a base game file, and it will load my modified file instead. This system has several problems:

  • When the game is updated the file can change, and your copy of the old file will still override it
  • If another mod you have installed also edits that file, only one of them can be applied

Unacceptable

So, what do we do? Well, reimplement a parser for CK3 datafiles, mod playset fetcher, file resolver, and while I'm at it a localisation parser, and another mod entirely. I use the parser to load the existing data files, apply the appropriate modifications, and save the result into a new mod.

If the file you want to edit has already been overwritten by another mod, I detect that and load the override for modification, so my changes get stacked on top. This way, I can have compatability with any game version, and any other mods - even total conversion mods like Elder Kings II:

Divayth Fyr has a scrict "no seducing the patients" policy

Here's some links, for anyone who wants to try things out themselves:

  • NoMore on the steam workshop - remove nesting from right click menus
  • Eurocentric on the steam workshop - display European feudal title tier names everywhere
  • Source code on github


Bonus section: Some details about parsing

So, why didn't I use an existing parser? Well, I had a look at a few of them, but from what I could tell they were all lacking something I consider a critical feature for this tool: the ability to round trip a file and have it come out identical to how it went in. The paradox data format is pretty loose. You can have all sorts of variation in whitespace, comments, etc. If you're authoring a mod, it's important that you can open the base game and your mod folder in something like winmerge and see if the changes your code is making are correct. If the entire file is being reformatted every time, it makes the diff super noisy and it's impossible to verify your change.

In the end, I put in some effort to record comments and whitespace, and match surrounding indentation levels when creating new objects, which results in reasonably clean diffs.

•••

Blog index
Subscribe via RSS, Email, twitter, or mastodon