fix(ecs): entity deletion is now type correct

This commit is contained in:
lisk77 2025-11-25 23:28:42 +01:00
parent 607bf94f1e
commit 2a37205c22
4 changed files with 77 additions and 3 deletions

View file

@ -112,9 +112,7 @@ impl Scene {
self.remove_entity_from_archetype(entity_id.index, self.get_component_set(idx)); self.remove_entity_from_archetype(entity_id.index, self.get_component_set(idx));
self.entities[idx] = None; self.entities[idx] = None;
info!("Deleted entity! ID: {}", entity_id.index); info!("Deleted entity! ID: {}", entity_id.index);
for (_, value) in self.components.iter_mut() { self.components.remove_entity(idx);
value.remove::<u8>(idx);
}
if let Some(gen) = self.generations.get_mut(idx) { if let Some(gen) = self.generations.get_mut(idx) {
*gen = gen.wrapping_add(1); *gen = gen.wrapping_add(1);
} }

View file

@ -272,6 +272,17 @@ impl Column {
} }
} }
/// Remove an element without knowing its concrete type. Drops in place.
pub fn remove_any(&mut self, index: usize) {
if index >= self.data.len() {
return;
}
unsafe {
let ptr = self.data.swap_remove_and_forget_unchecked(index);
(self.data.drop)(ptr);
}
}
/// Overwrites an existing element in place, dropping the previous value. /// Overwrites an existing element in place, dropping the previous value.
pub fn set<T: 'static>(&mut self, index: usize, item: T) -> Option<()> { pub fn set<T: 'static>(&mut self, index: usize, item: T) -> Option<()> {
assert_eq!(TypeId::of::<T>(), TypeId::of::<T>(), "Type mismatch"); assert_eq!(TypeId::of::<T>(), TypeId::of::<T>(), "Type mismatch");

View file

@ -55,4 +55,11 @@ impl ComponentStorage {
None None
} }
} }
/// Removes all components belonging to the given entity index.
pub fn remove_entity(&mut self, index: usize) {
for (_, value) in self.iter_mut() {
value.remove_any(index);
}
}
} }

View file

@ -75,6 +75,64 @@ impl SparseSet {
None None
} }
/// Removes an element by external index without knowing its type. Returns true if something was removed.
pub fn remove_any(&mut self, index: usize) -> bool {
if let Some(page_vec) = self
.sparse
.get(index / self.page_size)
.and_then(|x| x.as_ref())
{
if let Some(sparse_index) = page_vec
.get(index % self.page_size)
.and_then(|x| x.as_ref())
{
let dense_index = *sparse_index;
let last_dense_index = self.dense.data.len() - 1;
if dense_index != last_dense_index {
if let Some(ext_index) = self.find_external_index(last_dense_index) {
if let Some(page_vec) = self
.sparse
.get_mut(ext_index / self.page_size)
.and_then(|x| x.as_mut())
{
page_vec[ext_index % self.page_size] = Some(dense_index);
}
}
self.dense.swap(dense_index, last_dense_index);
}
if let Some(page_vec) = self
.sparse
.get_mut(index / self.page_size)
.and_then(|x| x.as_mut())
{
page_vec[index % self.page_size] = None;
}
self.dense.remove_any(dense_index);
return true;
}
}
false
}
/// Finds the external index that maps to a given dense index.
fn find_external_index(&self, dense_index: usize) -> Option<usize> {
for (page_idx, page_opt) in self.sparse.iter().enumerate() {
if let Some(page) = page_opt {
for (offset, entry) in page.iter().enumerate() {
if let Some(idx) = entry {
if *idx == dense_index {
return Some(page_idx * self.page_size + offset);
}
}
}
}
}
None
}
pub fn get<T: 'static>(&self, index: usize) -> Option<&T> { pub fn get<T: 'static>(&self, index: usize) -> Option<&T> {
if let Some(page_vec) = self if let Some(page_vec) = self
.sparse .sparse