Database tables (DBC & DB2)¶
The client keeps its gameplay data — maps, spells, items, creatures — in
DBFilesClient/: .dbc tables pre-Cataclysm, .db2 afterwards, across
six container generations (WDBC, WDB2, WDC1, WDC3, WDC4, WDC5). wowlib reads
and writes all of them through one engine whose schemas come from the
WoWDBDefs community data baked into
the library: open any of the ~1200 tables for any targeted client era, read
its rows, edit cells, write it back in the era's own on-disk format. The
format is sniffed from the file magic on read and re-emitted on write —
you never say "this is a WDC3".
Opening a table, typed¶
Each language has a typed per-table surface over the generic engine:
#include <wowlib/db/tables/map.hpp> // generated, one header per table
wowlib::db::tables::Map<wowlib::versions::Wotlk> map;
if (auto r = map.read(fs, wowlib::FileKey{"DBFilesClient/Map.dbc"}); !r)
return report(r.error());
for (auto& record : map.records) // typed structs, plain std::vector
if (record.instance_type == 0)
use(record.id, record.directory);
import wowlib
from wowlib.db.tables import wotlk # one module per era: vanilla … tww
table = wotlk.Map() # schema-bound, era-exact columns
table.read(fs, wowlib.FileKey("DBFilesClient\\Map.dbc"))
for row in table: # rows read/write as attributes
print(row.id, row.directory, row.map_name[0]) # enUS locale slot
The era modules create their classes lazily as plain subclasses of the
generic wowlib.db.Table — nothing is compiled per
table — and the stubs type every column era-exactly, so your IDE
completes row. with the wotlk-era Map schema.
The generic path¶
When the table name is dynamic (tooling, batch scripts), use the engine directly — same behavior, runtime schema:
table = wowlib.db.Table.open("Map", wowlib.versions.wotlk)
table.read(fs, wowlib.FileKey("DBFilesClient\\Map.dbc"))
print(wowlib.db.table_names(wowlib.versions.wotlk)) # the era's catalog
# Whole columns at once: zero-copy numpy for numerics.
ids = table.column("id") # numpy.int32, shape (rows,)
directories = table.column("directory")
Editing and writing back¶
Guarantees, era coverage, encryption¶
- Round-trip: WDBC/WDB2 (pre-Legion) writes are byte-perfect; WDC1..WDC5 writes are canonical re-encodes with a semantic guarantee (write → re-read → equal values) — the writer re-derives copy tables, pallets and common blocks the way the client's own tools do.
- Era accuracy: a table's schema differs per era (
map_nameis 8 locale slots in vanilla, 16 in TBC–WotLK, a single string from Cataclysm). The typed surfaces carry the era-exact shape; opening a table for an era it has no schema block for raises instead of guessing an adjacent layout. - Encrypted retail sections (TACT): keyless sections are preserved
verbatim and reported (
encrypted_sections,fully_decoded); import keys on the filesystem to read them decrypted, or write withEncryptedPolicyto control what happens to what you cannot decrypt. See ClientDB concepts for the full story.