373 lines
11 KiB
Rust
373 lines
11 KiB
Rust
use std::collections::BTreeMap;
|
|
use std::marker::PhantomData;
|
|
use std::iter::Iterator;
|
|
use std::cell::RefCell;
|
|
|
|
use crate::componentmap::{
|
|
AccessError,
|
|
Ref as ComponentMapRef,
|
|
RefMut as ComponentMapRefMut,
|
|
ComponentMap,
|
|
ComponentMapIter,
|
|
ComponentMapIterMut,
|
|
};
|
|
use crate::globalmap::{
|
|
GlobalMap,
|
|
GlobalRef,
|
|
GlobalRefMut,
|
|
};
|
|
use crate::entity;
|
|
use crate::component;
|
|
|
|
pub struct ReadComponent<'a, T: component::Component> {
|
|
world: &'a World,
|
|
phantom: PhantomData<&'a T>,
|
|
}
|
|
|
|
impl<'a, T: component::Component> ReadComponent<'a, T> {
|
|
pub fn iter(&self) -> ReadComponentIter<'a, T> {
|
|
let cm = self.world.components.get(&component::component_id::<T>());
|
|
ReadComponentIter {
|
|
phantom: PhantomData,
|
|
iter: cm.map(|e| e.try_iter().unwrap() ),
|
|
}
|
|
}
|
|
|
|
pub fn get(&self, e: entity::ID) -> Result<ComponentMapRef<'a, T>, AccessError> {
|
|
// TODO(q3k): fix the unwrap
|
|
let cm = self.world.components.get(&component::component_id::<T>()).unwrap();
|
|
unsafe {
|
|
cm.get(e)
|
|
}
|
|
}
|
|
}
|
|
|
|
pub struct ReadComponentIter<'a, T: component::Component> {
|
|
phantom: PhantomData<&'a T>,
|
|
iter: Option<ComponentMapIter<'a>>,
|
|
}
|
|
|
|
impl <'a, T: component::Component> Iterator for ReadComponentIter<'a, T> {
|
|
type Item = (entity::ID, &'a T);
|
|
|
|
fn next(&mut self) -> Option<Self::Item> {
|
|
if self.iter.is_none() {
|
|
return None;
|
|
}
|
|
match self.iter.as_mut().unwrap().iter.next() {
|
|
None => None,
|
|
Some((eid, component)) => {
|
|
let component = component.as_ref();
|
|
let component = unsafe { & *(component as *const (dyn component::Component) as *const T) };
|
|
Some((*eid, component))
|
|
},
|
|
}
|
|
}
|
|
}
|
|
|
|
pub struct ReadWriteComponent<'a, T: component::Component> {
|
|
world: &'a World,
|
|
phantom: PhantomData<&'a T>,
|
|
}
|
|
|
|
impl<'a, T: component::Component> ReadWriteComponent<'a, T> {
|
|
pub fn iter_mut(&self) -> ReadWriteComponentIter<'a, T> {
|
|
let cm = self.world.components.get(&component::component_id::<T>());
|
|
ReadWriteComponentIter {
|
|
phantom: PhantomData,
|
|
iter: cm.map(|e| e.try_iter_mut().unwrap() ),
|
|
}
|
|
}
|
|
|
|
pub fn get_mut(&self, e: entity::ID) -> Result<ComponentMapRefMut<'a, T>, AccessError> {
|
|
// TODO(q3k): fix the unwrap
|
|
let cm = self.world.components.get(&component::component_id::<T>()).unwrap();
|
|
unsafe {
|
|
cm.get_mut(e)
|
|
}
|
|
}
|
|
}
|
|
|
|
pub struct ReadWriteComponentIter<'a, T: component::Component> {
|
|
phantom: PhantomData<&'a T>,
|
|
iter: Option<ComponentMapIterMut<'a>>,
|
|
}
|
|
|
|
impl <'a, T: component::Component> Iterator for ReadWriteComponentIter<'a, T> {
|
|
type Item = (entity::ID, &'a mut T);
|
|
|
|
fn next(&mut self) -> Option<Self::Item> {
|
|
if self.iter.is_none() {
|
|
return None;
|
|
}
|
|
match self.iter.as_mut().unwrap().iter.next() {
|
|
None => None,
|
|
Some((eid, component)) => {
|
|
let component = component.as_mut();
|
|
let component = unsafe { &mut *(component as *mut (dyn component::Component) as *mut T) };
|
|
Some((*eid, component))
|
|
},
|
|
}
|
|
}
|
|
}
|
|
|
|
pub struct ReadGlobal<'a, T: component::Global> {
|
|
world: &'a World,
|
|
phantom: PhantomData<&'a T>,
|
|
}
|
|
|
|
impl<'a, T: component::Global> ReadGlobal<'a, T> {
|
|
pub fn get(&self) -> GlobalRef<'a, T> {
|
|
self.world.globals.get::<T>().unwrap()
|
|
}
|
|
}
|
|
|
|
pub struct ReadWriteGlobal<'a, T: component::Global> {
|
|
world: &'a World,
|
|
phantom: PhantomData<&'a T>,
|
|
}
|
|
|
|
impl<'a, T: component::Global> ReadWriteGlobal<'a, T> {
|
|
pub fn get(&self) -> GlobalRefMut<'a, T> {
|
|
self.world.globals.get_mut::<T>().unwrap()
|
|
}
|
|
}
|
|
|
|
/// ReadWriteAll gives access to all components/entities/globals within a world. Using it in a
|
|
/// system means that no other system can run in parallel, and limits performance. This should only
|
|
/// be used when absolutely necessary (eg. for scripting systems).
|
|
pub struct ReadWriteAll<'a> {
|
|
world: &'a World,
|
|
}
|
|
|
|
impl<'a> ReadWriteAll<'a> {
|
|
pub fn world(self) -> &'a World {
|
|
self.world
|
|
}
|
|
}
|
|
|
|
impl<'a> ReadWriteAll<'a> {}
|
|
|
|
impl<'a> std::ops::Deref for ReadWriteAll<'a> {
|
|
type Target = World;
|
|
fn deref(&self) -> &Self::Target {
|
|
self.world
|
|
}
|
|
}
|
|
|
|
|
|
pub struct World {
|
|
components: BTreeMap<component::ID, ComponentMap>,
|
|
component_by_idstr: BTreeMap<&'static str, component::ID>,
|
|
component_lua_bindings: BTreeMap<component::ID, Box<dyn component::LuaBindings>>,
|
|
component_queue: RefCell<Vec<(component::ID, Box<dyn component::Component>, entity::Entity)>>,
|
|
globals: GlobalMap,
|
|
next_id: RefCell<entity::ID>,
|
|
}
|
|
|
|
impl World {
|
|
pub fn new() -> Self {
|
|
Self {
|
|
components: BTreeMap::new(),
|
|
component_by_idstr: BTreeMap::new(),
|
|
component_lua_bindings: BTreeMap::new(),
|
|
component_queue: RefCell::new(Vec::new()),
|
|
globals: GlobalMap::new(),
|
|
next_id: RefCell::new(1u64),
|
|
}
|
|
}
|
|
|
|
fn allocate_next_id(&self) -> entity::ID {
|
|
let res = self.next_id.borrow().clone();
|
|
let mut nid = self.next_id.borrow_mut();
|
|
*nid = *nid + 1;
|
|
res
|
|
}
|
|
|
|
pub fn new_entity(&mut self) -> entity::EntityBuilder {
|
|
entity::EntityBuilder::new(self, self.allocate_next_id())
|
|
}
|
|
|
|
pub fn new_entity_lazy(&self) -> entity::LazyEntityBuilder {
|
|
entity::LazyEntityBuilder::new(self.allocate_next_id())
|
|
}
|
|
|
|
pub fn register_component_lua_bindings(
|
|
&mut self,
|
|
bindings: Box<dyn component::LuaBindings>,
|
|
) {
|
|
let idstr = bindings.idstr();
|
|
let cid = bindings.id();
|
|
if let Some(_) = self.component_by_idstr.get(idstr) {
|
|
log::warn!("Ignored attempted re-registration of Lua bindings for component {} (duplicate idstr)", idstr);
|
|
return
|
|
}
|
|
if let Some(_) = self.component_lua_bindings.get(&cid) {
|
|
log::warn!("Ignored attempted re-registration of Lua bindings for component {} (duplicate ID)", idstr);
|
|
return
|
|
}
|
|
self.component_by_idstr.insert(idstr, cid);
|
|
self.component_lua_bindings.insert(cid, bindings);
|
|
}
|
|
|
|
pub fn lua_any_into_dyn<'a, 'b>(&'a self, ud: &'a mlua::AnyUserData) -> Option<(String, Box<dyn component::Component>)> {
|
|
for (_, bindings) in self.component_lua_bindings.iter() {
|
|
if let Some(b) = bindings.any_into_dyn(ud) {
|
|
return Some((bindings.idstr().into(), b));
|
|
}
|
|
}
|
|
None
|
|
}
|
|
|
|
pub fn register_component_entity(
|
|
&mut self,
|
|
cid: component::ID,
|
|
c: Box<dyn component::Component>,
|
|
e: entity::Entity
|
|
) {
|
|
let map = self.components.entry(cid).or_insert(ComponentMap::new());
|
|
map.insert(e.id(), c).unwrap();
|
|
}
|
|
|
|
pub fn enqueue_register_component_entity(
|
|
&self,
|
|
cid: component::ID,
|
|
c: Box<dyn component::Component>,
|
|
e: entity::Entity
|
|
) {
|
|
self.component_queue.borrow_mut().push((cid, c, e));
|
|
}
|
|
|
|
pub fn queue_drain(
|
|
&mut self,
|
|
) {
|
|
for (cid, c, e) in self.component_queue.replace(Vec::new()).into_iter() {
|
|
self.register_component_entity(cid, c, e);
|
|
}
|
|
}
|
|
|
|
pub fn get_component_lua_bindings(
|
|
&self,
|
|
) -> Vec<(String, component::ID, &Box<dyn component::LuaBindings>)> {
|
|
self.component_by_idstr.iter().filter_map(|(idstr, cid)| {
|
|
let bindings = self.component_lua_bindings.get(cid)?;
|
|
Some((idstr.to_string(), *cid, bindings))
|
|
}).collect()
|
|
}
|
|
|
|
pub fn components<'a, T: component::Component>(&'a self) -> ReadComponent<'a, T> {
|
|
ReadComponent {
|
|
world: self,
|
|
phantom: PhantomData,
|
|
}
|
|
}
|
|
|
|
pub fn components_mut<'a, T: component::Component>(&'a self) -> ReadWriteComponent<'a, T> {
|
|
ReadWriteComponent {
|
|
world: self,
|
|
phantom: PhantomData,
|
|
}
|
|
}
|
|
|
|
pub fn component_get_dyn_cloned<'a>(
|
|
&'a self,
|
|
e: entity::ID,
|
|
cid: component::ID,
|
|
) -> Option<Box<dyn component::Component>> {
|
|
let map = self.components.get(&cid)?;
|
|
match map.get_dyn(e) {
|
|
Ok(val) => Some(val.clone_dyn()),
|
|
Err(err) => {
|
|
// Attempt to get from queue.
|
|
let cq = self.component_queue.borrow();
|
|
for (qcid, qc, qe) in cq.iter() {
|
|
if qe.id() == e && *qcid == cid {
|
|
return Some(qc.clone_dyn());
|
|
}
|
|
}
|
|
// TODO(q3k): better error handling
|
|
panic!("get_dyn({:?}): not in queue and ecs said: {:?}", e, err);
|
|
}
|
|
}
|
|
}
|
|
|
|
pub fn component_set_dyn<'a>(
|
|
&'a self,
|
|
e: entity::ID,
|
|
c: Box<dyn component::Component>
|
|
) {
|
|
// TODO(q3k): error handling
|
|
// TODO(q3k): do not insert component data if it's missing? That can happen if we attempt
|
|
// to set_dyn before the entity/components are registered.
|
|
match self.components.get(&c.id()) {
|
|
None => panic!("Component {:?} not found", c),
|
|
Some(map) => map.insert(e, c).unwrap(),
|
|
}
|
|
}
|
|
|
|
pub fn global<'a, T: component::Global>(&'a self) -> ReadGlobal<'a, T> {
|
|
ReadGlobal {
|
|
world: self,
|
|
phantom: PhantomData,
|
|
}
|
|
}
|
|
|
|
pub fn global_mut<'a, T: component::Global>(&'a self) -> ReadWriteGlobal<'a, T> {
|
|
ReadWriteGlobal {
|
|
world: self,
|
|
phantom: PhantomData,
|
|
}
|
|
}
|
|
|
|
pub fn all<'a>(&'a self) -> ReadWriteAll<'a> {
|
|
ReadWriteAll {
|
|
world: self,
|
|
}
|
|
}
|
|
|
|
pub fn set_global<T: component::Global>(&self, r: T) {
|
|
self.globals.set(r).unwrap();
|
|
}
|
|
|
|
pub fn lua_components(&self) -> &BTreeMap<component::ID, Box<dyn component::LuaBindings>> {
|
|
&self.component_lua_bindings
|
|
}
|
|
}
|
|
|
|
#[cfg(test)]
|
|
mod tests {
|
|
use crate::component;
|
|
use crate::world;
|
|
|
|
#[derive(Debug)]
|
|
struct Position {
|
|
x: u32,
|
|
y: u32,
|
|
z: u32,
|
|
}
|
|
impl component::Component for Position {}
|
|
|
|
#[derive(Debug)]
|
|
struct Name(String);
|
|
impl component::Component for Name {}
|
|
impl Name {
|
|
fn new(s: &str) -> Name {
|
|
Name(String::from(s))
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
fn new_list() {
|
|
let mut world = world::World::new();
|
|
world.new_entity().with(Name::new("foo")).with(Position { x: 1, y: 2, z: 3 }).build();
|
|
world.new_entity().with(Name::new("bar")).with(Position { x: 4, y: 5, z: 6 }).build();
|
|
|
|
let mut named = world.components::<Name>().iter();
|
|
let mut named2 = world.components::<Name>().iter();
|
|
assert_eq!(String::from("foo"), (named.next().unwrap().1).0);
|
|
assert_eq!(String::from("foo"), (named2.next().unwrap().1).0);
|
|
assert_eq!(String::from("bar"), (named.next().unwrap().1).0);
|
|
assert_eq!(String::from("bar"), (named2.next().unwrap().1).0);
|
|
}
|
|
}
|