diff --git a/crates/bevy_mod_scripting_core/src/commands.rs b/crates/bevy_mod_scripting_core/src/commands.rs index 57b37195a9..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, + CallbackLabel, IntoCallbackLabel, OnScriptLoaded, OnScriptReloaded, OnScriptUnloaded, 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,13 +258,24 @@ 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 +```