wowlib reads and writes World of Warcraft client files — a modern C++26 core, automatically bound to Python (and, later, Lua) by welder. It exists to make community tooling — map viewers, model viewers, Blender add-ons, exploration projects — possible on top of one shared, well-tested file layer.
- Filesystem gateway — one interface over MPQ (pre-WoD clients, via StormLib) and CASC (WoD+ clients, via CascLib), with client patch-chain resolution, listfile / FileDataID machinery and a project-directory overlay for modding workflows.
- Reflection-driven format framework — every chunked format is declared once as annotated C++26 structs; parsing, writing, per-expansion version ranges, the Python bindings and the documentation are all derived from that single declaration.
- Round-trip guarantees — formats whose containers allow it are
byte-perfect (
write(read(bytes)) == bytes); offset-table formats are semantic (read(write(x)) == x, canonical relayout on write). Unknown and undocumented chunks are preserved verbatim, never dropped. - ClientDB — every database container era from WDBC through WDC5, with typed record structs for 1221 tables generated from WoWDBDefs across all supported client versions.
- Typed Python bindings — a stable-ABI (
abi3) extension for CPython ≥ 3.13 with rich.pyistubs and zero-copy NumPy views over WoW vectors. MSVC-ABI-compatible builds for use inside Blender on Windows.
wowlib targets the last minor release of every major expansion, Vanilla through The War Within. Formats are modelled for all versions in one entity; the matrix below shows how far each has been verified:
- ✅ — implemented, round-trip verified against a real client's file corpus
- 🟡 — implemented, awaiting a client install to verify against
- ➖ — not applicable to that client
| Format | Round-trip | Vanilla 1.12.1 |
TBC 2.4.3 |
WotLK 3.3.5a |
Cata 4.3.4 |
MoP 5.4.8 |
WoD 6.2.4 |
Legion 7.3.5 |
BfA 8.3.7 |
SL 9.2.7 |
DF 10.2.7 |
TWW 11.2.7 |
|---|---|---|---|---|---|---|---|---|---|---|---|---|
| WMO (root + groups) | byte-perfect | 🟡 | 🟡 | ✅ | 🟡 | 🟡 | 🟡 | 🟡 | 🟡 | ✅ | 🟡 | 🟡 |
M2 (+ .skin .anim .skel .bone)¹ |
semantic | 🟡 | 🟡 | ✅ | 🟡 | 🟡 | 🟡 | 🟡 | 🟡 | ✅ | 🟡 | 🟡 |
| ADT (root + split files)² | semantic | 🟡 | 🟡 | ✅ | 🟡 | 🟡 | 🟡 | 🟡 | 🟡 | ✅ | 🟡 | 🟡 |
WDT (+ _occ _lgt _fogs _mpv) |
byte-perfect | 🟡 | 🟡 | ✅ | 🟡 | 🟡 | 🟡 | 🟡 | 🟡 | ✅ | 🟡 | 🟡 |
| WDL | byte-perfect | 🟡 | 🟡 | ✅ | 🟡 | 🟡 | 🟡 | 🟡 | 🟡 | ✅ | 🟡 | 🟡 |
| BLP³ | byte-perfect | 🟡 | 🟡 | ✅ | 🟡 | 🟡 | 🟡 | 🟡 | 🟡 | ✅ | 🟡 | 🟡 |
| DBC / DB2⁴ | byte-perfect (WDBC/WDB2), semantic (WDC*) | ✅ WDBC | ✅ WDBC | ✅ WDBC | ✅ WDB2 | 🟡 WDB2 | 🟡 WDB2 | 🟡 WDC1 | 🟡 WDC3 | ✅ WDC3 | 🟡 WDC5 | 🟡 WDC5 |
| MPQ storage & patch chain⁵ | — | ✅ | ✅ | ✅ | ✅ | 🟡 | ➖ | ➖ | ➖ | ➖ | ➖ | ➖ |
| CASC storage | — | ➖ | ➖ | ➖ | ➖ | ➖ | 🟡 | 🟡 | 🟡 | ✅ | 🟡 | 🟡 |
¹ .phys is carried as an opaque blob for now (structured records planned).
Semantic round-trip means the writer relays out offset tables canonically, so
output is equivalent, not byte-identical.
² Monolithic (WotLK-) and split (Cata+ _tex0/_obj0/_obj1/_lod) layouts
both supported; _obj1/_lod LOD chunks currently round-trip verbatim as raw
chunks, structured access planned.
³ BLP is identical across all client versions; verification spans the corpora
we have locally. JPEG-encoded BLPs round-trip verbatim but do not decode.
⁴ WDC4 (10.1–10.2.5) is implemented as well. Encrypted (TACT) DB2 sections are
preserved and reported; key injection is wired but not yet exercisable locally.
⁵ The 3.3.5a patch chain was verified against the client binary itself
(reverse-engineered); the MoP chain table awaits a 5.4.8 install.
Structured M2 .phys records · structured ADT _obj1/_lod (and blend-mesh)
chunks · TACT decryption of encrypted DB2 sections · cross-version format
conversion (scaffolding only) · Lua bindings (annotated throughout, module
deferred) · hotfix caches (DBCache.bin) · standalone formats not yet started
(.tex, .lit, .wlw/.wlq/.wlm, …).
wowlib requires gcc ≥ 16 (currently the only toolchain implementing C++26 reflection). All dependencies are fetched by CMake — no manual installs.
# C++ library + tests
cmake --preset gcc16-debug
cmake --build --preset gcc16-debug
ctest --preset gcc16-debug
# Python extension (stable-ABI, CPython ≥ 3.13) + .pyi stubs
cmake --preset gcc16-bindings
cmake --build --preset gcc16-bindings
# …or straight into your environment:
pip install -e ".[dev]"import wowlib
from wowlib.formats import wmo
root = wmo.WMOWotlk.read(open("Building.wmo", "rb").read())
for material in root.materials:
...
group = wmo.WMOWotlk.read_group(group_data)
verts = group.vertices # zero-copy numpy.ndarray view#include <wowlib/formats/wmo/wmo.hpp>
auto root = wowlib::formats::wmo::WMO<Expansion::Wotlk>::read(bytes);
for (auto const& mat : root.materials()) { /* … */ }The unit suite (Catch2 + pytest) runs anywhere — that is what CI runs. Integration tests validate round-trips against real client installs and self-skip unless you point them at one:
export WOWLIB_TEST_CLIENTS_DIR=/path/to/your/clients # folders with WoW installs
export WOWLIB_TEST_LISTFILE=/path/to/community-listfile.csv
ctest --preset gcc16-debugThe docs site (guide + typed Python API + Doxygen C++ reference) is hosted at skarndev.github.io/wowlib — start with Getting started. To build it locally:
pip install ".[docs]"
python docs/build.py serve # live-reload at http://127.0.0.1:8000/- welder — the reflection-based binding generator that produces wowlib's Python (and future Lua) surface.
- wowdev.wiki — the community file-format documentation this library is checked against (and occasionally corrects).
- WoWDBDefs — column definitions for every client database table.
- pywowlib / WoWLib — earlier iterations of this effort, superseded by this library.