use std::collections::HashMap; use lyra_ecs::{ResourceObject, Entity}; use crate::ScriptWorldPtr; #[derive(Debug, thiserror::Error)] pub enum ScriptError { #[error("{0}")] #[cfg(feature = "lua")] MluaError(mlua::Error), #[error("{0}")] Other(anyhow::Error), } #[cfg(feature = "lua")] impl From for ScriptError { fn from(value: mlua::Error) -> Self { ScriptError::MluaError(value) } } impl From for ScriptError { fn from(value: anyhow::Error) -> Self { ScriptError::Other(value) } } #[derive(Clone, Hash, PartialEq, Eq)] pub struct ScriptData { /// The script id pub script_id: u64, /// The name of the script pub name: String, /// The entity that this script exists on pub entity: Entity, } /// Provides an API to a scripting context. pub trait ScriptApiProvider { /// The type used as the script's context. type ScriptContext; /// Exposes an API in the provided script context. fn expose_api(&mut self, ctx: &mut Self::ScriptContext) -> Result<(), ScriptError>; /// Setup a script right before its 'init' method is called. fn setup_script(&mut self, data: &ScriptData, ctx: &mut Self::ScriptContext) -> Result<(), ScriptError>; /// A function that is used to update a script's environment. /// /// This is used to update stuff like the world pointer in the script context. fn update_script_environment(&mut self, world: ScriptWorldPtr, data: &ScriptData, ctx: &mut Self::ScriptContext) -> Result<(), ScriptError>; } /// A storage for a [`ScriptHost`]'s api providers #[derive(Default)] pub struct ScriptApiProviders { pub apis: Vec>>, } impl ScriptApiProviders { pub fn add_provider

(&mut self, provider: P) where P: ScriptApiProvider + 'static { self.apis.push(Box::new(provider)); } } pub trait ScriptHost: Default + ResourceObject { /// The type used as the script's context. type ScriptContext; /// Loads a script and creates a context for it. /// /// Before the script is executed, the API providers are exposed to the script. fn load_script(&mut self, script: &[u8], script_data: &ScriptData, providers: &mut crate::ScriptApiProviders) -> Result; /// Setup a script for execution. fn setup_script(&mut self, script_data: &ScriptData, ctx: &mut Self::ScriptContext, providers: &mut ScriptApiProviders) -> Result<(), ScriptError>; /// Executes the update step for the script. fn call_script(&mut self, world: ScriptWorldPtr, script_data: &crate::ScriptData, ctx: &mut Self::ScriptContext, providers: &mut crate::ScriptApiProviders, function_name: &str) -> Result<(), ScriptError>; } #[derive(Default)] pub struct ScriptContexts { contexts: HashMap, } impl ScriptContexts { pub fn new(contexts: HashMap) -> Self { Self { contexts, } } pub fn add_context(&mut self, script_id: u64, context: T) { self.contexts.insert(script_id, context); } pub fn get_context(&self, script_id: u64) -> Option<&T> { self.contexts.get(&script_id) } pub fn get_context_mut(&mut self, script_id: u64) -> Option<&mut T> { self.contexts.get_mut(&script_id) } pub fn has_context(&self, script_id: u64) -> bool { self.contexts.contains_key(&script_id) } }