working demo part 1
This commit is contained in:
194
cursebreaker-parser/examples/find_playsfx.rs
Normal file
194
cursebreaker-parser/examples/find_playsfx.rs
Normal file
@@ -0,0 +1,194 @@
|
||||
//! Demo: Find all PlaySFX components and their locations in VR_Horror_YouCantRun
|
||||
//!
|
||||
//! This example demonstrates:
|
||||
//! 1. Parsing a real Unity project
|
||||
//! 2. Finding custom MonoBehaviour components (PlaySFX)
|
||||
//! 3. Querying the ECS world for components
|
||||
//! 4. Accessing Transform data for component locations
|
||||
|
||||
use cursebreaker_parser::{UnityComponent, UnityFile};
|
||||
use std::path::Path;
|
||||
|
||||
/// PlaySFX component from VR_Horror_YouCantRun
|
||||
///
|
||||
/// C# definition:
|
||||
/// ```csharp
|
||||
/// public class PlaySFX : MonoBehaviour
|
||||
/// {
|
||||
/// [SerializeField] float volume;
|
||||
/// [SerializeField] float startTime;
|
||||
/// [SerializeField] float endTime;
|
||||
/// [SerializeField] bool isLoop;
|
||||
/// }
|
||||
/// ```
|
||||
#[derive(Debug, Clone, UnityComponent)]
|
||||
#[unity_class("PlaySFX")]
|
||||
pub struct PlaySFX {
|
||||
#[unity_field("volume")]
|
||||
pub volume: f64,
|
||||
|
||||
#[unity_field("startTime")]
|
||||
pub start_time: f64,
|
||||
|
||||
#[unity_field("endTime")]
|
||||
pub end_time: f64,
|
||||
|
||||
#[unity_field("isLoop")]
|
||||
pub is_loop: bool,
|
||||
}
|
||||
|
||||
fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
println!("🎮 VR Horror - PlaySFX Component Finder");
|
||||
println!("{}", "=".repeat(70));
|
||||
println!();
|
||||
|
||||
let project_path = Path::new("test_data/VR_Horror_YouCantRun");
|
||||
|
||||
// Check if project exists
|
||||
if !project_path.exists() {
|
||||
eprintln!("❌ Error: VR_Horror_YouCantRun project not found at {}", project_path.display());
|
||||
eprintln!(" Run the integration tests first to download it:");
|
||||
eprintln!(" cargo test test_vr_horror_project");
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
println!("📁 Scanning project: {}", project_path.display());
|
||||
println!();
|
||||
|
||||
// Find all Unity scene files
|
||||
let scene_files = find_unity_files(project_path, "unity");
|
||||
|
||||
println!("📄 Found {} scene file(s)", scene_files.len());
|
||||
println!();
|
||||
|
||||
let mut total_playsfx = 0;
|
||||
|
||||
// Parse each scene
|
||||
for scene_path in scene_files {
|
||||
println!("🔍 Parsing: {}", scene_path.file_name().unwrap().to_string_lossy());
|
||||
|
||||
match UnityFile::from_path(&scene_path) {
|
||||
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>();
|
||||
|
||||
// Find all entities that have PlaySFX
|
||||
let mut found_count = 0;
|
||||
let mut found_entities = Vec::new();
|
||||
|
||||
// Iterate through all entities in the entity_map
|
||||
for entity in scene.entity_map.values() {
|
||||
if let Some(playsfx) = playsfx_view.get(*entity) {
|
||||
found_entities.push((*entity, playsfx.clone()));
|
||||
found_count += 1;
|
||||
}
|
||||
}
|
||||
|
||||
if found_count > 0 {
|
||||
println!(" ✅ Found {} PlaySFX component(s)", found_count);
|
||||
total_playsfx += found_count;
|
||||
|
||||
// Process each found PlaySFX component
|
||||
for (entity, playsfx) in found_entities {
|
||||
let transform = transform_view.get(entity);
|
||||
let rect_transform = rect_transform_view.get(entity);
|
||||
let game_object = gameobject_view.get(entity);
|
||||
|
||||
let name = game_object
|
||||
.and_then(|go| go.name())
|
||||
.unwrap_or("(unnamed)");
|
||||
|
||||
println!();
|
||||
println!(" 🔊 PlaySFX on GameObject: \"{}\"", name);
|
||||
println!(" Entity: {:?}", entity);
|
||||
println!(" Properties:");
|
||||
println!(" • volume: {}", playsfx.volume);
|
||||
println!(" • startTime: {}", playsfx.start_time);
|
||||
println!(" • endTime: {}", playsfx.end_time);
|
||||
println!(" • isLoop: {}", playsfx.is_loop);
|
||||
|
||||
// Print position if available
|
||||
if let Some(transform) = transform {
|
||||
if let Some(pos) = transform.local_position() {
|
||||
println!(" Transform:");
|
||||
println!(" • Position: ({:.2}, {:.2}, {:.2})",
|
||||
pos.x, pos.y, pos.z);
|
||||
}
|
||||
if let Some(rot) = transform.local_rotation() {
|
||||
println!(" • Rotation: ({:.2}, {:.2}, {:.2}, {:.2})",
|
||||
rot.x, rot.y, rot.z, rot.w);
|
||||
}
|
||||
if let Some(scale) = transform.local_scale() {
|
||||
println!(" • Scale: ({:.2}, {:.2}, {:.2})",
|
||||
scale.x, scale.y, scale.z);
|
||||
}
|
||||
} else if let Some(rect_transform) = rect_transform {
|
||||
let transform = rect_transform.transform();
|
||||
if let Some(pos) = transform.local_position() {
|
||||
println!(" RectTransform (UI):");
|
||||
println!(" • Position: ({:.2}, {:.2}, {:.2})",
|
||||
pos.x, pos.y, pos.z);
|
||||
}
|
||||
} else {
|
||||
println!(" ⚠️ No Transform found");
|
||||
}
|
||||
}
|
||||
} else {
|
||||
println!(" ⊘ No PlaySFX components found");
|
||||
}
|
||||
|
||||
println!();
|
||||
}
|
||||
Ok(_) => {
|
||||
println!(" ⊘ Skipped (not a scene file)");
|
||||
println!();
|
||||
}
|
||||
Err(e) => {
|
||||
println!(" ❌ Parse error: {}", e);
|
||||
println!();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
println!("{}", "=".repeat(70));
|
||||
println!("📊 Summary:");
|
||||
println!(" Total PlaySFX components found: {}", total_playsfx);
|
||||
println!("{}", "=".repeat(70));
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Find all Unity files with a specific extension in a directory
|
||||
fn find_unity_files(dir: &Path, extension: &str) -> Vec<std::path::PathBuf> {
|
||||
let mut files = Vec::new();
|
||||
|
||||
fn visit_dir(dir: &Path, extension: &str, files: &mut Vec<std::path::PathBuf>) {
|
||||
if let Ok(entries) = std::fs::read_dir(dir) {
|
||||
for entry in entries.flatten() {
|
||||
let path = entry.path();
|
||||
|
||||
// Skip Library, Temp, Builds, and .git directories
|
||||
if let Some(name) = path.file_name().and_then(|n| n.to_str()) {
|
||||
if name == "Library" || name == "Temp" || name == "Builds" || name == ".git" {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if path.is_dir() {
|
||||
visit_dir(&path, extension, files);
|
||||
} else if let Some(ext) = path.extension().and_then(|e| e.to_str()) {
|
||||
if ext == extension {
|
||||
files.push(path);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
visit_dir(dir, extension, &mut files);
|
||||
files.sort();
|
||||
files
|
||||
}
|
||||
@@ -25,13 +25,20 @@ use std::collections::HashMap;
|
||||
pub fn build_world_from_documents(
|
||||
documents: Vec<RawDocument>,
|
||||
) -> Result<(World, HashMap<FileID, Entity>)> {
|
||||
// Create World with registered component types
|
||||
let mut world = World::builder()
|
||||
// Create World builder with registered component types
|
||||
let mut builder = World::builder();
|
||||
builder
|
||||
.register::<GameObject>()
|
||||
.register::<Transform>()
|
||||
.register::<RectTransform>()
|
||||
.register::<PrefabInstanceComponent>()
|
||||
.build();
|
||||
.register::<PrefabInstanceComponent>();
|
||||
|
||||
// Register all custom components from inventory
|
||||
for reg in inventory::iter::<crate::types::ComponentRegistration> {
|
||||
(reg.register)(&mut builder);
|
||||
}
|
||||
|
||||
let mut world = builder.build();
|
||||
|
||||
let linking_ctx = RefCell::new(LinkingContext::new());
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
use crate::types::*;
|
||||
use serde_yaml::{Mapping, Value};
|
||||
use sparsey::world::WorldBuilder;
|
||||
use sparsey::Entity;
|
||||
use std::cell::RefCell;
|
||||
use std::collections::HashMap;
|
||||
@@ -118,6 +119,8 @@ pub struct ComponentRegistration {
|
||||
pub class_name: &'static str,
|
||||
/// Parser function that parses and inserts the component into the ECS world
|
||||
pub parse_and_insert: fn(&Mapping, &ComponentContext, &mut sparsey::World, Entity) -> bool,
|
||||
/// Function to register this component type with a WorldBuilder
|
||||
pub register: for<'a> fn(&'a mut WorldBuilder) -> &'a mut WorldBuilder,
|
||||
}
|
||||
|
||||
// Collect all component registrations submitted via the macro
|
||||
|
||||
Reference in New Issue
Block a user