Parse World of Tanks (BigWorld engine) map files and pull out the rendering
geometry, the collision geometry, and the terrain heightfield — straight from a
game install. No game, no engine, no editor required: everything is read out of the
shipped *.pkg archives.
It's a Rust library plus a small CLI, wot-extract, that can dump geometry to OBJ/PNG
or open an interactive 3D fly-through of a whole map in your browser.
wot-extract --wot "C:\Games\World_of_Tanks" view 13_erlenberg --open
| File | Contents | Module |
|---|---|---|
<map>_bin.pkg → space.bin |
map layout: terrain bounds, chunk list, water volumes | space |
*.pkg (ZIP) |
asset archive index | pkg |
*.primitives_processed |
render meshes (vertices + indices) | primitives, models |
*.havok |
Havok 2020.2 convex collision hulls | havok, models |
<map>.pkg → cdata_processed/terrain2 |
per-chunk terrain heightmaps + hole maps | heightmap |
wot-extract --wot <INSTALL> <COMMAND>
maps list the maps in the install
info <map> terrain bounds, chunks, water, geometry counts
render <map> --out f.obj placed render meshes -> Wavefront OBJ
collision <map> --out f.obj world-space collision hulls -> Wavefront OBJ
heightmap <map> --out f.png terrain heightfield -> greyscale PNG
view <map> [--port N] [--open] interactive 3D viewer in the browser
--wot points at the folder that contains res/packages.
use std::path::Path;
use wot_space_parser::{pkg, space, models, heightmap};
let wot = Path::new(r"C:\Games\World_of_Tanks");
let packages = wot.join("res/packages");
let map = "13_erlenberg";
// index the asset archives (havok + dds + render meshes)
let mut exts = pkg::ASSET_EXTS.to_vec();
exts.push("primitives_processed");
let index = pkg::PkgIndex::build(&packages, &exts)?;
// parse the map
let scene = space::parse_space_bin(&packages.join(format!("{map}_bin.pkg")), map)?;
// rendering geometry (unique meshes + placed instances)
let (meshes, instances) = models::extract_render_meshes(&scene, &index)?;
// collision geometry (world-space Havok convex hulls)
let hulls = models::extract_collision_geometry(&scene, &index)?;
// terrain heightmaps (per chunk)
let (heights, holes) =
heightmap::extract_all_heightmaps(&packages.join(format!("{map}.pkg")), map, &scene.terrain.chunks)?;
# Ok::<(), anyhow::Error>(())- Coordinates are in meters, in BigWorld's left-handed world space (X east, Y up, Z north). Instance transforms are row-major 4×4.
- Collision is recovered from
hknpConvexHullshapes. Models whose collision is ahkcdStaticMeshTree(thin/lattice geometry) are skipped — seeFORMATS.md. - See
FORMATS.mdfor the binary layouts.
WTFPL — do whatever you want.