Skip to main content

Dragoman

Translate maps between Open Doctrines (.odmap) and Greater Diplomacy 5 (map directories), in both directions, losing as little as the two formats allow — and nothing at all on a round trip.

A dragoman was the interpreter attached to an embassy: the person through whom two powers who shared no language could nonetheless sign something. This is that, for map files.

pip install open-dragoman

dragoman convert 1914.odmap base_maps/1914 --to gd5
dragoman convert base_maps/GD4 gd4.odmap   --to odmap
dragoman roundtrip 1914.odmap              # prove nothing was lost
import dragoman

dragoman.convert("1914.odmap", "base_maps/1914", to="gd5")

world = dragoman.load("1914.odmap")
print(world.name, len(world.provinces), "provinces")

Read the wiki → — what it is, how to use it, what every message means, and what it cannot do.

Status

Every map both games ship round-trips without losing a single modelled field:

Suite Result
Greater Diplomacy 5 maps (12 base maps + 16 scenarios) 28 / 28
Open Doctrines maps (5 scenarios + the world map) 6 / 6
Unit tests (raster, scripts, ABI, versioning, round trip) 5 / 5

Verified against Open Doctrines and against GitGetGot415/Greater-Diplomacy-5. Reproduce with python3 tools/conformance.py <directory of maps>.

Converted maps have also been played in both games, not merely loaded by this library. Open Doctrines' world map converted to GD5 boots through GD5's own Controller and Map state with all 23 screens, its flags drawn, its oceans navigable and every province centre inside its own province; a GD5 map converted to Open Doctrines plays five AI turns under OpenDoctrines --simulate. Nearly everything this library gets right, it gets right because somebody opened the result in the game and looked at it — the flag encoding, the ocean, the political layer's colour key and the province-border fill were all found that way.

One thing crossing to Open Doctrines still needs a human: GD5 starts its nations with an empty stockpile and Open Doctrines expects a starting endowment, so a converted map bankrupts its world on the first turn unless treasuries are set. Reported as od.treasury rather than guessed at.

What "lossless" means here

The two games are not the same game, so a straight translation always loses something: Open Doctrines models a province's population, its port and its ethnic minorities, and GD5 has no field for any of them; GD5 models terrain, province adjacency, unit rosters and research, and Open Doctrines has no field for those.

Dragoman writes the difference down. Everything the destination cannot hold goes into a sidecar beside the map — dragoman_sidecar/ in a GD5 directory, dragoman/ inside a .odmap archive. Both games read a fixed list of filenames and ignore everything else, so the sidecar is invisible to them and costs the converted map nothing.

The result:

  • Converting one way is as faithful as the target format permits, and every approximation is reported by a stable code you can act on.
  • Converting back restores what the target could not hold. A → B → A keeps every province, nation, relation, claim, core, script and carried file, and the province raster hashes identical.

dragoman roundtrip <map> asserts exactly that. Pass --no-sidecar for a smaller, genuinely lossy conversion — the round trip then fails, on purpose.

Not promised: byte-identical container files. Two zip archives holding identical members are different files, because deflate is not reproducible across implementations, and Open Doctrines packs with Python's zlib while this packs with miniz. Every file inside is preserved exactly.

What crosses

Open Doctrines Greater Diplomacy 5
Province raster provinces.png, id packed big-endian id_map.png, id packed little-endian
Province identity preserved exactly — the rasters differ only by swapping red and blue
Owner, name, claims ✅ ✅
Cores — ✅ (carried)
Sea provinces — (synthesised for GD5) ✅
Population, ports ✅ — (carried)
Fortification ✅ 0–5 ✅ Fort Lvl N, 1–20 (scaled ×4)
Political axis ✅ auth, −100..100 ✅ political_value, −10..10 (scaled 10:1)
Guarantees, truces ✅ ✅
Minorities, economic axis, policies ✅ — (carried)
Terrain, adjacency, province centres — (derived from the raster) ✅
Units, buildings, research, factions — (armies carried) ✅
Flags a PNG in the archive raw 60x40 pixels, base64
Relations ally, non-aggression, guarantee war and alliance only (rest carried)
Scripts imperative #OD/MapEngine/1 declarative scripted events

Adjacency and centroids are computed from the province raster when converting to GD5, since Open Doctrines derives both at load and never stores them. The centroid finder deliberately handles crescent-shaped provinces, whose mean pixel falls outside themselves.

Full field-by-field detail: docs/mapping.md.

Scripts

Open Doctrines' scripting is imperative and line-based, with loops and waitUntil suspension points. GD5's is a list of declarative events, each a set of conditions and a set of actions. The overlap is the shape both express: a gate, and things that happen when it opens.

An Open Doctrines script written as top-level waitUntil stages becomes GD5 events, one stage at a time. A GD5 event becomes an entry script with a waitUntil and some set lines. Anything outside that overlap — a foreach over a country's provinces, conditions chained with XOR — is reported by name and carried unchanged rather than half-translated. GD5 event types this library has never heard of pass through untouched, so a GD5 → OD → GD5 trip is lossless even for conditions added to the game after this was written.

Details and the full vocabulary: docs/scripting.md.

Installing

pip install open-dragoman

The wheel carries the compiled library inside the package, so there is no compiler needed at install time and nothing to locate afterwards. You get both the Python API and a dragoman command.

Prebuilt binaries for people who want nothing to do with Python are attached to each release. The full set of options — release archives, source builds, CMake FetchContent — is on the Installing page.

Building from source

Needs CMake 3.16 and a C++17 compiler. There are no external dependencies — miniz, stb and nlohmann/json are vendored, all MIT or public domain.

cmake -S . -B build -DCMAKE_BUILD_TYPE=Release
cmake --build build
ctest --test-dir build --output-on-failure

This produces libdragoman.a, a shared libdragoman.{so,dylib,dll}, and the dragoman command line tool.

Using it from your language

The core is C++17 behind a flat C99 ABI, so anything with an FFI can call it. The whole interchange model is available as JSON through dg_world_to_json, which is how a binding reads or edits a map without needing an accessor per field.

  • C — #include <dragoman/dragoman.h>, link dragoman. See bindings/c/example.c.
  • C++ — #include <dragoman/dragoman.hpp> for an RAII wrapper over the same ABI. See bindings/cpp/example.cpp.
  • Python — pip install open-dragoman. Pure ctypes, and the wheel carries the library, so no compiler is needed at install time.
  • Anything else — Rust, Go, C#, Java, Lua and WebAssembly all bind the same header. docs/abi.md documents the contract.

Versioning

Two numbers that move for different reasons:

  • Library version (VERSION, semver) — the release. (Look in VERSION file to find current latest version).
  • ABI version (DRAGOMAN_ABI_VERSION) — bumped only when an existing symbol changes meaning, so a binding can refuse to load a library it cannot speak to without parsing semver.

The version lives in VERSION and is mirrored into the C header, the Python package and the CMake project. tools/check_version.py and tests/test_version.cpp both fail if any copy drifts, and CI runs them on every push. Details: docs/versioning.md.

Licence

Dragoman is MIT. It is an independent implementation written from observing both file formats; no code from either game is copied into it. Open Doctrines and Greater Diplomacy 5 remain under their own licences (Open Doctrines Non-Commercial, and GPL-3.0 respectively), and neither project's maps are redistributed here.

Metadata

Release files for open-dragoman 0.5.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for open-dragoman 0.5.0
File Size Uploaded Provenance Actions
open_dragoman-0.5.0.tar.gz 478.5 kB With provenance Details for open_dragoman-0.5.0.tar.gz

Built distributions (wheels)

Table of built distributions (wheels) for open-dragoman 0.5.0
File Actions
open_dragoman-0.5.0-py3-none-win_amd64.whl Python 3 none Windows x86-64 Details for open_dragoman-0.5.0-py3-none-win_amd64.whl
open_dragoman-0.5.0-py3-none-win32.whl Python 3 none Windows x86-32 Details for open_dragoman-0.5.0-py3-none-win32.whl
open_dragoman-0.5.0-py3-none-musllinux_1_2_x86_64.whl Python 3 none Linux musl 1.2+ x86-64 Details for open_dragoman-0.5.0-py3-none-musllinux_1_2_x86_64.whl
open_dragoman-0.5.0-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl Python 3 none Linux glibc 2.17+ x86-64 Details for open_dragoman-0.5.0-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
open_dragoman-0.5.0-py3-none-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl Python 3 none Linux glibc 2.12+ x86-32, Linux glibc 2.17+ x86-32 Details for open_dragoman-0.5.0-py3-none-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl
open_dragoman-0.5.0-py3-none-macosx_11_0_universal2.whl Python 3 none macOS 11.0+ universal2 (ARM64, x86-64) Details for open_dragoman-0.5.0-py3-none-macosx_11_0_universal2.whl

Total release size: 13.3 MB

Release files / open_dragoman-0.5.0.tar.gz

Download URL open_dragoman-0.5.0.tar.gz
Size 478.5 kB
Tags Source
SHA-256 checksum
How to use checksums
f75ac3dde9552d5ed32f00db0b25cc2a1ac6e0a6d43caad94f88f970bb372ec7
BLAKE2b-256 checksum
How to use checksums
75773b3d8e4111fdc3081e8dbd38d1a55a38fbc5e32c0de119aee5fa46701f20
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 27, 2026.

Transparency log

Release files / open_dragoman-0.5.0-py3-none-win_amd64.whl

Download URL open_dragoman-0.5.0-py3-none-win_amd64.whl
Size 355.7 kB
Tags Python 3 Windows x86-64
SHA-256 checksum
How to use checksums
39aa9cc7b0563f585d5e2e4f70ed6fa6f51167980f6bd292a8947f98ecbd8c7f
BLAKE2b-256 checksum
How to use checksums
acf9ee47ca2188fd8c2b92f208eab9d843a2fab5f3a10ae01087680a5dbfd458
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 27, 2026.

Transparency log

Release files / open_dragoman-0.5.0-py3-none-win32.whl

Download URL open_dragoman-0.5.0-py3-none-win32.whl
Size 328.2 kB
Tags Python 3 Windows x86-32
SHA-256 checksum
How to use checksums
60edc8d6a2fa9940e25c80606c70e8debf7f6b50aa781416fb358f81650ef822
BLAKE2b-256 checksum
How to use checksums
d32caf8638bc8f2e6bc02cf06f9215ab5b367abadc4cb9b7134d98eb1049dbe0
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 27, 2026.

Transparency log

Release files / open_dragoman-0.5.0-py3-none-musllinux_1_2_x86_64.whl

Download URL open_dragoman-0.5.0-py3-none-musllinux_1_2_x86_64.whl
Size 3.3 MB
Tags Linux musl 1.2+ x86-64 Python 3
SHA-256 checksum
How to use checksums
732ff84d0a6aa36fe58c5303699463c08df60745f5eb46b6fe77bcb4cf7963c4
BLAKE2b-256 checksum
How to use checksums
91ddfda1b54767df8fe07c5f131cb95569e0316bb19e75bad714132680672cf5
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 27, 2026.

Transparency log

Release files / open_dragoman-0.5.0-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl

Download URL open_dragoman-0.5.0-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Size 3.1 MB
Tags Linux glibc 2.17+ x86-64 Python 3
SHA-256 checksum
How to use checksums
613c6195f30b966d3093330393931c792a035a61ed02cda9cb856409c5493e0f
BLAKE2b-256 checksum
How to use checksums
cd455cb84eda3f4ac81b9ff9f0f6b2475581897ea862af3f4b81485d8db1f36e
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 27, 2026.

Transparency log

Release files / open_dragoman-0.5.0-py3-none-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl

Download URL open_dragoman-0.5.0-py3-none-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl
Size 3.4 MB
Tags Linux glibc 2.12+ x86-32 Linux glibc 2.17+ x86-32 Python 3
SHA-256 checksum
How to use checksums
f2efb61b8775f2d6ed34fc2fb0b62309ff3dc95195bfdf7118e8e87d9f37bfa9
BLAKE2b-256 checksum
How to use checksums
39704c0bed2118b00a2231b3c9634e0a0497adbaf531fc6732fd13d136a1e0a9
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 27, 2026.

Transparency log

Release files / open_dragoman-0.5.0-py3-none-macosx_11_0_universal2.whl

Download URL open_dragoman-0.5.0-py3-none-macosx_11_0_universal2.whl
Size 2.3 MB
Tags Python 3 macOS 11.0+ universal2 (ARM64, x86-64)
SHA-256 checksum
How to use checksums
48ede52fa996f95f96f4f4665df1e5cf400c3ab33fb9c5da05ba49fa0c64da97
BLAKE2b-256 checksum
How to use checksums
11c8b1b8c82f5ca204a035419f2a620a374e3cb4dfa87dc8659fc615f5f123ee
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 27, 2026.

Transparency log

Security for open-dragoman 0.5.0

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

Full provenance

All 7 files in this release have been uploaded with provenance metadata.

Select from 7 files

Attestation for open_dragoman-0.5.0.tar.gz

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 27, 2026.

Transparency log

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page