components store data instead of yaml
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
//! Component trait and generic component wrapper
|
||||
|
||||
use crate::model::UnityDocument;
|
||||
use crate::types::FileID;
|
||||
use crate::types::FileRef;
|
||||
|
||||
/// A trait for Unity components
|
||||
@@ -15,8 +16,8 @@ pub trait Component {
|
||||
true // Default implementation
|
||||
}
|
||||
|
||||
/// Get the underlying UnityDocument
|
||||
fn document(&self) -> &UnityDocument;
|
||||
/// Get the file ID of this component
|
||||
fn file_id(&self) -> FileID;
|
||||
}
|
||||
|
||||
/// A generic component wrapper that works with any component type
|
||||
@@ -29,8 +30,8 @@ pub trait Component {
|
||||
/// let file = UnityFile::from_path("Scene.unity")?;
|
||||
/// for doc in &file.documents {
|
||||
/// if !doc.is_game_object() {
|
||||
/// if let Some(comp) = GenericComponent::new(doc) {
|
||||
/// println!("Component: {}", doc.class_name);
|
||||
/// if let Some(comp) = GenericComponent::parse(doc) {
|
||||
/// println!("Component: {}", comp.class_name());
|
||||
/// if let Some(go_ref) = comp.game_object() {
|
||||
/// println!(" Attached to: {}", go_ref.file_id);
|
||||
/// }
|
||||
@@ -39,52 +40,63 @@ pub trait Component {
|
||||
/// }
|
||||
/// # Ok::<(), cursebreaker_parser::Error>(())
|
||||
/// ```
|
||||
#[derive(Debug)]
|
||||
pub struct GenericComponent<'a> {
|
||||
document: &'a UnityDocument,
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct GenericComponent {
|
||||
file_id: FileID,
|
||||
class_name: String,
|
||||
game_object: Option<FileRef>,
|
||||
is_enabled: bool,
|
||||
}
|
||||
|
||||
impl<'a> GenericComponent<'a> {
|
||||
/// Create a GenericComponent wrapper from a UnityDocument
|
||||
impl GenericComponent {
|
||||
/// Parse a GenericComponent from a UnityDocument
|
||||
///
|
||||
/// Returns None if the document is a GameObject (GameObjects are not components).
|
||||
pub fn new(document: &'a UnityDocument) -> Option<Self> {
|
||||
if !document.is_game_object() {
|
||||
Some(Self { document })
|
||||
} else {
|
||||
None
|
||||
pub fn parse(document: &UnityDocument) -> Option<Self> {
|
||||
if document.is_game_object() {
|
||||
return None;
|
||||
}
|
||||
|
||||
// Extract m_GameObject and m_Enabled from the component properties
|
||||
let props = document
|
||||
.get(&document.class_name)
|
||||
.and_then(|obj| obj.as_object());
|
||||
|
||||
let game_object = props
|
||||
.and_then(|p| p.get("m_GameObject"))
|
||||
.and_then(|v| v.as_file_ref())
|
||||
.copied();
|
||||
|
||||
let is_enabled = props
|
||||
.and_then(|p| p.get("m_Enabled"))
|
||||
.and_then(|v| v.as_bool())
|
||||
.unwrap_or(true);
|
||||
|
||||
Some(Self {
|
||||
file_id: document.file_id,
|
||||
class_name: document.class_name.clone(),
|
||||
game_object,
|
||||
is_enabled,
|
||||
})
|
||||
}
|
||||
|
||||
/// Get the class name of this component
|
||||
pub fn class_name(&self) -> &str {
|
||||
&self.document.class_name
|
||||
&self.class_name
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Component for GenericComponent<'a> {
|
||||
impl Component for GenericComponent {
|
||||
fn game_object(&self) -> Option<FileRef> {
|
||||
// Look for m_GameObject property which is common to all components
|
||||
self.document
|
||||
.get(&self.document.class_name)
|
||||
.and_then(|obj| obj.as_object())
|
||||
.and_then(|props| props.get("m_GameObject"))
|
||||
.and_then(|v| v.as_file_ref())
|
||||
.copied()
|
||||
self.game_object
|
||||
}
|
||||
|
||||
fn is_enabled(&self) -> bool {
|
||||
// Look for m_Enabled property
|
||||
self.document
|
||||
.get(&self.document.class_name)
|
||||
.and_then(|obj| obj.as_object())
|
||||
.and_then(|props| props.get("m_Enabled"))
|
||||
.and_then(|v| v.as_bool())
|
||||
.unwrap_or(true) // Default to enabled
|
||||
self.is_enabled
|
||||
}
|
||||
|
||||
fn document(&self) -> &UnityDocument {
|
||||
self.document
|
||||
fn file_id(&self) -> FileID {
|
||||
self.file_id
|
||||
}
|
||||
}
|
||||
|
||||
@@ -118,14 +130,14 @@ mod tests {
|
||||
#[test]
|
||||
fn test_component_creation() {
|
||||
let doc = create_test_component();
|
||||
let comp = GenericComponent::new(&doc);
|
||||
let comp = GenericComponent::parse(&doc);
|
||||
assert!(comp.is_some());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_component_game_object_ref() {
|
||||
let doc = create_test_component();
|
||||
let comp = GenericComponent::new(&doc).unwrap();
|
||||
let comp = GenericComponent::parse(&doc).unwrap();
|
||||
let go_ref = comp.game_object();
|
||||
assert!(go_ref.is_some());
|
||||
assert_eq!(go_ref.unwrap().file_id.as_i64(), 67890);
|
||||
@@ -134,17 +146,24 @@ mod tests {
|
||||
#[test]
|
||||
fn test_component_is_enabled() {
|
||||
let doc = create_test_component();
|
||||
let comp = GenericComponent::new(&doc).unwrap();
|
||||
let comp = GenericComponent::parse(&doc).unwrap();
|
||||
assert!(comp.is_enabled());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_component_class_name() {
|
||||
let doc = create_test_component();
|
||||
let comp = GenericComponent::new(&doc).unwrap();
|
||||
let comp = GenericComponent::parse(&doc).unwrap();
|
||||
assert_eq!(comp.class_name(), "Transform");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_component_file_id() {
|
||||
let doc = create_test_component();
|
||||
let comp = GenericComponent::parse(&doc).unwrap();
|
||||
assert_eq!(comp.file_id().as_i64(), 12345);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_game_object_is_not_component() {
|
||||
let mut properties = IndexMap::new();
|
||||
@@ -157,7 +176,7 @@ mod tests {
|
||||
properties,
|
||||
};
|
||||
|
||||
let comp = GenericComponent::new(&doc);
|
||||
let comp = GenericComponent::parse(&doc);
|
||||
assert!(comp.is_none());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,7 +14,7 @@ use crate::types::{FileID, FileRef};
|
||||
///
|
||||
/// let file = UnityFile::from_path("Scene.unity")?;
|
||||
/// for doc in &file.documents {
|
||||
/// if let Some(go) = GameObject::new(doc) {
|
||||
/// if let Some(go) = GameObject::parse(doc) {
|
||||
/// println!("GameObject: {}", go.name().unwrap_or("Unnamed"));
|
||||
/// println!(" Active: {}", go.is_active());
|
||||
/// println!(" Components: {}", go.components().len());
|
||||
@@ -22,66 +22,50 @@ use crate::types::{FileID, FileRef};
|
||||
/// }
|
||||
/// # Ok::<(), cursebreaker_parser::Error>(())
|
||||
/// ```
|
||||
#[derive(Debug)]
|
||||
pub struct GameObject<'a> {
|
||||
document: &'a UnityDocument,
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct GameObject {
|
||||
file_id: FileID,
|
||||
name: Option<String>,
|
||||
is_active: bool,
|
||||
layer: Option<i64>,
|
||||
tag: Option<i64>,
|
||||
components: Vec<FileRef>,
|
||||
}
|
||||
|
||||
impl<'a> GameObject<'a> {
|
||||
/// Create a GameObject wrapper from a UnityDocument
|
||||
impl GameObject {
|
||||
/// Parse a GameObject from a UnityDocument
|
||||
///
|
||||
/// Returns None if the document is not a GameObject.
|
||||
pub fn new(document: &'a UnityDocument) -> Option<Self> {
|
||||
if document.is_game_object() {
|
||||
Some(Self { document })
|
||||
} else {
|
||||
None
|
||||
}
|
||||
pub fn parse(document: &UnityDocument) -> Option<Self> {
|
||||
if !document.is_game_object() {
|
||||
return None;
|
||||
}
|
||||
|
||||
/// Get the GameObject's name
|
||||
pub fn name(&self) -> Option<&str> {
|
||||
self.document
|
||||
// Get the GameObject properties object
|
||||
let props = document
|
||||
.get("GameObject")
|
||||
.and_then(|obj| obj.as_object())
|
||||
.and_then(|props| props.get("m_Name"))
|
||||
.and_then(|obj| obj.as_object());
|
||||
|
||||
let name = props
|
||||
.and_then(|p| p.get("m_Name"))
|
||||
.and_then(|v| v.as_str())
|
||||
}
|
||||
.map(|s| s.to_string());
|
||||
|
||||
/// Check if the GameObject is active
|
||||
pub fn is_active(&self) -> bool {
|
||||
self.document
|
||||
.get("GameObject")
|
||||
.and_then(|obj| obj.as_object())
|
||||
.and_then(|props| props.get("m_IsActive"))
|
||||
let is_active = props
|
||||
.and_then(|p| p.get("m_IsActive"))
|
||||
.and_then(|v| v.as_bool())
|
||||
.unwrap_or(true) // Default to true if not specified
|
||||
}
|
||||
.unwrap_or(true);
|
||||
|
||||
/// Get the GameObject's layer
|
||||
pub fn layer(&self) -> Option<i64> {
|
||||
self.document
|
||||
.get("GameObject")
|
||||
.and_then(|obj| obj.as_object())
|
||||
.and_then(|props| props.get("m_Layer"))
|
||||
.and_then(|v| v.as_i64())
|
||||
}
|
||||
let layer = props
|
||||
.and_then(|p| p.get("m_Layer"))
|
||||
.and_then(|v| v.as_i64());
|
||||
|
||||
/// Get the GameObject's tag as a tag ID
|
||||
pub fn tag(&self) -> Option<i64> {
|
||||
self.document
|
||||
.get("GameObject")
|
||||
.and_then(|obj| obj.as_object())
|
||||
.and_then(|props| props.get("m_TagString"))
|
||||
.and_then(|v| v.as_i64())
|
||||
}
|
||||
let tag = props
|
||||
.and_then(|p| p.get("m_TagString"))
|
||||
.and_then(|v| v.as_i64());
|
||||
|
||||
/// Get the list of component references attached to this GameObject
|
||||
pub fn components(&self) -> Vec<FileRef> {
|
||||
self.document
|
||||
.get("GameObject")
|
||||
.and_then(|obj| obj.as_object())
|
||||
.and_then(|props| props.get("m_Component"))
|
||||
let components = props
|
||||
.and_then(|p| p.get("m_Component"))
|
||||
.and_then(|v| v.as_array())
|
||||
.map(|arr| {
|
||||
arr.iter()
|
||||
@@ -94,17 +78,46 @@ impl<'a> GameObject<'a> {
|
||||
})
|
||||
.collect()
|
||||
})
|
||||
.unwrap_or_default()
|
||||
.unwrap_or_default();
|
||||
|
||||
Some(Self {
|
||||
file_id: document.file_id,
|
||||
name,
|
||||
is_active,
|
||||
layer,
|
||||
tag,
|
||||
components,
|
||||
})
|
||||
}
|
||||
|
||||
/// Get the GameObject's name
|
||||
pub fn name(&self) -> Option<&str> {
|
||||
self.name.as_deref()
|
||||
}
|
||||
|
||||
/// Check if the GameObject is active
|
||||
pub fn is_active(&self) -> bool {
|
||||
self.is_active
|
||||
}
|
||||
|
||||
/// Get the GameObject's layer
|
||||
pub fn layer(&self) -> Option<i64> {
|
||||
self.layer
|
||||
}
|
||||
|
||||
/// Get the GameObject's tag as a tag ID
|
||||
pub fn tag(&self) -> Option<i64> {
|
||||
self.tag
|
||||
}
|
||||
|
||||
/// Get the list of component references attached to this GameObject
|
||||
pub fn components(&self) -> &[FileRef] {
|
||||
&self.components
|
||||
}
|
||||
|
||||
/// Get the file ID of this GameObject
|
||||
pub fn file_id(&self) -> FileID {
|
||||
self.document.file_id
|
||||
}
|
||||
|
||||
/// Get the underlying UnityDocument
|
||||
pub fn document(&self) -> &'a UnityDocument {
|
||||
self.document
|
||||
self.file_id
|
||||
}
|
||||
}
|
||||
|
||||
@@ -136,35 +149,35 @@ mod tests {
|
||||
#[test]
|
||||
fn test_game_object_creation() {
|
||||
let doc = create_test_game_object();
|
||||
let go = GameObject::new(&doc);
|
||||
let go = GameObject::parse(&doc);
|
||||
assert!(go.is_some());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_game_object_name() {
|
||||
let doc = create_test_game_object();
|
||||
let go = GameObject::new(&doc).unwrap();
|
||||
let go = GameObject::parse(&doc).unwrap();
|
||||
assert_eq!(go.name(), Some("TestObject"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_game_object_is_active() {
|
||||
let doc = create_test_game_object();
|
||||
let go = GameObject::new(&doc).unwrap();
|
||||
let go = GameObject::parse(&doc).unwrap();
|
||||
assert!(go.is_active());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_game_object_layer() {
|
||||
let doc = create_test_game_object();
|
||||
let go = GameObject::new(&doc).unwrap();
|
||||
let go = GameObject::parse(&doc).unwrap();
|
||||
assert_eq!(go.layer(), Some(0));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_game_object_file_id() {
|
||||
let doc = create_test_game_object();
|
||||
let go = GameObject::new(&doc).unwrap();
|
||||
let go = GameObject::parse(&doc).unwrap();
|
||||
assert_eq!(go.file_id().as_i64(), 12345);
|
||||
}
|
||||
|
||||
@@ -174,7 +187,7 @@ mod tests {
|
||||
doc.type_id = 4; // Transform type ID
|
||||
doc.class_name = "Transform".to_string();
|
||||
|
||||
let go = GameObject::new(&doc);
|
||||
let go = GameObject::parse(&doc);
|
||||
assert!(go.is_none());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
//! Transform and RectTransform component wrappers
|
||||
|
||||
use crate::model::UnityDocument;
|
||||
use crate::types::{Component, FileRef, Quaternion, Vector2, Vector3};
|
||||
use crate::types::{Component, FileID, FileRef, Quaternion, Vector2, Vector3};
|
||||
|
||||
/// A wrapper around a UnityDocument that represents a Transform component
|
||||
///
|
||||
@@ -14,7 +14,7 @@ use crate::types::{Component, FileRef, Quaternion, Vector2, Vector3};
|
||||
///
|
||||
/// let file = UnityFile::from_path("Scene.unity")?;
|
||||
/// for doc in &file.documents {
|
||||
/// if let Some(transform) = Transform::new(doc) {
|
||||
/// if let Some(transform) = Transform::parse(doc) {
|
||||
/// if let Some(pos) = transform.local_position() {
|
||||
/// println!("Position: ({}, {}, {})", pos.x, pos.y, pos.z);
|
||||
/// }
|
||||
@@ -22,56 +22,58 @@ use crate::types::{Component, FileRef, Quaternion, Vector2, Vector3};
|
||||
/// }
|
||||
/// # Ok::<(), cursebreaker_parser::Error>(())
|
||||
/// ```
|
||||
#[derive(Debug)]
|
||||
pub struct Transform<'a> {
|
||||
document: &'a UnityDocument,
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct Transform {
|
||||
file_id: FileID,
|
||||
game_object: Option<FileRef>,
|
||||
local_position: Option<Vector3>,
|
||||
local_rotation: Option<Quaternion>,
|
||||
local_scale: Option<Vector3>,
|
||||
parent: Option<FileRef>,
|
||||
children: Vec<FileRef>,
|
||||
}
|
||||
|
||||
impl<'a> Transform<'a> {
|
||||
/// Create a Transform wrapper from a UnityDocument
|
||||
impl Transform {
|
||||
/// Parse a Transform from a UnityDocument
|
||||
///
|
||||
/// Returns None if the document is not a Transform or RectTransform.
|
||||
pub fn new(document: &'a UnityDocument) -> Option<Self> {
|
||||
if document.class_name == "Transform" || document.class_name == "RectTransform" {
|
||||
Some(Self { document })
|
||||
} else {
|
||||
None
|
||||
}
|
||||
pub fn parse(document: &UnityDocument) -> Option<Self> {
|
||||
if document.class_name != "Transform" && document.class_name != "RectTransform" {
|
||||
return None;
|
||||
}
|
||||
|
||||
/// Get the local position of this transform
|
||||
pub fn local_position(&self) -> Option<&Vector3> {
|
||||
self.get_transform_props()
|
||||
.and_then(|props| props.get("m_LocalPosition"))
|
||||
.and_then(|v| v.as_vector3())
|
||||
}
|
||||
// Get the transform properties object
|
||||
let props = document
|
||||
.get(&document.class_name)
|
||||
.and_then(|v| v.as_object());
|
||||
|
||||
/// Get the local rotation of this transform
|
||||
pub fn local_rotation(&self) -> Option<&Quaternion> {
|
||||
self.get_transform_props()
|
||||
.and_then(|props| props.get("m_LocalRotation"))
|
||||
.and_then(|v| v.as_quaternion())
|
||||
}
|
||||
|
||||
/// Get the local scale of this transform
|
||||
pub fn local_scale(&self) -> Option<&Vector3> {
|
||||
self.get_transform_props()
|
||||
.and_then(|props| props.get("m_LocalScale"))
|
||||
.and_then(|v| v.as_vector3())
|
||||
}
|
||||
|
||||
/// Get the parent transform reference
|
||||
pub fn parent(&self) -> Option<FileRef> {
|
||||
self.get_transform_props()
|
||||
.and_then(|props| props.get("m_Father"))
|
||||
let game_object = props
|
||||
.and_then(|p| p.get("m_GameObject"))
|
||||
.and_then(|v| v.as_file_ref())
|
||||
.copied()
|
||||
}
|
||||
.copied();
|
||||
|
||||
/// Get the list of child transform references
|
||||
pub fn children(&self) -> Vec<FileRef> {
|
||||
self.get_transform_props()
|
||||
.and_then(|props| props.get("m_Children"))
|
||||
let local_position = props
|
||||
.and_then(|p| p.get("m_LocalPosition"))
|
||||
.and_then(|v| v.as_vector3())
|
||||
.copied();
|
||||
|
||||
let local_rotation = props
|
||||
.and_then(|p| p.get("m_LocalRotation"))
|
||||
.and_then(|v| v.as_quaternion())
|
||||
.copied();
|
||||
|
||||
let local_scale = props
|
||||
.and_then(|p| p.get("m_LocalScale"))
|
||||
.and_then(|v| v.as_vector3())
|
||||
.copied();
|
||||
|
||||
let parent = props
|
||||
.and_then(|p| p.get("m_Father"))
|
||||
.and_then(|v| v.as_file_ref())
|
||||
.copied();
|
||||
|
||||
let children = props
|
||||
.and_then(|p| p.get("m_Children"))
|
||||
.and_then(|v| v.as_array())
|
||||
.map(|arr| {
|
||||
arr.iter()
|
||||
@@ -79,31 +81,56 @@ impl<'a> Transform<'a> {
|
||||
.copied()
|
||||
.collect()
|
||||
})
|
||||
.unwrap_or_default()
|
||||
.unwrap_or_default();
|
||||
|
||||
Some(Self {
|
||||
file_id: document.file_id,
|
||||
game_object,
|
||||
local_position,
|
||||
local_rotation,
|
||||
local_scale,
|
||||
parent,
|
||||
children,
|
||||
})
|
||||
}
|
||||
|
||||
/// Helper to get the transform properties object
|
||||
fn get_transform_props(&self) -> Option<&indexmap::IndexMap<String, crate::property::PropertyValue>> {
|
||||
self.document
|
||||
.get(&self.document.class_name)
|
||||
.and_then(|v| v.as_object())
|
||||
/// Get the local position of this transform
|
||||
pub fn local_position(&self) -> Option<&Vector3> {
|
||||
self.local_position.as_ref()
|
||||
}
|
||||
|
||||
/// Get the local rotation of this transform
|
||||
pub fn local_rotation(&self) -> Option<&Quaternion> {
|
||||
self.local_rotation.as_ref()
|
||||
}
|
||||
|
||||
/// Get the local scale of this transform
|
||||
pub fn local_scale(&self) -> Option<&Vector3> {
|
||||
self.local_scale.as_ref()
|
||||
}
|
||||
|
||||
/// Get the parent transform reference
|
||||
pub fn parent(&self) -> Option<FileRef> {
|
||||
self.parent
|
||||
}
|
||||
|
||||
/// Get the list of child transform references
|
||||
pub fn children(&self) -> &[FileRef] {
|
||||
&self.children
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Component for Transform<'a> {
|
||||
impl Component for Transform {
|
||||
fn game_object(&self) -> Option<FileRef> {
|
||||
self.get_transform_props()
|
||||
.and_then(|props| props.get("m_GameObject"))
|
||||
.and_then(|v| v.as_file_ref())
|
||||
.copied()
|
||||
self.game_object
|
||||
}
|
||||
|
||||
fn is_enabled(&self) -> bool {
|
||||
true // Transforms are always enabled
|
||||
}
|
||||
|
||||
fn document(&self) -> &UnityDocument {
|
||||
self.document
|
||||
fn file_id(&self) -> FileID {
|
||||
self.file_id
|
||||
}
|
||||
}
|
||||
|
||||
@@ -118,7 +145,7 @@ impl<'a> Component for Transform<'a> {
|
||||
///
|
||||
/// let file = UnityFile::from_path("Canvas.prefab")?;
|
||||
/// for doc in &file.documents {
|
||||
/// if let Some(rect_transform) = RectTransform::new(doc) {
|
||||
/// if let Some(rect_transform) = RectTransform::parse(doc) {
|
||||
/// if let Some(anchor_min) = rect_transform.anchor_min() {
|
||||
/// println!("Anchor Min: ({}, {})", anchor_min.x, anchor_min.y);
|
||||
/// }
|
||||
@@ -126,58 +153,91 @@ impl<'a> Component for Transform<'a> {
|
||||
/// }
|
||||
/// # Ok::<(), cursebreaker_parser::Error>(())
|
||||
/// ```
|
||||
#[derive(Debug)]
|
||||
pub struct RectTransform<'a> {
|
||||
transform: Transform<'a>,
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct RectTransform {
|
||||
transform: Transform,
|
||||
anchor_min: Option<Vector2>,
|
||||
anchor_max: Option<Vector2>,
|
||||
anchored_position: Option<Vector2>,
|
||||
size_delta: Option<Vector2>,
|
||||
pivot: Option<Vector2>,
|
||||
}
|
||||
|
||||
impl<'a> RectTransform<'a> {
|
||||
/// Create a RectTransform wrapper from a UnityDocument
|
||||
impl RectTransform {
|
||||
/// Parse a RectTransform from a UnityDocument
|
||||
///
|
||||
/// Returns None if the document is not a RectTransform.
|
||||
pub fn new(document: &'a UnityDocument) -> Option<Self> {
|
||||
if document.class_name == "RectTransform" {
|
||||
Some(Self {
|
||||
transform: Transform { document },
|
||||
})
|
||||
} else {
|
||||
None
|
||||
pub fn parse(document: &UnityDocument) -> Option<Self> {
|
||||
if document.class_name != "RectTransform" {
|
||||
return None;
|
||||
}
|
||||
|
||||
// Parse the base Transform
|
||||
let transform = Transform::parse(document)?;
|
||||
|
||||
// Get the RectTransform properties object
|
||||
let props = document
|
||||
.get("RectTransform")
|
||||
.and_then(|v| v.as_object());
|
||||
|
||||
let anchor_min = props
|
||||
.and_then(|p| p.get("m_AnchorMin"))
|
||||
.and_then(|v| v.as_vector2())
|
||||
.copied();
|
||||
|
||||
let anchor_max = props
|
||||
.and_then(|p| p.get("m_AnchorMax"))
|
||||
.and_then(|v| v.as_vector2())
|
||||
.copied();
|
||||
|
||||
let anchored_position = props
|
||||
.and_then(|p| p.get("m_AnchoredPosition"))
|
||||
.and_then(|v| v.as_vector2())
|
||||
.copied();
|
||||
|
||||
let size_delta = props
|
||||
.and_then(|p| p.get("m_SizeDelta"))
|
||||
.and_then(|v| v.as_vector2())
|
||||
.copied();
|
||||
|
||||
let pivot = props
|
||||
.and_then(|p| p.get("m_Pivot"))
|
||||
.and_then(|v| v.as_vector2())
|
||||
.copied();
|
||||
|
||||
Some(Self {
|
||||
transform,
|
||||
anchor_min,
|
||||
anchor_max,
|
||||
anchored_position,
|
||||
size_delta,
|
||||
pivot,
|
||||
})
|
||||
}
|
||||
|
||||
/// Get the anchor min (bottom-left anchor)
|
||||
pub fn anchor_min(&self) -> Option<&Vector2> {
|
||||
self.get_rect_props()
|
||||
.and_then(|props| props.get("m_AnchorMin"))
|
||||
.and_then(|v| v.as_vector2())
|
||||
self.anchor_min.as_ref()
|
||||
}
|
||||
|
||||
/// Get the anchor max (top-right anchor)
|
||||
pub fn anchor_max(&self) -> Option<&Vector2> {
|
||||
self.get_rect_props()
|
||||
.and_then(|props| props.get("m_AnchorMax"))
|
||||
.and_then(|v| v.as_vector2())
|
||||
self.anchor_max.as_ref()
|
||||
}
|
||||
|
||||
/// Get the anchored position
|
||||
pub fn anchored_position(&self) -> Option<&Vector2> {
|
||||
self.get_rect_props()
|
||||
.and_then(|props| props.get("m_AnchoredPosition"))
|
||||
.and_then(|v| v.as_vector2())
|
||||
self.anchored_position.as_ref()
|
||||
}
|
||||
|
||||
/// Get the size delta
|
||||
pub fn size_delta(&self) -> Option<&Vector2> {
|
||||
self.get_rect_props()
|
||||
.and_then(|props| props.get("m_SizeDelta"))
|
||||
.and_then(|v| v.as_vector2())
|
||||
self.size_delta.as_ref()
|
||||
}
|
||||
|
||||
/// Get the pivot point
|
||||
pub fn pivot(&self) -> Option<&Vector2> {
|
||||
self.get_rect_props()
|
||||
.and_then(|props| props.get("m_Pivot"))
|
||||
.and_then(|v| v.as_vector2())
|
||||
self.pivot.as_ref()
|
||||
}
|
||||
|
||||
/// Get the local position (from Transform)
|
||||
@@ -201,17 +261,12 @@ impl<'a> RectTransform<'a> {
|
||||
}
|
||||
|
||||
/// Get the list of child transform references (from Transform)
|
||||
pub fn children(&self) -> Vec<FileRef> {
|
||||
pub fn children(&self) -> &[FileRef] {
|
||||
self.transform.children()
|
||||
}
|
||||
|
||||
/// Helper to get the RectTransform properties object
|
||||
fn get_rect_props(&self) -> Option<&indexmap::IndexMap<String, crate::property::PropertyValue>> {
|
||||
self.transform.get_transform_props()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Component for RectTransform<'a> {
|
||||
impl Component for RectTransform {
|
||||
fn game_object(&self) -> Option<FileRef> {
|
||||
self.transform.game_object()
|
||||
}
|
||||
@@ -220,8 +275,8 @@ impl<'a> Component for RectTransform<'a> {
|
||||
self.transform.is_enabled()
|
||||
}
|
||||
|
||||
fn document(&self) -> &UnityDocument {
|
||||
self.transform.document()
|
||||
fn file_id(&self) -> FileID {
|
||||
self.transform.file_id()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -314,14 +369,14 @@ mod tests {
|
||||
#[test]
|
||||
fn test_transform_creation() {
|
||||
let doc = create_test_transform();
|
||||
let transform = Transform::new(&doc);
|
||||
let transform = Transform::parse(&doc);
|
||||
assert!(transform.is_some());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_transform_local_position() {
|
||||
let doc = create_test_transform();
|
||||
let transform = Transform::new(&doc).unwrap();
|
||||
let transform = Transform::parse(&doc).unwrap();
|
||||
let pos = transform.local_position().unwrap();
|
||||
assert_eq!(pos.x, 1.0);
|
||||
assert_eq!(pos.y, 2.0);
|
||||
@@ -331,7 +386,7 @@ mod tests {
|
||||
#[test]
|
||||
fn test_transform_local_rotation() {
|
||||
let doc = create_test_transform();
|
||||
let transform = Transform::new(&doc).unwrap();
|
||||
let transform = Transform::parse(&doc).unwrap();
|
||||
let rot = transform.local_rotation().unwrap();
|
||||
assert_eq!(rot.w, 1.0);
|
||||
}
|
||||
@@ -339,22 +394,29 @@ mod tests {
|
||||
#[test]
|
||||
fn test_transform_local_scale() {
|
||||
let doc = create_test_transform();
|
||||
let transform = Transform::new(&doc).unwrap();
|
||||
let transform = Transform::parse(&doc).unwrap();
|
||||
let scale = transform.local_scale().unwrap();
|
||||
assert_eq!(scale, &Vector3::ONE);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_transform_file_id() {
|
||||
let doc = create_test_transform();
|
||||
let transform = Transform::parse(&doc).unwrap();
|
||||
assert_eq!(transform.file_id().as_i64(), 12345);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_rect_transform_creation() {
|
||||
let doc = create_test_rect_transform();
|
||||
let rect_transform = RectTransform::new(&doc);
|
||||
let rect_transform = RectTransform::parse(&doc);
|
||||
assert!(rect_transform.is_some());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_rect_transform_anchor_min() {
|
||||
let doc = create_test_rect_transform();
|
||||
let rect_transform = RectTransform::new(&doc).unwrap();
|
||||
let rect_transform = RectTransform::parse(&doc).unwrap();
|
||||
let anchor_min = rect_transform.anchor_min().unwrap();
|
||||
assert_eq!(anchor_min, &Vector2::ZERO);
|
||||
}
|
||||
@@ -362,7 +424,7 @@ mod tests {
|
||||
#[test]
|
||||
fn test_rect_transform_anchor_max() {
|
||||
let doc = create_test_rect_transform();
|
||||
let rect_transform = RectTransform::new(&doc).unwrap();
|
||||
let rect_transform = RectTransform::parse(&doc).unwrap();
|
||||
let anchor_max = rect_transform.anchor_max().unwrap();
|
||||
assert_eq!(anchor_max, &Vector2::ONE);
|
||||
}
|
||||
@@ -370,7 +432,7 @@ mod tests {
|
||||
#[test]
|
||||
fn test_rect_transform_size_delta() {
|
||||
let doc = create_test_rect_transform();
|
||||
let rect_transform = RectTransform::new(&doc).unwrap();
|
||||
let rect_transform = RectTransform::parse(&doc).unwrap();
|
||||
let size_delta = rect_transform.size_delta().unwrap();
|
||||
assert_eq!(size_delta.x, 100.0);
|
||||
assert_eq!(size_delta.y, 50.0);
|
||||
@@ -379,7 +441,7 @@ mod tests {
|
||||
#[test]
|
||||
fn test_rect_transform_pivot() {
|
||||
let doc = create_test_rect_transform();
|
||||
let rect_transform = RectTransform::new(&doc).unwrap();
|
||||
let rect_transform = RectTransform::parse(&doc).unwrap();
|
||||
let pivot = rect_transform.pivot().unwrap();
|
||||
assert_eq!(pivot.x, 0.5);
|
||||
assert_eq!(pivot.y, 0.5);
|
||||
@@ -388,7 +450,7 @@ mod tests {
|
||||
#[test]
|
||||
fn test_rect_transform_inherits_from_transform() {
|
||||
let doc = create_test_rect_transform();
|
||||
let rect_transform = RectTransform::new(&doc).unwrap();
|
||||
let rect_transform = RectTransform::parse(&doc).unwrap();
|
||||
|
||||
// Test inherited methods
|
||||
assert!(rect_transform.local_position().is_some());
|
||||
|
||||
Reference in New Issue
Block a user