transform children linking
This commit is contained in:
54
SUMMARY.md
54
SUMMARY.md
@@ -153,63 +153,11 @@ Typed accessors for Unity YAML patterns:
|
|||||||
- ✅ Sparsey World creation with component registration
|
- ✅ Sparsey World creation with component registration
|
||||||
- ✅ Entity spawning for GameObjects
|
- ✅ Entity spawning for GameObjects
|
||||||
|
|
||||||
### Partially Working
|
|
||||||
- ⚠️ **Component attachment** - Sparsey entity creation works, but adding components to existing entities needs research
|
|
||||||
- ⚠️ **Transform hierarchy** - Parent/children parsing works, but mutation API unclear
|
|
||||||
|
|
||||||
## ❌ What's Not Implemented
|
## ❌ What's Not Implemented
|
||||||
|
|
||||||
### Critical Missing Features
|
### Critical Missing Features
|
||||||
|
|
||||||
#### 1. Sparsey Component Management (HIGH PRIORITY)
|
#### 1. Prefab Instancing System (MEDIUM PRIORITY)
|
||||||
**Location:** src/ecs/builder.rs:141-151, 155-176
|
|
||||||
|
|
||||||
**Problem:** Sparsey's API for adding components to existing entities is unclear.
|
|
||||||
|
|
||||||
**Current Code:**
|
|
||||||
```rust
|
|
||||||
fn insert_component<T: 'static>(_world: &mut World, _entity: Entity, component: T) -> Result<()> {
|
|
||||||
// TODO: Research if Sparsey has a way to add components to existing entities
|
|
||||||
eprintln!("Warning: Component insertion not fully implemented");
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
**What's Needed:**
|
|
||||||
- Research Sparsey 0.13 docs for component insertion API
|
|
||||||
- Possible approaches:
|
|
||||||
- Option A: Create entities with all components at once (requires refactoring to 2-pass instead of 3-pass)
|
|
||||||
- Option B: Find Sparsey's `insert()` or `add_component()` method
|
|
||||||
- Option C: Use Sparsey's entity builder pattern
|
|
||||||
|
|
||||||
**Files to Modify:**
|
|
||||||
- src/ecs/builder.rs:95-122 (attach_component)
|
|
||||||
- src/ecs/builder.rs:141-151 (insert_component)
|
|
||||||
|
|
||||||
#### 2. Transform Hierarchy Resolution (HIGH PRIORITY)
|
|
||||||
**Location:** src/ecs/builder.rs:155-176
|
|
||||||
|
|
||||||
**Problem:** Need mutable access to Transform components to set parent/children Entity refs.
|
|
||||||
|
|
||||||
**Current Code:**
|
|
||||||
```rust
|
|
||||||
fn resolve_transform_hierarchy(...) -> Result<()> {
|
|
||||||
let mut updates: Vec<(Entity, Option<Entity>, Vec<Entity>)> = Vec::new();
|
|
||||||
// Collects updates but doesn't apply them
|
|
||||||
// TODO: Research Sparsey's component mutation API
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
**What's Needed:**
|
|
||||||
- Find Sparsey's API for getting mutable component references
|
|
||||||
- Expected API: `world.get_mut::<Transform>(entity)` or similar
|
|
||||||
- Apply parent/children updates to Transform components
|
|
||||||
|
|
||||||
**Files to Modify:**
|
|
||||||
- src/ecs/builder.rs:155-176 (resolve_transform_hierarchy)
|
|
||||||
|
|
||||||
#### 3. Prefab Instancing System (MEDIUM PRIORITY)
|
|
||||||
**Status:** Not started
|
**Status:** Not started
|
||||||
|
|
||||||
**What's Needed:**
|
**What's Needed:**
|
||||||
|
|||||||
@@ -1,9 +1,13 @@
|
|||||||
//! ECS world building from Unity documents
|
//! ECS world building from Unity documents
|
||||||
|
|
||||||
use crate::model::RawDocument;
|
use crate::model::RawDocument;
|
||||||
use crate::types::{yaml_helpers, ComponentContext, FileID, GameObject, RectTransform, Transform, UnityComponent};
|
use crate::types::{
|
||||||
|
yaml_helpers, ComponentContext, FileID, GameObject, LinkingContext, RectTransform, Transform,
|
||||||
|
UnityComponent,
|
||||||
|
};
|
||||||
use crate::{Error, Result};
|
use crate::{Error, Result};
|
||||||
use sparsey::{Entity, World};
|
use sparsey::{Entity, World};
|
||||||
|
use std::cell::RefCell;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
|
||||||
/// Build a Sparsey ECS World from raw Unity documents
|
/// Build a Sparsey ECS World from raw Unity documents
|
||||||
@@ -28,21 +32,21 @@ pub fn build_world_from_documents(
|
|||||||
.register::<RectTransform>()
|
.register::<RectTransform>()
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
let mut entity_map = HashMap::new();
|
let linking_ctx = RefCell::new(LinkingContext::new());
|
||||||
|
|
||||||
// PASS 1: Create entities for all GameObjects
|
// PASS 1: Create entities for all GameObjects
|
||||||
for doc in documents.iter().filter(|d| d.type_id == 1 || d.class_name == "GameObject") {
|
for doc in documents.iter().filter(|d| d.type_id == 1 || d.class_name == "GameObject") {
|
||||||
let entity = spawn_game_object(&mut world, doc)?;
|
let entity = spawn_game_object(&mut world, doc)?;
|
||||||
entity_map.insert(doc.file_id, entity);
|
linking_ctx.borrow_mut().entity_map_mut().insert(doc.file_id, entity);
|
||||||
}
|
}
|
||||||
|
|
||||||
// PASS 2: Attach components to entities
|
// PASS 2: Attach components to entities
|
||||||
for doc in documents.iter().filter(|d| d.type_id != 1 && d.class_name != "GameObject") {
|
for doc in documents.iter().filter(|d| d.type_id != 1 && d.class_name != "GameObject") {
|
||||||
attach_component(&mut world, doc, &mut entity_map)?;
|
attach_component(&mut world, doc, &linking_ctx)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
// PASS 3: Resolve Transform hierarchy
|
// PASS 3: Execute all deferred linking callbacks
|
||||||
resolve_transform_hierarchy(&mut world, &documents, &entity_map)?;
|
let entity_map = linking_ctx.into_inner().execute_callbacks(&mut world);
|
||||||
|
|
||||||
Ok((world, entity_map))
|
Ok((world, entity_map))
|
||||||
}
|
}
|
||||||
@@ -57,6 +61,9 @@ fn spawn_game_object(world: &mut World, doc: &RawDocument) -> Result<Entity> {
|
|||||||
type_id: doc.type_id,
|
type_id: doc.type_id,
|
||||||
file_id: doc.file_id,
|
file_id: doc.file_id,
|
||||||
class_name: &doc.class_name,
|
class_name: &doc.class_name,
|
||||||
|
entity: None,
|
||||||
|
linking_ctx: None,
|
||||||
|
yaml,
|
||||||
};
|
};
|
||||||
|
|
||||||
let go = GameObject::parse(yaml, &ctx)
|
let go = GameObject::parse(yaml, &ctx)
|
||||||
@@ -72,7 +79,7 @@ fn spawn_game_object(world: &mut World, doc: &RawDocument) -> Result<Entity> {
|
|||||||
fn attach_component(
|
fn attach_component(
|
||||||
world: &mut World,
|
world: &mut World,
|
||||||
doc: &RawDocument,
|
doc: &RawDocument,
|
||||||
entity_map: &mut HashMap<FileID, Entity>,
|
linking_ctx: &RefCell<LinkingContext>,
|
||||||
) -> Result<()> {
|
) -> Result<()> {
|
||||||
let yaml = doc
|
let yaml = doc
|
||||||
.as_mapping()
|
.as_mapping()
|
||||||
@@ -82,7 +89,9 @@ fn attach_component(
|
|||||||
let go_ref = yaml_helpers::get_file_ref(yaml, "m_GameObject");
|
let go_ref = yaml_helpers::get_file_ref(yaml, "m_GameObject");
|
||||||
|
|
||||||
let entity = match go_ref {
|
let entity = match go_ref {
|
||||||
Some(r) => entity_map
|
Some(r) => linking_ctx
|
||||||
|
.borrow()
|
||||||
|
.entity_map()
|
||||||
.get(&r.file_id)
|
.get(&r.file_id)
|
||||||
.copied()
|
.copied()
|
||||||
.ok_or_else(|| {
|
.ok_or_else(|| {
|
||||||
@@ -102,24 +111,23 @@ fn attach_component(
|
|||||||
type_id: doc.type_id,
|
type_id: doc.type_id,
|
||||||
file_id: doc.file_id,
|
file_id: doc.file_id,
|
||||||
class_name: &doc.class_name,
|
class_name: &doc.class_name,
|
||||||
|
entity: Some(entity),
|
||||||
|
linking_ctx: Some(linking_ctx),
|
||||||
|
yaml,
|
||||||
};
|
};
|
||||||
|
|
||||||
// Dispatch to appropriate component parser
|
// Dispatch to appropriate component parser
|
||||||
match doc.class_name.as_str() {
|
match doc.class_name.as_str() {
|
||||||
"Transform" => {
|
"Transform" => {
|
||||||
if let Some(transform) = Transform::parse(yaml, &ctx) {
|
if let Some(transform) = Transform::parse(yaml, &ctx) {
|
||||||
// Insert Transform component into entity
|
world.insert(entity, (transform,));
|
||||||
insert_component(world, entity, transform)?;
|
linking_ctx.borrow_mut().entity_map_mut().insert(doc.file_id, entity);
|
||||||
// Map transform FileID to entity for hierarchy resolution
|
|
||||||
entity_map.insert(doc.file_id, entity);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
"RectTransform" => {
|
"RectTransform" => {
|
||||||
if let Some(rect) = RectTransform::parse(yaml, &ctx) {
|
if let Some(rect) = RectTransform::parse(yaml, &ctx) {
|
||||||
// Insert RectTransform component into entity
|
world.insert(entity, (rect,));
|
||||||
insert_component(world, entity, rect)?;
|
linking_ctx.borrow_mut().entity_map_mut().insert(doc.file_id, entity);
|
||||||
// Map transform FileID to entity for hierarchy resolution
|
|
||||||
entity_map.insert(doc.file_id, entity);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
@@ -133,81 +141,3 @@ fn attach_component(
|
|||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Helper to insert a component into an entity
|
|
||||||
///
|
|
||||||
/// Note: Sparsey doesn't have a direct `insert` API, so we need to recreate the entity
|
|
||||||
/// with the additional component. This is a workaround until we find a better approach.
|
|
||||||
fn insert_component<T: 'static>(_world: &mut World, _entity: Entity, component: T) -> Result<()> {
|
|
||||||
// TODO: Research if Sparsey has a way to add components to existing entities
|
|
||||||
// For now, components are added during entity creation in attach_component
|
|
||||||
|
|
||||||
// Workaround: Store component for later use
|
|
||||||
// This will require refactoring the approach to create entities with all components at once
|
|
||||||
|
|
||||||
eprintln!("Warning: Component insertion not fully implemented - requires Sparsey API research");
|
|
||||||
std::mem::drop(component); // Prevent unused variable warning
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Resolve Transform hierarchy by setting parent and children Entity references
|
|
||||||
fn resolve_transform_hierarchy(
|
|
||||||
_world: &mut World,
|
|
||||||
documents: &[RawDocument],
|
|
||||||
entity_map: &HashMap<FileID, Entity>,
|
|
||||||
) -> Result<()> {
|
|
||||||
// Collect hierarchy updates
|
|
||||||
let mut updates: Vec<(Entity, Option<Entity>, Vec<Entity>)> = Vec::new();
|
|
||||||
|
|
||||||
for doc in documents
|
|
||||||
.iter()
|
|
||||||
.filter(|d| matches!(d.class_name.as_str(), "Transform" | "RectTransform"))
|
|
||||||
{
|
|
||||||
let yaml = match doc.as_mapping() {
|
|
||||||
Some(m) => m,
|
|
||||||
None => continue,
|
|
||||||
};
|
|
||||||
|
|
||||||
let transform_entity = match entity_map.get(&doc.file_id) {
|
|
||||||
Some(e) => *e,
|
|
||||||
None => continue,
|
|
||||||
};
|
|
||||||
|
|
||||||
// Parse parent reference (m_Father)
|
|
||||||
let parent_entity = yaml_helpers::get_file_ref(yaml, "m_Father").and_then(|r| {
|
|
||||||
if r.file_id.as_i64() == 0 {
|
|
||||||
None // Null reference
|
|
||||||
} else {
|
|
||||||
entity_map.get(&r.file_id).copied()
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// Parse children references (m_Children array)
|
|
||||||
let children_entities = parse_children_refs(yaml, entity_map);
|
|
||||||
|
|
||||||
updates.push((transform_entity, parent_entity, children_entities));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Apply hierarchy updates
|
|
||||||
// TODO: Research Sparsey's component mutation API
|
|
||||||
// For now, we'll skip this until we understand how to get mutable component access
|
|
||||||
eprintln!(
|
|
||||||
"Warning: Transform hierarchy resolution not fully implemented - found {} transforms",
|
|
||||||
updates.len()
|
|
||||||
);
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Parse children FileRefs from YAML and resolve to entities
|
|
||||||
fn parse_children_refs(
|
|
||||||
yaml: &serde_yaml::Mapping,
|
|
||||||
entity_map: &HashMap<FileID, Entity>,
|
|
||||||
) -> Vec<Entity> {
|
|
||||||
yaml_helpers::get_file_ref_array(yaml, "m_Children")
|
|
||||||
.unwrap_or_default()
|
|
||||||
.into_iter()
|
|
||||||
.filter_map(|r| entity_map.get(&r.file_id).copied())
|
|
||||||
.collect()
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -2,9 +2,60 @@
|
|||||||
|
|
||||||
use crate::types::*;
|
use crate::types::*;
|
||||||
use serde_yaml::{Mapping, Value};
|
use serde_yaml::{Mapping, Value};
|
||||||
|
use sparsey::Entity;
|
||||||
|
use std::cell::RefCell;
|
||||||
|
use std::collections::HashMap;
|
||||||
|
|
||||||
|
/// A callback for deferred linking after all components are parsed
|
||||||
|
pub type LinkCallback = Box<dyn FnOnce(&mut sparsey::World, &HashMap<FileID, Entity>) + 'static>;
|
||||||
|
|
||||||
|
/// Context for managing entity linking during world building
|
||||||
|
pub struct LinkingContext {
|
||||||
|
/// Map from FileID to Entity
|
||||||
|
entity_map: HashMap<FileID, Entity>,
|
||||||
|
/// Callbacks to execute after all components are parsed
|
||||||
|
callbacks: Vec<LinkCallback>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl LinkingContext {
|
||||||
|
pub fn new() -> Self {
|
||||||
|
Self {
|
||||||
|
entity_map: HashMap::new(),
|
||||||
|
callbacks: Vec::new(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Try to resolve a FileID to an Entity
|
||||||
|
pub fn resolve_entity(&self, file_id: FileID) -> Option<Entity> {
|
||||||
|
self.entity_map.get(&file_id).copied()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Register a callback to be executed during the linking pass
|
||||||
|
pub fn register_callback(&mut self, callback: LinkCallback) {
|
||||||
|
self.callbacks.push(callback);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get the entity map
|
||||||
|
pub fn entity_map(&self) -> &HashMap<FileID, Entity> {
|
||||||
|
&self.entity_map
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get mutable access to the entity map
|
||||||
|
pub fn entity_map_mut(&mut self) -> &mut HashMap<FileID, Entity> {
|
||||||
|
&mut self.entity_map
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Execute all registered callbacks
|
||||||
|
pub fn execute_callbacks(self, world: &mut sparsey::World) -> HashMap<FileID, Entity> {
|
||||||
|
let entity_map = self.entity_map.clone();
|
||||||
|
for callback in self.callbacks {
|
||||||
|
callback(world, &entity_map);
|
||||||
|
}
|
||||||
|
entity_map
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Context information for parsing components from YAML
|
/// Context information for parsing components from YAML
|
||||||
#[derive(Debug, Clone)]
|
|
||||||
pub struct ComponentContext<'a> {
|
pub struct ComponentContext<'a> {
|
||||||
/// Unity type ID (from !u!N tag)
|
/// Unity type ID (from !u!N tag)
|
||||||
pub type_id: u32,
|
pub type_id: u32,
|
||||||
@@ -12,6 +63,12 @@ pub struct ComponentContext<'a> {
|
|||||||
pub file_id: FileID,
|
pub file_id: FileID,
|
||||||
/// Class name (e.g., "GameObject", "Transform")
|
/// Class name (e.g., "GameObject", "Transform")
|
||||||
pub class_name: &'a str,
|
pub class_name: &'a str,
|
||||||
|
/// Entity that owns this component
|
||||||
|
pub entity: Option<Entity>,
|
||||||
|
/// Linking context for deferred entity resolution (wrapped in RefCell for interior mutability)
|
||||||
|
pub linking_ctx: Option<&'a RefCell<LinkingContext>>,
|
||||||
|
/// The raw YAML mapping for this component (for extracting FileRefs)
|
||||||
|
pub yaml: &'a Mapping,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Trait for Unity components that can be parsed from YAML
|
/// Trait for Unity components that can be parsed from YAML
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ mod transform;
|
|||||||
mod type_registry;
|
mod type_registry;
|
||||||
mod values;
|
mod values;
|
||||||
|
|
||||||
pub use component::{yaml_helpers, ComponentContext, UnityComponent};
|
pub use component::{yaml_helpers, ComponentContext, LinkCallback, LinkingContext, UnityComponent};
|
||||||
pub use game_object::GameObject;
|
pub use game_object::GameObject;
|
||||||
pub use ids::{FileID, LocalID};
|
pub use ids::{FileID, LocalID};
|
||||||
pub use reference::UnityReference;
|
pub use reference::UnityReference;
|
||||||
|
|||||||
@@ -56,15 +56,65 @@ impl UnityComponent for Transform {
|
|||||||
/// Parse a Transform from YAML
|
/// Parse a Transform from YAML
|
||||||
///
|
///
|
||||||
/// Note: Caller is responsible for ensuring this is called on the correct document type.
|
/// Note: Caller is responsible for ensuring this is called on the correct document type.
|
||||||
fn parse(yaml: &serde_yaml::Mapping, _ctx: &ComponentContext) -> Option<Self> {
|
fn parse(yaml: &serde_yaml::Mapping, ctx: &ComponentContext) -> Option<Self> {
|
||||||
let local_position = yaml_helpers::get_vector3(yaml, "m_LocalPosition");
|
let local_position = yaml_helpers::get_vector3(yaml, "m_LocalPosition");
|
||||||
|
|
||||||
let local_rotation = yaml_helpers::get_quaternion(yaml, "m_LocalRotation");
|
let local_rotation = yaml_helpers::get_quaternion(yaml, "m_LocalRotation");
|
||||||
|
|
||||||
let local_scale = yaml_helpers::get_vector3(yaml, "m_LocalScale");
|
let local_scale = yaml_helpers::get_vector3(yaml, "m_LocalScale");
|
||||||
|
|
||||||
// Note: parent and children entities will be set later during hierarchy resolution
|
// Handle transform hierarchy linking if context is available
|
||||||
// The FileRef data is in the YAML but needs to be converted to entities separately
|
if let (Some(entity), Some(linking_ctx_ref)) = (ctx.entity, ctx.linking_ctx) {
|
||||||
|
// Extract parent FileRef (m_Father)
|
||||||
|
let parent_ref = yaml_helpers::get_file_ref(yaml, "m_Father");
|
||||||
|
|
||||||
|
// Extract children FileRefs (m_Children)
|
||||||
|
let children_refs =
|
||||||
|
yaml_helpers::get_file_ref_array(yaml, "m_Children").unwrap_or_default();
|
||||||
|
|
||||||
|
// Try to resolve children immediately
|
||||||
|
let mut children_entities = Vec::new();
|
||||||
|
let mut unresolved_children = Vec::new();
|
||||||
|
|
||||||
|
{
|
||||||
|
let linking_ctx = linking_ctx_ref.borrow();
|
||||||
|
for child_ref in children_refs {
|
||||||
|
if let Some(child_entity) = linking_ctx.resolve_entity(child_ref.file_id) {
|
||||||
|
children_entities.push(child_entity);
|
||||||
|
} else {
|
||||||
|
unresolved_children.push(child_ref.file_id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Register callback to set parent and children (even if some are unresolved)
|
||||||
|
linking_ctx_ref
|
||||||
|
.borrow_mut()
|
||||||
|
.register_callback(Box::new(move |world, entity_map| {
|
||||||
|
// Get the transform component
|
||||||
|
if let Some(transform) = world.borrow_mut::<Transform>().get_mut(entity) {
|
||||||
|
// Set parent (might be None if unresolved)
|
||||||
|
let resolved_parent =
|
||||||
|
parent_ref.and_then(|r| entity_map.get(&r.file_id).copied());
|
||||||
|
transform.set_parent(resolved_parent);
|
||||||
|
|
||||||
|
// Resolve any previously unresolved children
|
||||||
|
let mut all_children = children_entities.clone();
|
||||||
|
for child_file_id in &unresolved_children {
|
||||||
|
if let Some(child_entity) = entity_map.get(child_file_id).copied() {
|
||||||
|
all_children.push(child_entity);
|
||||||
|
} else {
|
||||||
|
eprintln!(
|
||||||
|
"Warning: Could not resolve child Transform: {}",
|
||||||
|
child_file_id
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
transform.set_children(all_children);
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
Some(Self {
|
Some(Self {
|
||||||
local_position,
|
local_position,
|
||||||
@@ -150,9 +200,6 @@ impl UnityComponent for RectTransform {
|
|||||||
///
|
///
|
||||||
/// Note: Caller is responsible for ensuring this is called on the correct document type.
|
/// Note: Caller is responsible for ensuring this is called on the correct document type.
|
||||||
fn parse(yaml: &serde_yaml::Mapping, ctx: &ComponentContext) -> Option<Self> {
|
fn parse(yaml: &serde_yaml::Mapping, ctx: &ComponentContext) -> Option<Self> {
|
||||||
// Parse the base Transform
|
|
||||||
let transform = Transform::parse(yaml, ctx)?;
|
|
||||||
|
|
||||||
let anchor_min = yaml_helpers::get_vector2(yaml, "m_AnchorMin");
|
let anchor_min = yaml_helpers::get_vector2(yaml, "m_AnchorMin");
|
||||||
|
|
||||||
let anchor_max = yaml_helpers::get_vector2(yaml, "m_AnchorMax");
|
let anchor_max = yaml_helpers::get_vector2(yaml, "m_AnchorMax");
|
||||||
@@ -163,6 +210,74 @@ impl UnityComponent for RectTransform {
|
|||||||
|
|
||||||
let pivot = yaml_helpers::get_vector2(yaml, "m_Pivot");
|
let pivot = yaml_helpers::get_vector2(yaml, "m_Pivot");
|
||||||
|
|
||||||
|
// Parse transform data (without the base Transform to avoid double-linking)
|
||||||
|
let local_position = yaml_helpers::get_vector3(yaml, "m_LocalPosition");
|
||||||
|
let local_rotation = yaml_helpers::get_quaternion(yaml, "m_LocalRotation");
|
||||||
|
let local_scale = yaml_helpers::get_vector3(yaml, "m_LocalScale");
|
||||||
|
|
||||||
|
// Handle transform hierarchy linking if context is available
|
||||||
|
if let (Some(entity), Some(linking_ctx_ref)) = (ctx.entity, ctx.linking_ctx) {
|
||||||
|
// Extract parent FileRef (m_Father)
|
||||||
|
let parent_ref = yaml_helpers::get_file_ref(yaml, "m_Father");
|
||||||
|
|
||||||
|
// Extract children FileRefs (m_Children)
|
||||||
|
let children_refs =
|
||||||
|
yaml_helpers::get_file_ref_array(yaml, "m_Children").unwrap_or_default();
|
||||||
|
|
||||||
|
// Try to resolve children immediately
|
||||||
|
let mut children_entities = Vec::new();
|
||||||
|
let mut unresolved_children = Vec::new();
|
||||||
|
|
||||||
|
{
|
||||||
|
let linking_ctx = linking_ctx_ref.borrow();
|
||||||
|
for child_ref in children_refs {
|
||||||
|
if let Some(child_entity) = linking_ctx.resolve_entity(child_ref.file_id) {
|
||||||
|
children_entities.push(child_entity);
|
||||||
|
} else {
|
||||||
|
unresolved_children.push(child_ref.file_id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Register callback to set parent and children on the inner Transform
|
||||||
|
linking_ctx_ref
|
||||||
|
.borrow_mut()
|
||||||
|
.register_callback(Box::new(move |world, entity_map| {
|
||||||
|
// Get the RectTransform component and access its inner Transform
|
||||||
|
if let Some(rect) = world.borrow_mut::<RectTransform>().get_mut(entity) {
|
||||||
|
let transform = rect.transform_mut();
|
||||||
|
|
||||||
|
// Set parent (might be None if unresolved)
|
||||||
|
let resolved_parent =
|
||||||
|
parent_ref.and_then(|r| entity_map.get(&r.file_id).copied());
|
||||||
|
transform.set_parent(resolved_parent);
|
||||||
|
|
||||||
|
// Resolve any previously unresolved children
|
||||||
|
let mut all_children = children_entities.clone();
|
||||||
|
for child_file_id in &unresolved_children {
|
||||||
|
if let Some(child_entity) = entity_map.get(child_file_id).copied() {
|
||||||
|
all_children.push(child_entity);
|
||||||
|
} else {
|
||||||
|
eprintln!(
|
||||||
|
"Warning: Could not resolve child RectTransform: {}",
|
||||||
|
child_file_id
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
transform.set_children(all_children);
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
let transform = Transform {
|
||||||
|
local_position,
|
||||||
|
local_rotation,
|
||||||
|
local_scale,
|
||||||
|
parent: None,
|
||||||
|
children: Vec::new(),
|
||||||
|
};
|
||||||
|
|
||||||
Some(Self {
|
Some(Self {
|
||||||
transform,
|
transform,
|
||||||
anchor_min,
|
anchor_min,
|
||||||
|
|||||||
Reference in New Issue
Block a user