use std::sync::Mutex; use mlua::IntoLua; use tracing::debug; use crate::{ScriptHost, ScriptError, ScriptWorldPtr, ScriptEntity}; #[derive(Default)] pub struct LuaHost; fn try_call_lua_function(lua: &mlua::Lua, fn_name: &str) -> Result<(), ScriptError> { let globals = lua.globals(); match globals.get::<_, mlua::Function>(fn_name) { Ok(init_fn) => { init_fn.call(()) .map_err(ScriptError::MluaError)?; }, Err(mlua::Error::FromLuaConversionError { from: "nil", to: "function", message: None }) => { debug!("Function '{}' was not found, ignoring...", fn_name) // ignore }, Err(e) => { return Err(ScriptError::MluaError(e)); }, } 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(mlua::Lua::new()); for provider in providers.apis.iter_mut() { provider.expose_api(&mut ctx)?; } let lua = ctx.lock().unwrap(); lua.load(script) .set_name(&script_data.name) .exec() .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)?; } let ctx = ctx.lock().expect("Failure to get Lua ScriptContext"); try_call_lua_function(&ctx, "on_init")?; 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.into_lua(&ctx)?)?; globals.set("entity", ScriptEntity(script_data.entity).into_lua(&ctx)?)?; try_call_lua_function(&ctx, function_name)?; Ok(()) } }