Data Types
The data types in ConflictInterface model the GameObjects that Conflict of Nations uses. They are the bridge between Python objects and the JSON payloads we get from the game/client.
Versioning
The game changes its JSON schema over time. To keep replays, parsing, and tooling working across client updates, ConflictInterface supports multiple datatype versions.
- Where versions live:
libs/conflict_interface/conflict_interface/data_types/- Versioned snapshots:
v210/,v211/, ... - Current development head:
newest/
- Versioned snapshots:
- What “latest” means:
- The canonical latest version number is
conflict_interface.versions.LATEST_VERSION, which is re-exported fromconflict_interface/data_types/newest/version.py. - Supported versions are the ones that are registered with the
JsonParser(seelibs/conflict_interface/conflict_interface/versions.py).
- The canonical latest version number is
Retention policy
ConflictInterface intentionally keeps only a rolling window of datatype snapshots:
- We keep at most the latest 4
v###directories underconflict_interface/data_types/. newest/is the current latest; thev###/directories are the legacy snapshots.- When a new client version lands and we add support:
- we add a new snapshot directory for the previous latest (see workflow below)
- and we delete the oldest snapshot directory if that would take us above 4 legacy versions
This keeps maintenance overhead and repository size under control while still giving us enough history to:
- parse a reasonable span of older replays/test data
Updating data types to a new client version
This is the workflow we use when the game/client bumps its schema version.
1) Get the new “full test data” JSON
ConflictInterface’s conversion tests are driven by a captured gamestate JSON named:
full_test_data_1_v<VERSION>.json.
In CI, the tests download this file from the zDox/ConflictData repo (see .github/workflows/conflict_interface-tests.yml), using the current LATEST_VERSION.
Locally you can do the same (replace <VERSION>):
cd libs/conflict_interface
mkdir -p tests/test_data
wget -O "tests/test_data/full_test_data_1_v<VERSION>.json" \
"https://raw.githubusercontent.com/zDox/ConflictData/refs/heads/main/FullTestData/full_test_data_1_v<VERSION>.json"
If you maintain the test-data capture pipeline, there is also a scheduled workflow that detects version changes and opens a PR to ConflictData (see .github/workflows/conflict_interface-update-testdata.yml).
2) Snapshot the previous latest into a v###/ package
Before you start changing newest/, snapshot the current state so older versions remain supported.
- Create a new directory:
libs/conflict_interface/conflict_interface/data_types/v<OLD_LATEST>/ - Copy the current
newest/contents into it.
Example (illustrative):
- if
newest/version.pycurrently says212, you snapshot intov212/before movingnewest/forward.
Why: conflict_interface/data_types/__init__.py auto-imports version packages like v210, v211, ... so the parser registry keeps knowledge of those versions.
3) Bump newest/ to the new version number
Update:
libs/conflict_interface/conflict_interface/data_types/newest/version.py(VERSION = ...)
This is what flows through:
conflict_interface.versions.LATEST_VERSION- CI selecting which
full_test_data_1_v<VERSION>.jsonto download - the conversion test selecting which test file to load (see below)
4) Update the dataclasses/parsers in newest/ until conversion passes
Now edit the types under:
libs/conflict_interface/conflict_interface/data_types/newest/
Goal: parsing and dumping the new gamestate JSON should round-trip cleanly (or at least within the comparison constraints).
5) Enforce the “newest + 4 legacy versions” rule
If adding the new snapshot makes you exceed 4 legacy v###/ directories:
- delete the oldest
v###/directory (the smallest version number)
Using the game_object conversion test to see what changed
The fastest way to learn “what broke” after a client update is to run the conversion test and read its diff output.
What the test does
libs/conflict_interface/tests/test_gameobject_conversion.py:
- loads
tests/test_data/full_test_data_1_v{VERSION}.jsonwhereVERSIONcomes fromdata_types/newest/version.py - parses the JSON into
GameState(and each individual*State) - dumps the parsed objects back to JSON
- compares original vs dumped using
tests/helper_functions.compare_dicts, printing paths for any missing keys, changed values, or type mismatches
Those printed paths are your “what changed” map.
How to run it locally
cd libs/conflict_interface
python -m unittest -v tests.test_gameobject_conversion
Output looks like:
Type at path ultshared.UltMod/upgrades/4117/ut/c/30 is different:
Original: float
Processed: int
Type at path ultshared.UltMod/upgrades/4117/ut/rnf is different:
Original: float
Processed: int
How to interpret the output
- “Type at path … is different”: the dump produced a different JSON type than the input (e.g.
intvsfloat). - The path is your breadcrumb trail:
- the prefix (e.g.
ultshared.UltMod) typically identifies which top-level state/object you’re in - following segments (
upgrades/4117/...) lead you to the exact nested field that mismatched
- the prefix (e.g.
- What to do next:
- find the corresponding type in
libs/conflict_interface/conflict_interface/data_types/newest/for that state/object - adjust the field type logic so the round-trip preserves the expected JSON shape for the new client version
- find the corresponding type in