use core::cell::Cell;
use core::ops::Drop;
use crate::{
component::*,
entity::*,
system::{System, SystemStore, SystemStoreBuilder},
};
pub struct World<E, Ctx>
where
E: EntityStore,
{
entity_component_manager: EntityComponentManager<E>,
system_store: SystemStore<E, Ctx>,
system_counter: u32,
first_run: bool,
}
impl<E, Ctx> Drop for World<E, Ctx>
where
E: EntityStore,
{
fn drop(&mut self) {
if let Some(cleanup_system) = self.system_store.borrow_cleanup_system() {
cleanup_system
.system
.run(&mut self.entity_component_manager);
}
}
}
unsafe impl<E, Ctx> Send for World<E, Ctx> where E: EntityStore {}
impl<E, Ctx> World<E, Ctx>
where
E: EntityStore,
{
pub fn from_entity_store(entity_store: E) -> Self {
World {
entity_component_manager: EntityComponentManager::new(entity_store),
system_counter: 0,
system_store: SystemStore::new(),
first_run: true,
}
}
pub fn create_entity(&mut self) -> EntityBuilder<'_, E> {
self.entity_component_manager.create_entity()
}
pub fn remove_entity(&mut self, entity: impl Into<Entity>) {
self.entity_component_manager.remove_entity(entity);
}
pub fn register_init_system(&mut self, init_system: impl System<E, Ctx>) {
self.system_store.register_init_system(init_system);
}
pub fn register_cleanup_system(&mut self, cleanup_system: impl System<E, Ctx>) {
self.system_store.register_cleanup_system(cleanup_system);
}
pub fn create_system(&mut self, system: impl System<E, Ctx>) -> SystemStoreBuilder<'_, E, Ctx> {
let entity_system_id = self.system_counter;
self.system_store.register_system(system, entity_system_id);
self.system_counter += 1;
SystemStoreBuilder {
system_store: &mut self.system_store,
entity_system_id,
priority: Cell::new(0),
}
}
pub fn remove_system(&mut self, system_id: u32) {
self.system_store.remove_system(system_id);
}
pub fn entity_component_manager(&mut self) -> &mut EntityComponentManager<E> {
&mut self.entity_component_manager
}
pub fn print_entity(&self, entity: impl Into<Entity>) {
self.entity_component_manager
.component_store()
.print_entity(entity);
}
pub fn run(&mut self) {
if self.first_run {
if let Some(init_system) = self.system_store.borrow_init_system() {
init_system.system.run(&mut self.entity_component_manager);
}
self.first_run = false;
}
let priorities = &self.system_store.priorities;
for priority in priorities.values() {
for system in priority {
self.system_store
.borrow_entity_system(*system)
.unwrap()
.system
.run(&mut self.entity_component_manager);
}
}
}
pub fn run_with_context(&mut self, ctx: &mut Ctx) {
if self.first_run {
if let Some(init_system) = self.system_store.borrow_init_system() {
init_system
.system
.run_with_context(&mut self.entity_component_manager, ctx);
}
self.first_run = false;
}
let priorities = &self.system_store.priorities;
for priority in priorities.values() {
for system in priority {
self.system_store
.borrow_entity_system(*system)
.unwrap()
.system
.run_with_context(&mut self.entity_component_manager, ctx);
}
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::entity::{Entity, VecEntityStore};
use crate::system::PhantomContext;
#[derive(Default)]
struct TestSystem;
impl System<VecEntityStore, PhantomContext> for TestSystem {
fn run(&self, _ecm: &mut EntityComponentManager<VecEntityStore>) {}
}
#[test]
fn create_entity() {
let mut world: World<VecEntityStore, PhantomContext> =
World::from_entity_store(VecEntityStore::default());
assert_eq!(Entity(0), world.create_entity().build());
assert_eq!(Entity(1), world.create_entity().build());
}
#[test]
fn create_system() {
let mut world = World::from_entity_store(VecEntityStore::default());
assert_eq!(0, world.create_system(TestSystem).build());
assert_eq!(1, world.create_system(TestSystem).build());
}
}