Map, Model, And Unit Data
This document turns the public references into a practical data-resolution plan for OpenWarcraft3. The important lesson is that a placed SC2 unit usually is not enough by itself to find an .m3 file. The map places a unit ID; catalog XML resolves that unit through actors and models; model data then resolves art paths, animation add-ons, scale, selection, shadows, texture swap declarations, and attachment points.
Data Layers
| Layer | Typical Files | What To Extract First |
|---|---|---|
| Container | .SC2Map, .SC2Mod, .s2ma, .SC2Components |
Archive listing, dependency/content roots, normalized paths. |
| Map metadata | MapInfo, localized GameStrings.txt |
Map dimensions, bounds, tileset/theme, player slots, title/author/description. |
| Placement | Objects |
Placed Unit, Doodad, Point, Camera, position, rotation, scale, player, resources. |
| Terrain | t3HeightMap, t3SyncHeightMap, t3SyncCliffLevel, t3CellFlags, t3TextureMasks, t3Water, t3Terrain.xml |
Height/cliff grids, holes/cell flags, texture layer masks, water rectangles/templates. |
| Catalog XML | Base.SC2Data/GameData/*.xml, dependency mods |
UnitData, ActorData, ModelData, terrain/water/texture data, buttons/requirements later. |
| Assets | .m3, .m3a, .dds, .tga, sounds, layouts |
Model geometry/animations, supplementary animation sets, material textures, portraits/icons. |
Map Placement: Objects
SC2Mapster documents Objects as a <PlacedObjects> XML file. The documented children include:
Unit:id,position,rotation,scale,unitType,player,resources, plus AI/flag children.Doodad:id,position,rotation,scale,type,tintColor, plus flags.Point:id,position,rotation,scale,type,name,model,animProps,sound,objectID, pathing radii.Camera:id,position,rotation,scale,name,target,CameraValue, flags.
Implementation guidance:
- Parse
positionas a three-component value and preserve the raw text for diagnostics. - Accept both the documented attribute style and simple fixture-friendly
x/y/zattributes. - Treat
id/unitTypeas catalog keys, not model paths. - A
Pointcan carry a direct model field; aUnitnormally should resolve through catalogs. - Placed resources are units too in many maps, so resource/base detection should happen after unit catalog resolution, not as a separate hardcoded object kind.
Unit To Model Resolution
The useful catalog path is:
Objects Unit id/unitType
-> Unit catalog entry, usually CUnit
-> unit actor, usually CActorUnit
-> model token / hosted model / build/death/portrait models
-> Model catalog entry, usually CModel
-> Art: Model path (.m3), optional/required .m3a animation files, scale/radius/shadow/texture metadata
SC2Mapster's actor docs describe unit actors as the main visual form for units: they drive model display, click/order sounds, armor textures, selection picture, portrait, and minimap icon. That means a renderer should avoid assuming Assets\Units\Terran\<Unit>\<Unit>.m3 except as a fallback for tiny fixtures.
Catalog extraction order:
- Read
GameData.xmlincludes underBase.SC2Data. - Load catalog XML in include order.
- Layer dependencies before map-local data.
- Apply map-local modifications after dependency/base data.
- Resolve localized display text separately from catalog IDs.
For a first resolver, collect only the minimum fields:
- Unit: ID, life/radius/mover/footprint, actor reference if explicit, resource flags/amounts if available.
- Actor: unit name/token, hosted model/model ID, portrait/icon/minimap fields where easy.
- Model: model file path, low-quality path, variation count, selection radius, shadow radius, scale min/max,
.m3aanimation files, texture declaration slots.
Model Data And M3
SC2Mapster's file-format notes identify .m3 as the model-plus-animation format and .m3a as supplemental bone animation data. ModelData fields add important runtime policy around that raw asset:
Art: Modelpoints to the model.m3.- Optional and required animation fields can add
.m3afiles. Walk Animation Move Speedcalibrates walk animation against terrain tiles per second.Selection Radius,Shadow Radius,Visual Radius, and model scale fields affect selection, shadows, culling, and footprint-like UI.Tipabilityfields describe how far a model may tilt over uneven terrain.- Texture declaration fields define texture swap slots and substrings used by actor texture-select events.
- Variation fields define model variants and probabilities; do not collapse variants at load time.
OpenWarcraft3 already has M3 geometry/animation loading. The next useful step is not more filename guessing; it is catalog-driven model lookup plus optional .m3a support.
Terrain Reconstruction
The public terrain notes are strong enough for staged parser work:
| File | Magic | Version Seen | Payload |
|---|---|---|---|
t3HeightMap |
HMAP |
101 |
sizeX, sizeY, then chunks with heightAdjustments, heightBase, mask. |
t3SyncHeightMap |
SMAP |
102 |
smaller signed height offsets; height value divided by 256 gives level-like offset. |
t3SyncCliffLevel |
CLIF |
100 |
sizeX, sizeY, then USHORT height[sizeX * sizeY]. |
t3CellFlags |
LFCT |
101 |
cell type bytes; useful for holes/visualization, not authoritative pathing. |
t3TextureMasks |
MASK |
102 |
per-texture layer masks; texture definitions come from t3Terrain.xml. |
t3Water |
WATR |
110 |
water/lava rectangles with template names resolved through WaterData.xml. |
SC2Mapster gives the t3HeightMap level formula:
The required quantizeBias, quantizeScale, and standardHeight values come from t3Terrain.xml. So the terrain renderer should parse t3Terrain.xml before interpreting height values into world-space Z.
t3TextureMasks uses 4-bit values packed in byte nibbles and is organized into layer blocks. The number of layers can be derived from file size and dimensions, while the actual texture assigned to each mask is defined in t3Terrain.xml.
For pathing, SC2 Map Analyzer is a useful reality check: it historically approximated ground pathing from t3CellFlags when t3SyncPathingInfo was not decoded, then compared ground, cliff-walking, and air shortest paths. That implies:
t3CellFlagscan support early debug overlays.t3SyncPathingInfoshould be treated as the target for real movement/building pathing.- Footprints matter, and building pathing footprint rotation may differ from no-build footprint behavior.
Implementation Plan
Near-term:
- Replace fixture filename fallback with catalog-driven Unit -> Actor -> Model resolution.
- Parse
Objectsdocumented attributes exactly, keeping fixturex/y/zas compatibility sugar. - Keep binary terrain readers (
t3HeightMap,t3SyncHeightMap,t3SyncCliffLevel,t3CellFlags,t3TextureMasks) aligned with playable MapInfo bounds. - Expand
t3Terrain.xmlsupport beyond quantization and texture-layer metadata as needed. - Improve cliff/water/pathing reconstruction from source map data.
- Add debug dumps that compare with sc2reader metadata and SC2 Map Analyzer-style pathing views.
Keep these boundaries:
- Map/archive parsing stays in
games/starcraft-2/common. - Model rendering stays in
games/starcraft-2/renderer. - Game spawning consumes resolved object records and registers normal model handles.
- Engine code only knows generic map paths, media handles, and entity state.
Shadow and catalog diagnostics
The SC2 shadow pass uses the map's CLight key direction, loaded from the dependency catalogs and map
overrides. sc2_catalog_roots[] already includes Base.SC2Data: append only the relative filename when
reading a loose catalog and prepend only data/ when opening the archive. Commit 08178496c appended
Base.SC2Data again, producing paths such as Mods/Liberty.SC2Mod/Base.SC2Data/Base.SC2Data. Runtime
logs confirmed that no dependency light catalog opened, despite a global override catalog being readable.
MarSara's actual key direction is (0.724693,-0.124265,-0.677775), with ambient (0.525490,0.466667,0.4).
MarSara marks AmbientColor with Colorize="1" and authors ColorizationBlend=0.30; feeding the tint
straight into the Lambert sum washed the scene out (ambient 0.525 + key ~0.6 clamped to 1.0) and hid the
shadows. The catalog parser retains both fields, and terrain/cliff/M3 lighting uses the authored blend as
the ambient strength for colorized lights. Non-colorized lights retain their direct ambient value; missing
map lighting uses (0.35,0.35,0.40). Temporary runtime diagnostics compared transformed cliff face and
vertex normals (typical dot 0.88..1.00) and found negative key-light dots on the reported dark-facing
surfaces, confirming that normals and the model normal-matrix path were not the cause. One reported normal
had dot(key)=-0.723 but dot(back)=+0.607: treating authored Fill/Back channels as two additional
unshadowed Lambert suns caused the contradiction. Diffuse terrain, cliffs, and M3 models therefore use only
the shadow-casting Key channel; all three channels remain parsed rather than discarding authoritative data.
Loading those catalogs exposes CModel VariationCount. A positive count means the inherited model path
is a stem for _NN.m3; the map's Variation selects NN. Zero means unsuffixed; absent values inherit
(variants == -1 internally). Catalog layers retain omitted fields. The resolution cache key includes
both object name and variation; caching by name alone collapsed all cacti/bones into the first variation.
Out-of-range placed variations are logged and their requested paths preserved, not replaced with _00.
Local TRaynor01 includes Bush variation 6 against a five-variation catalog; missing assets remain visible
in logs/placeholders. make test-sc2 covers dependency light loading and variation cache hits/misses.
sc2_shadow_matrix fits the visible ground footprint (inverse camera rays at target terrain height) in
native SC2 units. The old WC3 +/-1500-unit light volume gave small units almost no shadow texels. The same
light matrix now drives terrain/cliff and M3 depth draws and color-pass receivers. Terrain previously used
the camera matrix even in the depth pass, and neither terrain nor the shared M3 fragment path sampled the
shadow map. Terrain layers/masks occupy units 0..4, so its shadow sampler uses unit 5; M3 restores its shadow
binding on unit 1 after terrain. During depth/UI draws bind white instead of the active depth target.
BZ_SHADOW_GLSL supplies a bounds-checked 3x3 PCF comparison with normalized-depth bias 0.0001. It attenuates
the key's direct contribution while ambient remains. Missing or invalid key/camera data
raises a renderer error rather than repeatedly drawing with the unrelated legacy matrix. Tests cover fitted
ground coverage, unit-scale resolution, vertical key basis, invalid input, and shader source contracts in
both make test-renderer-model and make test-renderer-shadows builds.
build/bin/mpqtool -data data/StarCraft2 cat GameData/LightData.xml
build/bin/mpqtool -data data/StarCraft2 cat GameData/ModelData.xml
build/bin/mpqtool -mpq data/StarCraft2/Mods/Liberty.SC2Mod/base.SC2Assets ls Assets/Doodads/MarSaraCactus
build/bin/opensc2 -data data/StarCraft2 +vid_mode 4 +map TRaynor01 +screenshot 5 +com_frame_limit 10
build/bin/opensc2 -data data/StarCraft2 +vid_mode 4 +map Maps/TerranTest.SC2Components +screenshot 5 +com_frame_limit 10
Use renderer bone/vertex diagnostics if m3tool --info --dump-all fails: the local tool aborted before
printing console model data during this investigation. Console behavior is described in
hud-layout-pipeline.md.