From 6a692ba37d118ea8e3f13851920a363ce654e037 Mon Sep 17 00:00:00 2001 From: Thinkofname Date: Sun, 27 Mar 2016 14:25:34 +0100 Subject: [PATCH] Allow for tracking for component removals and additions --- src/ecs/mod.rs | 156 ++++++++++++++++++++++++++++++++++-------- src/entity/player.rs | 4 ++ src/entity/systems.rs | 12 ++++ 3 files changed, 145 insertions(+), 27 deletions(-) diff --git a/src/ecs/mod.rs b/src/ecs/mod.rs index 6271957..129b6d4 100644 --- a/src/ecs/mod.rs +++ b/src/ecs/mod.rs @@ -13,7 +13,9 @@ // limitations under the License. use types::bit::Set as BSet; -use std::collections::HashMap; +use std::collections::{HashMap, HashSet}; +use std::hash::BuildHasherDefault; +use types::hash::FNVHash; use std::any::{Any, TypeId}; use std::cell::RefCell; use std::marker::PhantomData; @@ -21,7 +23,7 @@ use std::mem; use std::ptr; /// Used to reference an entity. -#[derive(Clone, Copy)] +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] pub struct Entity { id: usize, generation: u32, @@ -68,21 +70,36 @@ impl Filter { /// A system processes entities pub trait System { + fn filter(&self) -> &Filter; fn update(&mut self, m: &mut Manager); + + fn entity_added(&mut self, _m: &mut Manager, _e: Entity) { + } + + fn entity_removed(&mut self, _m: &mut Manager, _e: Entity) { + } } +#[derive(Clone)] +struct EntityState { + last_components: BSet, + components: BSet, +} /// Stores and manages a collection of entities. pub struct Manager { num_components: usize, - entities: Vec<(Option, u32)>, + entities: Vec<(Option, u32)>, free_entities: Vec, components: Vec>, - component_ids: RefCell>, + component_ids: RefCell>>, systems: Vec>, render_systems: Vec>, + + changed_entity_components: HashSet>, + removed_entities: HashSet>, } impl Manager { @@ -90,13 +107,19 @@ impl Manager { pub fn new() -> Manager { Manager { num_components: 0, - entities: vec![(Some(BSet::new(0)), 0)], // Has the world entity pre-defined + entities: vec![(Some(EntityState { + last_components: BSet::new(0), + components: BSet::new(0), + }), 0)], // Has the world entity pre-defined free_entities: vec![], components: vec![], - component_ids: RefCell::new(HashMap::new()), + component_ids: RefCell::new(HashMap::with_hasher(BuildHasherDefault::default())), systems: vec![], render_systems: vec![], + + changed_entity_components: HashSet::with_hasher(BuildHasherDefault::default()), + removed_entities: HashSet::with_hasher(BuildHasherDefault::default()), } } @@ -120,20 +143,50 @@ impl Manager { /// Ticks all tick systems pub fn tick(&mut self) { + self.process_entity_changes(); let mut systems = mem::replace(&mut self.systems, unsafe { mem::uninitialized() }); for sys in &mut systems { sys.update(self); } mem::forget(mem::replace(&mut self.systems, systems)); + self.process_entity_changes(); } /// Ticks all render systems pub fn render_tick(&mut self) { + self.process_entity_changes(); let mut systems = mem::replace(&mut self.render_systems, unsafe { mem::uninitialized() }); for sys in &mut systems { sys.update(self); } mem::forget(mem::replace(&mut self.render_systems, systems)); + self.process_entity_changes(); + } + + fn process_entity_changes(&mut self) { + let changes = self.changed_entity_components.clone(); + self.changed_entity_components = HashSet::with_hasher(BuildHasherDefault::default()); + for entity in changes { + let state = self.entities[entity.id].0.as_mut().unwrap().clone(); + self.trigger_add_for_systems(entity, &state.last_components, &state.components); + self.trigger_add_for_render_systems(entity, &state.last_components, &state.components); + self.trigger_remove_for_systems(entity, &state.last_components, &state.components); + self.trigger_remove_for_render_systems(entity, &state.last_components, &state.components); + for i in 0 .. self.components.len() { + if !state.components.get(i) && state.last_components.get(i) { + let components = self.components.get_mut(i).and_then(|v| v.as_mut()).unwrap(); + components.remove(entity.id); + } + } + + if self.removed_entities.remove(&entity) { + self.free_entities.push(entity.id); + self.entities[entity.id].0 = None; + } else { + let state = self.entities[entity.id].0.as_mut().unwrap(); + state.last_components = state.components.clone(); + } + } } /// Returns all entities matching the filter @@ -142,7 +195,7 @@ impl Manager { // Skip the world entity. for (i, &(ref set, gen)) in self.entities[1..].iter().enumerate() { if let Some(set) = set.as_ref() { - if set.includes_set(&filter.bits) { + if set.components.includes_set(&filter.bits) { ret.push(Entity { id: i + 1, generation: gen, @@ -157,7 +210,10 @@ impl Manager { pub fn create_entity(&mut self) -> Entity { if let Some(id) = self.free_entities.pop() { let entity = &mut self.entities[id]; - entity.0 = Some(BSet::new(self.num_components)); + entity.0 = Some(EntityState { + last_components: BSet::new(self.num_components), + components: BSet::new(self.num_components), + }); entity.1 += 1; return Entity { id: id, @@ -166,7 +222,10 @@ impl Manager { } let id = self.entities.len(); self.entities.push(( - Some(BSet::new(self.num_components)), + Some(EntityState { + last_components: BSet::new(self.num_components), + components: BSet::new(self.num_components), + }), 0 )); Entity { @@ -177,15 +236,10 @@ impl Manager { /// Deallocates an entity and frees its components pub fn remove_entity(&mut self, e: Entity) { - if let Some(set) = self.entities[e.id].0.as_ref() { - for i in 0 .. COMPONENTS_PER_BLOCK { - if set.get(i) { - self.components[i].as_mut().unwrap().remove(e.id); - } - } - self.free_entities.push(e.id); + if let Some(set) = self.entities[e.id].0.as_mut() { + set.components = BSet::new(self.components.len()); + self.removed_entities.insert(e); } - self.entities[e.id].0 = None; } /// Returns whether an entity reference is valid. @@ -222,11 +276,11 @@ impl Manager { self.num_components += 1; for &mut (ref mut set, _) in &mut self.entities { if let Some(set) = set.as_mut() { - set.resize(self.num_components); + set.last_components.resize(self.num_components); + set.components.resize(self.num_components); } } } - let components = self.components.get_mut(key.id).and_then(|v| v.as_mut()).unwrap(); let mut e = self.entities.get_mut(entity.id); let set = match e { Some(ref mut val) => if val.1 == entity.generation { &mut val.0 } else { panic!("Missing entity") }, @@ -236,13 +290,38 @@ impl Manager { Some(val) => val, None => panic!("Missing entity"), }; - if set.get(key.id) { + if set.components.get(key.id) != set.last_components.get(key.id) { + panic!("Double change within a single tick"); + } + if set.components.get(key.id) { panic!("Duplicate add"); } - set.set(key.id, true); + set.components.set(key.id, true); + self.changed_entity_components.insert(entity); + let components = self.components.get_mut(key.id).and_then(|v| v.as_mut()).unwrap(); components.add(entity.id, val); } + fn trigger_add_for_systems(&mut self, e: Entity, old_set: &BSet, new_set: &BSet) { + let mut systems = mem::replace(&mut self.systems, unsafe { mem::uninitialized() }); + for sys in &mut systems { + if new_set.includes_set(&sys.filter().bits) && !old_set.includes_set(&sys.filter().bits) { + sys.entity_added(self, e); + } + } + mem::forget(mem::replace(&mut self.systems, systems)); + } + + fn trigger_add_for_render_systems(&mut self, e: Entity, old_set: &BSet, new_set: &BSet) { + let mut systems = mem::replace(&mut self.render_systems, unsafe { mem::uninitialized() }); + for sys in &mut systems { + if new_set.includes_set(&sys.filter().bits) && !old_set.includes_set(&sys.filter().bits) { + sys.entity_added(self, e); + } + } + mem::forget(mem::replace(&mut self.render_systems, systems)); + } + /// Same as `add_component` but doesn't require a key. Using a key /// is better for frequent lookups. pub fn add_component_direct(&mut self, entity: Entity, val: T) { @@ -261,7 +340,6 @@ impl Manager { if self.components[key.id].is_none() { return false; } - let components = self.components.get_mut(key.id).and_then(|v| v.as_mut()).unwrap(); let mut e = self.entities.get_mut(entity.id); let set = match e { Some(ref mut val) => if val.1 == entity.generation { &mut val.0 } else { panic!("Missing entity") }, @@ -271,14 +349,38 @@ impl Manager { Some(val) => val, None => panic!("Missing entity"), }; - if !set.get(key.id) { + if set.components.get(key.id) != set.last_components.get(key.id) { + panic!("Double change within a single tick"); + } + if !set.components.get(key.id) { return false } - set.set(key.id, false); - components.remove(entity.id); + set.components.set(key.id, false); + self.changed_entity_components.insert(entity); + // Actual removal is delayed until ticking finishes true } + fn trigger_remove_for_systems(&mut self, e: Entity, old_set: &BSet, new_set: &BSet) { + let mut systems = mem::replace(&mut self.systems, unsafe { mem::uninitialized() }); + for sys in &mut systems { + if !new_set.includes_set(&sys.filter().bits) && old_set.includes_set(&sys.filter().bits) { + sys.entity_removed(self, e); + } + } + mem::forget(mem::replace(&mut self.systems, systems)); + } + + fn trigger_remove_for_render_systems(&mut self, e: Entity, old_set: &BSet, new_set: &BSet) { + let mut systems = mem::replace(&mut self.render_systems, unsafe { mem::uninitialized() }); + for sys in &mut systems { + if new_set.includes_set(&sys.filter().bits) && !old_set.includes_set(&sys.filter().bits) { + sys.entity_removed(self, e); + } + } + mem::forget(mem::replace(&mut self.render_systems, systems)); + } + /// Same as `remove_component` but doesn't require a key. Using a key /// is better for frequent lookups. pub fn remove_component_direct(&mut self, entity: Entity) -> bool { @@ -296,7 +398,7 @@ impl Manager { Some(ref val) => if val.1 == entity.generation { &val.0 } else { return None }, None => return None, }; - if !set.as_ref().map_or(false, |v| v.get(key.id)) { + if !set.as_ref().map_or(false, |v| v.components.get(key.id)) { return None; } @@ -320,7 +422,7 @@ impl Manager { Some(ref val) => if val.1 == entity.generation { &val.0 } else { return None }, None => return None, }; - if !set.as_ref().map_or(false, |v| v.get(key.id)) { + if !set.as_ref().map_or(false, |v| v.components.get(key.id)) { return None; } diff --git a/src/entity/player.rs b/src/entity/player.rs index 8565500..7b6a272 100644 --- a/src/entity/player.rs +++ b/src/entity/player.rs @@ -131,6 +131,10 @@ impl MovementHandler { impl ecs::System for MovementHandler { + fn filter(&self) -> &ecs::Filter { + &self.filter + } + fn update(&mut self, m: &mut ecs::Manager) { let world_entity = m.get_world(); let world: &world::World = m.get_component(world_entity, self.world).unwrap(); diff --git a/src/entity/systems.rs b/src/entity/systems.rs index da30e28..83db33e 100644 --- a/src/entity/systems.rs +++ b/src/entity/systems.rs @@ -26,6 +26,10 @@ impl ApplyVelocity { impl ecs::System for ApplyVelocity { + fn filter(&self) -> &ecs::Filter { + &self.filter + } + fn update(&mut self, m: &mut ecs::Manager) { for e in m.find(&self.filter) { if m.get_component(e, self.movement).is_some() { @@ -61,6 +65,10 @@ impl ApplyGravity { impl ecs::System for ApplyGravity { + fn filter(&self) -> &ecs::Filter { + &self.filter + } + fn update(&mut self, m: &mut ecs::Manager) { for e in m.find(&self.filter) { if m.get_component(e, self.movement).is_some() { @@ -95,6 +103,10 @@ impl UpdateLastPosition { impl ecs::System for UpdateLastPosition { + fn filter(&self) -> &ecs::Filter { + &self.filter + } + fn update(&mut self, m: &mut ecs::Manager) { for e in m.find(&self.filter) { let pos = m.get_component_mut(e, self.position).unwrap();