diff --git a/src/runner/runner.rs b/src/runner/runner.rs index 22e65f5..0811be0 100644 --- a/src/runner/runner.rs +++ b/src/runner/runner.rs @@ -137,7 +137,7 @@ impl Runnable<'_>{ })?; if let Some(render_stepped)=render_stepped{ let signal:&super::script_signal::ScriptSignal=&*render_stepped.borrow()?; - signal.fire(mlua::MultiValue::new()); + signal.fire(&mlua::MultiValue::new()); } Ok(()) } diff --git a/src/runner/script_signal.rs b/src/runner/script_signal.rs index 5df43cd..ba6af7b 100644 --- a/src/runner/script_signal.rs +++ b/src/runner/script_signal.rs @@ -44,6 +44,7 @@ pub struct ScriptSignal{ callbacks:RcFunctionList, once:RcFunctionList, wait:Rc>>, + wait_function:std::cell::OnceCell, } pub struct ScriptConnection{ connection:RcFunctionList, @@ -55,6 +56,7 @@ impl ScriptSignal{ callbacks:RcFunctionList::new(), once:RcFunctionList::new(), wait:Rc::new(RefCell::new(Vec::new())), + wait_function:std::cell::OnceCell::new(), } } pub fn fire(&self,args:&mlua::MultiValue){ @@ -94,7 +96,45 @@ impl ScriptConnection{ } } +fn wait_thread(lua:&mlua::Lua,this:ScriptSignal)->Result<(),mlua::Error>{ + Ok(this.wait(lua.current_thread())) +} + +// This is used to avoid calling coroutine.yield from the rust side. +const LUA_WAIT:&str= +"local coroutine_yield=coroutine.yield +local wait_thread=wait_thread +return function() + wait_thread() + return coroutine_yield() +end"; + impl mlua::UserData for ScriptSignal{ + fn add_fields>(fields:&mut F){ + fields.add_field_method_get("Wait",|lua,this|{ + Ok(match this.wait_function.get(){ + Some(f)=>f.clone(), + None=>{ + let coroutine_table=lua.globals().get::("coroutine")?; + let wait_thread=lua.create_function(wait_thread)?; + + //create wait function environment + let wait_env=lua.create_table()?; + wait_env.raw_set("coroutine",coroutine_table)?; + wait_env.raw_set("wait_thread",wait_thread)?; + + //construct wait function from Lua code + let wait=lua.load(LUA_WAIT) + .set_name("wait") + .set_environment(wait_env) + .call::(())?; + + this.wait_function.set(wait.clone()).unwrap(); + wait + } + }) + }); + } fn add_methods>(methods:&mut M){ methods.add_method("Connect",|_lua,this,f:mlua::Function| Ok(this.connect(f)) @@ -102,10 +142,6 @@ impl mlua::UserData for ScriptSignal{ methods.add_method("Once",|_lua,this,f:mlua::Function| Ok(this.once(f)) ); - methods.add_method("Wait",|lua,this,()| - Ok(this.wait(lua.current_thread())) - todo!("coroutine.yield"); - ); // Fire is not allowed to be called from Lua // methods.add_method("Fire",|_lua,this,args:mlua::MultiValue| // Ok(this.fire(args))