Walkmesh (BWM / WOK)
Walkmeshes govern physical collision and pathfinding across an area. They dictate exactly where a character can stand, what slopes they can climb, and what physical materials block their path.
BWM Binary
The binary implementation of the Walkmesh is entirely designed to be dumped straight into memory. Instead of smoothly parsing the file piece-by-piece, the engine constantly jumps around the file using a complex array of offsets located at the very top.
At a Glance
| Property | Value |
|---|---|
| Extension(s) | .bwm, .wok |
| Magic Signature | None standard header block |
| Type | Memory-Mapped Collision Net |
| Rust Reference | View rakata_formats::Bwm in Rustdocs |
Engine Audits & Decompilation
The following documents the engine’s exact load sequence and field requirements for Binary Walkmeshes mapped from swkotor.exe.
(Decompilation logic for this section was entirely audited and verified via native Ghidra pipeline against swkotor.exe, explicitly pulling from CSWCollisionMesh::LoadMeshBinary at 0x00597120.)
| Pipeline Event | Ghidra Provenance & Engine Behavior |
|---|---|
| Pointer Jumping | The engine doesn’t read the file linearly from top to bottom. Instead, it uses direct memory math (pointer arithmetic) to aggressively jump between the header and the raw data payload. |
| Offset Extraction | The beginning of the file contains exact byte locations the engine uses to orient itself: • +0x08 yields the total vertex_count• +0x0C..+0x18 provides the maximum limits for faces, materials, and walk-edges• +0x18..+0x24 yields adjacency boundaries• +0x3C..+0x48 stores the direct starting addresses for the geometry data |
| Bounding Box Offsets | The spans immediately following (+0x48..+0x6C and +0x6C..+0x84) are reserved specifically for tracking offsets that point to the Axis-Aligned Bounding Box (AABB) collision trees. |
| Ignoring the Magic ID | Magic bypass: Magic and version identifiers (BWM ) are actually ignored natively during the LoadMeshBinary process. It relies on a different system entirely to verify file signatures beforehand. |
| Read-Only Format | One-Way Flow: Vanilla KOTOR contains strictly read-only capabilities for BWM binaries. Developers removed any functionality needed to compile or save collision data dynamically! |
Tip
Orphaned Memory Gaps: The engine entirely skips reading two massive blocks of bytes off the disk:
+0x24..+0x3C(24 bytes) and+0x64..+0x6C(8 bytes). For a byte-perfect roundtrip toolset, these gaps must absolutely be preserved verbatim!
BWM ASCII
For tooling purposes, BioWare engine modules support a raw ASCII readable version of the walkmesh that can be dynamically parsed at runtime at a massive performance cost.
At a Glance
| Property | Value |
|---|---|
| Extension(s) | .bwm (ASCII formatted) |
| Magic Signature | ASCII Text Directives |
| Type | Uncompiled Collision Text |
Engine Audits & Decompilation
The following documents the engine’s exact load sequence and constraints for ASCII text walkmeshes mapped from swkotor.exe.
(Decompilation logic for this section was audited and verified via native Ghidra pipeline against swkotor.exe, explicitly pulling from CSWRoomSurfaceMesh::LoadMeshText at 0x00582d70.)
| Pipeline Event | Ghidra Provenance & Engine Behavior |
|---|---|
| Searching for Keywords | The engine scans the text file reading line-by-line to look for the specific keywords node, verts, faces, and aabb. |
| Strict Face Formatting | Every defined face string must strictly format exactly 8 numbers separated by spaces. Interestingly, while the engine reads the adjacency input, it immediately deletes it! The engine forces adjacency math to be physically recomputed from scratch post-load to prevent geometric errors from old assets. |
| Line Length Limits | The engine will aggressively truncate or glitch if any single text line stretches beyond 256 characters (0x100 bytes). |
| Face Reordering | Using the surfacemat.2da file, the engine completely shuffles the order of the faces while loading. It essentially groups every geometry face marked “walkable” at the absolute top of the array, and pushes all non-walkable geometry straight to the bottom. |
| Fudging the Boundaries | When figuring out the Axis-Aligned Bounding Box (AABB) limits, the text loader artificially stretches the box outwards by roughly 0.01 across every axis. Due to the face reordering mentioned above, the engine also has to build a temporary remap table under the hood just to keep track of where everything moved! |
Warning
Because the ASCII face-reordering mechanism radically shuffles the root array indexes from walkable to unwalkable clusters via the LoadMeshText routine, it is impossible to do a clean 1-to-1 binary-to-ASCII-to-binary round trip of a KOTOR walkmesh without completely losing the original face indexing format!