project restructure
This commit is contained in:
@@ -11,7 +11,8 @@
|
||||
"Bash(cargo check:*)",
|
||||
"Bash(ls:*)",
|
||||
"Bash(find:*)",
|
||||
"Bash(grep:*)"
|
||||
"Bash(grep:*)",
|
||||
"Bash(wc:*)"
|
||||
],
|
||||
"additionalDirectories": [
|
||||
"/home/connor/repos/CBAssets/"
|
||||
|
||||
56
Cargo.lock
generated
56
Cargo.lock
generated
@@ -23,34 +23,6 @@ version = "0.1.13"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "41e67cd8309bbd06cd603a9e693a784ac2e5d1e955f11286e355089fcab3047c"
|
||||
|
||||
[[package]]
|
||||
name = "cursebreaker-parser"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"cursebreaker-parser-macros",
|
||||
"glam",
|
||||
"indexmap",
|
||||
"inventory",
|
||||
"lru",
|
||||
"once_cell",
|
||||
"pretty_assertions",
|
||||
"regex",
|
||||
"serde",
|
||||
"serde_yaml",
|
||||
"sparsey",
|
||||
"thiserror",
|
||||
"walkdir",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cursebreaker-parser-macros"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "diff"
|
||||
version = "0.1.13"
|
||||
@@ -318,6 +290,34 @@ version = "1.0.22"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9312f7c4f6ff9069b165498234ce8be658059c6728633667c526e27dc2cf1df5"
|
||||
|
||||
[[package]]
|
||||
name = "unity-parser"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"glam",
|
||||
"indexmap",
|
||||
"inventory",
|
||||
"lru",
|
||||
"once_cell",
|
||||
"pretty_assertions",
|
||||
"regex",
|
||||
"serde",
|
||||
"serde_yaml",
|
||||
"sparsey",
|
||||
"thiserror",
|
||||
"unity-parser-macros",
|
||||
"walkdir",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "unity-parser-macros"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "unsafe-libyaml"
|
||||
version = "0.2.11"
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
[workspace]
|
||||
members = ["cursebreaker-parser", "cursebreaker-parser-macros"]
|
||||
members = ["unity-parser", "unity-parser-macros"]
|
||||
resolver = "2"
|
||||
|
||||
[workspace.package]
|
||||
@@ -7,4 +7,4 @@ version = "0.1.0"
|
||||
edition = "2021"
|
||||
authors = ["Your Name <your.email@example.com>"]
|
||||
license = "MIT OR Apache-2.0"
|
||||
repository = "https://github.com/yourusername/cursebreaker-parser-rust"
|
||||
repository = "https://github.com/yourusername/unity-parser-rust"
|
||||
|
||||
24
README.md
24
README.md
@@ -1,4 +1,4 @@
|
||||
# Cursebreaker Parser
|
||||
# Unity Parser
|
||||
|
||||
A high-performance Rust library for parsing Unity project files (.unity scenes, .prefab prefabs, and .asset ScriptableObjects) with automatic MonoBehaviour component discovery and ECS integration.
|
||||
|
||||
@@ -32,7 +32,7 @@ Add to your `Cargo.toml`:
|
||||
|
||||
```toml
|
||||
[dependencies]
|
||||
cursebreaker-parser = "0.1"
|
||||
unity-parser = "0.1"
|
||||
sparsey = "0.13" # For ECS queries
|
||||
```
|
||||
|
||||
@@ -41,7 +41,7 @@ sparsey = "0.13" # For ECS queries
|
||||
### Parse a Unity Scene
|
||||
|
||||
```rust
|
||||
use cursebreaker_parser::UnityFile;
|
||||
use unity_parser::UnityFile;
|
||||
|
||||
fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
let file = UnityFile::from_path("Scene.unity")?;
|
||||
@@ -51,7 +51,7 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
println!("Scene with {} entities", scene.entity_map.len());
|
||||
|
||||
// Query transforms
|
||||
let transforms = scene.world.borrow::<cursebreaker_parser::Transform>();
|
||||
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());
|
||||
@@ -73,7 +73,7 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
### Define Custom Components
|
||||
|
||||
```rust
|
||||
use cursebreaker_parser::UnityComponent;
|
||||
use unity_parser::UnityComponent;
|
||||
|
||||
#[derive(Debug, Clone, UnityComponent)]
|
||||
#[unity_class("PlaySFX")]
|
||||
@@ -133,7 +133,7 @@ Parse only scenes matching specific patterns:
|
||||
|
||||
```rust
|
||||
use regex::Regex;
|
||||
use cursebreaker_parser::parse_unity_file_filtered;
|
||||
use unity_parser::parse_unity_file_filtered;
|
||||
|
||||
// Only parse production scenes
|
||||
let filter = Regex::new(r"Assets/Scenes/Production/")?;
|
||||
@@ -161,7 +161,7 @@ let filter = Regex::new(r"Level[1-5]\.unity$")?;
|
||||
Selectively parse components for better performance:
|
||||
|
||||
```rust
|
||||
use cursebreaker_parser::{TypeFilter, parse_with_types};
|
||||
use unity_parser::{TypeFilter, parse_with_types};
|
||||
|
||||
// Parse only transforms and custom components
|
||||
let filter = TypeFilter::parse_with_types(&["Transform", "PlaySFX"]);
|
||||
@@ -232,7 +232,7 @@ Raw YAML Documents
|
||||
### Find All Components of a Type
|
||||
|
||||
```rust
|
||||
use cursebreaker_parser::UnityFile;
|
||||
use unity_parser::UnityFile;
|
||||
|
||||
let scene = UnityFile::from_path("Scene.unity")?;
|
||||
|
||||
@@ -378,7 +378,7 @@ Benchmarks on VR Horror project (21 scenes, 77 C# scripts):
|
||||
## Project Structure
|
||||
|
||||
```
|
||||
cursebreaker-parser/
|
||||
unity-parser/
|
||||
├── src/
|
||||
│ ├── ecs/ # ECS world building
|
||||
│ ├── model/ # UnityFile, Scene, Prefab models
|
||||
@@ -387,11 +387,15 @@ cursebreaker-parser/
|
||||
│ │ ├── meta.rs # .meta file parsing
|
||||
│ │ └── yaml.rs # YAML document splitting
|
||||
│ ├── types/ # Unity types and components
|
||||
│ │ ├── unity_types/ # Unity-specific types
|
||||
│ │ │ ├── game_object.rs
|
||||
│ │ │ ├── prefab_instance.rs
|
||||
│ │ │ └── transform.rs
|
||||
│ │ ├── guid.rs # 128-bit GUID type
|
||||
│ │ ├── component.rs # Component trait system
|
||||
│ │ └── ...
|
||||
│ └── lib.rs
|
||||
├── cursebreaker-parser-macros/ # Derive macro crate
|
||||
├── unity-parser-macros/ # Derive macro crate
|
||||
├── examples/ # Usage examples
|
||||
├── tests/ # Integration tests
|
||||
└── test_data/ # Test Unity projects
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
[package]
|
||||
name = "cursebreaker-parser-macros"
|
||||
name = "unity-parser-macros"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
authors = ["Your Name <your.email@example.com>"]
|
||||
license = "MIT OR Apache-2.0"
|
||||
description = "Procedural macros for cursebreaker-parser"
|
||||
repository = "https://github.com/yourusername/cursebreaker-parser-rust"
|
||||
description = "Procedural macros for unity-parser"
|
||||
repository = "https://github.com/yourusername/unity-parser-rust"
|
||||
|
||||
[lib]
|
||||
proc-macro = true
|
||||
@@ -1,4 +1,4 @@
|
||||
//! Procedural macros for cursebreaker-parser
|
||||
//! Procedural macros for unity-parser
|
||||
//!
|
||||
//! This crate provides the `#[derive(UnityComponent)]` macro for automatically
|
||||
//! generating Unity component parsing code.
|
||||
@@ -1,17 +1,17 @@
|
||||
[package]
|
||||
name = "cursebreaker-parser"
|
||||
name = "unity-parser"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
authors = ["Your Name <your.email@example.com>"]
|
||||
license = "MIT OR Apache-2.0"
|
||||
description = "A high-performance Rust library for parsing Unity project files (.unity, .prefab, .asset)"
|
||||
repository = "https://github.com/yourusername/cursebreaker-parser-rust"
|
||||
repository = "https://github.com/yourusername/unity-parser-rust"
|
||||
keywords = ["unity", "parser", "yaml", "gamedev"]
|
||||
categories = ["parser-implementations", "game-development"]
|
||||
rust-version = "1.70"
|
||||
|
||||
[lib]
|
||||
name = "cursebreaker_parser"
|
||||
name = "unity_parser"
|
||||
path = "src/lib.rs"
|
||||
|
||||
[dependencies]
|
||||
@@ -47,7 +47,7 @@ once_cell = "1.19"
|
||||
inventory = "0.3"
|
||||
|
||||
# Procedural macro for derive(UnityComponent)
|
||||
cursebreaker-parser-macros = { path = "../cursebreaker-parser-macros" }
|
||||
unity-parser-macros = { path = "../unity-parser-macros" }
|
||||
|
||||
[dev-dependencies]
|
||||
# Testing utilities
|
||||
@@ -1,4 +1,4 @@
|
||||
use cursebreaker_parser::UnityFile;
|
||||
use unity_parser::UnityFile;
|
||||
use std::path::Path;
|
||||
|
||||
fn main() {
|
||||
@@ -1,7 +1,7 @@
|
||||
//! Example demonstrating how to define custom Unity MonoBehaviour components
|
||||
//! using the #[derive(UnityComponent)] macro.
|
||||
|
||||
use cursebreaker_parser::{yaml_helpers, ComponentContext, UnityComponent};
|
||||
use unity_parser::{yaml_helpers, ComponentContext, UnityComponent};
|
||||
|
||||
/// Custom Unity MonoBehaviour component for playing sound effects
|
||||
///
|
||||
@@ -71,7 +71,7 @@ isLoop: 1
|
||||
let mapping = yaml.as_mapping().unwrap();
|
||||
|
||||
// Create a dummy context
|
||||
use cursebreaker_parser::{ComponentContext, FileID};
|
||||
use unity_parser::{ComponentContext, FileID};
|
||||
let ctx = ComponentContext {
|
||||
type_id: 114,
|
||||
file_id: FileID::from_i64(12345),
|
||||
@@ -5,7 +5,7 @@
|
||||
//! 2. Using the parse_with_types! macro for selective parsing
|
||||
//! 3. Querying the ECS world for components
|
||||
|
||||
use cursebreaker_parser::{parse_with_types, ComponentContext, EcsInsertable, FileID, TypeFilter, UnityComponent};
|
||||
use unity_parser::{parse_with_types, ComponentContext, EcsInsertable, FileID, TypeFilter, UnityComponent};
|
||||
|
||||
/// Custom Unity MonoBehaviour component
|
||||
#[derive(Debug, Clone, UnityComponent)]
|
||||
@@ -6,7 +6,7 @@
|
||||
//! 3. Querying the ECS world for components
|
||||
//! 4. Accessing Transform data for component locations
|
||||
|
||||
use cursebreaker_parser::{UnityComponent, UnityFile};
|
||||
use unity_parser::{UnityComponent, UnityFile};
|
||||
use std::path::Path;
|
||||
|
||||
/// PlaySFX component from VR_Horror_YouCantRun
|
||||
@@ -71,9 +71,9 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
Ok(UnityFile::Scene(scene)) => {
|
||||
// Get views for all component types we need
|
||||
let playsfx_view = scene.world.borrow::<PlaySFX>();
|
||||
let transform_view = scene.world.borrow::<cursebreaker_parser::Transform>();
|
||||
let rect_transform_view = scene.world.borrow::<cursebreaker_parser::RectTransform>();
|
||||
let gameobject_view = scene.world.borrow::<cursebreaker_parser::GameObject>();
|
||||
let transform_view = scene.world.borrow::<unity_parser::Transform>();
|
||||
let rect_transform_view = scene.world.borrow::<unity_parser::RectTransform>();
|
||||
let gameobject_view = scene.world.borrow::<unity_parser::GameObject>();
|
||||
|
||||
// Find all entities that have PlaySFX
|
||||
let mut found_count = 0;
|
||||
@@ -10,7 +10,7 @@
|
||||
//! doesn't yet support resolving components from nested prefabs. This example
|
||||
//! parses the prefab files directly instead.
|
||||
|
||||
use cursebreaker_parser::{GuidResolver, UnityComponent, UnityFile};
|
||||
use unity_parser::{GuidResolver, UnityComponent, UnityFile};
|
||||
use std::fs::File;
|
||||
use std::io::Write;
|
||||
use std::path::Path;
|
||||
@@ -6,7 +6,7 @@
|
||||
//! 3. Extracting typeId and transform positions
|
||||
//! 4. Writing resource data to an output file
|
||||
|
||||
use cursebreaker_parser::{UnityComponent, UnityFile};
|
||||
use unity_parser::{UnityComponent, UnityFile};
|
||||
use std::fs::File;
|
||||
use std::io::Write;
|
||||
use std::path::Path;
|
||||
@@ -58,8 +58,8 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
|
||||
// Get views for component types we need
|
||||
let resource_view = scene.world.borrow::<InteractableResource>();
|
||||
let transform_view = scene.world.borrow::<cursebreaker_parser::Transform>();
|
||||
let gameobject_view = scene.world.borrow::<cursebreaker_parser::GameObject>();
|
||||
let transform_view = scene.world.borrow::<unity_parser::Transform>();
|
||||
let gameobject_view = scene.world.borrow::<unity_parser::GameObject>();
|
||||
|
||||
// Find all entities that have Interactable_Resource
|
||||
let mut found_resources = Vec::new();
|
||||
@@ -6,7 +6,7 @@
|
||||
//! # Example
|
||||
//!
|
||||
//! ```no_run
|
||||
//! use cursebreaker_parser::UnityFile;
|
||||
//! use unity_parser::UnityFile;
|
||||
//!
|
||||
//! let file = UnityFile::from_path("Scene.unity")?;
|
||||
//! match file {
|
||||
@@ -21,7 +21,7 @@
|
||||
//! println!("Asset with {} documents", asset.documents.len());
|
||||
//! }
|
||||
//! }
|
||||
//! # Ok::<(), cursebreaker_parser::Error>(())
|
||||
//! # Ok::<(), unity_parser::Error>(())
|
||||
//! ```
|
||||
|
||||
// Public modules
|
||||
@@ -53,4 +53,4 @@ pub use types::{
|
||||
};
|
||||
|
||||
// Re-export the derive macro from the macro crate
|
||||
pub use cursebreaker_parser_macros::UnityComponent;
|
||||
pub use unity_parser_macros::UnityComponent;
|
||||
@@ -5,28 +5,25 @@
|
||||
//! wrappers for GameObjects and Components.
|
||||
|
||||
mod component;
|
||||
mod game_object;
|
||||
mod guid;
|
||||
mod ids;
|
||||
mod prefab_instance;
|
||||
mod reference;
|
||||
mod transform;
|
||||
mod type_filter;
|
||||
mod type_registry;
|
||||
mod unity_types;
|
||||
mod values;
|
||||
|
||||
pub use component::{
|
||||
yaml_helpers, ComponentContext, ComponentRegistration, EcsInsertable, LinkCallback,
|
||||
LinkingContext, UnityComponent,
|
||||
};
|
||||
pub use game_object::GameObject;
|
||||
pub use guid::Guid;
|
||||
pub use ids::{FileID, LocalID};
|
||||
pub use prefab_instance::{
|
||||
PrefabInstance, PrefabInstanceComponent, PrefabModification, PrefabResolver,
|
||||
};
|
||||
pub use reference::UnityReference;
|
||||
pub use transform::{RectTransform, Transform};
|
||||
pub use type_filter::TypeFilter;
|
||||
pub use type_registry::{get_class_name, get_type_id};
|
||||
pub use unity_types::{
|
||||
GameObject, PrefabInstance, PrefabInstanceComponent, PrefabModification, PrefabResolver,
|
||||
RectTransform, Transform,
|
||||
};
|
||||
pub use values::{Color, ExternalRef, FileRef, Quaternion, Vector2, Vector3};
|
||||
11
unity-parser/src/types/unity_types/mod.rs
Normal file
11
unity-parser/src/types/unity_types/mod.rs
Normal file
@@ -0,0 +1,11 @@
|
||||
//! Unity-specific types (GameObjects, Transforms, PrefabInstances)
|
||||
|
||||
pub mod game_object;
|
||||
pub mod prefab_instance;
|
||||
pub mod transform;
|
||||
|
||||
pub use game_object::GameObject;
|
||||
pub use prefab_instance::{
|
||||
PrefabInstance, PrefabInstanceComponent, PrefabModification, PrefabResolver,
|
||||
};
|
||||
pub use transform::{RectTransform, Transform};
|
||||
@@ -1,6 +1,6 @@
|
||||
//! Integration tests for parsing real Unity projects
|
||||
|
||||
use cursebreaker_parser::{GuidResolver, UnityFile};
|
||||
use unity_parser::{GuidResolver, UnityFile};
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::process::Command;
|
||||
use std::time::Instant;
|
||||
@@ -449,7 +449,7 @@ fn test_guid_resolution() {
|
||||
}
|
||||
|
||||
// Test resolution by Guid type
|
||||
use cursebreaker_parser::Guid;
|
||||
use unity_parser::Guid;
|
||||
let playsfx_guid = Guid::from_hex(playsfx_guid_str).unwrap();
|
||||
match resolver.resolve_class_name(&playsfx_guid) {
|
||||
Some(class_name) => {
|
||||
@@ -478,7 +478,7 @@ fn test_guid_resolution() {
|
||||
/// Test parsing PlaySFX components from actual scene file
|
||||
#[test]
|
||||
fn test_playsfx_parsing() {
|
||||
use cursebreaker_parser::UnityComponent;
|
||||
use unity_parser::UnityComponent;
|
||||
|
||||
/// PlaySFX component from VR_Horror_YouCantRun
|
||||
#[derive(Debug, Clone, UnityComponent)]
|
||||
@@ -520,8 +520,8 @@ fn test_playsfx_parsing() {
|
||||
|
||||
println!("\n Parsing scene: {}", scene_path.display());
|
||||
|
||||
match cursebreaker_parser::UnityFile::from_path(&scene_path) {
|
||||
Ok(cursebreaker_parser::UnityFile::Scene(scene)) => {
|
||||
match unity_parser::UnityFile::from_path(&scene_path) {
|
||||
Ok(unity_parser::UnityFile::Scene(scene)) => {
|
||||
println!(" ✓ Scene parsed successfully");
|
||||
println!(" - Total entities: {}", scene.entity_map.len());
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
//! Tests for the #[derive(UnityComponent)] macro
|
||||
|
||||
use cursebreaker_parser::{ComponentContext, FileID, UnityComponent};
|
||||
use unity_parser::{ComponentContext, FileID, UnityComponent};
|
||||
|
||||
/// Test component matching the PlaySFX script from VR_Horror_YouCantRun
|
||||
#[derive(Debug, Clone, UnityComponent)]
|
||||
@@ -133,7 +133,7 @@ fn test_component_registration() {
|
||||
let mut found_play_sfx = false;
|
||||
let mut found_test_component = false;
|
||||
|
||||
for reg in inventory::iter::<cursebreaker_parser::ComponentRegistration> {
|
||||
for reg in inventory::iter::<unity_parser::ComponentRegistration> {
|
||||
if reg.class_name == "PlaySFX" {
|
||||
found_play_sfx = true;
|
||||
assert_eq!(reg.type_id, 114);
|
||||
@@ -177,7 +177,7 @@ isLoop: 0
|
||||
};
|
||||
|
||||
// Find the PlaySFX registration and call its parser
|
||||
for reg in inventory::iter::<cursebreaker_parser::ComponentRegistration> {
|
||||
for reg in inventory::iter::<unity_parser::ComponentRegistration> {
|
||||
if reg.class_name == "PlaySFX" {
|
||||
let result = (reg.parser)(mapping, &ctx);
|
||||
assert!(result.is_some(), "Registered parser failed to parse");
|
||||
Reference in New Issue
Block a user