feat: impl proper entity handles

Signed-off-by: Schmarni <marnistromer@gmail.com>
This commit is contained in:
Schmarni
2025-10-28 23:02:24 +01:00
parent ec468b6752
commit 65c426f981
6 changed files with 59 additions and 38 deletions

View File

@@ -1,3 +1,6 @@
use std::ops::Deref;
use std::sync::Arc;
use bevy::prelude::*; use bevy::prelude::*;
use super::bevy_channel::{BevyChannel, BevyChannelReader}; use super::bevy_channel::{BevyChannel, BevyChannelReader};
@@ -16,16 +19,28 @@ fn despawn(mut cmds: Commands, mut reader: ResMut<BevyChannelReader<Entity>>) {
} }
} }
#[derive(Debug, Hash, PartialEq, Eq, PartialOrd, Ord, Clone)]
pub struct EntityHandle(Arc<EntityHandleInner>);
impl EntityHandle {
pub fn get(&self) -> Entity {
self.0.0
}
pub fn new(entity: Entity) -> Self {
Self(EntityHandleInner(entity).into())
}
}
impl Deref for EntityHandle {
type Target = Entity;
fn deref(&self) -> &Self::Target {
&self.0.0
}
}
static DESTROY: BevyChannel<Entity> = BevyChannel::new(); static DESTROY: BevyChannel<Entity> = BevyChannel::new();
#[derive(Deref, DerefMut, Debug, Hash, PartialEq, Eq, PartialOrd, Ord)] #[derive(Debug, Hash, PartialEq, Eq, PartialOrd, Ord)]
pub struct EntityHandle(pub Entity); pub struct EntityHandleInner(Entity);
impl Drop for EntityHandle { impl Drop for EntityHandleInner {
fn drop(&mut self) { fn drop(&mut self) {
DESTROY.send(self.0); DESTROY.send(self.0);
} }
} }
impl From<Entity> for EntityHandle {
fn from(value: Entity) -> Self {
Self(value)
}
}

View File

@@ -73,10 +73,11 @@ fn update_sound_event(
}, },
)) ))
.id(); .id();
sound.spatial.set_entity(entity); let entity = EntityHandle::new(entity);
sound.entity.set(entity.into()).unwrap(); sound.spatial.set_entity(entity.clone());
sound.entity.set(entity).unwrap();
} }
if let Some(sink) = sound.entity.get().and_then(|e| sinks.get(e.0).ok()) { if let Some(sink) = sound.entity.get().and_then(|e| sinks.get(e.get()).ok()) {
if sound.play.lock().take().is_some() { if sound.play.lock().take().is_some() {
sink.play(); sink.play();
} }

View File

@@ -257,7 +257,7 @@ fn build_line_mesh(
extension: LineExtension {}, extension: LineExtension {},
})), })),
)); ));
_ = lines.entity.set(e.id().into()); _ = lines.entity.set(EntityHandle::new(e.id()));
e e
} }
}; };

View File

@@ -107,7 +107,10 @@ fn load_models(
Visibility::Hidden, Visibility::Hidden,
)) ))
.id(); .id();
model.bevy_scene_entity.set(entity.into()).unwrap(); model
.bevy_scene_entity
.set(EntityHandle::new(entity))
.unwrap();
} }
} }
@@ -144,7 +147,7 @@ fn apply_materials(
for (param_name, param) in model_part.pending_material_parameters.lock().drain() { for (param_name, param) in model_part.pending_material_parameters.lock().drain() {
let mut new_mat = materials.get(&mesh_mat.0).unwrap().clone(); let mut new_mat = materials.get(&mesh_mat.0).unwrap().clone();
param.apply_to_material( param.apply_to_material(
&model_part.space.node().unwrap().get_client().unwrap(), &model_part.spatial.node().unwrap().get_client().unwrap(),
&mut new_mat, &mut new_mat,
&param_name, &param_name,
&asset_server, &asset_server,
@@ -193,7 +196,7 @@ fn gen_model_parts(
.unwrap_or_else(|| name.to_string()); .unwrap_or_else(|| name.to_string());
let parent_spatial = parent let parent_spatial = parent
.as_ref() .as_ref()
.map(|p| p.space.clone()) .map(|p| p.spatial.clone())
.unwrap_or_else(|| model.spatial.clone()); .unwrap_or_else(|| model.spatial.clone());
let client = model.spatial.node()?.get_client()?; let client = model.spatial.node()?.get_client()?;
let (spatial, model_part) = let (spatial, model_part) =
@@ -211,8 +214,7 @@ fn gen_model_parts(
entity: OnceLock::new(), entity: OnceLock::new(),
mesh_entity: OnceLock::new(), mesh_entity: OnceLock::new(),
path, path,
space: spatial.clone(), spatial: spatial.clone(),
_model: Arc::downgrade(&model),
pending_material_parameters: Mutex::default(), pending_material_parameters: Mutex::default(),
pending_material_replacement: Mutex::default(), pending_material_replacement: Mutex::default(),
holdout: AtomicBool::new(false), holdout: AtomicBool::new(false),
@@ -222,8 +224,8 @@ fn gen_model_parts(
(spatial, model_part) (spatial, model_part)
} }
Some(part) => { Some(part) => {
part.space.set_spatial_parent(&parent_spatial).unwrap(); part.spatial.set_spatial_parent(&parent_spatial).unwrap();
(part.space.clone(), part.clone()) (part.spatial.clone(), part.clone())
} }
}; };
let aabb = Aabb::enclosing( let aabb = Aabb::enclosing(
@@ -247,8 +249,8 @@ fn gen_model_parts(
}); });
let _ = spatial.set_spatial_parent(&parent_spatial); let _ = spatial.set_spatial_parent(&parent_spatial);
spatial.set_local_transform(transform.compute_matrix()); spatial.set_local_transform(transform.compute_matrix());
let entity_handle = EntityHandle::new(entity);
spatial.set_entity(entity); spatial.set_entity(entity_handle.clone());
cmds.entity(entity) cmds.entity(entity)
.insert(SpatialNode(Arc::downgrade(&spatial))); .insert(SpatialNode(Arc::downgrade(&spatial)));
let mesh_entity = children_query let mesh_entity = children_query
@@ -257,17 +259,18 @@ fn gen_model_parts(
.flat_map(|v| v.iter()) .flat_map(|v| v.iter())
.find(|e| has_mesh.get(*e).unwrap_or(false))?; .find(|e| has_mesh.get(*e).unwrap_or(false))?;
_ = model_part.bounds.set(aabb); _ = model_part.bounds.set(aabb);
_ = model_part.entity.set(entity.into()); _ = model_part.entity.set(entity_handle);
_ = model_part.mesh_entity.set(mesh_entity.into()); _ = model_part.mesh_entity.set(EntityHandle::new(mesh_entity));
parts.push(model_part.clone()); parts.push(model_part.clone());
Some(model_part) Some(model_part)
}, },
); );
} }
_ = model.parts.set(parts); _ = model.parts.set(parts);
model.pre_bound_parts.lock().clear();
model model
.spatial .spatial
.set_entity(model.bevy_scene_entity.get().unwrap().0); .set_entity(model.bevy_scene_entity.get().unwrap().clone());
} }
} }
@@ -324,8 +327,6 @@ impl HashedPbrMaterial {
mat.emissive_texture.hash(state); mat.emissive_texture.hash(state);
mat.metallic_roughness_texture.hash(state); mat.metallic_roughness_texture.hash(state);
mat.occlusion_texture.hash(state); mat.occlusion_texture.hash(state);
// should always be the same, TODO: make the spherical harmonics buffer a per mesh instance thing
// mat.spherical_harmonics.hash(state);
} }
} }
fn hash_color<H: Hasher>(color: Color, state: &mut H) { fn hash_color<H: Hasher>(color: Color, state: &mut H) {
@@ -463,8 +464,7 @@ pub struct ModelPart {
entity: OnceLock<EntityHandle>, entity: OnceLock<EntityHandle>,
mesh_entity: OnceLock<EntityHandle>, mesh_entity: OnceLock<EntityHandle>,
path: String, path: String,
space: Arc<Spatial>, spatial: Arc<Spatial>,
_model: Weak<Model>,
pending_material_parameters: Mutex<FxHashMap<String, MaterialParameter>>, pending_material_parameters: Mutex<FxHashMap<String, MaterialParameter>>,
pending_material_replacement: Mutex<Option<Handle<BevyMaterial>>>, pending_material_replacement: Mutex<Option<Handle<BevyMaterial>>>,
holdout: AtomicBool, holdout: AtomicBool,
@@ -591,8 +591,7 @@ impl Model {
entity: OnceLock::new(), entity: OnceLock::new(),
mesh_entity: OnceLock::new(), mesh_entity: OnceLock::new(),
path: part_path, path: part_path,
space: spatial, spatial,
_model: Arc::downgrade(self),
pending_material_parameters: Mutex::default(), pending_material_parameters: Mutex::default(),
pending_material_replacement: Mutex::default(), pending_material_replacement: Mutex::default(),
holdout: AtomicBool::new(false), holdout: AtomicBool::new(false),
@@ -617,7 +616,7 @@ impl ModelAspect for Model {
let model = node.get_aspect::<Model>()?; let model = node.get_aspect::<Model>()?;
let part = model.get_model_part(part_path)?; let part = model.get_model_part(part_path)?;
Alias::create_with_id( Alias::create_with_id(
&part.space.node().unwrap(), &part.spatial.node().unwrap(),
&calling_client, &calling_client,
id, id,
MODEL_PART_ASPECT_ALIAS_INFO.clone(), MODEL_PART_ASPECT_ALIAS_INFO.clone(),
@@ -628,6 +627,11 @@ impl ModelAspect for Model {
} }
impl Drop for Model { impl Drop for Model {
fn drop(&mut self) { fn drop(&mut self) {
for p in self.parts.get().unwrap().iter() {
if let Some(node) = p.spatial.node() {
node.destroy();
}
}
MODEL_REGISTRY.remove(self); MODEL_REGISTRY.remove(self);
} }
} }

View File

@@ -152,7 +152,8 @@ fn spawn_text(
)) ))
.add_children(&letters) .add_children(&letters)
.id(); .id();
text.entity.lock().replace(EntityHandle(entity)); let entity = EntityHandle::new(entity);
text.entity.lock().replace(entity.clone());
text.spatial.set_entity(entity); text.spatial.set_entity(entity);
} }
} }

View File

@@ -49,7 +49,7 @@ fn spawn_spatial_nodes(mut cmds: Commands) {
let entity = cmds let entity = cmds
.spawn((SpatialNode(Arc::downgrade(&spatial)), Name::new("Spatial"))) .spawn((SpatialNode(Arc::downgrade(&spatial)), Name::new("Spatial")))
.id(); .id();
spatial.set_entity(entity); spatial.set_entity(EntityHandle::new(entity));
} }
} }
@@ -160,15 +160,15 @@ impl Spatial {
spatial.mark_dirty(); spatial.mark_dirty();
spatial spatial
} }
pub fn set_entity(&self, entity: Entity) { pub fn set_entity(&self, entity: EntityHandle) {
self.entity.write().replace(entity.into()); self.entity.write().replace(entity);
self.mark_dirty(); self.mark_dirty();
for child in self.children.get_valid_contents() { for child in self.children.get_valid_contents() {
child.mark_dirty(); child.mark_dirty();
} }
} }
pub fn get_entity(&self) -> Option<Entity> { pub fn get_entity(&self) -> Option<Entity> {
self.entity.read().as_ref().map(|v| v.0) self.entity.read().as_ref().map(|v| v.get())
} }
pub fn add_to( pub fn add_to(
node: &Arc<Node>, node: &Arc<Node>,
@@ -222,7 +222,7 @@ impl Spatial {
bounds bounds
} }
pub(super) fn mark_dirty(&self) { pub(super) fn mark_dirty(&self) {
let Some(entity) = self.entity.read().as_ref().map(|v| v.0) else { let Some(entity) = self.entity.read().as_ref().map(|v| v.get()) else {
return; return;
}; };
let enabled = self let enabled = self
@@ -232,7 +232,7 @@ impl Spatial {
let transform = enabled.then(|| BevyTransform::from_matrix(self.local_transform())); let transform = enabled.then(|| BevyTransform::from_matrix(self.local_transform()));
let parent = self let parent = self
.get_parent() .get_parent()
.and_then(|v| v.entity.read().as_ref().map(|v| v.0)); .and_then(|v| v.entity.read().as_ref().map(|v| v.get()));
UPDATED_SPATIALS_NODES UPDATED_SPATIALS_NODES
.lock() .lock()
.insert(entity, (transform, parent)); .insert(entity, (transform, parent));