Rose Online Asset File Format Technical Specification

This document will serve as a technical reference for the very old MMORPG Rose Online. The goal is that this information is never lost and may help decades later.

Table of Contents

Table of Contents

  1. Introduction
  2. Core Systems
  3. File Format Specifications
  4. Client-Side Rendering Pipeline
  5. Blender Plugin Implementation Guide
  6. Code Examples and Reference Implementations
  7. Quick Reference
  8. Appendices

1. Introduction

1.1 Rose Online Asset System Overview

Rose Online uses a sophisticated asset management system organized around a Virtual Filesystem (VFS) architecture. Assets are stored in proprietary binary formats optimized for real-time rendering in the game engine.

Key Characteristics:

  • Coordinate System: Y-up, centimeter-based (cm)
  • File Format Versions: Multiple format versions with backward compatibility
  • Asset Organization: Hierarchical structure with clear separation of concerns
  • Rendering Pipeline: GPU-accelerated with skinned mesh support

Asset File Extensions:

ExtensionDescriptionPrimary Use
.zmsMesh geometryCharacter models, objects, terrain tiles
.zmdSkeleton definitionBone hierarchies for skinned meshes
.zmoMotion/animationCharacter animations, object animations
.zonZone definitionTerrain composition, grid system
.zscObject compositionMulti-part object assembly
.ifoZone object placementNPC spawns, objects, events
.himHeightmapTerrain elevation data
.tilTile indexTerrain tile mapping
.chrCharacter definitionNPC and character asset references

1.2 File Format Relationships

graph TD
    ZON[ZON Zone File] -->|References| TIL[TIL Tile Index]
    ZON -->|Uses| HIM[HIM Heightmap]
    ZON -->|Contains| Tiles[Tiles Block]

    IFO[IFO Zone Object File] -->|Instantiates| ZSC[ZSC Object Files]
    IFO -->|References| CHR[CHR Character File]
    IFO -->|Places| Objects[Zone Objects]

    CHR -->|References| ZMD[ZMD Skeleton]
    CHR -->|References| ZSC
    CHR -->|References| ZMO[ZMO Animation]
    CHR -->|Maps| Motions[Motion Actions]

    ZSC -->|Contains| ZMS[ZMS Mesh]
    ZSC -->|Contains| Materials[ZSC Materials]
    ZSC -->|Defines| Parts[Object Parts]
    ZSC -->|Contains| Effects[Effect References]

    ZMS -->|Requires| ZMD
    ZMS -->|Contains| Vertices[Vertex Data]
    ZMS -->|Contains| Indices[Index Data]
    ZMS -->|Contains| BoneWeights[Bone Weights]

    ZMO -->|Targets| ZMD bones
    ZMO -->|Contains| Channels[Animation Channels]
    ZMO -->|Contains| FrameEvents[Frame Events]
    ZMO -->|Extended| EZMO[EZMO/3ZMO]

    ZMD -->|Contains| Bones[Regular Bones]
    ZMD -->|Contains| DummyBones[Dummy Bones]

    HIM -->|Provides| Heights[Terrain Heights]
    TIL -->|Provides| Indices[Tile Indices]

Complete Asset Loading Workflows

Zone Loading and Composition Workflow:
1. Load ZON File
   ├─ Parse ZoneInfo block (grid configuration)
   ├─ Parse EventPositions block (spawn points)
   ├─ Parse Textures block (texture paths)
   └─ Parse Tiles block (tile composition)

2. Load Terrain Data
   ├─ Load HIM file (heightmap)
   ├─ Load TIL file (tile indices)
   └─ Generate terrain mesh from ZON tiles + HIM heights

3. Load IFO File
   ├─ Parse object blocks (NPCs, monsters, decorations)
   ├─ Parse spawn points
   ├─ Parse warp positions
   └─ Parse water planes

4. Load Zone Objects
   ├─ For each IFO object:
   │  ├─ Load ZSC file (object composition)
   │  ├─ For each ZSC part:
   │  │  ├─ Load ZMS mesh file
   │  │  ├─ Load ZSC material
   │  │  ├─ Apply material to mesh
   │  │  └─ Parent to object entity
   │  └─ For each ZSC effect:
   │     └─ Load and spawn effect
   └─ Place object at IFO position with transform
Character/NPC Assembly Pipeline:
1. Load CHR File
   ├─ Parse skeleton file list
   ├─ Parse motion file list
   ├─ Parse effect file list
   └─ Parse character definitions

2. For Character/NPC:
   ├─ Load ZMD skeleton file
   │  ├─ Parse bone hierarchy
   │  ├─ Create bone entities
   │  ├─ Compute bind pose matrices
   │  ├─ Compute inverse bind matrices
   │  └─ Create SkinnedMesh component
   │
   ├─ Load ZSC object files (one per body part)
   │  ├─ For each ZSC object:
   │  │  ├─ Parse material definitions
   │  │  ├─ Parse object parts
   │  │  ├─ Parse effect definitions
   │  │  └─ Load ZMS mesh files
   │
   ├─ Load ZMS mesh files
   │  ├─ Parse vertex data (positions, normals, UVs)
   │  ├─ Parse bone weights and indices
   │  ├─ Parse index data
   │  └─ Create mesh entities
   │
   ├─ Bind meshes to skeleton
   │  ├─ Attach to bone entities (or dummy bones)
   │  ├─ Apply SkinnedMesh component
   │  └─ Set material properties
   │
   ├─ Load ZMO animation files
   │  ├─ Parse frame data
   │  ├─ Parse channel data (position, rotation, scale)
   │  ├─ Parse frame events
   │  └─ Create animation handles
   │
   └─ Attach effects to dummy bones
      ├─ Load effect files from CHR
      ├─ Spawn effect entities
      └─ Parent to dummy bone entities
Animation Application Pipeline:
1. Load ZMO Animation File
   ├─ Parse FPS and frame count
   ├─ Parse channel definitions
   ├─ Parse frame data per channel
   └─ Parse frame events

2. Create ZmoAsset
   ├─ Organize channels by bone ID
   ├─ Store translation vectors per frame
   ├─ Store rotation quaternions per frame
   ├─ Store scale values per frame
   └─ Store frame events

3. Animation Playback
   ├─ Calculate current frame from time
   ├─ Get frame fraction for interpolation
   ├─ Sample bone transforms:
   │  ├─ Position: Linear interpolation
   │  ├─ Rotation: Quaternion slerp
   │  └─ Scale: Linear interpolation
   ├─ Apply transforms to bone entities
   └─ Trigger frame events

4. Skinned Mesh Update
   ├─ GPU computes vertex positions
   ├─ Using bone weights and current pose
   ├─ Apply skinning matrices
   └─ Render final mesh

Detailed File Type Interactions:

ZON ↔ HIM/TIL Interaction:

Purpose: Generate terrain geometry from zone definition

Data Flow:

ZON File:
  ├─ Grid per patch (float)
  ├─ Grid size (float)
  ├─ Tile textures (array of paths)
  └─ Tiles (array of ZonTile)
     ├─ Layer1 texture index
     ├─ Layer2 texture index
     ├─ Offset1, Offset2 (UV offsets)
     ├─ Blend flag
     └─ Rotation enum

HIM File:
  ├─ Width, Height (grid dimensions)
  └─ Heights array (width × height floats)

TIL File:
  ├─ Width, Height (grid dimensions)
  └─ Tiles array (width × height indices)

Terrain Generation:
  For each grid cell (x, y):
    ├─ Get tile index from TIL[x][y]
    ├─ Get tile definition from ZON.tiles[tile_index]
    ├─ Get texture path from ZON.textures[tile.layer1]
    ├─ Get height from HIM[x][y]
    ├─ Apply tile rotation and offset
    ├─ Generate vertices with height
    └─ Apply texture coordinates

Client Implementation (observed in rendering code):

  • Terrain is rendered as a grid of tiles
  • Each tile is a quad with 4 vertices
  • Vertices are positioned using HIM heights
  • UVs are computed from TIL tile indices and ZON tile data
  • Layer blending is applied if tile.blend is true
IFO ↔ ZSC/ZMS/ZMD Interaction:

Purpose: Place objects in zone with correct models and transforms

Data Flow:

IFO File:
  ├─ Object type (Deco, NPC, MonsterSpawn, etc.)
  ├─ Object ID (references CHR or ZSC)
  ├─ Position (X, Y, Z)
  ├─ Rotation (quaternion XYZW)
  ├─ Scale (X, Y, Z)
  └─ Additional type-specific data

For NPC Objects:
  ├─ Load CHR file by NPC ID
  │  ├─ Get skeleton file path
  │  ├─ Get model IDs
  │  ├─ Get motion IDs
  │  └─ Get effect IDs
  │
  ├─ Load ZMD skeleton
  ├─ Load ZSC model files (from CHR.model_ids)
  │  └─ For each ZSC object:
  │     ├─ Load ZMS meshes
  │     ├─ Load materials
  │     └─ Create mesh entities
  │
  └─ Load ZMO animations (from CHR.motion_ids)
     └─ Create animation handles

For Decoration Objects:
  ├─ Load ZSC file directly (from IFO.object_id)
  └─ Same process as above
CHR ↔ ZMD/ZSC/ZMO Interaction:

Purpose: Define character/NPC asset composition and animations

Data Flow:

CHR File:
  ├─ Skeleton files (array of paths)
  ├─ Motion files (array of paths)
  ├─ Effect files (array of paths)
  └─ Character definitions (map: ID → NpcModelData)

NpcModelData:
  ├─ Skeleton index (into skeleton_files)
  ├─ Name
  ├─ Model IDs (array: into ZSC objects)
  ├─ Motion IDs (array of tuples: (motion_id, file_index))
  └─ Effect IDs (array of tuples: (motion_id, file_index))
ZSC ↔ ZMS/Material Interaction:

Purpose: Define multi-part objects with materials and transforms

Data Flow:

ZSC File:
  ├─ Meshes (array of paths to ZMS files)
  ├─ Materials (array of ZscMaterial)
  ├─ Effects (array of paths to effect files)
  └─ Objects (array of ZscObject)

ZscObject:
  └─ Parts (array of ZscObjectPart)

ZscObjectPart:
  ├─ Mesh ID (into meshes array)
  ├─ Material ID (into materials array)
  ├─ Transform (position, rotation, scale)
  ├─ Bone index (optional: bind to skeleton bone)
  ├─ Dummy index (optional: bind to dummy bone)
  ├─ Parent index (optional: parent part)
  └─ Animation path (optional: animation override)

ZscMaterial:
  ├─ Path (texture file)
  ├─ Alpha enabled, two-sided
  ├─ Alpha test (threshold)
  ├─ Z write/test enabled
  ├─ Blend mode
  ├─ Specular enabled
  ├─ Alpha value
  └─ Glow type and color
ZMO ↔ ZMD Interaction:

Purpose: Drive skeleton bones with animation data

Data Flow:

ZMO File:
  ├─ FPS (frames per second)
  ├─ Frame count
  ├─ Channels (array of (bone_id, channel_type))
  └─ Frame events (array of frame numbers)

ZmoChannel Types:
  ├─ Position: Vec3 per frame
  ├─ Rotation: Quat4 per frame
  ├─ Scale: f32 per frame
  ├─ Normal: Vec3 per frame (morph targets)
  ├─ UV1-UV4: Vec2 per frame (texture animation)
  ├─ Alpha: f32 per frame
  └─ Texture: f32 per frame
ZMS ↔ ZMD Interaction:

Purpose: Bind mesh vertices to skeleton bones for skinning

Data Flow:

ZMS File:
  ├─ Format flags (vertex attributes)
  ├─ Bone count
  ├─ Bone mapping (version 5/6 only)
  ├─ Vertex count
  ├─ Vertex data (based on flags):
  │  ├─ Positions (Vec3)
  │  ├─ Normals (Vec3)
  │  ├─ Colors (Vec4)
  │  ├─ Bone weights (Vec4: w1, w2, w3, w4)
  │  ├─ Bone indices (Vec4: i1, i2, i3, i4)
  │  ├─ Tangents (Vec3)
  │  └─ UV1-UV4 (Vec2)
  ├─ Triangle indices (u16)
  └─ Material face counts (u16)
Effect System Integration:

Purpose: Attach particle and mesh effects to objects

Data Flow:

CHR File:
  └─ Effect IDs (array of tuples: (motion_id, file_index))

ZSC File:
  └─ Effects (array of paths to effect files)



##### Vehicle Assembly Pipeline:

**Purpose**: Assemble vehicle models with skeleton and parts

**Data Flow**:

Vehicle Item Database:
└─ Vehicle item data
├─ Vehicle type (Cart/CastleGear)
├─ Base motion index
├─ Base avatar motion index
└─ Dummy effect file IDs

Client-Side Rendering Integration Summary:

The Rose Offline client integrates all file types through a hierarchical asset loading system:

  1. VFS Layer: Unified file access across packed archives and host filesystem
  2. Asset Server: Asynchronous loading and caching of assets
  3. ECS Components:
  • SkinnedMesh: Bone binding data (inverse bind matrices, joint entities)
  • CharacterModel: Character parts and animation handles
  • NpcModel: NPC-specific data
  • VehicleModel: Vehicle-specific data
  • ObjectMaterial: Material properties and textures
  1. Systems: Update bone poses, apply animations, render skinned meshes

Coordinate Transformations Applied in Client:

  • All positions: (x, y, z) → (x, z, -y) / 100.0
  • All rotations: (w, x, y, z) → (x, z, -y, w)
  • Scale: 100.0 (cm to m conversion)

Blender Import Implications:

  1. Apply inverse coordinate transformations for Blender’s coordinate system
  2. Preserve bone hierarchy and parent-child relationships
  3. Convert bone weights to vertex groups
  4. Map frame-based animations to Blender actions
  5. Convert materials to Principled BSDF nodes
  6. Handle dummy bones as separate bone entities
  7. Preserve animation events for Blender NLA tracks

1.3 Blender Integration Strategy

Conversion Goals:

  1. Coordinate System Conversion: Rose Online (cm, Y-up) → Blender (m, Y-up)
  2. Data Model Mapping: Binary structures → Blender Python API objects
  3. Hierarchy Preservation: Bone and object relationships maintained
  4. Material Translation: Rose Online materials → Blender Principled BSDF
  5. Animation Support: Frame-based animation → Blender NLA tracks

Data Model Mapping:

Rose Online ConceptBlender Equivalent
ZMS Meshbpy.types.Mesh
ZMD Skeletonbpy.types.Armature
ZMD Bonebpy.types.Bone
ZMO Animationbpy.types.Action
ZSC ObjectCollection of mesh objects
Materialbpy.types.Material
Bone WeightsVertex Groups

2. Core Systems

2.1 Virtual Filesystem (VFS) Abstraction Layer

Architecture Overview:

The VFS provides a unified interface for accessing game assets across multiple storage devices (packed archives, host filesystem).

Key Components:

// VFS Device Trait
trait VirtualFilesystemDevice {
    fn open_file(&self, path: &VfsPath) -> Result<VfsFile>;
    fn exists(&self, path: &VfsPath) -> bool;
}

// VFS Implementation
struct VirtualFilesystem {
    devices: Vec<Box<dyn VirtualFilesystemDevice + Send + Sync>>
}

Path Normalization:

All paths are normalized to:

  • Forward slashes (/)
  • Uppercase
  • No leading/trailing whitespace
  • No double slashes

Example: 3DDATA\AVATAR\MALE.ZMD3DDATA/AVATAR/MALE.ZMD

File Loading Mechanism:

// Generic file loading
vfs.read_file::<ZmsFile, _>("3DDATA/MODELS/CHARACTER.ZMS")?;

// With options
vfs.read_file_with::<ZonFile, _, _>("DATA/ZONES/01.ZON", &options)?;

Caching Strategy:

  • Assets are loaded on-demand
  • VFS devices are queried in order
  • First successful read wins
  • No built-in caching (handled by application layer)

2.2 Coordinate System Conversions

Rose Online Coordinate System:

  • Units: Centimeters (cm)
  • Up Axis: Y-up
  • Handedness: Right-handed
  • Forward: -Z direction
  • Right: +X direction

Blender Coordinate System:

  • Units: Meters (m)
  • Up Axis: Y-up
  • Handedness: Right-handed
  • Forward: -Y direction (in view space)
  • Right: +X direction

Conversion Formulas:

Position Conversion:

# Rose Online (cm) to Blender (m)
def convert_position(x, y, z):
    return (x / 100.0, y / 100.0, z / 100.0)

# For client rendering (observed in model_loader.rs):
# Rose: (x, y, z) → Blender: (x, z, -y) / 100.0
def convert_position_for_client(x, y, z):
    return (x / 100.0, z / 100.0, -y / 100.0)

Rotation Conversion:

# Rose Online quaternion (W, X, Y, Z) to Blender (W, X, Y, Z)
# Note: Some files store as WXYZ, others as XYZW
def convert_quaternion(w, x, y, z):
    # Blender uses (w, x, y, z)
    return (w, x, y, z)

# For client rendering (observed):
# Rose: (x, y, z, w) → Blender: (x, z, -y, w)
def convert_quaternion_for_client(x, y, z, w):
    return (x, z, -y, w)

Scale Conversion:

# ZMS mesh data is scaled by 100.0
# ZMD bone positions are in cm
def convert_scale(value):
    return value / 100.0

Coordinate System Mappings:

Rose Online AxisBlender AxisNotes
+X+XSame direction
+Y+ZClient rotates Y to Z
+Z-YClient inverts Z to -Y

2.3 Bone Binding Matrices and Skinning

Bone Hierarchy Structure:

Bones form a tree structure where each bone has a parent index (0 = root).

pub struct ZmdBone {
    pub parent: u16,        // Parent bone index (0 = root)
    pub position: Vec3<f32>,  // Position in parent space (cm)
    pub rotation: Quat4<f32>, // Rotation in parent space (WXYZ)
}

Bone-to-Vertex Binding System:

Each vertex can be bound to up to 4 bones with weights.

// Vertex bone binding data
pub bone_weights: Vec<[f32; 4]>,    // Weight for each of 4 bones
pub bone_indices: Vec<[u16; 4]>,    // Bone indices (mapped to skeleton)

Weight Normalization: The 4 weights should sum to 1.0 for proper skinning.

Skinning Transformation Pipeline:

  1. Bind Pose: Bone positions at rest (from ZMD)
  2. Inverse Bind Matrix: Pre-computed for each bone
  3. Current Pose: Bone transformation from animation (ZMO)
  4. Skinning Matrix: CurrentPose × InverseBindMatrix
  5. Vertex Transformation: Σ (Weight_i × SkinningMatrix_i × VertexPosition)

Bone Pose Matrices and Bone Spaces:

Bone Spaces:

  • Local Space: Position/rotation relative to parent
  • Object Space: Position/rotation relative to mesh origin
  • World Space: Position/rotation in game world

2.4 Animation Track Interpolation

Frame-Based Animation System:

Animations are stored as discrete frames with fixed FPS.

pub struct ZmoFile {
    pub fps: usize,              // Frames per second (typically 30)
    pub num_frames: usize,       // Total frame count
    pub channels: Vec<(u32, ZmoChannel)>,  // (bone_index, channel_data)
    pub frame_events: Vec<u16>,  // Frame event triggers
    pub interpolation_interval_ms: Option<u32>,  // For 3ZMO format
}

Channel Types and Data Structures:

Channel TypeValueData TypePurpose
Empty1No animation data
Position2Vec3Bone position
Rotation4Quat4Bone rotation (WXYZ)
Normal8Vec3Vertex normal
Alpha16f32Transparency
UV132Vec2First UV set
UV264Vec2Second UV set
UV3128Vec2Third UV set
UV4256Vec2Fourth UV set
Texture512f32Texture animation
Scale1024f32Scale factor

Frame Events and Interpolation Intervals:

Frame Events:

  • Triggered at specific frames
  • Used for sound effects, particle spawns, etc.
  • Event IDs: 10, 20-28, 56-57, 66-67 (attack events)

3ZMO Extended Format:

  • Includes interpolation_interval_ms field
  • Specifies custom interpolation timing
  • Allows for variable frame rates

2.5 Material System

Material Properties and Flags:

pub struct ZscMaterial {
    pub path: VfsPathBuf,              // Material file path
    pub is_skin: bool,                 // Skin/shader type
    pub alpha_enabled: bool,            // Transparency enabled
    pub two_sided: bool,                // Double-sided rendering
    pub alpha_test: Option<f32>,        // Alpha test threshold
    pub z_write_enabled: bool,           // Depth write
    pub z_test_enabled: bool,           // Depth test
    pub blend_mode: ZscMaterialBlend,   // Blending mode
    pub specular_enabled: bool,           // Specular highlights
    pub alpha: f32,                    // Global alpha
    pub glow: Option<ZscMaterialGlow>, // Glow effect
}

Blend Modes and Transparency:

Blend ModeValueDescriptionBlender Equivalent
Normal0Standard alpha blendingAlpha Blend
Lighten1Additive blendingAdd Mix

Alpha Test:

  • Threshold value (0-1) for pixel discard
  • Typical value: alpha_ref / 256.0
  • Pixels below threshold are discarded

Glow Effects and Shader Integration:

pub enum ZscMaterialGlow {
    Simple(Vec3<f32>),      // Simple glow color
    Light(Vec3<f32>),        // Light-based glow
    Texture(Vec3<f32>),      // Texture-based glow
    TextureLight(Vec3<f32>), // Texture + light glow
    Alpha(Vec3<f32>),        // Alpha-based glow
}

Texture Referencing and UV Mapping:

UV Channels:

  • ZMS supports up to 4 UV sets (UV1-UV4)
  • UV1 is primary texture coordinates
  • UV2-UV4 used for multi-texturing or effects

Texture Paths:

  • Stored in ZSC material definitions
  • Resolved through VFS
  • File extensions: .dds, .tga, .jpg

2.6 Vertex Format Flags and Data Layout

ZmsFormatFlags Bitfield Structure:

bitflags! {
    pub struct ZmsFormatFlags: u32 {
        const POSITION = (1 << 1);      // 0x0002
        const NORMAL = (1 << 2);        // 0x0004
        const COLOR = (1 << 3);         // 0x0008
        const BONE_WEIGHT = (1 << 4);   // 0x0010
        const BONE_INDEX = (1 << 5);    // 0x0020
        const TANGENT = (1 << 6);       // 0x0040
        const UV1 = (1 << 7);          // 0x0080
        const UV2 = (1 << 8);          // 0x0100
        const UV3 = (1 << 9);          // 0x0200
        const UV4 = (1 << 10);         // 0x0400
    }
}

Vertex Attribute Variations:

Version 5/6 (Legacy):

  • Each vertex preceded by 32-bit vertex ID
  • Bone indices stored as 32-bit, mapped to 16-bit
  • Position scaled by 100.0 (cm to m conversion)

Version 7/8 (Modern):

  • No vertex IDs
  • Bone indices stored as 16-bit directly
  • No scaling (already in correct units)

Position, Normal, Color, Bone Weights:

pub position: Vec<[f32; 3]>,      // X, Y, Z position
pub normal: Vec<[f32; 3]>,        // X, Y, Z normal vector
pub color: Vec<[f32; 4]>,         // R, G, B, A vertex color
pub bone_weights: Vec<[f32; 4]>,   // Weight for 4 bones
pub bone_indices: Vec<[u16; 4]>,    // Bone index mapping

UV Coordinate Sets (UV1-4):

pub uv1: Vec<[f32; 2]>,  // Primary UV coordinates
pub uv2: Vec<[f32; 2]>,  // Secondary UV coordinates
pub uv3: Vec<[f32; 2]>,  // Tertiary UV coordinates
pub uv4: Vec<[f32; 2]>,  // Quaternary UV coordinates

Tangent and Binormal Data:

pub tangent: Vec<[f32; 3]>,  // Tangent vector for normal mapping

Note: Binormals can be computed from tangent and normal:

binormal = cross(normal, tangent)

Material Face Mapping:

pub material_num_faces: Vec<u16>,  // Face count per material

Faces are grouped by material index for efficient rendering.


3. File Format Specifications

3.1 ZMS Mesh Files (.zms)

File Header and Magic Number:

Offset  Type    Description
0x00    char[7]  Magic string ("ZMS0005", "ZMS0006", "ZMS0007", "ZMS0008")

Version Detection:

Magic StringVersionNotes
ZMS00055Legacy format
ZMS00066Legacy format with material mapping
ZMS00077Modern format
ZMS00088Modern format with strip indices

Binary Layout and Data Structures:

Version 5/6 Layout:

Offset  Type    Description
0x00    char[7]  Magic string
0x07    u32      Format flags (ZmsFormatFlags)
0x0B    Vec3     Bounding box minimum
0x17    Vec3     Bounding box maximum
0x23    u32      Bone count
0x27    u32[]    Bone mapping (bone_count × 4 bytes)
0x??    u32      Vertex count
0x??    Vertex[]  Vertex data (based on format flags)
0x??    u32      Triangle count
0x??    u16[]    Index data (triangle_count × 3)
0x??    u32      Material ID count (version 6+)
0x??    u16[]    Material face counts

Version 7/8 Layout:

Offset  Type    Description
0x00    char[7]  Magic string
0x07    u32      Format flags (ZmsFormatFlags)
0x0B    Vec3     Bounding box minimum
0x17    Vec3     Bounding box maximum
0x23    u16      Bone count
0x25    u16[]    Bone indices (bone_count × 2 bytes)
0x??    u16      Vertex count
0x??    Vertex[]  Vertex data (based on format flags)
0x??    u16      Triangle count
0x??    u16[]    Index data (triangle_count × 3)
0x??    u16      Material ID count
0x??    u16[]    Material face counts
0x??    u16      Strip index count (version 8)
0x??    u16[]    Strip indices
0x??    u16      Pool type (version 8)

Vertex Data Arrays:

Vertex Data Structure (per vertex):

struct Vertex {
    // Present if POSITION flag set
    float position[3];  // X, Y, Z

    // Present if NORMAL flag set
    float normal[3];    // X, Y, Z

    // Present if COLOR flag set
    float color[4];     // R, G, B, A

    // Present if BONE_WEIGHT and BONE_INDEX flags set
    float bone_weight[4];   // W1, W2, W3, W4
    uint32 bone_index[4];   // I1, I2, I3, I4 (v5/6)
    uint16 bone_index[4];   // I1, I2, I3, I4 (v7/8)

    // Present if TANGENT flag set
    float tangent[3];   // X, Y, Z

    // Present if UV1 flag set
    float uv1[2];      // U, V

    // Present if UV2 flag set
    float uv2[2];      // U, V

    // Present if UV3 flag set
    float uv3[2];      // U, V

    // Present if UV4 flag set
    float uv4[2];      // U, V
};

Version 5/6: Each vertex preceded by 32-bit vertex ID.

Material Face Mapping:

pub material_num_faces: Vec<u16>
  • Each entry specifies number of triangles for a material
  • Faces are grouped contiguously by material
  • Used for efficient multi-material rendering

Bone Index Mapping:

Version 5/6:

let bone_count = reader.read_u32()?;
let mut bones = Vec::new();
for _ in 0..bone_count {
    let _ = reader.read_u32()?;  // Unused
    bones.push(reader.read_u32()? as u16);
}

Bone indices in vertices are 32-bit, mapped through this table to 16-bit.

Version 7/8:

let bone_count = reader.read_u16()?;
let mut bones = Vec::new();
for _ in 0..bone_count {
    bones.push(reader.read_u16()?);
}

Bone indices in vertices are already 16-bit, no mapping needed.

Vertex Attribute Flags:

See Section 2.6 for flag definitions.

Scaling Factors:

Version 5/6: Position data is scaled by 100.0 (cm to m conversion).

for [x, y, z] in position.iter_mut() {
    *x /= 100.0;
    *y /= 100.0;
    *z /= 100.0;
}

Version 7/8: No scaling applied.

Parsing Algorithms and Edge Cases:

  1. Invalid Bone Index: Throw error if bone index >= bone_count
  2. Missing Attributes: Only read attributes present in format flags
  3. Empty Mesh: Handle vertex_count = 0 gracefully
  4. Material Count: May be 0 (single material mesh)

3.2 ZMD Skeleton Files (.zmd)

File Header and Magic Number:

Offset  Type    Description
0x00    char[7]  Magic string ("ZMD0002" or "ZMD0003")

Version Detection:

Magic StringVersionNotes
ZMD00022Legacy format
ZMD00033Modern format with dummy bone rotation

Binary Layout and Data Structures:

Offset  Type    Description
0x00    char[7]  Magic string
0x07    u32      Bone count
0x0B    Bone[]   Bone data
0x??    u32      Dummy bone count
0x??    DummyBone[] Dummy bone data

Bone Count and Hierarchy:

let bone_count = reader.read_u32()? as usize;
let mut bones = Vec::with_capacity(bone_count);

Bone Data Structure:

struct ZmdBone {
    uint32 parent;       // Parent bone index (0 = root)
    char   name[];      // Null-terminated bone name
    float  position[3];  // X, Y, Z (cm)
    float  rotation[4];  // W, X, Y, Z (quaternion)
};

Bone Name and ID Mapping:

Bone names are stored but not typically used in rendering. Bone ID is the array index.

Dummy Bone Support:

Dummy bones are attachment points for weapons, effects, etc.

struct DummyBone {
    char   name[];      // Null-terminated name
    uint32 parent;      // Parent bone index
    float  position[3];  // X, Y, Z (cm)
    float  rotation[4];  // W, X, Y, Z (version 3 only)
};

Version 2: Dummy bones have identity rotation (0, 0, 0, 1).

Pose Transformation Matrices:

Not stored in ZMD file. Computed at runtime from bone hierarchy.

Bone-to-Object Binding:

Bones are in local space (relative to parent). Object space matrices computed by traversing hierarchy.

Scaling from cm to m:

Bone positions are in centimeters. Scale by 0.01 for meters.

3.3 ZMO Animation Files (.zmo)

File Header and Magic Number:

Offset  Type    Description
0x00    char[7]  Magic string ("ZMO0002")

Channel Definitions and Types:

struct ChannelDef {
    uint32 channel_type;   // 1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024
    uint32 bone_index;    // Target bone index
};

Frame Data Structures:

Frame data is stored per channel, not per frame.

Channel 0:
  Frame 0: value
  Frame 1: value
  ...
  Frame N: value

Channel 1:
  Frame 0: value
  ...

Extended Format Support (EZMO/3ZMO):

Extended data at end of file:

End-4:  char[4]  Magic ("EZMO" or "3ZMO")
End-8:  u32      Extended data offset
Offset: u16      Frame event count
Offset+2: u16[]   Frame events (event_count)
...

3ZMO Only:

  • After frame events: u32 interpolation_interval_ms

Frame Events and Interpolation Intervals:

Frame Events:

pub frame_events: Vec<u16>

Triggered at specific frames. Attack events: 10, 20-28, 56-57, 66-67.

Interpolation Interval:

pub interpolation_interval_ms: Option<u32>

Custom interpolation timing for 3ZMO format.

Channel Interpolation Methods:

  • Position: Linear interpolation
  • Rotation: Quaternion Slerp
  • UV/Scale/Alpha: Linear interpolation

3.4 ZON Zone Files (.zon)

Block-Based File Structure:

Offset  Type    Description
0x00    u32      Block count
0x04    BlockHeader[] Block headers (count × 8 bytes)
...
Block Data...

Block Header:

struct BlockHeader {
    uint32 block_type;   // Block type enum
    uint32 block_offset;  // Offset to block data
};

Block Type Enumeration:

enum BlockType {
    ZoneInfo = 0,
    EventPositions = 1,
    Textures = 2,
    Tiles = 3,
    Economy = 4,
};

ZoneInfo Block – Grid Configuration:

Offset  Type    Description
0x00    u32[3]   Unknown (12 bytes)
0x0C    u32      Grid per patch
0x10    f32      Grid size
0x14    u32[2]   Unknown (8 bytes)

EventPositions Block – Spawn Points:

struct EventPosition {
    float  position[3];  // X, Y, Z
    uint8  name_len;     // Name length
    char   name[name_len]; // Event name
};

Textures Block – Texture References:

struct TextureRef {
    uint8  path_len;     // Path length
    char   path[path_len]; // Texture path
};

Tiles Block – Tile Composition:

struct ZonTile {
    uint32 layer1;       // Primary layer texture index
    uint32 layer2;       // Secondary layer texture index
    uint32 offset1;      // Primary layer offset
    uint32 offset2;      // Secondary layer offset
    uint32 blend;        // Blend flag (0/1)
    uint32 rotation;     // Rotation enum
    uint32 padding;      // 4 bytes padding
};

ZonTile Structure and Layer Composition:

Rotation Enum:

pub enum ZonTileRotation {
    Unknown = 0,
    None = 1,
    FlipHorizontal = 2,
    FlipVertical = 3,
    Flip = 4,
    Clockwise90 = 5,
    CounterClockwise90 = 6,
};

Tile Offset and Blend Modes:

  • Offset: UV offset for texture sampling
  • Blend: Enable/disable layer blending
  • Rotation: Texture rotation transformation

Spatial Partitioning and Grid System:

Zone is divided into a grid of tiles. Each tile references textures from the Textures block.

3.5 ZSC Object Composition Files (.zsc)

Material List Structure:

struct MaterialList {
    uint16 material_count;
    MaterialEntry materials[material_count];
};

ZscMaterial Properties:

struct ZscMaterial {
    char   path[];        // Null-terminated path
    uint16 is_skin;       // 0/1
    uint16 alpha_enabled; // 0/1
    uint16 two_sided;    // 0/1
    uint16 alpha_test_enabled; // 0/1
    uint16 alpha_ref;     // Alpha reference (0-255)
    uint16 z_test_enabled; // 0/1
    uint16 z_write_enabled; // 0/1
    uint16 blend_mode;    // 0=Normal, 1=Lighten
    uint16 specular_enabled; // 0/1
    float  alpha;         // Global alpha
    uint16 glow_type;     // 0=None, 2=Simple, 3=Light, 4=TextureLight, 5=Alpha
    float  glow_color[3]; // R, G, B
};

Object Part Definitions:

struct ObjectPart {
    uint16 mesh_id;      // Mesh index
    uint16 material_id;   // Material index
    // Properties follow (variable length)
};

Mesh and Material References:

  • Mesh List: Array of mesh file paths
  • Material List: Array of material definitions
  • Effect List: Array of effect file paths

Part Transforms (Position, Rotation, Scale):

struct Transform {
    float position[3];   // X, Y, Z
    float rotation[4];   // W, X, Y, Z (quaternion)
    float scale[3];      // X, Y, Z
};

Bone Index and Dummy Bone Binding:

struct BoneBinding {
    uint16 bone_index;    // Regular bone index
    uint16 dummy_index;   // Dummy bone index
};

Parent-Child Relationships:

struct ParentRef {
    uint16 parent_id;    // Parent part index (0 = none)
};

Parent IDs are 1-indexed. Subtract 1 to get array index.

Collision Shape and Flags:

struct CollisionData {
    uint16 flags;        // Collision flags
    // Bits 0-2: Shape (0=None, 1=Sphere, 2=AABB, 3=OBB, 4=Polygon)
    // Bit 3: NOT_MOVEABLE
    // Bit 4: NOT_PICKABLE
    // Bit 5: HEIGHT_ONLY
    // Bit 6: NOT_CAMERA_COLLISION
    // Bit 7: PASSTHROUGH
};

Animation Path References:

struct AnimationRef {
    uint8  property_id;  // Must be 30
    uint8  size;         // Path length
    char   path[size];   // Animation path
};

Object Effects and Properties:

struct ObjectEffect {
    uint16 effect_id;    // Effect index
    uint16 effect_type;  // 0=Normal, 1=DayNight, 2=LightContainer
    Transform transform;   // Position, rotation, scale
    uint16 parent;       // Parent part index
};

3.6 IFO Zone Object Files (.ifo)

Object Type Enumeration:

enum BlockType {
    DeprecatedMapInfo = 0,
    DecoObject = 1,
    Npc = 2,
    CnstObject = 3,
    SoundObject = 4,
    EffectObject = 5,
    AnimatedObject = 6,
    DeprecatedWater = 7,
    MonsterSpawn = 8,
    WaterPlanes = 9,
    Warp = 10,
    CollisionObject = 11,
    EventObject = 12,
};

Object Placement Data:

struct IfoObject {
    uint8  name_len;       // Name length
    char   name[name_len]; // Object name
    uint16 warp_id;        // Warp ID
    uint16 event_id;       // Event ID
    uint32 object_type;    // Object type enum
    uint32 object_id;      // Object ID
    uint32 minimap_x;     // Minimap X position
    uint32 minimap_y;     // Minimap Y position
    float  rotation[4];    // X, Y, Z, W (quaternion)
    float  position[3];    // X, Y, Z
    float  scale[3];       // X, Y, Z
};

Minimap Position and ID:

Used for minimap display and object identification.

Warp and Event References:

  • Warp ID: Link to warp destination
  • Event ID: Link to event script

Spawn Point Definitions:

struct MonsterSpawnPoint {
    IfoObject object;          // Spawn position
    char     spawn_name[];     // Spawn name
    uint32   basic_count;      // Basic spawn count
    BasicSpawn basic_spawns[basic_count];
    uint32   tactic_count;     // Tactic spawn count
    TacticSpawn tactic_spawns[tactic_count];
    uint32   interval;        // Spawn interval (seconds)
    uint32   limit_count;     // Max monsters
    uint32   range;           // Spawn range
    uint32   tactic_points;   // Tactic points
};

struct BasicSpawn {
    char   monster_name[];
    uint32 monster_id;
    uint32 count;
};

Object-Specific Properties:

NPC:

struct IfoNpc {
    IfoObject object;
    uint32 ai_id;               // AI behavior ID
    char   quest_file_name[];   // Quest file
};

Effect Object:

struct IfoEffect {
    IfoObject object;
    char   effect_path[];       // Effect file path
};

Sound Object:

struct IfoSound {
    IfoObject object;
    char   sound_path[];        // Sound file path
    uint32 range;              // Sound range
    uint32 interval;           // Play interval (seconds)
};

Monster Spawn Configuration:

See MonsterSpawnPoint above.

NPC and Character Placement:

See IfoNpc structure above.

Animated Object Definitions:

Objects with animation references. Uses standard IfoObject structure.

Collision Object Properties:

Objects that participate in physics collision.

Deco and CNST Object Types:

  • Deco: Decorative objects (no collision)
  • Cnst: Construction objects (with collision)

Effect and Sound Object Types:

See IfoEffect and IfoSound structures above.

3.7 HIM Heightmap Files (.him)

File Header and Magic Number:

No magic string. Direct data layout.

Offset  Type    Description
0x00    u32      Width
0x04    u32      Height
0x08    u32[2]   Unknown (8 bytes)
0x10    f32[]    Height data (width × height)

Heightmap Grid Structure:

2D grid of floating-point height values.

Height Data Encoding:

32-bit float per grid cell.

Grid Size and Resolution:

Width and height in grid cells.

Coordinate Mapping:

Grid coordinates map directly to world coordinates (with scaling).

Heightmap Scaling Factors:

Height values are in centimeters. Scale by 0.01 for meters.

3.8 TIL Tile Index Files (.til)

Tile Index Structure:

Offset  Type    Description
0x00    u32      Width
0x04    u32      Height
0x08    Tile[]   Tile data (width × height)

Tile Entry:

Offset  Type    Description
0x00    u8[3]    Unknown (3 bytes)
0x03    u32      Tile index

Texture Mapping:

Tile indices reference textures from ZON file’s Textures block.

Tile Coordinate System:

2D grid matching HIM heightmap resolution.

Tile Size and Resolution:

Each tile covers a fixed area of terrain.

Texture Atlas Organization:

Textures are individual files, not a single atlas.

Tile-to-Texture Mapping Algorithms:

def get_tile_texture_index(til_file, zon_file, x, y):
    tile_index = til_file.get_clamped(x, y)
    texture_path = zon_file.tile_textures[tile_index]
    return texture_path

3.9 CHR Character Files (.chr)

Character Definition Structure:

struct ChrFile {
    uint16 skeleton_count;
    char   skeleton_files[skeleton_count][];

    uint16 motion_count;
    char   motion_files[motion_count][];

    uint16 effect_count;
    char   effect_files[effect_count][];

    uint16 character_count;
    CharacterData characters[character_count];
};

NPC Data Organization:

Characters are indexed by NPC ID.

Skeleton, Motion, and Effect References:

  • Skeleton: ZMD file index
  • Motion: ZMO file index (per action)
  • Effect: Effect file index (per action)

Character Type Classification:

NPCs, monsters, and other entities.

Asset Path Resolution:

Paths are resolved through VFS.

Character-Specific Properties:

struct NpcModelData {
    uint16 skeleton_index;              // Skeleton file index
    char   name[];                    // NPC name
    uint16 mesh_count;                // Number of mesh parts
    uint16 model_ids[mesh_count];     // ZSC model IDs
    uint16 motion_count;              // Number of motions
    MotionRef motions[motion_count];    // (motion_id, file_index)
    uint16 effect_count;              // Number of effects
    EffectRef effects[effect_count];    // (motion_id, file_index)
};

struct MotionRef {
    uint16 motion_id;     // Action ID
    uint16 file_index;    // Motion file index
};

struct EffectRef {
    uint16 motion_id;     // Trigger motion ID
    uint16 file_index;    // Effect file index
};

6.3 Edge Cases and Format Variations

Version Differences and Compatibility:

  • ZMS v5/6: Vertex IDs, bone index mapping, scaling
  • ZMS v7/8: No vertex IDs, direct bone indices, no scaling
  • ZMD v2: Dummy bones have identity rotation
  • ZMD v3: Dummy bones have explicit rotation

Missing or Optional Data Handling:

  • Use default values for missing attributes
  • Skip empty arrays gracefully
  • Validate data bounds before access

Invalid or Corrupted File Detection:

  • Check magic strings
  • Validate version numbers
  • Verify data bounds
  • Check for read errors

Format Extensions and Customizations:

  • EZMO/3ZMO extended animation format
  • Custom collision shapes in ZSC
  • Additional property IDs in ZSC

7. Quick Reference

7.1 File Format Summary Table

FormatMagicVersionsKey FeaturesComplexity
ZMSZMS000X5-8Mesh, skinning, materialsHigh
ZMDZMD000X2-3Skeleton, dummy bonesMedium
ZMOZMO00022Animation, frame eventsMedium
ZONNoneZone, tiles, eventsHigh
ZSCNoneObjects, materials, effectsHigh
IFONoneObject placement, spawnsHigh
HIMNoneHeightmapLow
TILNoneTile indicesLow
CHRNoneCharacter definitionsMedium

7.2 Key Constants and Conversions

Scaling Factors:

MESH_SCALE = 100.0      # ZMS v5/6 position scaling
CM_TO_M = 0.01         # Centimeters to meters

Binary Data Type Sizes:

TypeSize
u81 byte
u162 bytes
u324 bytes
f324 bytes
Vec312 bytes
Quat416 bytes

7.4 Troubleshooting Guide

Common Import Errors:

ErrorCauseSolution
Invalid magicWrong file typeCheck file extension
Version mismatchUnsupported versionUpdate parser
Bone index out of rangeCorrupted dataValidate indices
Missing vertex dataFormat flags wrongCheck flags

Asset Loading Workflow:

    participant App
    participant VFS
    participant ZON
    participant ZMS
    participant ZMD
    participant ZMO

    App->>VFS: Load Zone
    VFS->>ZON: Read ZON file
    ZON-->>VFS: Zone data

    App->>VFS: Load Mesh
    VFS->>ZMS: Read ZMS file
    ZMS-->>VFS: Mesh data

    App->>VFS: Load Skeleton
    VFS->>ZMD: Read ZMD file
    ZMD-->>VFS: Skeleton data

    App->>VFS: Load Animation
    VFS->>ZMO: Read ZMO file
    ZMO-->>VFS: Animation data

Bone Hierarchy Structure:

    Root[Bone 0: Root] --> Bone1[Bone 1]
    Root --> Bone2[Bone 2]
    Bone1 --> Bone3[Bone 3]
    Bone1 --> Bone4[Bone 4]
    Bone2 --> Bone5[Bone 5]

Animation Interpolation Pipeline:

Frame1[Frame 1] -->|t=0.0| Interp[Interpolation]
Frame2[Frame 2] -->|t=1.0| Interp
Interp -->|Linear/Slerp| Result[Animated Pose]
#### Zone Composition System:
ZON[ZON File] --> Tiles[Tiles Block]
ZON --> Textures[Textures Block]
ZON --> Events[EventPositions Block]

Tiles --> HIM[HIM Heightmap]
Tiles --> TIL[TIL Tile Index]

Textures --> TextureFiles[.DDS/.TGA Files]

Events --> Spawns[Spawn Points]

“`

8.3 Glossary

Technical Terminology:

  • VFS: Virtual Filesystem – Abstracted file access layer
  • ECS: Entity Component System – Architecture pattern
  • WGSL: WebGPU Shading Language – Shader language
  • Skinned Mesh: Mesh with bone-based vertex deformation
  • Inverse Bind Matrix: Matrix transforming from bind pose to bone space

Rose Online-Specific Terms:

  • ZMS: Z-Model-Structure – Mesh file format
  • ZMD: Z-Model-Definition – Skeleton file format
  • ZMO: Z-Motion-Object – Animation file format
  • ZON: Z-One – Zone file format
  • ZSC: Z-Structure-Composition – Object composition format
  • IFO: Information File Object – Zone object placement format
  • HIM: Height Map – Terrain elevation format
  • TIL: Tile – Terrain tile index format
  • CHR: Character – Character definition format

Blender-Specific Terms:

  • Armature: Skeleton/bone hierarchy
  • Action: Animation data
  • Vertex Group: Bone weight assignment
  • Material: Surface properties
  • Mesh: Geometry data
  • NLA: Non-Linear Animation – Animation layering system