#![feature( never_type, try_blocks, trait_alias, control_flow_enum, let_chains, binary_heap_drain_sorted, fn_traits, unboxed_closures, tuple_trait, trait_upcasting )] pub mod ai; pub mod data; pub mod event; pub mod gen; pub mod rule; pub use self::{ data::Data, event::{Event, EventCtx, OnTick}, rule::{Rule, RuleError}, }; use anymap2::SendSyncAnyMap; use atomic_refcell::AtomicRefCell; use common::resources::{Time, TimeOfDay}; use std::{ any::type_name, ops::{Deref, DerefMut}, }; use tracing::{error, info}; use world::{IndexRef, World}; pub struct RtState { resources: SendSyncAnyMap, rules: SendSyncAnyMap, event_handlers: SendSyncAnyMap, } type RuleState = AtomicRefCell; type EventHandlersOf = Vec>; impl RtState { pub fn new(data: Data) -> Self { let mut this = Self { resources: SendSyncAnyMap::new(), rules: SendSyncAnyMap::new(), event_handlers: SendSyncAnyMap::new(), } .with_resource(data); this.start_default_rules(); this } pub fn with_resource(mut self, r: R) -> Self { self.resources.insert(AtomicRefCell::new(r)); self } fn start_default_rules(&mut self) { info!("Starting default rtsim rules..."); self.start_rule::(); self.start_rule::(); self.start_rule::(); self.start_rule::(); self.start_rule::(); self.start_rule::(); self.start_rule::(); } pub fn start_rule(&mut self) { info!("Initiating '{}' rule...", type_name::()); match R::start(self) { Ok(rule) => { self.rules.insert::>(AtomicRefCell::new(rule)); }, Err(e) => error!("Error when initiating '{}' rule: {}", type_name::(), e), } } fn rule_mut(&self) -> impl DerefMut + '_ { self.rules .get::>() .unwrap_or_else(|| { panic!( "Tried to access rule '{}' but it does not exist", type_name::() ) }) .borrow_mut() } // TODO: Consider whether it's worth explicitly calling rule event handlers // instead of allowing them to bind event handlers. Less modular, but // potentially easier to deal with data dependencies? pub fn bind( &mut self, f: impl FnMut(EventCtx) + Send + Sync + 'static, ) { let f = AtomicRefCell::new(f); self.event_handlers .entry::>() .or_default() .push(Box::new(move |state, world, index, event| { (f.borrow_mut())(EventCtx { state, rule: &mut state.rule_mut(), event, world, index, }) })); } pub fn data(&self) -> impl Deref + '_ { self.resource() } pub fn data_mut(&self) -> impl DerefMut + '_ { self.resource_mut() } pub fn get_data_mut(&mut self) -> &mut Data { self.get_resource_mut() } pub fn resource(&self) -> impl Deref + '_ { self.resources .get::>() .unwrap_or_else(|| { panic!( "Tried to access resource '{}' but it does not exist", type_name::() ) }) .borrow() } pub fn get_resource_mut(&mut self) -> &mut R { self.resources .get_mut::>() .unwrap_or_else(|| { panic!( "Tried to access resource '{}' but it does not exist", type_name::() ) }) .get_mut() } pub fn resource_mut(&self) -> impl DerefMut + '_ { self.resources .get::>() .unwrap_or_else(|| { panic!( "Tried to access resource '{}' but it does not exist", type_name::() ) }) .borrow_mut() } pub fn emit(&mut self, e: E, world: &World, index: IndexRef) { // TODO: Queue these events up and handle them on a regular rtsim tick instead // of executing their handlers immediately. if let Some(handlers) = self.event_handlers.get::>() { handlers.iter().for_each(|f| f(self, world, index, &e)); } } pub fn tick( &mut self, world: &World, index: IndexRef, time_of_day: TimeOfDay, time: Time, dt: f32, ) { let tick = { let mut data = self.data_mut(); data.time_of_day = time_of_day; data.tick += 1; data.tick }; let event = OnTick { time_of_day, tick, time, dt, }; self.emit(event, world, index); } }