2026-01-12 03:02:45 +00:00
2026-01-12 03:02:45 +00:00
2026-01-11 02:46:49 +00:00
2026-01-12 03:02:45 +00:00
2026-01-11 03:03:39 +00:00
2026-01-03 14:04:12 +00:00
2026-01-02 09:28:22 +00:00
2026-01-11 02:46:49 +00:00
2026-01-11 02:46:49 +00:00
2026-01-12 03:02:45 +00:00
2026-01-11 13:48:15 +00:00
2026-01-05 12:23:09 +00:00
2026-01-11 02:46:49 +00:00
2026-01-11 13:48:15 +00:00

Cursebreaker Unity Parser

A high-performance Rust library for parsing Unity project files (.unity scenes, .prefab prefabs, and .asset files) with automatic MonoBehaviour component discovery and ECS integration.

Rust License

⚠️ Work in Progress: This library is under active development. APIs may change.

Features

Core Parsing

  • Multi-format support: Parse .unity scenes, .prefab prefabs, and .asset files
  • ECS integration: Automatically builds Sparsey ECS worlds from scenes
  • Type-safe: Strong typing for Unity primitives (Vector3, Quaternion, Color, etc.)
  • Fast: Efficient YAML parsing with minimal allocations

Component System

  • Derive macro: #[derive(UnityComponent)] for automatic component parsing
  • Auto-registration: Components register themselves via inventory
  • GUID resolution: Automatically resolves MonoBehaviour script GUIDs to class names
  • Prefab resolution: Resolves prefab GUIDs for nested prefab references
  • Type filtering: Selectively parse only the components you need

Advanced Features

  • Prefab instantiation: Clone and modify prefab instances (basic support)
  • Reference resolution: FileID → Entity mapping
  • Regex filtering: Parse only files matching specific patterns
  • Transform hierarchies: Parent-child relationships preserved
  • Memory efficient: 128-bit GUIDs stored as u128 (16 bytes vs ~56 bytes for String)

Installation

Add to your Cargo.toml:

[dependencies]
unity_parser = { path = "unity-parser" }
sparsey = "0.13"  # For ECS queries

Quick Start

Parse a Unity Scene

use unity_parser::UnityFile;

fn main() -> Result<(), Box<dyn std::error::Error>> {
    let file = UnityFile::from_path("Scene.unity")?;

    match file {
        UnityFile::Scene(scene) => {
            println!("Scene with {} entities", scene.entity_map.len());

            // Query transforms
            let transforms = scene.world.borrow::<unity_parser::Transform>();
            for (file_id, entity) in &scene.entity_map {
                if let Some(transform) = transforms.get(*entity) {
                    println!("Entity {} at {:?}", file_id, transform.local_position());
                }
            }
        }
        UnityFile::Prefab(prefab) => {
            println!("Prefab with {} documents", prefab.documents.len());
        }
        UnityFile::Asset(asset) => {
            println!("Asset with {} documents", asset.documents.len());
        }
    }

    Ok(())
}

Parse a Prefab

use unity_parser::UnityFile;

fn main() -> Result<(), Box<dyn std::error::Error>> {
    let file = UnityFile::from_path("Player.prefab")?;

    if let UnityFile::Prefab(prefab) = file {
        // Find all GameObjects
        let game_objects = prefab.get_documents_by_class("GameObject");
        for doc in game_objects {
            if let Some(mapping) = doc.as_mapping() {
                if let Some(name) = mapping.get("m_Name").and_then(|v| v.as_str()) {
                    println!("GameObject: {}", name);
                }
            }
        }

        // Find documents by type ID
        let transforms = prefab.get_documents_by_type(4); // Transform = type 4
        println!("Found {} Transforms", transforms.len());
    }

    Ok(())
}

Define Custom Components

⚠️ Note: The derive macro currently has namespace issues and may not compile. Manual implementation is recommended until fixed.

use unity_parser::{UnityComponent, ComponentContext};
use serde_yaml::Mapping;

#[derive(Debug, Clone)]
pub struct PlaySFX {
    pub volume: f64,
    pub start_time: f64,
    pub end_time: f64,
    pub is_loop: bool,
}

// Manual implementation (recommended until macro is fixed)
impl UnityComponent for PlaySFX {
    fn parse(yaml: &Mapping, _ctx: &ComponentContext) -> Option<Self> {
        Some(Self {
            volume: unity_parser::yaml_helpers::get_f64(yaml, "volume").unwrap_or(1.0),
            start_time: unity_parser::yaml_helpers::get_f64(yaml, "startTime").unwrap_or(0.0),
            end_time: unity_parser::yaml_helpers::get_f64(yaml, "endTime").unwrap_or(0.0),
            is_loop: unity_parser::yaml_helpers::get_bool(yaml, "isLoop").unwrap_or(false),
        })
    }
}

GUID Resolution

The parser automatically resolves Unity MonoBehaviour GUIDs to class names:

Unity Scene File                    Rust Code
─────────────────                   ─────────
MonoBehaviour:                      Custom component
  m_Script:                         in ECS World
    guid: 091c537...  ──────────>
  volume: 1.0
  isLoop: 0

How It Works

  1. Scan: Parser scans Unity project's Assets/ for *.cs.meta files
  2. Build Map: Extracts GUIDs from .meta files
  3. Extract Class: Parses .cs files to get class Name : MonoBehaviour
  4. Resolve: Maps GUID → Class Name → Registered Component
  5. Parse: Automatically parses MonoBehaviour YAML into components

The GUID resolver builds automatically when parsing scenes if a Unity project root is detected.

Type Filtering

Parse only specific Unity types and MonoBehaviours for better performance:

use unity_parser::{TypeFilter, parse_unity_file_filtered};
use std::collections::HashSet;

// Parse only Transforms and GameObjects
let mut types = HashSet::new();
types.insert("Transform".to_string());
types.insert("GameObject".to_string());
let filter = TypeFilter::with_unity_types(types);

let file = parse_unity_file_filtered(
    Path::new("Scene.unity"),
    None,  // No regex filter
    Some(&filter)
)?;

Regex Path Filtering

Parse only files matching specific patterns:

use regex::Regex;
use unity_parser::parse_unity_file_filtered;

// Only parse production scenes
let filter = Regex::new(r"Assets/Scenes/Production/")?;
let scene = parse_unity_file_filtered(
    Path::new("Assets/Scenes/Production/Level1.unity"),
    Some(&filter),
    None
)?;

Supported Unity Types

Built-in Components

  • GameObject
  • Transform
  • RectTransform
  • PrefabInstance

Value Types

  • Vector2, Vector3
  • Quaternion
  • Color
  • FileID, GUID
  • ExternalRef, FileRef

Custom Components

  • Any MonoBehaviour via manual UnityComponent implementation
  • ⚠️ #[derive(UnityComponent)] macro (has namespace bugs, not recommended)

Architecture

Component Flow

Unity Scene File
      ↓
Raw YAML Documents
      ↓
┌─────────────────────┐
│  GUID Resolution    │  ← .meta files + .cs files
│  (MonoBehaviour)    │     (Script GUID → Class Name)
└─────────────────────┘
      ↓
┌─────────────────────┐
│  Prefab GUID Res.   │  ← .prefab.meta files
│  (Nested Prefabs)   │     (Prefab GUID → Prefab Path)
└─────────────────────┘
      ↓
┌─────────────────────┐
│ Component Registry  │  ← UnityComponent trait impls
│  (inventory)        │
└─────────────────────┘
      ↓
┌─────────────────────┐
│  ECS World          │  ← Sparsey entities & components
│  (Transform, etc)   │
└─────────────────────┘

Memory Efficiency

GUID Storage:

  • Old approach: String (24 bytes stack + 32 bytes heap = 56 bytes)
  • Current: u128 (16 bytes on stack)
  • 3.5x memory reduction for GUID storage

GUID Comparison:

  • Old: O(n) string comparison (32 characters)
  • New: O(1) integer comparison
  • Significant speedup for HashMap lookups

Running Examples

# Parse basic Unity file
cargo run --example basic_parsing

# Custom component parsing (requires Unity project)
cargo run --example custom_component

# ECS integration showcase
cargo run --example ecs_integration

# Find PlaySFX components (requires CBAssets project)
cargo run --example find_playsfx

Testing

# Unit tests
cargo test --lib

# Integration tests
cargo test --test integration_tests

# All tests
cargo test

Roadmap

Completed

  • Phase 1: GUID Resolution (Script GUID → Class Name)
  • Phase 2: MonoBehaviour Parser
  • Phase 3: Prefab GUID Resolution
  • Type filtering for selective parsing
  • Regex path filtering
  • Basic prefab instantiation

In Progress / Needs Work

  • 🔧 Refactor project module for new architecture
  • 🔧 Update disabled example/test files
  • 🔧 Fix example code YAML access patterns

Future Enhancements

  • Full prefab modification system
  • Persistent GUID cache for instant loading
  • Watch mode for live Unity project monitoring
  • More built-in Unity component types
  • Better error messages with line numbers
  • Parallel processing support
  • Cross-platform path handling improvements

Contributing

Contributions welcome! Areas needing help:

  • Documentation: API docs, more examples, tutorials
  • Testing: Integration tests with real Unity projects
  • Performance: Optimize YAML parsing, parallel processing

Acknowledgments

  • Unity Technologies: For the YAML-based file format
  • Sparsey: ECS library for component storage
  • serde_yaml: YAML parsing foundation
  • inventory: Compile-time component registration
Description
No description provided
Readme 296 MiB
Languages
Rust 94.6%
JavaScript 4.2%
CSS 0.7%
HTML 0.5%