From c2087b142bd36a0fc240b396f5af187a1de2e701 Mon Sep 17 00:00:00 2001 From: Shane Celis Date: Mon, 19 May 2025 07:19:26 -0400 Subject: [PATCH 1/4] feature: Warn on unknown language. --- crates/bevy_mod_scripting_core/src/asset.rs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/crates/bevy_mod_scripting_core/src/asset.rs b/crates/bevy_mod_scripting_core/src/asset.rs index 5b122ab7f8..c077ce82e6 100644 --- a/crates/bevy_mod_scripting_core/src/asset.rs +++ b/crates/bevy_mod_scripting_core/src/asset.rs @@ -225,6 +225,14 @@ pub(crate) fn dispatch_script_asset_events( let script_id = converter(path); let language = settings.select_script_language(path); + if language == Language::Unknown { + let extension = path + .path() + .extension() + .and_then(|ext| ext.to_str()) + .unwrap_or_default(); + warn!("A script {:?} was added but its language is unknown. Consider adding the {:?} extension to the `ScriptAssetSettings`.", &script_id, extension); + } let metadata = ScriptMetadata { asset_id: *id, script_id, From 7cda1782193a5a91002e89659b9425395dc3df8a Mon Sep 17 00:00:00 2001 From: Shane Celis Date: Wed, 21 May 2025 06:50:25 -0400 Subject: [PATCH 2/4] feature: Add on_script_reloaded callback. --- .../bevy_mod_scripting_core/src/commands.rs | 40 +++++++++++++++++-- crates/bevy_mod_scripting_core/src/event.rs | 1 + docs/src/ScriptingReference/core-callbacks.md | 24 ++++++++++- 3 files changed, 61 insertions(+), 4 deletions(-) diff --git a/crates/bevy_mod_scripting_core/src/commands.rs b/crates/bevy_mod_scripting_core/src/commands.rs index 57b37195a9..ca888daa85 100644 --- a/crates/bevy_mod_scripting_core/src/commands.rs +++ b/crates/bevy_mod_scripting_core/src/commands.rs @@ -6,7 +6,7 @@ use crate::{ context::ContextBuilder, error::{InteropError, ScriptError}, event::{ - CallbackLabel, IntoCallbackLabel, OnScriptLoaded, OnScriptUnloaded, + CallbackLabel, IntoCallbackLabel, OnScriptLoaded, OnScriptUnloaded, OnScriptReloaded, ScriptCallbackResponseEvent, }, extractors::{with_handler_system_state, HandlerContext}, @@ -150,6 +150,7 @@ impl CreateOrUpdateScript

{ #[profiling::all_functions] impl Command for CreateOrUpdateScript

{ fn apply(self, world: &mut bevy::prelude::World) { + let mut reload_state = None; let success = with_handler_system_state( world, |guard, handler_ctxt: &mut HandlerContext

| { @@ -194,6 +195,28 @@ impl Command for CreateOrUpdateScript

{ // it can potentially be loaded but without a successful script reload but that // leaves us in an okay state handler_ctxt.scripts.scripts.insert(self.id.clone(), script); + } else { + match handler_ctxt.call_dynamic_label( + &OnScriptReloaded::into_callback_label(), + &self.id, + Entity::from_raw(0), + vec![ScriptValue::Bool(true)], + guard.clone(), + ) { + Ok(state) => { + reload_state = Some(state); + } + Err(err) => { + handle_script_errors( + guard.clone(), + vec![err + .with_script(self.id.clone()) + .with_context(P::LANGUAGE) + .with_context("saving reload state")] + .into_iter(), + ); + } + } } bevy::log::debug!("{}: reloading script with id: {}", P::LANGUAGE, self.id); self.reload_context(guard.clone(), handler_ctxt) @@ -235,14 +258,25 @@ impl Command for CreateOrUpdateScript

{ // immediately run command for callback, but only if loading went fine if success { RunScriptCallback::

::new( - self.id, + self.id.clone(), Entity::from_raw(0), OnScriptLoaded::into_callback_label(), vec![], false, ) - .apply(world) + .apply(world); + + if let Some(state) = reload_state { + RunScriptCallback::

::new( + self.id, + Entity::from_raw(0), + OnScriptReloaded::into_callback_label(), + vec![ScriptValue::Bool(false), state], + false, + ).apply(world); + } } + } } diff --git a/crates/bevy_mod_scripting_core/src/event.rs b/crates/bevy_mod_scripting_core/src/event.rs index 7d9c5c3da7..5146e52134 100644 --- a/crates/bevy_mod_scripting_core/src/event.rs +++ b/crates/bevy_mod_scripting_core/src/event.rs @@ -75,6 +75,7 @@ macro_rules! callback_labels { callback_labels!( OnScriptLoaded => "on_script_loaded", OnScriptUnloaded => "on_script_unloaded", + OnScriptReloaded => "on_script_reloaded", ); /// A trait for types that can be converted into a callback label diff --git a/docs/src/ScriptingReference/core-callbacks.md b/docs/src/ScriptingReference/core-callbacks.md index b8f81a7b95..150badeaab 100644 --- a/docs/src/ScriptingReference/core-callbacks.md +++ b/docs/src/ScriptingReference/core-callbacks.md @@ -2,9 +2,10 @@ On top of callbacks which are registered by your application, BMS provides a set of core callbacks which are always available. -The two core callbacks are: +The three core callbacks are: - `on_script_loaded` - `on_script_unloaded` +- `on_script_reloaded` ## `on_script_loaded` @@ -30,3 +31,24 @@ function on_script_unloaded() print("Goodbye world") end ``` + +## `on_script_reloaded` + +This will be called twice: right before and after a script is reloaded. + +The first parameter `save` informs you whether it is time to save a value or restore it. + +Before the reload, it is called with one argument: `true`. After the script is reloaded, it is called with two parameters: the first is `false` and the second is value returned from before. + +```lua +mode = 1 +function on_script_reloaded(save, value) + if save then + print("Before I go, take this.") + return mode + else + print("I'm back. Where was I?") + mode = value + end +end +``` From d59839ebd6a8615afebcc6df9405707b57f937ed Mon Sep 17 00:00:00 2001 From: Shane Celis Date: Wed, 21 May 2025 07:07:00 -0400 Subject: [PATCH 3/4] style: Reformat. --- crates/bevy_mod_scripting_core/src/commands.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/crates/bevy_mod_scripting_core/src/commands.rs b/crates/bevy_mod_scripting_core/src/commands.rs index ca888daa85..2d75719edb 100644 --- a/crates/bevy_mod_scripting_core/src/commands.rs +++ b/crates/bevy_mod_scripting_core/src/commands.rs @@ -6,7 +6,7 @@ use crate::{ context::ContextBuilder, error::{InteropError, ScriptError}, event::{ - CallbackLabel, IntoCallbackLabel, OnScriptLoaded, OnScriptUnloaded, OnScriptReloaded, + CallbackLabel, IntoCallbackLabel, OnScriptLoaded, OnScriptReloaded, OnScriptUnloaded, ScriptCallbackResponseEvent, }, extractors::{with_handler_system_state, HandlerContext}, @@ -273,10 +273,10 @@ impl Command for CreateOrUpdateScript

{ OnScriptReloaded::into_callback_label(), vec![ScriptValue::Bool(false), state], false, - ).apply(world); + ) + .apply(world); } } - } } From ed8b2af23c4b502f3fb236530ecbe6797e63eca6 Mon Sep 17 00:00:00 2001 From: Shane Celis Date: Mon, 26 May 2025 00:32:12 -0400 Subject: [PATCH 4/4] feature: Reload hook for non-shared context. --- .../bevy_mod_scripting_core/src/commands.rs | 23 ++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/crates/bevy_mod_scripting_core/src/commands.rs b/crates/bevy_mod_scripting_core/src/commands.rs index 2d75719edb..8fddc9855b 100644 --- a/crates/bevy_mod_scripting_core/src/commands.rs +++ b/crates/bevy_mod_scripting_core/src/commands.rs @@ -212,7 +212,7 @@ impl Command for CreateOrUpdateScript

{ vec![err .with_script(self.id.clone()) .with_context(P::LANGUAGE) - .with_context("saving reload state")] + .with_context("saving reload state (shared-context)")] .into_iter(), ); } @@ -222,6 +222,27 @@ impl Command for CreateOrUpdateScript

{ self.reload_context(guard.clone(), handler_ctxt) } None => { + match handler_ctxt.call_dynamic_label( + &OnScriptReloaded::into_callback_label(), + &self.id, + Entity::from_raw(0), + vec![ScriptValue::Bool(true)], + guard.clone(), + ) { + Ok(state) => { + reload_state = Some(state); + } + Err(err) => { + handle_script_errors( + guard.clone(), + vec![err + .with_script(self.id.clone()) + .with_context(P::LANGUAGE) + .with_context("saving reload state")] + .into_iter(), + ); + } + } bevy::log::debug!("{}: loading script with id: {}", P::LANGUAGE, self.id); self.load_context(guard.clone(), handler_ctxt) }