removed examples

This commit is contained in:
2026-01-04 14:17:32 +00:00
parent 31662cda3b
commit b3f09bb742
6 changed files with 0 additions and 882 deletions

View File

@@ -1,76 +0,0 @@
use unity_parser::UnityFile;
use std::path::Path;
fn main() {
// Parse a Unity prefab file
let prefab_path = Path::new("data/tests/unity-sampleproject/PiratePanic/Assets/PiratePanic/Prefabs/Menu/Battle/Hand/CardGrabber.prefab");
if !prefab_path.exists() {
eprintln!("Error: Unity sample project not found.");
eprintln!("Please ensure the git submodule is initialized:");
eprintln!(" git submodule update --init --recursive");
return;
}
// Parse the file
match UnityFile::from_path(prefab_path) {
Ok(file) => {
println!("Successfully parsed: {:?}", file.path().file_name().unwrap());
// Handle the different file types
match file {
UnityFile::Prefab(prefab) => {
println!("Found {} documents\n", prefab.documents.len());
// List all documents
for (i, doc) in prefab.documents.iter().enumerate() {
println!("Document {}: {} (Type ID: {}, File ID: {})",
i + 1,
doc.class_name,
doc.type_id,
doc.file_id
);
}
println!();
// Find all GameObjects
let game_objects = prefab.get_documents_by_class("GameObject");
println!("Found {} GameObjects:", game_objects.len());
for go in game_objects {
// doc.yaml already contains the inner content (after class wrapper)
if let Some(mapping) = go.as_mapping() {
if let Some(name) = mapping.get("m_Name").and_then(|v| v.as_str()) {
println!(" - {}", name);
}
}
}
println!();
// Find all Transforms
let transforms = prefab.get_documents_by_type(224); // RectTransform type ID
println!("Found {} RectTransforms", transforms.len());
// Look up a specific document by file ID
if let Some(first_doc) = prefab.documents.first() {
let file_id = first_doc.file_id;
if let Some(found) = prefab.get_document(file_id) {
println!("\nLooking up document by file ID {}:", file_id);
println!(" Class: {}", found.class_name);
}
}
}
UnityFile::Scene(scene) => {
println!("This is a scene file with {} entities", scene.entity_map.len());
}
UnityFile::Asset(asset) => {
println!("This is an asset file with {} documents", asset.documents.len());
}
}
}
Err(e) => {
eprintln!("Error parsing file: {}", e);
}
}
}

View File

@@ -1,101 +0,0 @@
//! Example demonstrating how to define custom Unity MonoBehaviour components
//! using the #[derive(UnityComponent)] macro.
use unity_parser::{yaml_helpers, ComponentContext, UnityComponent};
/// Custom Unity MonoBehaviour component for playing sound effects
///
/// This mirrors the C# PlaySFX MonoBehaviour:
/// ```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,
}
/// Another example - a custom damage component
#[derive(Debug, Clone, UnityComponent)]
#[unity_class("DamageDealer")]
pub struct DamageDealer {
#[unity_field("damageAmount")]
pub damage_amount: f64,
#[unity_field("damageType")]
pub damage_type: String,
#[unity_field("canCrit")]
pub can_crit: bool,
#[unity_field("critMultiplier")]
pub crit_multiplier: f64,
}
fn main() {
println!("Custom Unity Component Example");
println!("===============================\n");
println!("Defined custom components:");
println!(" - PlaySFX: volume, start_time, end_time, is_loop");
println!(" - DamageDealer: damage_amount, damage_type, can_crit, crit_multiplier\n");
println!("These components are automatically registered via the inventory crate.");
println!("When parsing Unity files, they will be recognized and parsed automatically.\n");
// Demonstrate parsing from YAML
let yaml_str = r#"
volume: 0.75
startTime: 1.5
endTime: 3.0
isLoop: 1
"#;
let yaml: serde_yaml::Value = serde_yaml::from_str(yaml_str).unwrap();
let mapping = yaml.as_mapping().unwrap();
// Create a dummy context
use unity_parser::{ComponentContext, FileID};
let ctx = ComponentContext {
type_id: 114,
file_id: FileID::from_i64(12345),
class_name: "PlaySFX",
entity: None,
linking_ctx: None,
yaml: mapping,
};
// Parse the component
if let Some(play_sfx) = PlaySFX::parse(mapping, &ctx) {
println!("Successfully parsed PlaySFX component:");
println!(" volume: {}", play_sfx.volume);
println!(" start_time: {}", play_sfx.start_time);
println!(" end_time: {}", play_sfx.end_time);
println!(" is_loop: {}", play_sfx.is_loop);
} else {
println!("Failed to parse PlaySFX component");
}
println!("\nTo use in your own code:");
println!(" 1. Define a struct matching your C# MonoBehaviour fields");
println!(" 2. Add #[derive(UnityComponent)] to the struct");
println!(" 3. Add #[unity_class(\"YourClassName\")] to specify the Unity class name");
println!(" 4. Add #[unity_field(\"fieldName\")] to each field");
println!(" 5. The component will be automatically registered and parsed!");
}

View File

@@ -1,146 +0,0 @@
//! Example demonstrating ECS integration and selective type parsing
//!
//! This example shows:
//! 1. Custom components being automatically inserted into the ECS world
//! 2. Using the parse_with_types! macro for selective parsing
//! 3. Querying the ECS world for components
use unity_parser::{parse_with_types, ComponentContext, EcsInsertable, FileID, TypeFilter, UnityComponent};
/// Custom Unity MonoBehaviour component
#[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,
}
/// Another custom component
#[derive(Debug, Clone, UnityComponent)]
#[unity_class("Interactable")]
pub struct Interactable {
#[unity_field("interactionRadius")]
pub interaction_radius: f32,
#[unity_field("interactionText")]
pub interaction_text: String,
#[unity_field("canInteract")]
pub can_interact: bool,
}
fn main() {
println!("ECS Integration & Selective Parsing Example");
println!("{}", "=".repeat(60));
// Example 1: Using parse_with_types! macro
println!("\n1. Creating type filters:");
println!("{}", "-".repeat(60));
let _filter_all = TypeFilter::parse_all();
println!("✓ Filter that parses ALL types");
let filter_selective = parse_with_types! {
unity_types(Transform, Camera),
custom_types(PlaySFX)
};
println!("✓ Filter for Transform, Camera, and PlaySFX only");
let filter_custom_only = parse_with_types! {
custom_types(PlaySFX, Interactable)
};
println!("✓ Filter for PlaySFX and Interactable only (no Unity types)");
// Example 2: Demonstrating ECS insertion
println!("\n2. ECS Integration:");
println!("{}", "-".repeat(60));
// Simulate parsing a PlaySFX component
let yaml_str = r#"
volume: 0.8
startTime: 0.0
endTime: 5.0
isLoop: 0
"#;
let yaml: serde_yaml::Value = serde_yaml::from_str(yaml_str).unwrap();
let mapping = yaml.as_mapping().unwrap();
let ctx = ComponentContext {
type_id: 114,
file_id: FileID::from_i64(12345),
class_name: "PlaySFX",
entity: None,
linking_ctx: None,
yaml: mapping,
};
// Parse the component
if let Some(play_sfx) = PlaySFX::parse(mapping, &ctx) {
println!("✓ Parsed PlaySFX component:");
println!(" - volume: {}", play_sfx.volume);
println!(" - start_time: {}", play_sfx.start_time);
println!(" - end_time: {}", play_sfx.end_time);
println!(" - is_loop: {}", play_sfx.is_loop);
// Create a minimal ECS world to demonstrate insertion
use sparsey::World;
let mut world = World::builder().register::<PlaySFX>().build();
let entity = world.create(());
println!("\n✓ Created ECS entity: {:?}", entity);
// Insert the component into the world
play_sfx.clone().insert_into_world(&mut world, entity);
println!("✓ Inserted PlaySFX component into ECS world");
// Query it back
{
let view = world.borrow::<PlaySFX>();
if let Some(component) = view.get(entity) {
println!("✓ Successfully queried component from ECS:");
println!(" - volume: {}", component.volume);
}
}
}
// Example 3: Type filter usage
println!("\n3. Type Filter Behavior:");
println!("{}", "-".repeat(60));
println!("Filter checks:");
println!(" Transform in selective filter: {}", filter_selective.should_parse_unity("Transform"));
println!(" Camera in selective filter: {}", filter_selective.should_parse_unity("Camera"));
println!(" Light in selective filter: {}", filter_selective.should_parse_unity("Light"));
println!(" PlaySFX in selective filter: {}", filter_selective.should_parse_custom("PlaySFX"));
println!(" Interactable in selective filter: {}", filter_selective.should_parse_custom("Interactable"));
println!("\n PlaySFX in custom-only filter: {}", filter_custom_only.should_parse_custom("PlaySFX"));
println!(" Transform in custom-only filter: {}", filter_custom_only.should_parse_unity("Transform"));
// Example 4: Benefits of selective parsing
println!("\n4. Benefits of Selective Parsing:");
println!("{}", "-".repeat(60));
println!("When parsing a large Unity project:");
println!(" • Parse ALL types: Parse everything (default)");
println!(" • Parse specific types: Faster parsing & less memory");
println!(" • Parse only what you need for your tool/analysis");
println!("\nExample use cases:");
println!(" • Animation tool: Only parse Animator, AnimationClip");
println!(" • Audio tool: Only parse AudioSource, PlaySFX");
println!(" • Transform analyzer: Only parse Transform, RectTransform");
println!();
println!("{}", "=".repeat(60));
println!("Complete! Custom components now work with ECS!");
println!("{}", "=".repeat(60));
}

View File

@@ -1,194 +0,0 @@
//! 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 unity_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::<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;
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
}

View File

@@ -1,218 +0,0 @@
//! Parse Cursebreaker Resource Prefabs
//!
//! This example demonstrates:
//! 1. Parsing Cursebreaker prefab files directly
//! 2. Finding Interactable_Resource components in prefabs
//! 3. Extracting typeId and maxHealth data
//! 4. Writing resource data to an output file
//!
//! Note: The 10_3.unity scene uses prefab instances, and the current parser
//! doesn't yet support resolving components from nested prefabs. This example
//! parses the prefab files directly instead.
use unity_parser::{GuidResolver, UnityComponent, UnityFile};
use std::fs::File;
use std::io::Write;
use std::path::Path;
use walkdir::WalkDir;
/// Interactable_Resource component from Cursebreaker
///
/// C# definition from Interactable_Resource.cs:
/// ```csharp
/// public class Interactable_Resource : Interactable
/// {
/// public int health;
/// public int maxHealth;
/// public int typeId;
/// // ... other fields
/// }
/// ```
#[derive(Debug, Clone, UnityComponent)]
#[unity_class("Interactable_Resource")]
pub struct InteractableResource {
#[unity_field("maxHealth")]
pub max_health: i64,
#[unity_field("typeId")]
pub type_id: i64,
}
fn main() -> Result<(), Box<dyn std::error::Error>> {
println!("🎮 Cursebreaker - Resource Prefab Parser");
println!("{}", "=".repeat(70));
println!();
// Build GUID resolver for the project
let project_path = Path::new("/home/connor/repos/CBAssets");
println!("📦 Building GUID resolver for project: {}", project_path.display());
let resolver = match GuidResolver::from_project(project_path) {
Ok(r) => {
println!(" ✅ GUID resolver built successfully ({} mappings)", r.len());
// Debug: Check if we have Interactable_Resource
if let Some(class) = r.resolve_class_name("d39ddbf1c2c3d1a4baa070e5e76548bd") {
println!(" ✅ Found Interactable_Resource in resolver: {}", class);
} else {
println!(" ⚠️ Interactable_Resource NOT found in resolver");
// Try to find what we did find related to "Interactable"
println!(" Searching for similar class names...");
}
Some(r)
}
Err(e) => {
eprintln!(" ❌ Failed to build GUID resolver: {}", e);
None
}
};
println!();
let harvestables_dir = Path::new("/home/connor/repos/CBAssets/_GameAssets/Prefabs/Harvestables");
if !harvestables_dir.exists() {
eprintln!("❌ Error: Harvestables directory not found at {}", harvestables_dir.display());
return Err("Harvestables directory not found".into());
}
println!("📁 Scanning for harvestable prefabs in:");
println!(" {}", harvestables_dir.display());
println!();
// Find all prefab files
let mut prefab_files = Vec::new();
for entry in WalkDir::new(harvestables_dir)
.follow_links(false)
.into_iter()
.filter_map(|e| e.ok())
{
let path = entry.path();
if path.extension().and_then(|s| s.to_str()) == Some("prefab") {
prefab_files.push(path.to_path_buf());
}
}
println!("📄 Found {} prefab file(s)", prefab_files.len());
println!();
let mut all_resources = Vec::new();
// Parse each prefab using the GUID resolver we built
for prefab_path in &prefab_files {
println!("🔍 Parsing: {}", prefab_path.file_name().unwrap().to_string_lossy());
// For prefabs, we need to manually parse and check documents
// since prefabs don't have an ECS world like scenes do
match UnityFile::from_path(prefab_path) {
Ok(UnityFile::Prefab(prefab)) => {
// Search through YAML documents for Interactable_Resource components
let mut found_in_prefab = false;
for doc in &prefab.documents {
// Check if this document is a MonoBehaviour
if doc.class_name == "MonoBehaviour" {
// Try to extract the m_Script GUID
if let Some(m_script) = doc.yaml.get("m_Script").and_then(|v| v.as_mapping()) {
if let Some(guid_val) = m_script.get("guid").and_then(|v| v.as_str()) {
// Resolve GUID to class name
if let Some(ref res) = resolver {
if let Some(class_name) = res.resolve_class_name(guid_val) {
// Debug: print what we found
if prefab_path.file_name().unwrap().to_string_lossy().contains("Copper Ore") {
eprintln!("DEBUG: Found class '{}' in Copper Ore prefab", class_name);
}
if class_name == "Interactable_Resource" {
// Extract fields
let type_id = doc.yaml.get("typeId")
.and_then(|v| v.as_i64())
.unwrap_or(0);
let max_health = doc.yaml.get("maxHealth")
.and_then(|v| v.as_i64())
.unwrap_or(0);
let prefab_name = prefab_path
.file_stem()
.and_then(|s| s.to_str())
.unwrap_or("unknown");
all_resources.push((
prefab_name.to_string(),
type_id,
max_health,
));
found_in_prefab = true;
}
} else if prefab_path.file_name().unwrap().to_string_lossy().contains("Copper Ore") {
eprintln!("DEBUG: Could not resolve GUID '{}' in Copper Ore prefab", guid_val);
}
}
}
}
}
}
if found_in_prefab {
println!(" ✅ Found Interactable_Resource");
} else {
println!(" ⊘ No Interactable_Resource found");
}
}
Ok(_) => {
println!(" ⊘ Not a prefab file");
}
Err(e) => {
println!(" ❌ Parse error: {}", e);
}
}
}
println!();
println!("{}", "=".repeat(70));
println!("📊 Summary: Found {} resource(s)", all_resources.len());
println!("{}", "=".repeat(70));
println!();
if !all_resources.is_empty() {
// Display resources
for (name, type_id, max_health) in &all_resources {
println!(" 📦 Prefab: \"{}\"", name);
println!(" • typeId: {}", type_id);
println!(" • maxHealth: {}", max_health);
println!();
}
// Write to output file
let output_path = "resource_prefabs_output.txt";
let mut output_file = File::create(output_path)?;
writeln!(output_file, "Cursebreaker Resource Prefabs")?;
writeln!(output_file, "{}", "=".repeat(70))?;
writeln!(output_file)?;
writeln!(output_file, "Total resources found: {}", all_resources.len())?;
writeln!(output_file)?;
writeln!(output_file, "{}", "-".repeat(70))?;
writeln!(output_file)?;
for (name, type_id, max_health) in &all_resources {
writeln!(output_file, "Prefab: {}", name)?;
writeln!(output_file, " TypeID: {}", type_id)?;
writeln!(output_file, " MaxHealth: {}", max_health)?;
writeln!(output_file)?;
}
writeln!(output_file, "{}", "=".repeat(70))?;
writeln!(output_file, "End of resource data")?;
println!("📝 Resource data written to: {}", output_path);
}
println!();
println!("{}", "=".repeat(70));
println!("✅ Parsing complete!");
println!("{}", "=".repeat(70));
Ok(())
}

View File

@@ -1,147 +0,0 @@
//! Parse Cursebreaker Resources from 10_3.unity Scene
//!
//! This example demonstrates:
//! 1. Parsing the Cursebreaker Unity project
//! 2. Finding Interactable_Resource components
//! 3. Extracting typeId and transform positions
//! 4. Writing resource data to an output file
use unity_parser::{UnityComponent, UnityFile};
use std::fs::File;
use std::io::Write;
use std::path::Path;
/// Interactable_Resource component from Cursebreaker
///
/// C# definition from Interactable_Resource.cs:
/// ```csharp
/// public class Interactable_Resource : Interactable
/// {
/// public int health;
/// public int maxHealth;
/// public int typeId;
/// // ... other fields
/// }
/// ```
#[derive(Debug, Clone, UnityComponent)]
#[unity_class("Interactable_Resource")]
pub struct InteractableResource {
#[unity_field("maxHealth")]
pub max_health: i64,
#[unity_field("typeId")]
pub type_id: i64,
}
fn main() -> Result<(), Box<dyn std::error::Error>> {
println!("🎮 Cursebreaker - Resource Parser");
println!("{}", "=".repeat(70));
println!();
let scene_path = Path::new("/home/connor/repos/CBAssets/_GameAssets/Scenes/Tiles/10_3.unity");
// Check if scene exists
if !scene_path.exists() {
eprintln!("❌ Error: Scene not found at {}", scene_path.display());
return Err("Scene file not found".into());
}
println!("📁 Parsing scene: {}", scene_path.display());
println!();
// Parse the scene
match UnityFile::from_path(&scene_path) {
Ok(UnityFile::Scene(scene)) => {
println!("✅ Scene parsed successfully!");
println!(" Total entities: {}", scene.entity_map.len());
println!();
// Get views for component types we need
let resource_view = scene.world.borrow::<InteractableResource>();
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();
for entity in scene.entity_map.values() {
if let Some(resource) = resource_view.get(*entity) {
let transform = transform_view.get(*entity);
let game_object = gameobject_view.get(*entity);
let name = game_object
.and_then(|go| go.name())
.unwrap_or("(unnamed)");
let position = transform
.and_then(|t| t.local_position())
.map(|p| (p.x, p.y, p.z));
found_resources.push((name.to_string(), resource.clone(), position));
}
}
println!("🔍 Found {} Interactable_Resource component(s)", found_resources.len());
println!();
if !found_resources.is_empty() {
// Display resources in console
for (name, resource, position) in &found_resources {
println!(" 📦 Resource: \"{}\"", name);
println!(" • typeId: {}", resource.type_id);
println!(" • maxHealth: {}", resource.max_health);
if let Some((x, y, z)) = position {
println!(" • Position: ({:.2}, {:.2}, {:.2})", x, y, z);
} else {
println!(" • Position: (no transform)");
}
println!();
}
// Write to output file
let output_path = "resources_output.txt";
let mut output_file = File::create(output_path)?;
writeln!(output_file, "Cursebreaker Resources - 10_3.unity Scene")?;
writeln!(output_file, "{}", "=".repeat(70))?;
writeln!(output_file)?;
writeln!(output_file, "Total resources found: {}", found_resources.len())?;
writeln!(output_file)?;
writeln!(output_file, "{}", "-".repeat(70))?;
writeln!(output_file)?;
for (name, resource, position) in &found_resources {
writeln!(output_file, "Resource: {}", name)?;
writeln!(output_file, " TypeID: {}", resource.type_id)?;
writeln!(output_file, " MaxHealth: {}", resource.max_health)?;
if let Some((x, y, z)) = position {
writeln!(output_file, " Position: ({:.6}, {:.6}, {:.6})", x, y, z)?;
} else {
writeln!(output_file, " Position: N/A")?;
}
writeln!(output_file)?;
}
writeln!(output_file, "{}", "=".repeat(70))?;
writeln!(output_file, "End of resource data")?;
println!("📝 Resource data written to: {}", output_path);
println!();
}
println!("{}", "=".repeat(70));
println!("✅ Parsing complete!");
println!("{}", "=".repeat(70));
}
Ok(_) => {
eprintln!("❌ Error: File is not a scene");
return Err("Not a Unity scene file".into());
}
Err(e) => {
eprintln!("❌ Parse error: {}", e);
return Err(Box::new(e));
}
}
Ok(())
}