removed examples
This commit is contained in:
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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!");
|
||||
}
|
||||
@@ -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));
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
@@ -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(())
|
||||
}
|
||||
@@ -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(())
|
||||
}
|
||||
Reference in New Issue
Block a user