Files
2026-01-05 12:23:09 +00:00

323 lines
9.6 KiB
Markdown

# 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](https://img.shields.io/badge/rust-1.70%2B-orange.svg)](https://www.rust-lang.org/)
[![License](https://img.shields.io/badge/license-MIT%20OR%20Apache--2.0-blue.svg)](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](https://github.com/LechintanTudor/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](https://github.com/dtolnay/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`:
```toml
[dependencies]
unity_parser = { path = "unity-parser" }
sparsey = "0.13" # For ECS queries
```
## Quick Start
### Parse a Unity Scene
```rust
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
```rust
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.
```rust
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:
```rust
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:
```rust
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
```bash
# 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
```bash
# 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