diff --git a/crates/bevy_mod_scripting_core/src/asset.rs b/crates/bevy_mod_scripting_core/src/asset.rs index a41e911237..6e121b9f12 100644 --- a/crates/bevy_mod_scripting_core/src/asset.rs +++ b/crates/bevy_mod_scripting_core/src/asset.rs @@ -18,6 +18,7 @@ use bevy::{ reflect::TypePath, utils::HashMap, }; +use mlua::Table; use std::borrow::Cow; /// Represents a scripting language. Languages which compile into another language should use the target language as their language. @@ -169,6 +170,13 @@ impl Default for AssetPathToLanguageMapper { } } +/// stores environments for each script +#[derive(Default, Debug, Resource)] +pub struct ScriptEnvironmentStore { + /// The map of Script id's to their env + pub map: HashMap, +} + /// A cache of asset id's to their script id's. Necessary since when we drop an asset we won't have the ability to get the path from the asset. #[derive(Default, Debug, Resource)] pub struct ScriptMetadataStore { @@ -349,6 +357,7 @@ pub(crate) fn configure_asset_systems(app: &mut App) -> &mut App { .before(ScriptingSystemSet::ScriptMetadataRemoval), ), ) + .init_resource::() .init_resource::() .init_resource::() .add_event::(); diff --git a/crates/languages/bevy_mod_scripting_lua/src/lib.rs b/crates/languages/bevy_mod_scripting_lua/src/lib.rs index 5ad3b18aea..0f03843b92 100644 --- a/crates/languages/bevy_mod_scripting_lua/src/lib.rs +++ b/crates/languages/bevy_mod_scripting_lua/src/lib.rs @@ -5,7 +5,7 @@ use bevy::{ ecs::{entity::Entity, world::World}, }; use bevy_mod_scripting_core::{ - asset::{AssetPathToLanguageMapper, Language}, + asset::{AssetPathToLanguageMapper, Language, ScriptEnvironmentStore}, bindings::{ function::namespace::Namespace, globals::AppScriptGlobalsRegistry, script_value::ScriptValue, ThreadWorldContainer, WorldContainer, @@ -172,11 +172,25 @@ fn load_lua_content_into_context( .iter() .try_for_each(|init| init(script_id, Entity::from_raw(0), context))?; + // isolate the script's globals into an environment + let metatable = context.create_table()?; + metatable.set("__index", context.globals())?; + let env = context.create_table()?; + env.set_metatable(Some(metatable)); + context .load(content) + .set_environment(env.clone()) .exec() .map_err(ScriptError::from_mlua_error)?; + // store the env in the store so we can call BMS event handlers from them + let world = ThreadWorldContainer.try_get_world()?; + world.with_global_access(move |w| { + let map = &mut w.resource_mut::().map; + map.insert(script_id.clone(), env.clone()); + })?; + Ok(()) } @@ -240,7 +254,21 @@ pub fn lua_handler( .iter() .try_for_each(|init| init(script_id, entity, context))?; - let handler: Function = match context.globals().raw_get(callback_label.as_ref()) { + // we need the world to access the ScriptEnvironmentStore + // we will find the environment that belongs to this script to call the function + let world = ThreadWorldContainer.try_get_world()?; + let env = world.with_global_access(|w| { + w.resource::() + .map + .get(script_id) + .ok_or(ScriptError::new(format!( + "Could not find environment for script with ScriptId: {}", + script_id + ))) + .cloned() + })?; + + let handler: Function = match env?.raw_get(callback_label.as_ref()) { Ok(handler) => handler, // not subscribed to this event type Err(_) => {