2026-05-06 02:57:07 -07:00
|
|
|
|
# Wowee Open Format Specification v1.2
|
2026-05-05 10:45:50 -07:00
|
|
|
|
|
|
|
|
|
|
Novel file formats for custom WoW zone content. No Blizzard IP.
|
|
|
|
|
|
|
|
|
|
|
|
## WOT — Wowee Open Terrain (JSON metadata)
|
|
|
|
|
|
- Extension: `.wot`
|
feat: WOB material serialization, FORMAT_SPEC v1.1, material tests
- WOB save/load now serializes Material struct fields (flags, shader,
blendMode, texturePath) per group — was saving only texture paths
- FORMAT_SPEC.md v1.1: documents WOT doodad/WMO placements, WOB
material fields, doodad rotation, terrain stamps, WCP file list
- Test coverage: 5 new assertions verify material round-trip (flags,
shader, blendMode all preserved through save→load cycle)
- 260 total assertions across 75 test cases, all passing
2026-05-05 14:53:28 -07:00
|
|
|
|
- Contains: tile coords, texture list, per-chunk layers/holes, water data,
|
|
|
|
|
|
doodad placements (M2 objects), WMO placements (buildings)
|
2026-05-05 10:45:50 -07:00
|
|
|
|
- Key: `"format": "wot-1.0"`
|
feat: WOB material serialization, FORMAT_SPEC v1.1, material tests
- WOB save/load now serializes Material struct fields (flags, shader,
blendMode, texturePath) per group — was saving only texture paths
- FORMAT_SPEC.md v1.1: documents WOT doodad/WMO placements, WOB
material fields, doodad rotation, terrain stamps, WCP file list
- Test coverage: 5 new assertions verify material round-trip (flags,
shader, blendMode all preserved through save→load cycle)
- 260 total assertions across 75 test cases, all passing
2026-05-05 14:53:28 -07:00
|
|
|
|
- Placement fields: `doodadNames[]`, `doodads[]` (nameId, uniqueId, pos, rot, scale, flags)
|
|
|
|
|
|
- WMO fields: `wmoNames[]`, `wmos[]` (nameId, uniqueId, pos, rot, flags, doodadSet)
|
2026-05-05 10:45:50 -07:00
|
|
|
|
|
|
|
|
|
|
## WHM — Wowee HeightMap (binary)
|
|
|
|
|
|
- Extension: `.whm`
|
|
|
|
|
|
- Magic: `WHM1` (0x314D4857)
|
2026-05-06 04:42:04 -07:00
|
|
|
|
- Layout: magic(4) + chunkCount(4=256) + vertsPerChunk(4=145) + per-chunk data × 256
|
|
|
|
|
|
- Per-chunk: baseHeight(4 float) + heights[145](580 = 145 floats) + alphaSize(4) + alphaData(alphaSize bytes)
|
2026-05-05 13:10:48 -07:00
|
|
|
|
- Alpha data: raw alpha blend maps for texture layers (same format as ADT MCAL)
|
|
|
|
|
|
- Backward compatible: older WHM files without alpha data still load (alphaSize=0)
|
2026-05-05 10:45:50 -07:00
|
|
|
|
|
|
|
|
|
|
## WOM — Wowee Open Model (binary)
|
|
|
|
|
|
- Extension: `.wom`
|
2026-05-06 01:07:00 -07:00
|
|
|
|
- Magic: `WOM1` (0x314D4F57) static, `WOM2` (0x324D4F57) animated, `WOM3` (0x334D4F57) multi-batch
|
2026-05-06 04:42:04 -07:00
|
|
|
|
- Layout: magic(4) + vertCount(4) + indexCount(4) + texCount(4) + boundRadius(4) + boundMin(12) + boundMax(12) + nameLen(2) + name + vertices + indices(uint32 each) + [pathLen(2) + path] × texCount
|
|
|
|
|
|
- WOM1 Vertex: position(vec3=12) + normal(vec3=12) + texCoord(vec2=8) = 32 bytes
|
2026-05-06 01:07:00 -07:00
|
|
|
|
- WOM2/WOM3 Vertex: + boneWeights(4) + boneIndices(4) = 40 bytes
|
2026-05-06 04:42:04 -07:00
|
|
|
|
- WOM2/WOM3 trailing block: boneCount(4) + [keyBoneId(4) + parentBone(2) + pivot(12) + flags(4)] × bones
|
|
|
|
|
|
+ animCount(4) + [id(4) + duration(4) + speed(4) + per-bone-keyframe-block] × anims
|
2026-05-05 16:16:07 -07:00
|
|
|
|
- Keyframe: timeMs(4) + translation(12) + rotation(16) + scale(12) = 44 bytes
|
2026-05-06 04:42:04 -07:00
|
|
|
|
- WOM3 Batches (after WOM2 trailing block): batchCount(4) + [indexStart(4) + indexCount(4) + textureIndex(4) + blendMode(2) + flags(2)] × N
|
2026-05-06 01:07:00 -07:00
|
|
|
|
- WOM3 blendMode: 0=opaque, 1=alpha-test, 2=alpha, 3=add, 4=mod, 5=mod2x, 6=blendAdd, 7=screen
|
|
|
|
|
|
- WOM3 flags: bit 0 = unlit, bit 1 = two-sided, bit 2 = no z-write
|
|
|
|
|
|
- Backward compatible: WOM1 files load without bone/animation data; WOM3 falls back to single-batch when batches block missing
|
2026-05-05 10:45:50 -07:00
|
|
|
|
|
|
|
|
|
|
## WOB — Wowee Open Building (binary)
|
|
|
|
|
|
- Extension: `.wob`
|
|
|
|
|
|
- Magic: `WOB1` (0x31424F57)
|
2026-05-06 04:38:15 -07:00
|
|
|
|
- Layout: magic(4) + groupCount(4) + portalCount(4) + doodadCount(4) + boundRadius(4) + nameLen(2) + name + groups + portals + doodads
|
|
|
|
|
|
- Group: nameLen(2) + name + vertexCount(4) + indexCount(4) + texCount(4) + outdoor(1) + boundMin(12) + boundMax(12)
|
|
|
|
|
|
+ vertices(pos+normal+uv+color = 48 bytes) + indices(uint32) + texPaths(prefixed) + materialCount(4) + materials
|
|
|
|
|
|
- Material: pathLen(2) + texturePath + flags(4) + shader(4) + blendMode(4)
|
|
|
|
|
|
- Doodad: pathLen(2) + modelPath + position(12) + rotation(12 euler degrees) + scale(4)
|
|
|
|
|
|
- Portal: groupA(4) + groupB(4) + vertexCount(4) + vertices(12 bytes each)
|
2026-05-06 03:31:04 -07:00
|
|
|
|
- toWMOModel restoration:
|
|
|
|
|
|
- Materials are deduplicated across all groups by (texture, blend, flags)
|
|
|
|
|
|
- Texture paths .png → .blp (renderer's PNG override is keyed on .blp)
|
|
|
|
|
|
- Outdoor flag → WMO group flag bit 0x08
|
|
|
|
|
|
- Portal vertices reconstruct MOPR refs for groupA / groupB
|
|
|
|
|
|
- Doodad euler degrees → glm::quat using glm::eulerAngles convention
|
|
|
|
|
|
- Default `Set_$DefaultGlobal` doodadSet emitted when doodads present
|
2026-05-05 10:45:50 -07:00
|
|
|
|
|
|
|
|
|
|
## WCP — Wowee Content Pack (archive)
|
|
|
|
|
|
- Extension: `.wcp`
|
|
|
|
|
|
- Magic: `WCP1` (0x31504357)
|
|
|
|
|
|
- Layout: magic(4) + fileCount(4) + infoJsonSize(4) + infoJSON + [pathLen(2) + path + dataSize(4) + data] × N
|
feat: WOB material serialization, FORMAT_SPEC v1.1, material tests
- WOB save/load now serializes Material struct fields (flags, shader,
blendMode, texturePath) per group — was saving only texture paths
- FORMAT_SPEC.md v1.1: documents WOT doodad/WMO placements, WOB
material fields, doodad rotation, terrain stamps, WCP file list
- Test coverage: 5 new assertions verify material round-trip (flags,
shader, blendMode all preserved through save→load cycle)
- 260 total assertions across 75 test cases, all passing
2026-05-05 14:53:28 -07:00
|
|
|
|
- Info JSON includes categorized file list (terrain/model/building/texture/data)
|
2026-05-05 10:45:50 -07:00
|
|
|
|
|
|
|
|
|
|
## zone.json — Map Definition
|
|
|
|
|
|
- Replaces WDT
|
feat: WOB material serialization, FORMAT_SPEC v1.1, material tests
- WOB save/load now serializes Material struct fields (flags, shader,
blendMode, texturePath) per group — was saving only texture paths
- FORMAT_SPEC.md v1.1: documents WOT doodad/WMO placements, WOB
material fields, doodad rotation, terrain stamps, WCP file list
- Test coverage: 5 new assertions verify material round-trip (flags,
shader, blendMode all preserved through save→load cycle)
- 260 total assertions across 75 test cases, all passing
2026-05-05 14:53:28 -07:00
|
|
|
|
- Fields: `mapName`, `displayName`, `mapId`, `biome`, `baseHeight`
|
2026-05-05 11:34:09 -07:00
|
|
|
|
- `hasCreatures`, `description`, `tiles` array, `files` map
|
feat: WOB material serialization, FORMAT_SPEC v1.1, material tests
- WOB save/load now serializes Material struct fields (flags, shader,
blendMode, texturePath) per group — was saving only texture paths
- FORMAT_SPEC.md v1.1: documents WOT doodad/WMO placements, WOB
material fields, doodad rotation, terrain stamps, WCP file list
- Test coverage: 5 new assertions verify material round-trip (flags,
shader, blendMode all preserved through save→load cycle)
- 260 total assertions across 75 test cases, all passing
2026-05-05 14:53:28 -07:00
|
|
|
|
- `doodadNames[]`, `doodads[]`, `wmoNames[]`, `wmos[]` for placed objects
|
2026-05-05 11:34:09 -07:00
|
|
|
|
- `editorVersion` for compatibility tracking
|
|
|
|
|
|
|
2026-05-05 13:10:48 -07:00
|
|
|
|
## JSON DBC — Data Table Replacement
|
|
|
|
|
|
- Replaces binary DBC files
|
|
|
|
|
|
- Format: `{"format": "wowee-dbc-json-1.0", "records": [...], "fieldCount": N}`
|
|
|
|
|
|
- Records are arrays of mixed types: integers, floats, strings
|
|
|
|
|
|
- Client loads via DBCFile::loadJSON() when found in custom_zones/ or output/
|
|
|
|
|
|
|
|
|
|
|
|
## PNG Textures — Texture Replacement
|
|
|
|
|
|
- Replaces BLP texture files
|
|
|
|
|
|
- Standard PNG format, loaded by client's texture override system
|
|
|
|
|
|
- Editor auto-converts BLP→PNG on export via stb_image_write
|
|
|
|
|
|
|
2026-05-05 15:23:58 -07:00
|
|
|
|
## WOC — Wowee Open Collision (binary)
|
|
|
|
|
|
- Extension: `.woc`
|
|
|
|
|
|
- Magic: `WOC1` (0x31434F57)
|
|
|
|
|
|
- Layout: magic(4) + triCount(4) + tileX(4) + tileY(4) + boundsMin(12) + boundsMax(12) + triangles
|
|
|
|
|
|
- Triangle: v0(12) + v1(12) + v2(12) + flags(1) = 37 bytes
|
|
|
|
|
|
- Flags: 0x01=walkable, 0x02=water, 0x04=steep, 0x08=indoor
|
|
|
|
|
|
- Generated from terrain heightmap with slope classification (50 deg threshold)
|
|
|
|
|
|
- Respects terrain holes (skips triangles in hole regions)
|
2026-05-06 02:57:07 -07:00
|
|
|
|
- WoweeCollisionBuilder::addMesh appends placed WMO group geometry
|
|
|
|
|
|
(transformed into world space, slope-classified) so collision covers
|
|
|
|
|
|
buildings as well as terrain.
|
2026-05-05 15:23:58 -07:00
|
|
|
|
|
feat: WOB material serialization, FORMAT_SPEC v1.1, material tests
- WOB save/load now serializes Material struct fields (flags, shader,
blendMode, texturePath) per group — was saving only texture paths
- FORMAT_SPEC.md v1.1: documents WOT doodad/WMO placements, WOB
material fields, doodad rotation, terrain stamps, WCP file list
- Test coverage: 5 new assertions verify material round-trip (flags,
shader, blendMode all preserved through save→load cycle)
- 260 total assertions across 75 test cases, all passing
2026-05-05 14:53:28 -07:00
|
|
|
|
## Terrain Stamps (.json)
|
|
|
|
|
|
- Portable terrain feature snapshots (mountains, craters, etc.)
|
|
|
|
|
|
- Format: `{"format": "wowee-stamp-1.0", "vertices": [[dx, dy, height], ...]}`
|
|
|
|
|
|
- Can be saved/loaded across zones and sessions
|
|
|
|
|
|
|
2026-05-05 15:23:58 -07:00
|
|
|
|
## Open Format Scoring (0-7)
|
2026-05-05 13:10:48 -07:00
|
|
|
|
1. WOT terrain metadata present
|
|
|
|
|
|
2. WHM heightmap with valid magic
|
|
|
|
|
|
3. zone.json map definition
|
|
|
|
|
|
4. PNG textures present
|
|
|
|
|
|
5. WOM models with valid magic
|
|
|
|
|
|
6. WOB buildings with valid magic
|
2026-05-05 15:23:58 -07:00
|
|
|
|
7. WOC collision mesh with valid magic
|
2026-05-05 13:10:48 -07:00
|
|
|
|
|
2026-05-06 02:57:07 -07:00
|
|
|
|
## SQL Server Export
|
|
|
|
|
|
- AzerothCore-flavored INSERT statements for: `creature_template`, `creature`,
|
|
|
|
|
|
`creature_addon`, `waypoint_data`, `quest_template`, `creature_queststarter`,
|
|
|
|
|
|
`creature_questender`.
|
|
|
|
|
|
- Coordinates: editor render coords are converted to WoW canonical via
|
|
|
|
|
|
`core::coords::renderToCanonical` (X/Y swap) before write.
|
|
|
|
|
|
- Orientation: editor degrees from +renderX (west) → WoW radians from +X (north).
|
|
|
|
|
|
Conversion: `wowYaw = π/2 - editorYaw` then normalised to [0, 2π).
|
|
|
|
|
|
- Quest objectives: KillCreature targets fill RequiredNpcOrGo[1..4]; CollectItem
|
|
|
|
|
|
targets fill RequiredItemId[1..6]. Target ID parsed from objective.targetName.
|
|
|
|
|
|
- Quest givers/turn-in NPCs: written as `creature_queststarter` /
|
|
|
|
|
|
`creature_questender` rows linking npc.id ↔ quest.id.
|
|
|
|
|
|
|
2026-05-06 04:44:24 -07:00
|
|
|
|
## Format Quick Reference
|
|
|
|
|
|
|
|
|
|
|
|
| Format | Replaces | Magic | Extension | Purpose |
|
|
|
|
|
|
|-----------|----------|--------------------|---------------|-------------------------------------|
|
|
|
|
|
|
| WOT | (part of ADT) | `wot-1.0` JSON | `.wot` | Terrain metadata + placements |
|
|
|
|
|
|
| WHM | ADT MCNK heights/alpha | `WHM1` (0x314D4857) | `.whm` | Heightmap + alpha layers |
|
|
|
|
|
|
| WOM1/2/3 | M2/skin | `WOM1/2/3` (0x31/32/33 4D4F57) | `.wom` | Static / animated / multi-batch model |
|
|
|
|
|
|
| WOB | WMO + group files | `WOB1` (0x31424F57) | `.wob` | Building (groups + portals + doodads) |
|
|
|
|
|
|
| WOC | (none, novel) | `WOC1` (0x31434F57) | `.woc` | Walkability collision mesh |
|
|
|
|
|
|
| WCP | MPQ archive | `WCP1` (0x31504357) | `.wcp` | Whole-zone bundle |
|
|
|
|
|
|
| zone.json | WDT | `"format":"wowee-zone-1.0"` | `zone.json` | Map definition + audio/flags |
|
|
|
|
|
|
| JSON DBC | DBC | `"format":"wowee-dbc-json-1.0"` | `*.json` | Data tables |
|
|
|
|
|
|
| PNG | BLP | PNG signature | `.png` | Textures (loaded via override sys) |
|
|
|
|
|
|
|
2026-05-05 10:45:50 -07:00
|
|
|
|
## All formats are novel, portable, and open for redistribution.
|
2026-05-05 11:34:09 -07:00
|
|
|
|
## No Blizzard intellectual property is used in any format definition.
|
2026-05-06 08:53:45 -07:00
|
|
|
|
|
|
|
|
|
|
## Headless CLI Surface
|
|
|
|
|
|
|
|
|
|
|
|
The `wowee_editor` binary provides a complete non-GUI workflow over these formats:
|
|
|
|
|
|
|
|
|
|
|
|
### Inspection
|
|
|
|
|
|
- `--info <wom-base>` — WOM metadata (vertices/bones/animations/batches)
|
|
|
|
|
|
- `--info-wob <wob-base>` — WOB groups/portals/doodads
|
|
|
|
|
|
- `--info-woc <woc-path>` — WOC triangles/walkability counts
|
|
|
|
|
|
- `--info-wot <wot-base>` — WOT/WHM tile coord, chunks, height range
|
|
|
|
|
|
- `--info-wcp <wcp-path>` — WCP archive metadata (per-category counts)
|
|
|
|
|
|
- `--list-wcp <wcp-path>` — every file in a WCP, sorted by path
|
|
|
|
|
|
- `--info-creatures <p>` — creatures.json summary
|
|
|
|
|
|
- `--info-objects <p>` — objects.json summary
|
|
|
|
|
|
- `--info-quests <p>` — quests.json summary + chain validation
|
|
|
|
|
|
|
|
|
|
|
|
### Validation
|
|
|
|
|
|
- `--validate <zoneDir>` — open-format completeness score (0/7) with per-format counts
|
|
|
|
|
|
- `--zone-summary <zoneDir>` — one-shot validate + creature/object/quest counts
|
|
|
|
|
|
- `--diff-wcp <a> <b>` — file-by-file WCP comparison (added/removed/changed)
|
|
|
|
|
|
|
|
|
|
|
|
### Authoring
|
|
|
|
|
|
- `--scaffold-zone <name> [tx ty]` — create a blank zone in custom_zones/<slug>/
|
|
|
|
|
|
- `--build-woc <wot-base>` — generate WOC collision mesh from WHM/WOT
|
|
|
|
|
|
- `--regen-collision <zoneDir>` — rebuild every WOC under a zone dir
|
|
|
|
|
|
- `--export-png <wot-base>` — render heightmap/normal/zone-map PNG previews
|
|
|
|
|
|
- `--convert-m2 <path>` — M2 → WOM
|
|
|
|
|
|
- `--convert-wmo <path>` — WMO → WOB
|
|
|
|
|
|
|
|
|
|
|
|
### Packaging
|
|
|
|
|
|
- `--pack-wcp <zone> [dst]` — pack a zone into a WCP archive
|
|
|
|
|
|
- `--unpack-wcp <wcp> [dst]` — extract a WCP archive
|
|
|
|
|
|
|
|
|
|
|
|
### Discovery
|
|
|
|
|
|
- `--list-zones` — list custom_zones/ + output/ contents
|
|
|
|
|
|
- `--version` — version info
|