diff --git a/files/luz.ksy b/files/luz.ksy index 355686c..86d6a2d 100644 --- a/files/luz.ksy +++ b/files/luz.ksy @@ -69,9 +69,16 @@ types: - id: unknown1 type: common::vector3 if: _root.file_version == 33 + doc: > + v33-only reserved field. Skipped by client (ptr += 12) in every + known build from 0.179.12 through 1.10.64. Never read into any + struct or used at runtime. - id: unknown2 type: f4 if: _root.file_version == 33 + doc: > + v33-only reserved field. Skipped by client (ptr += 4) in every + known build. See unknown1. - id: scene_color_r type: u1 if: _root.file_version >= 33 diff --git a/files/raw.ksy b/files/raw.ksy index 60eb468..c463820 100644 --- a/files/raw.ksy +++ b/files/raw.ksy @@ -4,11 +4,27 @@ meta: endian: le imports: - ../common/common +doc: > + LEGO Universe .raw terrain file format (chunked, version >= 30). + + There are two distinct formats sharing the .raw extension: + + 1. **Chunked format** (zone LUZ version >= 30): Self-describing with a + u16 version + u1 dev header, followed by chunked terrain data. + This is the format described here. File versions 31 and 32 exist. + + 2. **Legacy flat-grid format** (zone LUZ version < 30): No file header. + See `raw_legacy.ksy` for that format. + + The client's `OpenTerrain` function (0x01048080) selects the reader: + mapVersion < 30 → legacy flat-grid reader + mapVersion >= 30 → `ReadNewTerrainFormat` (chunked reader) seq: - id: version type: u2 - id: dev type: u1 + doc: Must be 0 for valid terrain data; non-zero aborts loading - id: num_chunks type: u4 if: dev == 0 @@ -43,58 +59,74 @@ types: type: u4 repeat: expr repeat-expr: 4 - - id: density + - id: scale type: f4 + doc: Heightmap scale factor, used to transform grid coords to world coords - id: height_map type: f4 repeat: expr repeat-expr: width * height - - id: diffuse_res + - id: color_map_resolution type: u4 if: _root.version >= 32 - - id: diffuse_res_pixels - size: diffuse_res * diffuse_res * 4 + doc: Resolution of the color/diffuse map + - id: color_map_pixels + size: color_map_resolution * color_map_resolution * 4 if: _root.version >= 32 - doc: RGBA - - id: unknown1 - type: u1 - repeat: eos + doc: RGBA color map pixels (raw block) + - id: color_map_pixels_legacy + size: width * width * 4 if: _root.version < 32 - doc: todo + doc: > + v<32 color map. Client reads width*width pixels (4 bytes each) + with per-pixel BGRA byte swizzle. colorMapResolution = width - 1; + only the inner (width-1)^2 pixels are used. - id: diffuse_map_dds_size type: u4 if: _root.version >= 32 - id: diffuse_map_dds size: diffuse_map_dds_size if: _root.version >= 32 + doc: DDS texture data for diffuse/light map - id: blend_res type: u4 - id: blend_pixels size: blend_res * blend_res * 4 - - id: bits + doc: > + Blend/texture map pixels. v>=32 reads as raw RGBA block; + v<32 reads per-pixel as B,G,R,A (byte-swizzled). + - id: blend_channel_mask type: u1 if: _root.version >= 32 + doc: Bitmask of active detail textures (bits 0-3) - id: blend_map_dds_size type: u4 if: _root.version >= 32 - id: blend_map_dds size: blend_map_dds_size if: _root.version >= 32 + doc: DDS texture data for blend map (DXT5) - id: num_flairs type: u4 - id: flairs type: flair_attributes - size: 36 repeat: expr repeat-expr: num_flairs - id: scene_map - size: diffuse_res * diffuse_res + size: color_map_resolution * color_map_resolution if: _root.version >= 32 - - id: unknown2 - type: u1 - repeat: eos - if: _root.version < 32 - doc: todo + doc: Per-pixel scene ID assignment, indexes into LUZ scene list + - id: scene_map_v31 + size: width * width + if: _root.version == 31 + doc: > + v31 scene map. Allocates (colorMapRes+1)^2 where colorMapRes=width-1. + Client reads (colorMapRes+1)^2 cells; inner colorMapRes^2 cells + contain scene IDs, border cells are skipped/discarded. + - id: scene_map_skip + size: 1 + if: _root.version < 31 + doc: v<31 skips 1 byte; scene map is zero-filled by client - id: vert_size type: u4 if: _root.version >= 32 @@ -102,14 +134,17 @@ types: type: u2 repeat: expr repeat-expr: vert_size + if: _root.version >= 32 and vert_size != 0 - id: mesh_vert_size type: u2 repeat: expr repeat-expr: 16 + if: _root.version >= 32 and vert_size != 0 - id: mesh_tri type: mesh_tri repeat: expr repeat-expr: 16 + if: _root.version >= 32 and vert_size != 0 flair_attributes: seq: @@ -127,6 +162,8 @@ types: type: u1 - id: color_b type: u1 + - id: color_a + type: u1 mesh_tri: seq: - id: mesh_tri_list_size diff --git a/files/raw_legacy.ksy b/files/raw_legacy.ksy new file mode 100644 index 0000000..89642b9 --- /dev/null +++ b/files/raw_legacy.ksy @@ -0,0 +1,109 @@ +meta: + id: raw_legacy + file-extension: raw + endian: le +doc: > + LEGO Universe legacy .raw terrain file format (zone LUZ version < 30). + + This format has no file header — the zone's LUZ file version determines + the field layout. It uses a single flat grid instead of chunks. + No known .raw files use this format in any shipped client. + + The `map_version` parameter must be provided externally (from the + zone's LUZ file version). The client's `OpenTerrain` (0x01048080) + calls four functions in sequence, each gated on map_version. + + See `raw.ksy` for the chunked format used by LUZ version >= 30. +params: + - id: map_version + type: u4 +seq: + # --- Heightmap (FUN_01013db0) --- + - id: width + type: u4 + if: map_version >= 11 + - id: height + type: u4 + if: map_version >= 11 + - id: scale + type: f4 + if: map_version >= 12 + doc: Heightmap scale factor; v<12 uses hardcoded 3.0 + - id: height_map_u16 + type: u2 + repeat: expr + repeat-expr: total_cells + if: map_version < 4 + doc: v<4 u16 heights, scaled to float by multiplying with scale + - id: height_map_f32 + type: f4 + repeat: expr + repeat-expr: total_cells + if: map_version >= 4 + doc: > + v4+ f32 heights. v4-10 are pre-scaled (multiply by scale factor + at load time); v11+ are already in world units. + + # --- Color map (FUN_01013880) --- + - id: color_map_argb + type: u4 + repeat: expr + repeat-expr: total_cells + if: map_version == 3 + doc: v3 packed ARGB color per cell + - id: color_map_float_rgba + type: f4 + repeat: expr + repeat-expr: total_cells * 4 + if: map_version >= 4 and map_version < 11 + doc: > + v4-10 float RGBA per cell (4 floats each). + v4-7 values are scaled by a constant at load time; + v8-10 are used directly. + - id: color_map_bytes + size: total_cells * 4 + if: map_version >= 11 + doc: v11+ RGBA bytes per cell (4 bytes each) + - id: uv_coords + type: f4 + repeat: expr + repeat-expr: total_cells * 2 + if: map_version >= 4 + doc: v4+ UV coordinates per cell (2 floats each) + + # --- Texture/material (FUN_01013640) --- + - id: material_ids + type: u4 + repeat: expr + repeat-expr: total_cells + if: map_version >= 6 and map_version < 10 + doc: v6-9 material ID per cell + - id: material_structs + size: 20 + repeat: expr + repeat-expr: total_cells + if: map_version >= 10 + doc: > + v10+ material struct per cell (20 bytes): + u1 materialId, f32 blendWeight, 3x f32 blend weights + + # --- Scene map (FUN_01013550) --- + - id: scene_palette + size: 1024 + if: map_version >= 20 + doc: v20+ scene palette/header (1024 bytes, usage unknown) + - id: scene_map + size: total_cells + if: map_version >= 20 + doc: v20+ u1 scene ID per cell +instances: + default_width: + value: 1280 + default_height: + value: 1280 + actual_width: + value: 'map_version >= 11 ? width : default_width' + actual_height: + value: 'map_version >= 11 ? height : default_height' + total_cells: + value: actual_width * actual_height