148 lines
5.4 KiB
Rust
148 lines
5.4 KiB
Rust
//! 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 cursebreaker_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::<cursebreaker_parser::Transform>();
|
|
let gameobject_view = scene.world.borrow::<cursebreaker_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(())
|
|
}
|