use std::{
any::Any,
cell::Cell,
collections::{BTreeMap, HashMap},
};
use crate::{
entity::{EntityComponentManager, EntityContainer},
error::NotFound,
};
#[cfg(test)]
mod tests;
pub type Priority = i32;
pub trait System<T>: Any
where
T: EntityContainer,
{
fn run(&self, entities: &T, ecm: &mut EntityComponentManager);
}
pub struct EntitySystem<T> {
pub system: Box<dyn System<T>>,
priority: Priority,
}
impl<T> EntitySystem<T> {
pub fn new(system: Box<dyn System<T>>) -> Self {
EntitySystem {
system,
priority: 0,
}
}
}
pub struct EntitySystemBuilder<'a, T>
where
T: EntityContainer,
{
pub entity_system_id: u32,
pub entity_system_manager: &'a mut EntitySystemManager<T>,
pub priority: Cell<i32>,
}
impl<'a, T> EntitySystemBuilder<'a, T>
where
T: EntityContainer,
{
pub fn with_priority(self, priority: Priority) -> Self {
self.priority.set(priority);
self
}
pub fn build(self) -> u32 {
self.entity_system_manager
.register_priority(self.priority.get(), self.entity_system_id);
self.entity_system_id
}
}
#[derive(Default)]
pub struct EntitySystemManager<T>
where
T: EntityContainer,
{
entity_systems: HashMap<u32, EntitySystem<T>>,
init_system: Option<EntitySystem<T>>,
cleanup_system: Option<EntitySystem<T>>,
pub priorities: BTreeMap<i32, Vec<u32>>,
}
impl<T> EntitySystemManager<T>
where
T: EntityContainer,
{
pub fn new() -> Self {
EntitySystemManager {
entity_systems: HashMap::new(),
init_system: None,
cleanup_system: None,
priorities: BTreeMap::new(),
}
}
pub fn register_init_system(&mut self, init_system: impl System<T>) {
self.init_system = Some(EntitySystem::new(Box::new(init_system)));
}
pub fn register_cleanup_system(&mut self, cleanup_system: impl System<T>) {
self.cleanup_system = Some(EntitySystem::new(Box::new(cleanup_system)));
}
pub fn register_system(&mut self, system: impl System<T>, system_id: u32) {
self.entity_systems
.insert(system_id, EntitySystem::new(Box::new(system)));
}
pub fn remove_system(&mut self, system_id: u32) {
self.entity_systems.remove(&system_id);
}
pub fn register_priority(&mut self, priority: Priority, system_id: u32) {
self.entity_systems.get_mut(&system_id).unwrap().priority = priority;
if !self.priorities.contains_key(&priority) {
self.priorities.insert(priority, vec![system_id]);
return;
}
self.priorities.get_mut(&priority).unwrap().push(system_id);
}
pub fn borrow_entity_system(
&self,
entity_system_id: u32,
) -> Result<&EntitySystem<T>, NotFound> {
self.entity_systems.get(&entity_system_id).map_or_else(
|| Err(NotFound::EntitySystem(entity_system_id)),
|es| Ok(es),
)
}
pub fn borrow_init_system(
&self,
) -> &Option<EntitySystem<T>> {
&self.init_system
}
pub fn borrow_cleanup_system(
&self,
) -> &Option<EntitySystem<T>> {
&self.cleanup_system
}
}