2024-01-05 01:52:47 +00:00
|
|
|
use std::sync::Mutex;
|
|
|
|
|
2024-01-07 05:57:19 +00:00
|
|
|
use mlua::IntoLua;
|
2024-01-12 19:11:33 +00:00
|
|
|
use tracing::{debug, trace};
|
2024-01-05 01:52:47 +00:00
|
|
|
|
2024-01-07 05:57:19 +00:00
|
|
|
use crate::{ScriptHost, ScriptError, ScriptWorldPtr, ScriptEntity};
|
2024-01-05 01:52:47 +00:00
|
|
|
|
|
|
|
#[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 }) => {
|
2024-01-12 19:11:33 +00:00
|
|
|
trace!("Function '{}' was not found, ignoring...", fn_name)
|
2024-01-05 01:52:47 +00:00
|
|
|
// ignore
|
|
|
|
},
|
|
|
|
Err(e) => {
|
|
|
|
return Err(ScriptError::MluaError(e));
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
|
|
|
impl ScriptHost for LuaHost {
|
|
|
|
type ScriptContext = Mutex<mlua::Lua>;
|
|
|
|
|
|
|
|
fn load_script(&mut self, script: &[u8], script_data: &crate::ScriptData, providers: &mut crate::ScriptApiProviders<Self>) -> Result<Self::ScriptContext, crate::ScriptError> {
|
|
|
|
let mut ctx = Mutex::new(mlua::Lua::new());
|
|
|
|
|
|
|
|
for provider in providers.apis.iter_mut() {
|
2024-01-17 04:04:17 +00:00
|
|
|
provider.expose_api(script_data, &mut ctx)?;
|
2024-01-05 01:52:47 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
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<Self>) -> 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");
|
2024-01-07 05:57:19 +00:00
|
|
|
try_call_lua_function(&ctx, "on_init")?;
|
2024-01-05 01:52:47 +00:00
|
|
|
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Runs the update step of the lua script.
|
|
|
|
///
|
|
|
|
/// It looks for an `update` function with zero parameters in [`the ScriptContext`] and executes it.
|
2024-01-07 05:57:19 +00:00
|
|
|
fn call_script(&mut self, world: ScriptWorldPtr, script_data: &crate::ScriptData,
|
|
|
|
ctx: &mut Self::ScriptContext, providers: &mut crate::ScriptApiProviders<Self>,
|
|
|
|
function_name: &str) -> Result<(), ScriptError> {
|
2024-01-05 01:52:47 +00:00
|
|
|
for provider in providers.apis.iter_mut() {
|
|
|
|
provider.update_script_environment(world.clone(), script_data, ctx)?;
|
|
|
|
}
|
2024-01-07 05:57:19 +00:00
|
|
|
|
2024-01-05 01:52:47 +00:00
|
|
|
let ctx = ctx.lock().expect("Failure to get Lua ScriptContext");
|
2024-01-07 05:57:19 +00:00
|
|
|
|
|
|
|
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)?;
|
2024-01-05 01:52:47 +00:00
|
|
|
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
}
|