Skip to content

Add reload hook support for non-shared contexts. #424

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 4 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions crates/bevy_mod_scripting_core/src/asset.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
61 changes: 58 additions & 3 deletions crates/bevy_mod_scripting_core/src/commands.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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},
Expand Down Expand Up @@ -150,6 +150,7 @@ impl<P: IntoScriptPluginParams> CreateOrUpdateScript<P> {
#[profiling::all_functions]
impl<P: IntoScriptPluginParams> Command for CreateOrUpdateScript<P> {
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<P>| {
Expand Down Expand Up @@ -194,11 +195,54 @@ impl<P: IntoScriptPluginParams> Command for CreateOrUpdateScript<P> {
// 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 (shared-context)")]
.into_iter(),
);
}
}
}
bevy::log::debug!("{}: reloading script with id: {}", P::LANGUAGE, self.id);
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)
}
Expand Down Expand Up @@ -235,13 +279,24 @@ impl<P: IntoScriptPluginParams> Command for CreateOrUpdateScript<P> {
// immediately run command for callback, but only if loading went fine
if success {
RunScriptCallback::<P>::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::<P>::new(
self.id,
Entity::from_raw(0),
OnScriptReloaded::into_callback_label(),
vec![ScriptValue::Bool(false), state],
false,
)
.apply(world);
}
}
}
}
Expand Down
1 change: 1 addition & 0 deletions crates/bevy_mod_scripting_core/src/event.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
24 changes: 23 additions & 1 deletion docs/src/ScriptingReference/core-callbacks.md
Original file line number Diff line number Diff line change
Expand Up @@ -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`

Expand All @@ -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
```
Loading