use std::any::{Any, TypeId};
use std::collections::HashMap;
use std::marker::PhantomData;
use super::entity::{Entity, EntityAllocator};
use super::storage::{AnyComponentStorage, ComponentStorage, StorageSet, TypedStorage};
pub trait Component: 'static + Send + Sync {}
impl<T: 'static + Send + Sync> Component for T {}
pub trait Resource: 'static + Send + Sync {}
impl<T: 'static + Send + Sync> Resource for T {}
pub struct World {
pub(crate) entities: EntityAllocator,
pub(crate) components: HashMap<TypeId, Box<dyn AnyComponentStorage>>,
pub(crate) resources: HashMap<TypeId, Box<dyn Any + Send + Sync>>,
pub(crate) tick: u64,
entity_count: usize,
}
impl World {
pub fn new() -> Self {
Self {
entities: EntityAllocator::new(),
components: HashMap::new(),
resources: HashMap::new(),
tick: 0,
entity_count: 0,
}
}
pub fn with_capacity(entity_cap: usize) -> Self {
Self {
entities: EntityAllocator::with_capacity(entity_cap),
components: HashMap::new(),
resources: HashMap::new(),
tick: 0,
entity_count: 0,
}
}
pub fn spawn(&mut self) -> EntityBuilder<'_> {
let entity = self.entities.allocate();
self.entity_count += 1;
EntityBuilder { world: self, entity }
}
pub fn spawn_empty(&mut self) -> Entity {
let entity = self.entities.allocate();
self.entity_count += 1;
entity
}
pub fn despawn(&mut self, entity: Entity) -> bool {
if !self.entities.is_alive(entity) {
return false;
}
for storage in self.components.values_mut() {
storage.remove_erased(entity);
}
let freed = self.entities.free(entity);
if freed {
self.entity_count = self.entity_count.saturating_sub(1);
}
freed
}
#[inline]
pub fn is_alive(&self, entity: Entity) -> bool {
self.entities.is_alive(entity)
}
#[inline]
pub fn entity_count(&self) -> usize {
self.entity_count
}
#[inline]
pub fn tick(&self) -> u64 {
self.tick
}
pub fn advance_tick(&mut self) {
self.tick += 1;
}
pub fn insert<T: Component>(&mut self, entity: Entity, component: T) -> Option<T> {
debug_assert!(self.entities.is_alive(entity), "insert: entity {:?} is not alive", entity);
self.get_or_create_storage_mut::<T>()
.borrow_mut()
.insert(entity, component)
}
pub fn insert_component<T: Component>(&mut self, entity: Entity, component: T) -> &mut Self {
self.insert(entity, component);
self
}
pub fn remove<T: Component>(&mut self, entity: Entity) -> Option<T> {
let storage = self.components.get_mut(&TypeId::of::<T>())?;
let typed = storage
.as_any_mut()
.downcast_mut::<TypedStorage<T>>()
.expect("storage downcast failed");
typed.borrow_mut().remove_and_return(entity)
}
pub fn get<T: Component>(&self, entity: Entity) -> Option<&T> {
let storage = self.components.get(&TypeId::of::<T>())?;
let typed = storage
.as_any()
.downcast_ref::<TypedStorage<T>>()
.expect("storage downcast failed");
let guard = typed.borrow();
let ptr = guard.get(entity)? as *const T;
Some(unsafe { &*ptr })
}
pub fn get_mut<T: Component>(&mut self, entity: Entity) -> Option<&mut T> {
let storage = self.components.get_mut(&TypeId::of::<T>())?;
let typed = storage
.as_any_mut()
.downcast_mut::<TypedStorage<T>>()
.expect("storage downcast failed");
let mut guard = typed.borrow_mut();
let ptr = guard.get_mut(entity)? as *mut T;
Some(unsafe { &mut *ptr })
}
pub fn has<T: Component>(&self, entity: Entity) -> bool {
self.components
.get(&TypeId::of::<T>())
.map(|s| s.contains_erased(entity))
.unwrap_or(false)
}
pub fn component_count<T: Component>(&self) -> usize {
self.components
.get(&TypeId::of::<T>())
.map(|s| s.len_erased())
.unwrap_or(0)
}
pub fn iter_component<T: Component>(&self) -> impl Iterator<Item = (Entity, &T)> {
match self.components.get(&TypeId::of::<T>()) {
None => ComponentIter::empty(),
Some(storage) => {
let typed = storage
.as_any()
.downcast_ref::<TypedStorage<T>>()
.expect("storage downcast failed");
ComponentIter::new(typed)
}
}
}
pub fn insert_resource<T: Resource>(&mut self, resource: T) {
self.resources.insert(TypeId::of::<T>(), Box::new(resource));
}
pub fn remove_resource<T: Resource>(&mut self) -> Option<T> {
let boxed = self.resources.remove(&TypeId::of::<T>())?;
Some(*boxed.downcast::<T>().expect("resource downcast failed"))
}
pub fn resource<T: Resource>(&self) -> &T {
self.try_resource::<T>()
.unwrap_or_else(|| panic!("resource {} not found", std::any::type_name::<T>()))
}
pub fn resource_mut<T: Resource>(&mut self) -> &mut T {
self.try_resource_mut::<T>()
.unwrap_or_else(|| panic!("resource {} not found", std::any::type_name::<T>()))
}
pub fn try_resource<T: Resource>(&self) -> Option<&T> {
self.resources
.get(&TypeId::of::<T>())?
.downcast_ref::<T>()
}
pub fn try_resource_mut<T: Resource>(&mut self) -> Option<&mut T> {
self.resources
.get_mut(&TypeId::of::<T>())?
.downcast_mut::<T>()
}
pub fn has_resource<T: Resource>(&self) -> bool {
self.resources.contains_key(&TypeId::of::<T>())
}
pub fn get_resource_or_insert<T: Resource + Default>(&mut self) -> &mut T {
self.resources
.entry(TypeId::of::<T>())
.or_insert_with(|| Box::new(T::default()))
.downcast_mut::<T>()
.expect("resource downcast failed")
}
pub fn query_component<T: Component>(&self) -> Vec<(Entity, &T)> {
self.iter_component::<T>().collect()
}
pub fn query_with<T: Component, F: Fn(&T) -> bool>(&self, pred: F) -> Vec<Entity> {
self.iter_component::<T>()
.filter(|(_, c)| pred(c))
.map(|(e, _)| e)
.collect()
}
pub fn entities_with_all(&self, type_ids: &[TypeId]) -> Vec<Entity> {
if type_ids.is_empty() {
return self.entities.alive_entities();
}
let all_types_registered = type_ids
.iter()
.all(|tid| self.components.contains_key(tid));
if !all_types_registered {
return Vec::new();
}
self.entities
.iter_alive()
.filter(|e| {
type_ids
.iter()
.all(|tid| self.components.get(tid).map_or(false, |s| s.contains_erased(*e)))
})
.collect()
}
pub fn entities_with<T: Component>(&self) -> Vec<Entity> {
self.iter_component::<T>().map(|(e, _)| e).collect()
}
pub fn clear(&mut self) {
for storage in self.components.values_mut() {
storage.clear_erased();
}
self.entities.clear();
self.entity_count = 0;
}
pub fn clear_all(&mut self) {
self.clear();
self.resources.clear();
}
pub fn component_type_count(&self) -> usize {
self.components.len()
}
pub fn resource_count(&self) -> usize {
self.resources.len()
}
pub(crate) fn get_or_create_storage_mut<T: Component>(&mut self) -> &mut TypedStorage<T> {
let entry = self
.components
.entry(TypeId::of::<T>())
.or_insert_with(|| Box::new(TypedStorage::<T>::new()));
entry
.as_any_mut()
.downcast_mut::<TypedStorage<T>>()
.expect("storage downcast failed")
}
pub(crate) fn get_storage<T: Component>(&self) -> Option<&TypedStorage<T>> {
self.components
.get(&TypeId::of::<T>())?
.as_any()
.downcast_ref::<TypedStorage<T>>()
}
pub(crate) fn get_storage_mut<T: Component>(&mut self) -> Option<&mut TypedStorage<T>> {
self.components
.get_mut(&TypeId::of::<T>())?
.as_any_mut()
.downcast_mut::<TypedStorage<T>>()
}
pub fn register<T: Component>(&mut self) {
self.components
.entry(TypeId::of::<T>())
.or_insert_with(|| Box::new(TypedStorage::<T>::new()));
}
pub fn for_each<T: Component>(&self, mut f: impl FnMut(Entity, &T)) {
if let Some(storage) = self.get_storage::<T>() {
let borrowed = storage.borrow();
for (&e, c) in borrowed.iter() {
f(e, c);
}
}
}
pub fn for_each_mut<T: Component>(&mut self, mut f: impl FnMut(Entity, &mut T)) {
if let Some(storage) = self.get_storage_mut::<T>() {
let mut borrowed = storage.borrow_mut();
for (&e, c) in borrowed.iter_mut() {
f(e, c);
}
}
}
}
impl Default for World {
fn default() -> Self {
Self::new()
}
}
impl std::fmt::Debug for World {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("World")
.field("entity_count", &self.entity_count)
.field("component_types", &self.components.len())
.field("resources", &self.resources.len())
.field("tick", &self.tick)
.finish()
}
}
pub struct ComponentIter<'w, T: Component> {
items: Vec<(Entity, *const T)>,
index: usize,
_marker: PhantomData<&'w T>,
}
impl<'w, T: Component> ComponentIter<'w, T> {
fn empty() -> Self {
Self { items: Vec::new(), index: 0, _marker: PhantomData }
}
fn new(typed: &'w TypedStorage<T>) -> Self {
let guard = typed.borrow();
let items: Vec<(Entity, *const T)> = guard
.iter()
.map(|(&e, v)| (e, v as *const T))
.collect();
drop(guard); Self { items, index: 0, _marker: PhantomData }
}
}
impl<'w, T: Component> Iterator for ComponentIter<'w, T> {
type Item = (Entity, &'w T);
fn next(&mut self) -> Option<Self::Item> {
let (entity, ptr) = *self.items.get(self.index)?;
self.index += 1;
Some((entity, unsafe { &*ptr }))
}
fn size_hint(&self) -> (usize, Option<usize>) {
let remaining = self.items.len() - self.index;
(remaining, Some(remaining))
}
}
unsafe impl<'w, T: Component> Send for ComponentIter<'w, T> {}
unsafe impl<'w, T: Component> Sync for ComponentIter<'w, T> {}
pub struct EntityBuilder<'w> {
world: &'w mut World,
entity: Entity,
}
impl<'w> EntityBuilder<'w> {
pub fn insert<T: Component>(self, component: T) -> Self {
let entity = self.entity;
self.world.insert(entity, component);
Self { world: self.world, entity }
}
pub fn insert_if<T: Component>(self, condition: bool, component: impl FnOnce() -> T) -> Self {
if condition {
self.insert(component())
} else {
self
}
}
#[inline]
pub fn id(self) -> Entity {
self.entity
}
#[inline]
pub fn entity(&self) -> Entity {
self.entity
}
pub fn despawn(self) {
let entity = self.entity;
self.world.despawn(entity);
}
}
pub struct WorldCell {
world: *mut World,
}
impl WorldCell {
pub unsafe fn new(world: &mut World) -> Self {
Self { world: world as *mut World }
}
pub fn get(&self) -> &World {
unsafe { &*self.world }
}
pub fn get_mut(&self) -> &mut World {
unsafe { &mut *self.world }
}
}
#[cfg(test)]
mod tests {
use super::*;
#[derive(Debug, Clone, PartialEq)]
struct Position { x: f32, y: f32 }
#[derive(Debug, Clone, PartialEq)]
struct Velocity { dx: f32, dy: f32 }
#[derive(Debug, Clone, PartialEq)]
struct Health(i32);
#[derive(Debug, Clone, PartialEq)]
struct Name(String);
#[derive(Debug, Clone, PartialEq)]
struct Gravity(f32);
#[test]
fn test_spawn_and_get() {
let mut world = World::new();
let e = world.spawn()
.insert(Position { x: 1.0, y: 2.0 })
.insert(Health(100))
.id();
assert!(world.is_alive(e));
assert_eq!(world.get::<Position>(e), Some(&Position { x: 1.0, y: 2.0 }));
assert_eq!(world.get::<Health>(e), Some(&Health(100)));
assert_eq!(world.get::<Velocity>(e), None);
assert_eq!(world.entity_count(), 1);
}
#[test]
fn test_despawn() {
let mut world = World::new();
let e = world.spawn().insert(Position { x: 0.0, y: 0.0 }).id();
assert!(world.is_alive(e));
assert!(world.despawn(e));
assert!(!world.is_alive(e));
assert_eq!(world.entity_count(), 0);
assert!(!world.despawn(e));
}
#[test]
fn test_insert_and_remove_component() {
let mut world = World::new();
let e = world.spawn_empty();
world.insert(e, Health(50));
assert_eq!(world.get::<Health>(e), Some(&Health(50)));
let old = world.remove::<Health>(e);
assert_eq!(old, Some(Health(50)));
assert!(!world.has::<Health>(e));
}
#[test]
fn test_get_mut() {
let mut world = World::new();
let e = world.spawn().insert(Health(10)).id();
if let Some(h) = world.get_mut::<Health>(e) {
h.0 += 5;
}
assert_eq!(world.get::<Health>(e), Some(&Health(15)));
}
#[test]
fn test_resources() {
let mut world = World::new();
world.insert_resource(Gravity(9.81));
assert!(world.has_resource::<Gravity>());
assert_eq!(world.resource::<Gravity>(), &Gravity(9.81));
world.resource_mut::<Gravity>().0 = 1.62;
assert_eq!(world.resource::<Gravity>().0, 1.62);
let removed = world.remove_resource::<Gravity>();
assert_eq!(removed, Some(Gravity(1.62)));
assert!(!world.has_resource::<Gravity>());
}
#[test]
fn test_for_each() {
let mut world = World::new();
for i in 0..5i32 {
world.spawn().insert(Health(i * 10)).insert(Position { x: i as f32, y: 0.0 });
}
let mut sum = 0;
world.for_each::<Health>(|_e, h| { sum += h.0; });
assert_eq!(sum, 0 + 10 + 20 + 30 + 40);
}
#[test]
fn test_for_each_mut() {
let mut world = World::new();
for i in 0..3i32 {
world.spawn().insert(Health(i));
}
world.for_each_mut::<Health>(|_e, h| { h.0 *= 2; });
let values: Vec<i32> = world
.entities_with::<Health>()
.iter()
.map(|&e| world.get::<Health>(e).unwrap().0)
.collect();
let mut sorted = values.clone();
sorted.sort();
assert_eq!(sorted, vec![0, 2, 4]);
}
#[test]
fn test_iter_component() {
let mut world = World::new();
let e1 = world.spawn().insert(Name("Alice".to_string())).id();
let e2 = world.spawn().insert(Name("Bob".to_string())).id();
let names: Vec<_> = world.iter_component::<Name>()
.map(|(e, n)| (e, n.0.clone()))
.collect();
assert_eq!(names.len(), 2);
}
#[test]
fn test_entities_with_all() {
let mut world = World::new();
let e1 = world.spawn().insert(Position { x: 0.0, y: 0.0 }).insert(Velocity { dx: 1.0, dy: 0.0 }).id();
let e2 = world.spawn().insert(Position { x: 1.0, y: 1.0 }).id(); let e3 = world.spawn().insert(Velocity { dx: 2.0, dy: 0.0 }).id();
let matches = world.entities_with_all(&[TypeId::of::<Position>(), TypeId::of::<Velocity>()]);
assert_eq!(matches.len(), 1);
assert!(matches.contains(&e1));
assert!(!matches.contains(&e2));
assert!(!matches.contains(&e3));
}
#[test]
fn test_clear() {
let mut world = World::new();
for _ in 0..10 {
world.spawn().insert(Health(1));
}
assert_eq!(world.entity_count(), 10);
world.clear();
assert_eq!(world.entity_count(), 0);
assert_eq!(world.component_count::<Health>(), 0);
}
#[test]
fn test_component_replace() {
let mut world = World::new();
let e = world.spawn().insert(Health(10)).id();
world.insert(e, Health(99));
assert_eq!(world.get::<Health>(e), Some(&Health(99)));
assert_eq!(world.component_count::<Health>(), 1);
}
#[test]
fn test_get_resource_or_insert_default() {
#[derive(Default, PartialEq, Debug)]
struct Counter(u32);
let mut world = World::new();
{
let c = world.get_resource_or_insert::<Counter>();
assert_eq!(c, &Counter(0));
c.0 = 5;
}
assert_eq!(world.resource::<Counter>(), &Counter(5));
}
#[test]
fn test_spawn_many() {
let mut world = World::new();
let mut entities = Vec::new();
for i in 0..100i32 {
let e = world.spawn().insert(Health(i)).id();
entities.push(e);
}
assert_eq!(world.entity_count(), 100);
for &e in entities.iter().step_by(2) {
world.despawn(e);
}
assert_eq!(world.entity_count(), 50);
}
#[test]
fn test_entity_builder_insert_if() {
let mut world = World::new();
let e = world.spawn()
.insert(Health(10))
.insert_if(false, || Velocity { dx: 1.0, dy: 0.0 })
.insert_if(true, || Position { x: 5.0, y: 5.0 })
.id();
assert!(world.has::<Health>(e));
assert!(!world.has::<Velocity>(e));
assert!(world.has::<Position>(e));
}
}