use std::any::TypeId; use std::collections::HashMap; use crate::entity::{Entity, EntityAllocator}; use crate::sparse_set::{SparseSet, ComponentStorage}; pub struct World { allocator: EntityAllocator, storages: HashMap>, } impl World { pub fn new() -> Self { Self { allocator: EntityAllocator::new(), storages: HashMap::new(), } } pub fn spawn(&mut self) -> Entity { self.allocator.allocate() } pub fn despawn(&mut self, entity: Entity) -> bool { if !self.allocator.deallocate(entity) { return false; } for storage in self.storages.values_mut() { storage.remove_entity(entity); } true } pub fn is_alive(&self, entity: Entity) -> bool { self.allocator.is_alive(entity) } pub fn entity_count(&self) -> usize { self.allocator.alive_count() } pub fn add(&mut self, entity: Entity, component: T) { let type_id = TypeId::of::(); let storage = self.storages .entry(type_id) .or_insert_with(|| Box::new(SparseSet::::new())); let set = storage.as_any_mut().downcast_mut::>().unwrap(); set.insert(entity, component); } pub fn get(&self, entity: Entity) -> Option<&T> { let type_id = TypeId::of::(); let storage = self.storages.get(&type_id)?; let set = storage.as_any().downcast_ref::>()?; set.get(entity) } pub fn get_mut(&mut self, entity: Entity) -> Option<&mut T> { let type_id = TypeId::of::(); let storage = self.storages.get_mut(&type_id)?; let set = storage.as_any_mut().downcast_mut::>()?; set.get_mut(entity) } pub fn remove(&mut self, entity: Entity) -> Option { let type_id = TypeId::of::(); let storage = self.storages.get_mut(&type_id)?; let set = storage.as_any_mut().downcast_mut::>()?; set.remove(entity) } pub fn storage(&self) -> Option<&SparseSet> { let type_id = TypeId::of::(); let storage = self.storages.get(&type_id)?; storage.as_any().downcast_ref::>() } pub fn storage_mut(&mut self) -> Option<&mut SparseSet> { let type_id = TypeId::of::(); let storage = self.storages.get_mut(&type_id)?; storage.as_any_mut().downcast_mut::>() } pub fn query(&self) -> impl Iterator { self.storage::() .map(|s| s.iter()) .into_iter() .flatten() } pub fn query2(&self) -> Vec<(Entity, &A, &B)> { let a_storage = match self.storage::() { Some(s) => s, None => return Vec::new(), }; let b_storage = match self.storage::() { Some(s) => s, None => return Vec::new(), }; // Iterate the smaller set, look up in the larger let mut result = Vec::new(); if a_storage.len() <= b_storage.len() { for (entity, a) in a_storage.iter() { if let Some(b) = b_storage.get(entity) { result.push((entity, a, b)); } } } else { for (entity, b) in b_storage.iter() { if let Some(a) = a_storage.get(entity) { result.push((entity, a, b)); } } } result } pub fn query3(&self) -> Vec<(Entity, &A, &B, &C)> { let a_storage = match self.storage::() { Some(s) => s, None => return Vec::new(), }; let b_storage = match self.storage::() { Some(s) => s, None => return Vec::new(), }; let c_storage = match self.storage::() { Some(s) => s, None => return Vec::new(), }; // Find the smallest storage to iterate let a_len = a_storage.len(); let b_len = b_storage.len(); let c_len = c_storage.len(); let mut result = Vec::new(); if a_len <= b_len && a_len <= c_len { for (entity, a) in a_storage.iter() { if let (Some(b), Some(c)) = (b_storage.get(entity), c_storage.get(entity)) { result.push((entity, a, b, c)); } } } else if b_len <= a_len && b_len <= c_len { for (entity, b) in b_storage.iter() { if let (Some(a), Some(c)) = (a_storage.get(entity), c_storage.get(entity)) { result.push((entity, a, b, c)); } } } else { for (entity, c) in c_storage.iter() { if let (Some(a), Some(b)) = (a_storage.get(entity), b_storage.get(entity)) { result.push((entity, a, b, c)); } } } result } pub fn query4( &self, ) -> Vec<(Entity, &A, &B, &C, &D)> { let a_storage = match self.storage::() { Some(s) => s, None => return Vec::new(), }; let b_storage = match self.storage::() { Some(s) => s, None => return Vec::new(), }; let c_storage = match self.storage::() { Some(s) => s, None => return Vec::new(), }; let d_storage = match self.storage::() { Some(s) => s, None => return Vec::new(), }; // Find the smallest storage to iterate let a_len = a_storage.len(); let b_len = b_storage.len(); let c_len = c_storage.len(); let d_len = d_storage.len(); let mut result = Vec::new(); if a_len <= b_len && a_len <= c_len && a_len <= d_len { for (entity, a) in a_storage.iter() { if let (Some(b), Some(c), Some(d)) = ( b_storage.get(entity), c_storage.get(entity), d_storage.get(entity), ) { result.push((entity, a, b, c, d)); } } } else if b_len <= a_len && b_len <= c_len && b_len <= d_len { for (entity, b) in b_storage.iter() { if let (Some(a), Some(c), Some(d)) = ( a_storage.get(entity), c_storage.get(entity), d_storage.get(entity), ) { result.push((entity, a, b, c, d)); } } } else if c_len <= a_len && c_len <= b_len && c_len <= d_len { for (entity, c) in c_storage.iter() { if let (Some(a), Some(b), Some(d)) = ( a_storage.get(entity), b_storage.get(entity), d_storage.get(entity), ) { result.push((entity, a, b, c, d)); } } } else { for (entity, d) in d_storage.iter() { if let (Some(a), Some(b), Some(c)) = ( a_storage.get(entity), b_storage.get(entity), c_storage.get(entity), ) { result.push((entity, a, b, c, d)); } } } result } pub fn has_component(&self, entity: Entity) -> bool { self.storage::().map_or(false, |s| s.contains(entity)) } /// Query entities that have component T AND also have component W. pub fn query_with(&self) -> Vec<(Entity, &T)> { let t_storage = match self.storage::() { Some(s) => s, None => return Vec::new(), }; let mut result = Vec::new(); for (entity, data) in t_storage.iter() { if self.has_component::(entity) { result.push((entity, data)); } } result } /// Query entities that have component T but NOT component W. pub fn query_without(&self) -> Vec<(Entity, &T)> { let t_storage = match self.storage::() { Some(s) => s, None => return Vec::new(), }; let mut result = Vec::new(); for (entity, data) in t_storage.iter() { if !self.has_component::(entity) { result.push((entity, data)); } } result } /// Query entities with components A and B, that also have component W. pub fn query2_with(&self) -> Vec<(Entity, &A, &B)> { self.query2::().into_iter() .filter(|(e, _, _)| self.has_component::(*e)) .collect() } /// Query entities with components A and B, that do NOT have component W. pub fn query2_without(&self) -> Vec<(Entity, &A, &B)> { self.query2::().into_iter() .filter(|(e, _, _)| !self.has_component::(*e)) .collect() } } impl Default for World { fn default() -> Self { Self::new() } } #[cfg(test)] mod tests { use super::*; #[derive(Debug, PartialEq)] struct Position { x: f32, y: f32 } #[derive(Debug, PartialEq)] struct Velocity { dx: f32, dy: f32 } #[derive(Debug, PartialEq)] struct Name(String); #[test] fn test_spawn_and_add() { let mut world = World::new(); let e = world.spawn(); world.add(e, Position { x: 1.0, y: 2.0 }); let pos = world.get::(e).unwrap(); assert_eq!(pos.x, 1.0); assert_eq!(pos.y, 2.0); } #[test] fn test_get_missing() { let world = World::new(); let e = Entity { id: 0, generation: 0 }; assert!(world.get::(e).is_none()); } #[test] fn test_get_mut() { let mut world = World::new(); let e = world.spawn(); world.add(e, Position { x: 0.0, y: 0.0 }); { let pos = world.get_mut::(e).unwrap(); pos.x = 42.0; } assert_eq!(world.get::(e).unwrap().x, 42.0); } #[test] fn test_remove_component() { let mut world = World::new(); let e = world.spawn(); world.add(e, Position { x: 5.0, y: 6.0 }); let removed = world.remove::(e); assert_eq!(removed, Some(Position { x: 5.0, y: 6.0 })); assert!(world.get::(e).is_none()); } #[test] fn test_despawn() { let mut world = World::new(); let e = world.spawn(); world.add(e, Position { x: 1.0, y: 2.0 }); world.add(e, Velocity { dx: 3.0, dy: 4.0 }); assert!(world.despawn(e)); assert!(!world.is_alive(e)); assert!(world.get::(e).is_none()); assert!(world.get::(e).is_none()); } #[test] fn test_query_single() { let mut world = World::new(); let e0 = world.spawn(); let e1 = world.spawn(); let _e2 = world.spawn(); // no Position world.add(e0, Position { x: 1.0, y: 0.0 }); world.add(e1, Position { x: 2.0, y: 0.0 }); let results: Vec<(Entity, &Position)> = world.query::().collect(); assert_eq!(results.len(), 2); let entities: Vec = results.iter().map(|(e, _)| *e).collect(); assert!(entities.contains(&e0)); assert!(entities.contains(&e1)); } #[test] fn test_query2() { let mut world = World::new(); let e0 = world.spawn(); let e1 = world.spawn(); let e2 = world.spawn(); // only Position, no Velocity world.add(e0, Position { x: 1.0, y: 0.0 }); world.add(e0, Velocity { dx: 1.0, dy: 0.0 }); world.add(e1, Position { x: 2.0, y: 0.0 }); world.add(e1, Velocity { dx: 2.0, dy: 0.0 }); world.add(e2, Position { x: 3.0, y: 0.0 }); let results = world.query2::(); assert_eq!(results.len(), 2); let entities: Vec = results.iter().map(|(e, _, _)| *e).collect(); assert!(entities.contains(&e0)); assert!(entities.contains(&e1)); assert!(!entities.contains(&e2)); } #[test] fn test_query3() { #[derive(Debug, PartialEq)] struct Health(i32); let mut world = World::new(); let e0 = world.spawn(); world.add(e0, Position { x: 1.0, y: 0.0 }); world.add(e0, Velocity { dx: 1.0, dy: 0.0 }); world.add(e0, Health(100)); let e1 = world.spawn(); world.add(e1, Position { x: 2.0, y: 0.0 }); world.add(e1, Velocity { dx: 2.0, dy: 0.0 }); // e1 has no Health let results = world.query3::(); assert_eq!(results.len(), 1); assert_eq!(results[0].0, e0); } #[test] fn test_query4() { #[derive(Debug, PartialEq)] struct Health(i32); #[derive(Debug, PartialEq)] struct Tag(u8); let mut world = World::new(); let e0 = world.spawn(); world.add(e0, Position { x: 1.0, y: 0.0 }); world.add(e0, Velocity { dx: 1.0, dy: 0.0 }); world.add(e0, Health(100)); world.add(e0, Tag(1)); let e1 = world.spawn(); world.add(e1, Position { x: 2.0, y: 0.0 }); world.add(e1, Velocity { dx: 2.0, dy: 0.0 }); world.add(e1, Health(50)); // e1 has no Tag let e2 = world.spawn(); world.add(e2, Position { x: 3.0, y: 0.0 }); world.add(e2, Velocity { dx: 3.0, dy: 0.0 }); world.add(e2, Tag(2)); // e2 has no Health let results = world.query4::(); assert_eq!(results.len(), 1); assert_eq!(results[0].0, e0); } #[test] fn test_has_component() { let mut world = World::new(); let e = world.spawn(); world.add(e, Position { x: 1.0, y: 2.0 }); assert!(world.has_component::(e)); assert!(!world.has_component::(e)); } #[test] fn test_query_with() { let mut world = World::new(); let e0 = world.spawn(); let e1 = world.spawn(); let e2 = world.spawn(); world.add(e0, Position { x: 1.0, y: 0.0 }); world.add(e0, Velocity { dx: 1.0, dy: 0.0 }); world.add(e1, Position { x: 2.0, y: 0.0 }); // e1 has Position but no Velocity world.add(e2, Position { x: 3.0, y: 0.0 }); world.add(e2, Velocity { dx: 3.0, dy: 0.0 }); let results = world.query_with::(); assert_eq!(results.len(), 2); let entities: Vec = results.iter().map(|(e, _)| *e).collect(); assert!(entities.contains(&e0)); assert!(entities.contains(&e2)); assert!(!entities.contains(&e1)); } #[test] fn test_query_without() { let mut world = World::new(); let e0 = world.spawn(); let e1 = world.spawn(); let e2 = world.spawn(); world.add(e0, Position { x: 1.0, y: 0.0 }); world.add(e0, Velocity { dx: 1.0, dy: 0.0 }); world.add(e1, Position { x: 2.0, y: 0.0 }); // e1 has Position but no Velocity — should be included world.add(e2, Position { x: 3.0, y: 0.0 }); world.add(e2, Velocity { dx: 3.0, dy: 0.0 }); let results = world.query_without::(); assert_eq!(results.len(), 1); assert_eq!(results[0].0, e1); } #[test] fn test_query2_with() { #[derive(Debug, PartialEq)] struct Health(i32); let mut world = World::new(); let e0 = world.spawn(); world.add(e0, Position { x: 1.0, y: 0.0 }); world.add(e0, Velocity { dx: 1.0, dy: 0.0 }); world.add(e0, Health(100)); let e1 = world.spawn(); world.add(e1, Position { x: 2.0, y: 0.0 }); world.add(e1, Velocity { dx: 2.0, dy: 0.0 }); // e1 has no Health let results = world.query2_with::(); assert_eq!(results.len(), 1); assert_eq!(results[0].0, e0); } #[test] fn test_query2_without() { #[derive(Debug, PartialEq)] struct Health(i32); let mut world = World::new(); let e0 = world.spawn(); world.add(e0, Position { x: 1.0, y: 0.0 }); world.add(e0, Velocity { dx: 1.0, dy: 0.0 }); world.add(e0, Health(100)); let e1 = world.spawn(); world.add(e1, Position { x: 2.0, y: 0.0 }); world.add(e1, Velocity { dx: 2.0, dy: 0.0 }); // e1 has no Health let results = world.query2_without::(); assert_eq!(results.len(), 1); assert_eq!(results[0].0, e1); } #[test] fn test_entity_count() { let mut world = World::new(); assert_eq!(world.entity_count(), 0); let e0 = world.spawn(); let e1 = world.spawn(); assert_eq!(world.entity_count(), 2); world.despawn(e0); assert_eq!(world.entity_count(), 1); world.despawn(e1); assert_eq!(world.entity_count(), 0); } }