pub use tick::Tick; mod tick{ #[derive(Clone,Copy,Default,Hash,PartialEq,Eq,PartialOrd,Ord)] pub struct Tick(u64); impl Tick{ pub const fn new(value:u64)->Self{ Self(value) } pub const fn get(&self)->u64{ self.0 } } impl std::ops::Add<u64> for Tick{ type Output=Self; fn add(self,rhs:u64)->Self::Output{ Self(self.0+rhs) } } impl std::ops::Sub<u64> for Tick{ type Output=Self; fn sub(self,rhs:u64)->Self::Output{ Self(self.0-rhs) } } impl std::ops::AddAssign<u64> for Tick{ fn add_assign(&mut self,rhs:u64){ self.0+=rhs; } } impl std::ops::SubAssign<u64> for Tick{ fn sub_assign(&mut self,rhs:u64){ self.0-=rhs; } } } #[derive(Default)] pub struct Scheduler{ tick:Tick, schedule:std::collections::HashMap<Tick,Vec<mlua::Thread>>, } impl Scheduler{ pub const fn tick(&self)->Tick{ self.tick } pub fn has_scheduled_threads(&self)->bool{ !self.schedule.is_empty() } pub fn schedule_thread(&mut self,delay:u64,thread:mlua::Thread){ self.schedule.entry(self.tick+delay.max(1)) .or_insert(Vec::new()) .push(thread); } pub fn tick_threads(&mut self)->Option<Vec<mlua::Thread>>{ self.tick+=1; self.schedule.remove(&self.tick) } } fn coerce_float64(value:&mlua::Value)->Option<f64>{ match value{ &mlua::Value::Integer(i)=>Some(i as f64), &mlua::Value::Number(f)=>Some(f), _=>None, } } pub fn scheduler_mut<T>(lua:&mlua::Lua,mut f:impl FnMut(&mut crate::scheduler::Scheduler)->mlua::Result<T>)->mlua::Result<T>{ let mut scheduler=lua.app_data_mut::<crate::scheduler::Scheduler>().ok_or(mlua::Error::runtime("Scheduler missing"))?; f(&mut *scheduler) } pub fn set_globals(lua:&mlua::Lua,globals:&mlua::Table)->Result<(),mlua::Error>{ let schedule_thread=lua.create_function(move|lua,dt:mlua::Value|{ let delay=coerce_float64(&dt).ok_or(mlua::Error::runtime("Expected float"))?.max(0.0)*60.0; if delay<u64::MAX as f64{ scheduler_mut(lua,|scheduler|{ scheduler.schedule_thread((delay as u64).max(2),lua.current_thread()); Ok(()) }).unwrap(); } Ok(()) })?; let wait_env=lua.create_table()?; wait_env.raw_set("coroutine",globals.get::<mlua::Table>("coroutine")?)?; wait_env.raw_set("schedule_thread",schedule_thread)?; let wait=lua.load(" local coroutine_yield=coroutine.yield local schedule_thread=schedule_thread return function(dt) schedule_thread(dt) return coroutine_yield() end ") .set_name("wait") .set_environment(wait_env) .call::<mlua::Function>(())?; globals.raw_set("wait",wait)?; Ok(()) }