Compare commits

...

4 Commits

Author SHA1 Message Date
2c4b58c5ca set_environment makes print disappear 2024-10-16 19:11:19 -07:00
909c00c5f6 game ticks api 2024-10-16 19:11:19 -07:00
3981d25305 why is there no coroutine 2024-10-16 19:11:19 -07:00
442d7af333 wait 2024-10-16 19:11:19 -07:00
2 changed files with 80 additions and 9 deletions

View File

@ -23,12 +23,58 @@ impl std::fmt::Display for Error{
} }
impl std::error::Error for Error{} impl std::error::Error for Error{}
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,
}
}
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)
}
fn init(lua:&mlua::Lua)->mlua::Result<()>{ fn init(lua:&mlua::Lua)->mlua::Result<()>{
lua.sandbox(true)?; lua.sandbox(true)?;
lua.load_std_libs(
mlua::StdLib::COROUTINE
|mlua::StdLib::TABLE
|mlua::StdLib::OS
|mlua::StdLib::STRING
|mlua::StdLib::UTF8
|mlua::StdLib::BIT
|mlua::StdLib::MATH
|mlua::StdLib::BUFFER
)?;
//global environment //global environment
let globals=lua.globals(); let globals=lua.globals();
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.raw_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)?;
super::r#enum::set_globals(lua,&globals)?; super::r#enum::set_globals(lua,&globals)?;
super::color3::set_globals(lua,&globals)?; super::color3::set_globals(lua,&globals)?;
super::vector3::set_globals(lua,&globals)?; super::vector3::set_globals(lua,&globals)?;
@ -83,20 +129,42 @@ impl Runnable<'_>{
} }
pub fn run_script(&self,script:super::instance::Instance)->Result<(),Error>{ pub fn run_script(&self,script:super::instance::Instance)->Result<(),Error>{
let (name,source)=super::instance::get_name_source(&self.lua,script).map_err(Error::RustLua)?; let (name,source)=super::instance::get_name_source(&self.lua,script).map_err(Error::RustLua)?;
let fenv=self.lua.create_table().map_err(Error::RustLua)?;
//there's gotta be a more concise way to do this
for pair in self.lua.globals().pairs::<mlua::Value,mlua::Value>(){
let (k,v)=pair.map_err(Error::RustLua)?;
fenv.raw_set(k,v).map_err(Error::RustLua)?;
}
fenv.raw_set("script",script).map_err(Error::RustLua)?;
let f=self.lua.load(source.as_str()) let f=self.lua.load(source.as_str())
.set_name(name).into_function().map_err(Error::RustLua)?; .set_name(name).into_function().map_err(Error::RustLua)?;
f.set_environment(fenv).map_err(Error::RustLua)?;
// let fenv=self.lua.create_table().map_err(Error::RustLua)?;
// //there's gotta be a more concise way to do this
// for pair in f.environment().unwrap().pairs::<mlua::Value,mlua::Value>(){
// let (k,v)=pair.map_err(Error::RustLua)?;
// fenv.raw_set(k,v).map_err(Error::RustLua)?;
// }
// fenv.raw_set("script",script).map_err(Error::RustLua)?;
// f.set_environment(fenv).map_err(Error::RustLua)?;
self.lua.globals().raw_set("script",script).map_err(Error::RustLua)?;
let thread=self.lua.create_thread(f).map_err(Error::RustLua)?; let thread=self.lua.create_thread(f).map_err(Error::RustLua)?;
thread.resume::<mlua::MultiValue>(()).map_err(|error|Error::Lua{source,error})?; thread.resume::<mlua::MultiValue>(()).map_err(|error|Error::Lua{source,error})?;
// wait() is called from inside Lua and goes to a rust function that schedules the thread and then yields // wait() is called from inside Lua and goes to a rust function that schedules the thread and then yields
// No need to schedule the thread here // No need to schedule the thread here
Ok(()) Ok(())
} }
pub fn has_scheduled_threads(&self)->Result<bool,mlua::Error>{
scheduler_mut(&self.lua,|scheduler|
Ok(scheduler.has_scheduled_threads())
)
}
pub fn game_tick(&self)->Result<(),mlua::Error>{
if let Some(threads)=scheduler_mut(&self.lua,|scheduler|Ok(scheduler.tick_threads()))?{
for thread in threads{
//TODO: return dt and total run time
let result=thread.resume::<mlua::MultiValue>((1.0/20.0,0.0))
.map_err(|error|Error::Lua{source:"source unavailable".to_owned(),error});
match result{
Ok(_)=>(),
Err(e)=>println!("game_tick Error: {e}"),
}
}
}
Ok(())
}
} }

View File

@ -43,6 +43,9 @@ impl Scheduler{
pub const fn tick(&self)->Tick{ pub const fn tick(&self)->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){ pub fn schedule_thread(&mut self,delay:u64,thread:mlua::Thread){
self.schedule.entry(self.tick+delay.max(1)) self.schedule.entry(self.tick+delay.max(1))
.or_insert(Vec::new()) .or_insert(Vec::new())