diff --git a/unity-parser/src/types/unity_types/box_collider.rs b/unity-parser/src/types/unity_types/box_collider.rs index 341a1d2..2d28c68 100644 --- a/unity-parser/src/types/unity_types/box_collider.rs +++ b/unity-parser/src/types/unity_types/box_collider.rs @@ -1,6 +1,7 @@ //! BoxCollider component wrapper use crate::types::{yaml_helpers, ComponentContext, UnityComponent, Vector3}; +use crate::types::unity_types::Collider; use sparsey::Entity; /// A BoxCollider component @@ -9,28 +10,39 @@ use sparsey::Entity; /// It defines a box-shaped volume that can be used for collision detection. #[derive(Debug, Clone)] pub struct BoxCollider { - size: Option, - center: Option, + size: Vector3, + center: Vector3, + collider: Collider, } impl BoxCollider { /// Get the size of the box collider - pub fn size(&self) -> Option<&Vector3> { - self.size.as_ref() + pub fn size(&self) -> &Vector3 { + &self.size } /// Get the center offset of the box collider - pub fn center(&self) -> Option<&Vector3> { - self.center.as_ref() + pub fn center(&self) -> &Vector3 { + &self.center + } + + /// Get the base collider component + pub fn collider(&self) -> &Collider { + &self.collider + } + + /// Get mutable access to the base collider component + pub fn collider_mut(&mut self) -> &mut Collider { + &mut self.collider } /// Set the size of the box collider - pub fn set_size(&mut self, size: Option) { + pub fn set_size(&mut self, size: Vector3) { self.size = size; } /// Set the center offset of the box collider - pub fn set_center(&mut self, center: Option) { + pub fn set_center(&mut self, center: Vector3) { self.center = center; } } @@ -39,17 +51,23 @@ impl UnityComponent for BoxCollider { /// Parse a BoxCollider from YAML /// /// Note: Caller is responsible for ensuring this is called on the correct document type. - fn parse(yaml: &serde_yaml::Mapping, _ctx: &ComponentContext) -> Option { - let size = yaml_helpers::get_vector3(yaml, "m_Size"); - let center = yaml_helpers::get_vector3(yaml, "m_Center"); + fn parse(yaml: &serde_yaml::Mapping, ctx: &ComponentContext) -> Option { + let size = yaml_helpers::get_vector3(yaml, "m_Size").unwrap_or_default(); + let center = yaml_helpers::get_vector3(yaml, "m_Center").unwrap_or_default(); - Some(Self { size, center }) + // Parse the base collider component (layer masks) + let collider = Collider::parse(yaml, ctx)?; + + Some(Self { size, center, collider }) } } impl crate::types::EcsInsertable for BoxCollider { fn insert_into_world(self, world: &mut sparsey::World, entity: Entity) { - world.insert(entity, (self,)); + // Insert both the BoxCollider and the base Collider component + // This allows querying for either specific collider types or all colliders + let collider = self.collider.clone(); + world.insert(entity, (self, collider)); } } @@ -61,6 +79,9 @@ inventory::submit! { parse_and_insert: |yaml, ctx, world, entity| { ::parse_and_insert(yaml, ctx, world, entity) }, - register: |builder| builder.register::(), + register: |builder| { + // Register both BoxCollider and the base Collider component + builder.register::().register::() + }, } } diff --git a/unity-parser/src/types/unity_types/capsule_collider.rs b/unity-parser/src/types/unity_types/capsule_collider.rs new file mode 100644 index 0000000..84b124a --- /dev/null +++ b/unity-parser/src/types/unity_types/capsule_collider.rs @@ -0,0 +1,117 @@ +//! CapsuleCollider component wrapper + +use crate::types::{yaml_helpers, ComponentContext, UnityComponent, Vector3}; +use crate::types::unity_types::Collider; +use sparsey::Entity; + +/// A CapsuleCollider component +/// +/// CapsuleCollider is a basic collision primitive in the shape of a capsule. +/// It defines a capsule-shaped volume (cylinder with hemispherical ends) that can be used for collision detection. +#[derive(Debug, Clone)] +pub struct CapsuleCollider { + radius: f32, + height: f32, + center: Vector3, + direction: i32, // 0 = X-axis, 1 = Y-axis, 2 = Z-axis + collider: Collider, +} + +impl CapsuleCollider { + /// Get the radius of the capsule collider + pub fn radius(&self) -> f32 { + self.radius + } + + /// Get the height of the capsule collider + pub fn height(&self) -> f32 { + self.height + } + + /// Get the center offset of the capsule collider + pub fn center(&self) -> &Vector3 { + &self.center + } + + /// Get the direction axis of the capsule (0=X, 1=Y, 2=Z) + pub fn direction(&self) -> i32 { + self.direction + } + + /// Get the base collider component + pub fn collider(&self) -> &Collider { + &self.collider + } + + /// Get mutable access to the base collider component + pub fn collider_mut(&mut self) -> &mut Collider { + &mut self.collider + } + + /// Set the radius of the capsule collider + pub fn set_radius(&mut self, radius: f32) { + self.radius = radius; + } + + /// Set the height of the capsule collider + pub fn set_height(&mut self, height: f32) { + self.height = height; + } + + /// Set the center offset of the capsule collider + pub fn set_center(&mut self, center: Vector3) { + self.center = center; + } + + /// Set the direction axis (0=X, 1=Y, 2=Z) + pub fn set_direction(&mut self, direction: i32) { + self.direction = direction; + } +} + +impl UnityComponent for CapsuleCollider { + /// Parse a CapsuleCollider from YAML + /// + /// Note: Caller is responsible for ensuring this is called on the correct document type. + fn parse(yaml: &serde_yaml::Mapping, ctx: &ComponentContext) -> Option { + let radius = yaml_helpers::get_f64(yaml, "m_Radius").unwrap_or(0.0) as f32; + let height = yaml_helpers::get_f64(yaml, "m_Height").unwrap_or(0.0) as f32; + let center = yaml_helpers::get_vector3(yaml, "m_Center").unwrap_or_default(); + let direction = yaml_helpers::get_i64(yaml, "m_Direction").unwrap_or(0) as i32; + + // Parse the base collider component (layer masks) + let collider = Collider::parse(yaml, ctx)?; + + Some(Self { + radius, + height, + center, + direction, + collider, + }) + } +} + +impl crate::types::EcsInsertable for CapsuleCollider { + fn insert_into_world(self, world: &mut sparsey::World, entity: Entity) { + // Insert both the CapsuleCollider and the base Collider component + // This allows querying for either specific collider types or all colliders + let collider = self.collider.clone(); + world.insert(entity, (self, collider)); + } +} + +// Register component with inventory +inventory::submit! { + crate::types::ComponentRegistration { + type_id: 136, // Unity type ID for CapsuleCollider + class_name: "CapsuleCollider", + parse_and_insert: |yaml, ctx, world, entity| { + ::parse_and_insert(yaml, ctx, world, entity) + }, + register: |builder| { + // Register both CapsuleCollider and the base Collider component + builder.register::().register::() + }, + } +} diff --git a/unity-parser/src/types/unity_types/collider.rs b/unity-parser/src/types/unity_types/collider.rs new file mode 100644 index 0000000..1f5b17f --- /dev/null +++ b/unity-parser/src/types/unity_types/collider.rs @@ -0,0 +1,87 @@ +//! Collider component wrapper + +use crate::types::{ComponentContext, UnityComponent}; +use serde_yaml::{Mapping, Value}; +use sparsey::Entity; + +/// A Collider component +/// +/// Collider is the base class for collision primitives. +/// Contains layer mask information for collision filtering. +#[derive(Debug, Clone)] +pub struct Collider { + /// Layer mask for which layers this collider can collide with + include_layers: u32, + /// Layer mask for which layers this collider should ignore + exclude_layers: u32, +} + +impl Collider { + /// Get the include layers bitset + pub fn include_layers(&self) -> u32 { + self.include_layers + } + + /// Get the exclude layers bitset + pub fn exclude_layers(&self) -> u32 { + self.exclude_layers + } + + /// Set the include layers bitset + pub fn set_include_layers(&mut self, layers: u32) { + self.include_layers = layers; + } + + /// Set the exclude layers bitset + pub fn set_exclude_layers(&mut self, layers: u32) { + self.exclude_layers = layers; + } + + /// Check if the collider can interact with a specific layer (0-31) + pub fn can_collide_with_layer(&self, layer: u8) -> bool { + if layer >= 32 { + return false; + } + let layer_bit = 1u32 << layer; + (self.include_layers & layer_bit) != 0 && (self.exclude_layers & layer_bit) == 0 + } +} + +/// Helper function to parse Unity's layer bitset structure +/// +/// Unity stores layer masks as: +/// ```yaml +/// m_IncludeLayers: +/// serializedVersion: 2 +/// m_Bits: 0 +/// ``` +fn parse_layer_bitset(map: &Mapping, key: &str) -> Option { + let obj = map + .get(&Value::String(key.to_string())) + .and_then(|v| v.as_mapping())?; + + obj.get(&Value::String("m_Bits".to_string())) + .and_then(|v| v.as_u64()) + .map(|bits| bits as u32) +} + +impl UnityComponent for Collider { + /// Parse a Collider from YAML + /// + /// Note: Caller is responsible for ensuring this is called on the correct document type. + fn parse(yaml: &Mapping, _ctx: &ComponentContext) -> Option { + let include_layers = parse_layer_bitset(yaml, "m_IncludeLayers").unwrap_or(0); + let exclude_layers = parse_layer_bitset(yaml, "m_ExcludeLayers").unwrap_or(0); + + Some(Self { + include_layers, + exclude_layers, + }) + } +} + +impl crate::types::EcsInsertable for Collider { + fn insert_into_world(self, world: &mut sparsey::World, entity: Entity) { + world.insert(entity, (self,)); + } +} \ No newline at end of file diff --git a/unity-parser/src/types/unity_types/mod.rs b/unity-parser/src/types/unity_types/mod.rs index cd9e8d4..63779df 100644 --- a/unity-parser/src/types/unity_types/mod.rs +++ b/unity-parser/src/types/unity_types/mod.rs @@ -1,14 +1,19 @@ //! Unity-specific types (GameObjects, Transforms, PrefabInstances) pub mod box_collider; +pub mod capsule_collider; +pub mod collider; pub mod game_object; pub mod mesh_filter; pub mod mesh_renderer; pub mod prefab_instance; pub mod renderer; +pub mod sphere_collider; pub mod transform; pub use box_collider::BoxCollider; +pub use capsule_collider::CapsuleCollider; +pub use collider::Collider; pub use game_object::GameObject; pub use mesh_filter::MeshFilter; pub use mesh_renderer::MeshRenderer; @@ -16,4 +21,5 @@ pub use prefab_instance::{ PrefabInstance, PrefabInstanceComponent, PrefabModification, PrefabResolver, }; pub use renderer::Renderer; +pub use sphere_collider::SphereCollider; pub use transform::{RectTransform, Transform}; diff --git a/unity-parser/src/types/unity_types/sphere_collider.rs b/unity-parser/src/types/unity_types/sphere_collider.rs new file mode 100644 index 0000000..62a7b51 --- /dev/null +++ b/unity-parser/src/types/unity_types/sphere_collider.rs @@ -0,0 +1,91 @@ +//! SphereCollider component wrapper + +use crate::types::{yaml_helpers, ComponentContext, UnityComponent, Vector3}; +use crate::types::unity_types::Collider; +use sparsey::Entity; + +/// A SphereCollider component +/// +/// SphereCollider is a basic collision primitive in the shape of a sphere. +/// It defines a sphere-shaped volume that can be used for collision detection. +#[derive(Debug, Clone)] +pub struct SphereCollider { + radius: f32, + center: Vector3, + collider: Collider, +} + +impl SphereCollider { + /// Get the radius of the sphere collider + pub fn radius(&self) -> f32 { + self.radius + } + + /// Get the center offset of the sphere collider + pub fn center(&self) -> &Vector3 { + &self.center + } + + /// Get the base collider component + pub fn collider(&self) -> &Collider { + &self.collider + } + + /// Get mutable access to the base collider component + pub fn collider_mut(&mut self) -> &mut Collider { + &mut self.collider + } + + /// Set the radius of the sphere collider + pub fn set_radius(&mut self, radius: f32) { + self.radius = radius; + } + + /// Set the center offset of the sphere collider + pub fn set_center(&mut self, center: Vector3) { + self.center = center; + } +} + +impl UnityComponent for SphereCollider { + /// Parse a SphereCollider from YAML + /// + /// Note: Caller is responsible for ensuring this is called on the correct document type. + fn parse(yaml: &serde_yaml::Mapping, ctx: &ComponentContext) -> Option { + let radius = yaml_helpers::get_f64(yaml, "m_Radius").unwrap_or(0.0) as f32; + let center = yaml_helpers::get_vector3(yaml, "m_Center").unwrap_or_default(); + + // Parse the base collider component (layer masks) + let collider = Collider::parse(yaml, ctx)?; + + Some(Self { + radius, + center, + collider, + }) + } +} + +impl crate::types::EcsInsertable for SphereCollider { + fn insert_into_world(self, world: &mut sparsey::World, entity: Entity) { + // Insert both the SphereCollider and the base Collider component + // This allows querying for either specific collider types or all colliders + let collider = self.collider.clone(); + world.insert(entity, (self, collider)); + } +} + +// Register component with inventory +inventory::submit! { + crate::types::ComponentRegistration { + type_id: 135, // Unity type ID for SphereCollider + class_name: "SphereCollider", + parse_and_insert: |yaml, ctx, world, entity| { + ::parse_and_insert(yaml, ctx, world, entity) + }, + register: |builder| { + // Register both SphereCollider and the base Collider component + builder.register::().register::() + }, + } +}