Allow for tracking for component removals and additions

This commit is contained in:
Thinkofname 2016-03-27 14:25:34 +01:00
parent 26bca302aa
commit 6a692ba37d
3 changed files with 145 additions and 27 deletions

View File

@ -13,7 +13,9 @@
// limitations under the License. // limitations under the License.
use types::bit::Set as BSet; 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::any::{Any, TypeId};
use std::cell::RefCell; use std::cell::RefCell;
use std::marker::PhantomData; use std::marker::PhantomData;
@ -21,7 +23,7 @@ use std::mem;
use std::ptr; use std::ptr;
/// Used to reference an entity. /// Used to reference an entity.
#[derive(Clone, Copy)] #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub struct Entity { pub struct Entity {
id: usize, id: usize,
generation: u32, generation: u32,
@ -68,21 +70,36 @@ impl Filter {
/// A system processes entities /// A system processes entities
pub trait System { pub trait System {
fn filter(&self) -> &Filter;
fn update(&mut self, m: &mut Manager); 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. /// Stores and manages a collection of entities.
pub struct Manager { pub struct Manager {
num_components: usize, num_components: usize,
entities: Vec<(Option<BSet>, u32)>, entities: Vec<(Option<EntityState>, u32)>,
free_entities: Vec<usize>, free_entities: Vec<usize>,
components: Vec<Option<ComponentMem>>, components: Vec<Option<ComponentMem>>,
component_ids: RefCell<HashMap<TypeId, usize>>, component_ids: RefCell<HashMap<TypeId, usize, BuildHasherDefault<FNVHash>>>,
systems: Vec<Box<System + Send>>, systems: Vec<Box<System + Send>>,
render_systems: Vec<Box<System + Send>>, render_systems: Vec<Box<System + Send>>,
changed_entity_components: HashSet<Entity, BuildHasherDefault<FNVHash>>,
removed_entities: HashSet<Entity, BuildHasherDefault<FNVHash>>,
} }
impl Manager { impl Manager {
@ -90,13 +107,19 @@ impl Manager {
pub fn new() -> Manager { pub fn new() -> Manager {
Manager { Manager {
num_components: 0, 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![], free_entities: vec![],
components: vec![], components: vec![],
component_ids: RefCell::new(HashMap::new()), component_ids: RefCell::new(HashMap::with_hasher(BuildHasherDefault::default())),
systems: vec![], systems: vec![],
render_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 /// Ticks all tick systems
pub fn tick(&mut self) { pub fn tick(&mut self) {
self.process_entity_changes();
let mut systems = mem::replace(&mut self.systems, unsafe { mem::uninitialized() }); let mut systems = mem::replace(&mut self.systems, unsafe { mem::uninitialized() });
for sys in &mut systems { for sys in &mut systems {
sys.update(self); sys.update(self);
} }
mem::forget(mem::replace(&mut self.systems, systems)); mem::forget(mem::replace(&mut self.systems, systems));
self.process_entity_changes();
} }
/// Ticks all render systems /// Ticks all render systems
pub fn render_tick(&mut self) { pub fn render_tick(&mut self) {
self.process_entity_changes();
let mut systems = mem::replace(&mut self.render_systems, unsafe { mem::uninitialized() }); let mut systems = mem::replace(&mut self.render_systems, unsafe { mem::uninitialized() });
for sys in &mut systems { for sys in &mut systems {
sys.update(self); sys.update(self);
} }
mem::forget(mem::replace(&mut self.render_systems, systems)); 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 /// Returns all entities matching the filter
@ -142,7 +195,7 @@ impl Manager {
// Skip the world entity. // Skip the world entity.
for (i, &(ref set, gen)) in self.entities[1..].iter().enumerate() { for (i, &(ref set, gen)) in self.entities[1..].iter().enumerate() {
if let Some(set) = set.as_ref() { if let Some(set) = set.as_ref() {
if set.includes_set(&filter.bits) { if set.components.includes_set(&filter.bits) {
ret.push(Entity { ret.push(Entity {
id: i + 1, id: i + 1,
generation: gen, generation: gen,
@ -157,7 +210,10 @@ impl Manager {
pub fn create_entity(&mut self) -> Entity { pub fn create_entity(&mut self) -> Entity {
if let Some(id) = self.free_entities.pop() { if let Some(id) = self.free_entities.pop() {
let entity = &mut self.entities[id]; 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; entity.1 += 1;
return Entity { return Entity {
id: id, id: id,
@ -166,7 +222,10 @@ impl Manager {
} }
let id = self.entities.len(); let id = self.entities.len();
self.entities.push(( 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 0
)); ));
Entity { Entity {
@ -177,15 +236,10 @@ impl Manager {
/// Deallocates an entity and frees its components /// Deallocates an entity and frees its components
pub fn remove_entity(&mut self, e: Entity) { pub fn remove_entity(&mut self, e: Entity) {
if let Some(set) = self.entities[e.id].0.as_ref() { if let Some(set) = self.entities[e.id].0.as_mut() {
for i in 0 .. COMPONENTS_PER_BLOCK { set.components = BSet::new(self.components.len());
if set.get(i) { self.removed_entities.insert(e);
self.components[i].as_mut().unwrap().remove(e.id);
}
}
self.free_entities.push(e.id);
} }
self.entities[e.id].0 = None;
} }
/// Returns whether an entity reference is valid. /// Returns whether an entity reference is valid.
@ -222,11 +276,11 @@ impl Manager {
self.num_components += 1; self.num_components += 1;
for &mut (ref mut set, _) in &mut self.entities { for &mut (ref mut set, _) in &mut self.entities {
if let Some(set) = set.as_mut() { 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 mut e = self.entities.get_mut(entity.id);
let set = match e { let set = match e {
Some(ref mut val) => if val.1 == entity.generation { &mut val.0 } else { panic!("Missing entity") }, 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, Some(val) => val,
None => panic!("Missing entity"), 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"); 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); 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 /// Same as `add_component` but doesn't require a key. Using a key
/// is better for frequent lookups. /// is better for frequent lookups.
pub fn add_component_direct<T: Any>(&mut self, entity: Entity, val: T) { pub fn add_component_direct<T: Any>(&mut self, entity: Entity, val: T) {
@ -261,7 +340,6 @@ impl Manager {
if self.components[key.id].is_none() { if self.components[key.id].is_none() {
return false; 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 mut e = self.entities.get_mut(entity.id);
let set = match e { let set = match e {
Some(ref mut val) => if val.1 == entity.generation { &mut val.0 } else { panic!("Missing entity") }, 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, Some(val) => val,
None => panic!("Missing entity"), 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 return false
} }
set.set(key.id, false); set.components.set(key.id, false);
components.remove(entity.id); self.changed_entity_components.insert(entity);
// Actual removal is delayed until ticking finishes
true 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 /// Same as `remove_component` but doesn't require a key. Using a key
/// is better for frequent lookups. /// is better for frequent lookups.
pub fn remove_component_direct<T: Any>(&mut self, entity: Entity) -> bool { pub fn remove_component_direct<T: Any>(&mut self, entity: Entity) -> bool {
@ -296,7 +398,7 @@ impl Manager {
Some(ref val) => if val.1 == entity.generation { &val.0 } else { return None }, Some(ref val) => if val.1 == entity.generation { &val.0 } else { return None },
None => 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; return None;
} }
@ -320,7 +422,7 @@ impl Manager {
Some(ref val) => if val.1 == entity.generation { &val.0 } else { return None }, Some(ref val) => if val.1 == entity.generation { &val.0 } else { return None },
None => 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; return None;
} }

View File

@ -131,6 +131,10 @@ impl MovementHandler {
impl ecs::System for MovementHandler { impl ecs::System for MovementHandler {
fn filter(&self) -> &ecs::Filter {
&self.filter
}
fn update(&mut self, m: &mut ecs::Manager) { fn update(&mut self, m: &mut ecs::Manager) {
let world_entity = m.get_world(); let world_entity = m.get_world();
let world: &world::World = m.get_component(world_entity, self.world).unwrap(); let world: &world::World = m.get_component(world_entity, self.world).unwrap();

View File

@ -26,6 +26,10 @@ impl ApplyVelocity {
impl ecs::System for ApplyVelocity { impl ecs::System for ApplyVelocity {
fn filter(&self) -> &ecs::Filter {
&self.filter
}
fn update(&mut self, m: &mut ecs::Manager) { fn update(&mut self, m: &mut ecs::Manager) {
for e in m.find(&self.filter) { for e in m.find(&self.filter) {
if m.get_component(e, self.movement).is_some() { if m.get_component(e, self.movement).is_some() {
@ -61,6 +65,10 @@ impl ApplyGravity {
impl ecs::System for ApplyGravity { impl ecs::System for ApplyGravity {
fn filter(&self) -> &ecs::Filter {
&self.filter
}
fn update(&mut self, m: &mut ecs::Manager) { fn update(&mut self, m: &mut ecs::Manager) {
for e in m.find(&self.filter) { for e in m.find(&self.filter) {
if m.get_component(e, self.movement).is_some() { if m.get_component(e, self.movement).is_some() {
@ -95,6 +103,10 @@ impl UpdateLastPosition {
impl ecs::System for UpdateLastPosition { impl ecs::System for UpdateLastPosition {
fn filter(&self) -> &ecs::Filter {
&self.filter
}
fn update(&mut self, m: &mut ecs::Manager) { fn update(&mut self, m: &mut ecs::Manager) {
for e in m.find(&self.filter) { for e in m.find(&self.filter) {
let pos = m.get_component_mut(e, self.position).unwrap(); let pos = m.get_component_mut(e, self.position).unwrap();