prefab spawning bugfix

This commit is contained in:
2026-01-05 12:23:09 +00:00
parent dea28f5b9c
commit 0f2cb68fa4
9 changed files with 91 additions and 833 deletions

View File

@@ -1,19 +0,0 @@
Cursebreaker Resources - 10_3.unity Scene
======================================================================
Total resources found: 2
----------------------------------------------------------------------
Resource: HarvestableSpawner_11Redberries
TypeID: 11
MaxHealth: 0
Position: (1769.135864, 32.664658, 150.395081)
Resource: HarvestableSpawner_38Dandelions
TypeID: 38
MaxHealth: 0
Position: (1746.709717, 44.599632, 299.696503)
======================================================================
End of resource data

View File

@@ -161,6 +161,8 @@ pub fn build_world_from_documents(
// PASS 3: Execute all deferred linking callbacks
let entity_map = linking_ctx.into_inner().execute_callbacks(&mut world);
info!("DEBUG (build_world_from_documents): Final scene entity_map size: {}", entity_map.len());
Ok((world, entity_map))
}
@@ -312,9 +314,14 @@ pub fn build_world_from_documents_into(
// PASS 3: Execute all deferred linking callbacks
let final_entity_map = linking_ctx.into_inner().execute_callbacks(world);
info!("DEBUG (build_world_from_documents_into): Spawned {} entities", spawned_entities.len());
info!("DEBUG (build_world_from_documents_into): final_entity_map size: {}, entity_map size before extend: {}", final_entity_map.len(), entity_map.len());
// Update caller's entity_map with new mappings
entity_map.extend(final_entity_map);
info!("DEBUG (build_world_from_documents_into): entity_map size after extend: {}", entity_map.len());
Ok(spawned_entities)
}
@@ -359,14 +366,30 @@ fn attach_component(
let go_ref = yaml_helpers::get_file_ref(yaml, "m_GameObject");
let entity = match go_ref {
Some(r) => linking_ctx
.borrow()
.entity_map()
.get(&r.file_id)
.copied()
.ok_or_else(|| {
Error::reference_error(format!("Unknown GameObject: {}", r.file_id))
})?,
Some(r) => {
let entity_opt = linking_ctx
.borrow()
.entity_map()
.get(&r.file_id)
.copied();
match entity_opt {
Some(e) => {
// Debug logging for Interactable_Resource MonoBehaviours
if doc.class_name == "MonoBehaviour" {
if let Some(script_ref) = yaml_helpers::get_external_ref(yaml, "m_Script") {
if script_ref.guid.as_str() == "d39ddbf1c2c3d1a4baa070e5e76548bd" {
info!("DEBUG: Found GameObject entity {:?} for Interactable_Resource MonoBehaviour (FileID: {})", e, doc.file_id);
}
}
}
e
}
None => {
return Err(Error::reference_error(format!("Unknown GameObject: {}", r.file_id)));
}
}
}
None => {
// Some components might not have m_GameObject (e.g., standalone assets)
warn!(
@@ -424,6 +447,11 @@ fn attach_component(
if let Some(script_ref) = yaml_helpers::get_external_ref(yaml, "m_Script") {
// Resolve GUID to class name
if let Some(class_name) = resolver.resolve_class_name(script_ref.guid.as_str()) {
// Debug logging for specific GUID
if script_ref.guid.as_str() == "d39ddbf1c2c3d1a4baa070e5e76548bd" {
info!("DEBUG: Found Interactable_Resource GUID! Resolved to class name: {}", class_name);
}
// Try to find a registered custom component with this class name
let mut found_custom = false;
for reg in inventory::iter::<crate::types::ComponentRegistration> {
@@ -433,6 +461,7 @@ fn attach_component(
if (reg.parse_and_insert)(yaml, &ctx, world, entity) {
// Successfully parsed and inserted
linking_ctx.borrow_mut().entity_map_mut().insert(doc.file_id, entity);
info!("DEBUG: Successfully inserted component: {}", class_name);
}
break;
}

View File

@@ -136,12 +136,12 @@ impl UnityPrefab {
///
/// # Example
/// ```ignore
/// let mut instance = prefab.instantiate();
/// let mut instance = prefab.instantiate(None);
/// instance.override_value(file_id, "m_Name", "Player1".into())?;
/// let entities = instance.spawn_into(&mut world, &mut entity_map)?;
/// ```
pub fn instantiate(&self) -> crate::types::PrefabInstance {
crate::types::PrefabInstance::new(self)
pub fn instantiate(&self, file_id_counter: Option<std::sync::Arc<std::cell::Cell<i64>>>) -> crate::types::PrefabInstance {
crate::types::PrefabInstance::new(self, file_id_counter)
}
}

View File

@@ -8,6 +8,7 @@ use sparsey::{Entity, World};
use std::collections::HashMap;
use std::path::PathBuf;
use std::sync::Arc;
use std::cell::Cell;
/// An instance of a Unity prefab ready for spawning into a scene
///
@@ -20,7 +21,7 @@ use std::sync::Arc;
/// # Example
/// ```ignore
/// let prefab = /* load UnityPrefab */;
/// let mut instance = prefab.instantiate();
/// let mut instance = prefab.instantiate(None);
/// instance.override_value(file_id, "m_Name", "Player1".into())?;
/// instance.override_value(file_id, "m_LocalPosition.x", 100.0.into())?;
/// let entities = instance.spawn_into(&mut world, &mut entity_map)?;
@@ -40,7 +41,8 @@ pub struct PrefabInstance {
/// Sequential counter for generating new FileIDs
/// Starts at i64::MAX and decrements to avoid collisions with scene FileIDs
next_file_id: i64,
/// NOTE: This should be shared across all instances via a reference
next_file_id: Arc<std::cell::Cell<i64>>,
/// Source prefab path for debugging
source_path: PathBuf,
@@ -50,15 +52,22 @@ impl PrefabInstance {
/// Create a new instance from a Unity prefab
///
/// This clones all documents from the prefab and initializes FileID remapping.
pub fn new(prefab: &UnityPrefab) -> Self {
///
/// # Arguments
/// * `prefab` - The prefab to instantiate
/// * `file_id_counter` - Optional shared FileID counter to ensure uniqueness across instances
pub fn new(prefab: &UnityPrefab, file_id_counter: Option<Arc<Cell<i64>>>) -> Self {
// Clone all documents from the prefab
let documents = prefab.documents.clone();
// Use provided counter or create a new one starting at i64::MAX
let next_file_id = file_id_counter.unwrap_or_else(|| Arc::new(Cell::new(i64::MAX)));
let mut instance = Self {
documents,
file_id_map: HashMap::new(),
overrides: HashMap::new(),
next_file_id: i64::MAX,
next_file_id,
source_path: prefab.path.clone(),
};
@@ -73,9 +82,9 @@ impl PrefabInstance {
///
/// Uses a sequential counter starting from i64::MAX and decrementing.
/// This avoids collisions with typical scene FileIDs which are positive.
fn generate_file_id(&mut self) -> FileID {
let id = self.next_file_id;
self.next_file_id -= 1;
fn generate_file_id(&self) -> FileID {
let id = self.next_file_id.get();
self.next_file_id.set(id - 1);
FileID::from_i64(id)
}
@@ -449,6 +458,9 @@ pub struct PrefabResolver<'a> {
/// Prefab GUID resolver for nested prefabs
prefab_guid_resolver: Option<&'a crate::parser::PrefabGuidResolver>,
/// Shared FileID counter to ensure uniqueness across all prefab instances
file_id_counter: Arc<Cell<i64>>,
}
impl<'a> PrefabResolver<'a> {
@@ -463,6 +475,7 @@ impl<'a> PrefabResolver<'a> {
instantiation_stack: Vec::new(),
guid_resolver: None,
prefab_guid_resolver: None,
file_id_counter: Arc::new(Cell::new(i64::MAX)),
}
}
@@ -490,6 +503,7 @@ impl<'a> PrefabResolver<'a> {
instantiation_stack: Vec::new(),
guid_resolver,
prefab_guid_resolver: Some(prefab_guid_resolver),
file_id_counter: Arc::new(Cell::new(i64::MAX)),
}
}
@@ -524,8 +538,8 @@ impl<'a> PrefabResolver<'a> {
// 2. Load prefab via load_prefab()
let prefab = self.load_prefab(guid)?;
// 3. Create PrefabInstance
let mut instance = prefab.instantiate();
// 3. Create PrefabInstance with shared FileID counter
let mut instance = prefab.instantiate(Some(self.file_id_counter.clone()));
// 4. Apply component.modifications using override_value()
for modification in &component.modifications {
@@ -605,8 +619,8 @@ impl<'a> PrefabResolver<'a> {
// Push to stack
self.instantiation_stack.push(prefab_id.clone());
// Create instance
let instance = prefab.instantiate();
// Create instance with shared FileID counter
let instance = prefab.instantiate(Some(self.file_id_counter.clone()));
// Find nested prefab references
let nested_prefabs = self.find_nested_prefabs(&instance)?;
@@ -617,8 +631,8 @@ impl<'a> PrefabResolver<'a> {
for (_parent_file_id, nested_component) in nested_prefabs {
// Load the referenced prefab
if let Ok(nested_prefab) = self.load_prefab(&nested_component.prefab_ref.guid) {
// Apply modifications
let mut nested_instance = nested_prefab.instantiate();
// Apply modifications with shared FileID counter
let mut nested_instance = nested_prefab.instantiate(Some(self.file_id_counter.clone()));
for modification in &nested_component.modifications {
nested_instance.override_value(
modification.target_file_id,