use std::sync::Mutex; use elua::{AsLua, StdLibraries}; use crate::{ScriptHost, ScriptError, ScriptWorldPtr, ScriptEntity}; #[derive(Default)] pub struct LuaHost; fn try_call_lua_function(lua: &elua::State, fn_name: &str) -> Result<(), ScriptError> { let globals = lua.globals()?; if globals.has_key(fn_name)? { let lua_fn = globals.get::<_, elua::Function>(fn_name)?; lua_fn.exec(()) .map_err(ScriptError::MluaError)?; } Ok(()) } impl ScriptHost for LuaHost { type ScriptContext = Mutex; fn load_script(&mut self, script: &[u8], script_data: &crate::ScriptData, providers: &mut crate::ScriptApiProviders) -> Result { let mut ctx = Mutex::new({ let s = elua::State::new(); s.expose_libraries(StdLibraries::all()); s }); for provider in providers.apis.iter_mut() { provider.expose_api(script_data, &mut ctx)?; } let lua = ctx.lock().unwrap(); lua.load(&script_data.name, script)? .execute(()) .map_err(|e| ScriptError::MluaError(e))?; drop(lua); Ok(ctx) } fn setup_script(&mut self, script_data: &crate::ScriptData, ctx: &mut Self::ScriptContext, providers: &mut crate::ScriptApiProviders) -> Result<(), ScriptError> { for provider in providers.apis.iter_mut() { provider.setup_script(script_data, ctx)?; } Ok(()) } /// Runs the update step of the lua script. /// /// It looks for an `update` function with zero parameters in the [`ScriptContext`] and executes it. fn call_script(&mut self, world: ScriptWorldPtr, script_data: &crate::ScriptData, ctx: &mut Self::ScriptContext, providers: &mut crate::ScriptApiProviders, function_name: &str) -> Result<(), ScriptError> { for provider in providers.apis.iter_mut() { provider.update_script_environment(world.clone(), script_data, ctx)?; } let ctx = ctx.lock().expect("Failure to get Lua ScriptContext"); let globals = ctx.globals()?; globals.set("world", world.as_lua(&ctx)?)?; globals.set("entity", ScriptEntity(script_data.entity).as_lua(&ctx)?)?; try_call_lua_function(&ctx, function_name)?; Ok(()) } }