44 endian : le
55 imports :
66 - ../common/common
7+ doc : >
8+ LEGO Universe .raw terrain file format.
9+
10+ There are two distinct formats sharing the .raw extension:
11+
12+ 1. **Chunked format** (zone LUZ version >= 30): Self-describing with a
13+ u16 version + u1 dev header, followed by chunked terrain data.
14+ This is the format described by the top-level seq below.
15+ File versions 31 and 32 are known to exist.
16+
17+ 2. **Legacy flat-grid format** (zone LUZ version < 30): No file header.
18+ The zone's LUZ file version determines the field layout. This format
19+ uses a single flat grid instead of chunks. Since the file is not
20+ self-describing, the legacy format cannot be expressed in this ksy
21+ and is documented in the `legacy_grid` type below for reference.
22+ No known .raw files use this format in any shipped client.
23+
24+ The client's `OpenTerrain` function (0x01048080) selects the reader:
25+ mapVersion < 30 → legacy flat-grid reader
26+ mapVersion >= 30 → `ReadNewTerrainFormat` (chunked reader)
727seq :
828 - id : version
929 type : u2
1030 - id : dev
1131 type : u1
32+ doc : Must be 0 for valid terrain data; non-zero aborts loading
1233 - id : num_chunks
1334 type : u4
1435 if : dev == 0
@@ -43,73 +64,92 @@ types:
4364 type : u4
4465 repeat : expr
4566 repeat-expr : 4
46- - id : density
67+ - id : scale
4768 type : f4
69+ doc : Heightmap scale factor, used to transform grid coords to world coords
4870 - id : height_map
4971 type : f4
5072 repeat : expr
5173 repeat-expr : width * height
52- - id : diffuse_res
74+ - id : color_map_resolution
5375 type : u4
5476 if : _root.version >= 32
55- - id : diffuse_res_pixels
56- size : diffuse_res * diffuse_res * 4
77+ doc : Resolution of the color/diffuse map
78+ - id : color_map_pixels
79+ size : color_map_resolution * color_map_resolution * 4
5780 if : _root.version >= 32
58- doc : RGBA
59- - id : unknown1
60- type : u1
61- repeat : eos
81+ doc : RGBA color map pixels (raw block)
82+ - id : color_map_pixels_legacy
83+ size : width * width * 4
6284 if : _root.version < 32
63- doc : todo
85+ doc : >
86+ v<32 color map. Client reads width*width pixels (4 bytes each)
87+ with per-pixel BGRA byte swizzle. colorMapResolution = width - 1;
88+ only the inner (width-1)^2 pixels are used.
6489 - id : diffuse_map_dds_size
6590 type : u4
6691 if : _root.version >= 32
6792 - id : diffuse_map_dds
6893 size : diffuse_map_dds_size
6994 if : _root.version >= 32
95+ doc : DDS texture data for diffuse/light map
7096 - id : blend_res
7197 type : u4
7298 - id : blend_pixels
7399 size : blend_res * blend_res * 4
74- - id : bits
100+ doc : >
101+ Blend/texture map pixels. v>=32 reads as raw RGBA block;
102+ v<32 reads per-pixel as B,G,R,A (byte-swizzled).
103+ - id : blend_channel_mask
75104 type : u1
76105 if : _root.version >= 32
106+ doc : Bitmask of active detail textures (bits 0-3)
77107 - id : blend_map_dds_size
78108 type : u4
79109 if : _root.version >= 32
80110 - id : blend_map_dds
81111 size : blend_map_dds_size
82112 if : _root.version >= 32
113+ doc : DDS texture data for blend map (DXT5)
83114 - id : num_flairs
84115 type : u4
85116 - id : flairs
86117 type : flair_attributes
87- size : 36
88118 repeat : expr
89119 repeat-expr : num_flairs
90120 - id : scene_map
91- size : diffuse_res * diffuse_res
121+ size : color_map_resolution * color_map_resolution
92122 if : _root.version >= 32
93- - id : unknown2
94- type : u1
95- repeat : eos
96- if : _root.version < 32
97- doc : todo
123+ doc : Per-pixel scene ID assignment, indexes into LUZ scene list
124+ - id : scene_map_v31
125+ size : width * width
126+ if : _root.version == 31
127+ doc : >
128+ v31 scene map. Allocates (colorMapRes+1)^2 where colorMapRes=width-1.
129+ Client reads (colorMapRes+1)^2 cells; inner colorMapRes^2 cells
130+ contain scene IDs, border cells are skipped/discarded.
131+ - id : scene_map_skip
132+ size : 1
133+ if : _root.version < 31
134+ doc : v<31 skips 1 byte; scene map is zero-filled by client
98135 - id : vert_size
99136 type : u4
100137 if : _root.version >= 32
101138 - id : mesh_vert_usage
102139 type : u2
103140 repeat : expr
104141 repeat-expr : vert_size
142+ if : _root.version >= 32 and vert_size != 0
105143 - id : mesh_vert_size
106144 type : u2
107145 repeat : expr
108146 repeat-expr : 16
147+ if : _root.version >= 32 and vert_size != 0
109148 - id : mesh_tri
110149 type : mesh_tri
111150 repeat : expr
112151 repeat-expr : 16
152+ if : _root.version >= 32 and vert_size != 0
113153
114154 flair_attributes :
115155 seq :
@@ -127,6 +167,8 @@ types:
127167 type : u1
128168 - id : color_b
129169 type : u1
170+ - id : color_a
171+ type : u1
130172 mesh_tri :
131173 seq :
132174 - id : mesh_tri_list_size
@@ -135,3 +177,42 @@ types:
135177 type : u2
136178 repeat : expr
137179 repeat-expr : mesh_tri_list_size
180+
181+ legacy_grid :
182+ doc : >
183+ Legacy flat-grid terrain format (zone LUZ version < 30).
184+ NOT parseable from this ksy — requires the zone's LUZ version
185+ as external context since the file has no header. Documented
186+ here for reference only.
187+
188+ This format uses a single flat grid of `width * height` cells
189+ instead of the chunked layout. No known .raw files use this
190+ format in any shipped client.
191+
192+ The client's OpenTerrain (0x01048080) calls four functions in
193+ sequence, each gated on the zone's map version:
194+
195+ FUN_01013db0 — Heightmap:
196+ v < 4: width = height = 1280; u16 heights (scaled to float)
197+ v 4-10: width = height = 1280; f32 heights (v<11 scaled)
198+ v 11+: u32 width, u32 height from file
199+ v 12+: f32 scale from file (v<12 uses hardcoded 3.0)
200+ All: totalCells = width * height; float heightmap[totalCells]
201+
202+ FUN_01013880 — Color map:
203+ v < 3: no data (defaults)
204+ v 3: u32 packed ARGB per cell
205+ v 4-7: 4x f32 RGBA per cell (scaled by constant)
206+ v 8-10: 4x f32 RGBA per cell (unscaled)
207+ v 11+: 4x u1 RGBA per cell
208+ v 4+: also 2x f32 UV per cell
209+
210+ FUN_01013640 — Texture/material:
211+ v < 6: no data
212+ v 6-9: u32 material ID per cell
213+ v 10+: 20-byte struct per cell (materialId + blend weights)
214+
215+ FUN_01013550 — Scene map:
216+ v < 20: no data (zero-filled)
217+ v 20+: 1024-byte palette, then u1 scene ID per cell
218+ seq : []
0 commit comments