Skip to content

Commit e40db41

Browse files
authored
fix: rhai reloading behavior regression from #345 [SKIP_CHANGELOG] (#351)
fix: fix issues with rhai after re-loading each context properly
1 parent 7f13097 commit e40db41

File tree

9 files changed

+83
-35
lines changed

9 files changed

+83
-35
lines changed

assets/tests/api_availability/api_available_on_callback.lua

Lines changed: 0 additions & 5 deletions
This file was deleted.

assets/tests/api_availability/api_available_on_callback.rhai

Lines changed: 0 additions & 5 deletions
This file was deleted.
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
assert(world ~= nil, "World was not found")
2+
assert(world.get_type_by_name("TestComponent") ~= nil, "Could not find TestComponent type")
3+
local global_invocation = Entity.from_raw(1)
4+
5+
function on_test()
6+
assert(world ~= nil, "World was not found")
7+
assert(world.get_type_by_name("TestComponent") ~= nil, "Could not find TestComponent type")
8+
Entity.from_raw(1)
9+
10+
-- assert global_invocation happened
11+
assert(global_invocation ~= nil, "Global invocation did not happen")
12+
13+
return true
14+
end
15+
16+
function on_test_post_update()
17+
return true
18+
end
19+
20+
function on_test_last()
21+
return true
22+
end
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
assert(type_of(world) != "()", "World was not found");
2+
assert(type_of(world.get_type_by_name.call("TestComponent")) != "()", "Could not find TestComponent type");
3+
let global_invocation = Entity.from_raw.call(1);
4+
5+
fn on_test(){
6+
assert(type_of(world) != "()", "World was not found");
7+
assert(type_of(world.get_type_by_name.call("TestComponent")) != "()", "Could not find TestComponent type");
8+
Entity.from_raw.call(1);
9+
10+
// assert global_invocation happened
11+
assert(type_of(global_invocation) != "()", "Global invocation did not happen");
12+
13+
return true;
14+
}
15+
16+
fn on_test_post_update(){
17+
return true;
18+
}
19+
20+
fn on_test_last(){
21+
return true;
22+
}

assets/tests/api_availability/api_available_on_script_load.lua

Lines changed: 0 additions & 3 deletions
This file was deleted.

assets/tests/api_availability/api_available_on_script_load.rhai

Lines changed: 0 additions & 3 deletions
This file was deleted.

assets/tests/pop/vec.rhai

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,4 +3,4 @@ let res = world.get_resource.call(res_type);
33

44
let popped = res.vec_usize.pop.call();
55

6-
assert(popped == 5, "Pop did not work");
6+
assert(popped == 5, "Pop did not work, got " + popped);

crates/languages/bevy_mod_scripting_rhai/src/lib.rs

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -188,16 +188,18 @@ fn load_rhai_content_into_context(
188188
pre_handling_initializers: &[ContextPreHandlingInitializer<RhaiScriptingPlugin>],
189189
runtime: &mut RhaiRuntime,
190190
) -> Result<(), ScriptError> {
191-
let mut ast = runtime.compile(std::str::from_utf8(content)?)?;
192-
ast.set_source(script.to_string());
191+
context.ast = runtime.compile(std::str::from_utf8(content)?)?;
192+
context.ast.set_source(script.to_string());
193+
193194
initializers
194195
.iter()
195196
.try_for_each(|init| init(script, context))?;
196197
pre_handling_initializers
197198
.iter()
198199
.try_for_each(|init| init(script, Entity::from_raw(0), context))?;
199-
runtime.eval_ast_with_scope(&mut context.scope, &ast)?;
200-
// Unlike before, do not clear statements so that definitions persist.
200+
runtime.eval_ast_with_scope(&mut context.scope, &context.ast)?;
201+
202+
context.ast.clear_statements();
201203
Ok(())
202204
}
203205

crates/testing_crates/script_integration_test_harness/src/lib.rs

Lines changed: 32 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ use bevy_mod_scripting_core::{
2222
asset::ScriptAsset,
2323
bindings::{pretty_print::DisplayWithWorld, script_value::ScriptValue, WorldGuard},
2424
callback_labels,
25+
error::{InteropError, ScriptError},
2526
event::{IntoCallbackLabel, ScriptErrorEvent},
2627
extractors::{HandlerContext, WithWorldGuard},
2728
handler::handle_script_errors,
@@ -43,13 +44,14 @@ struct TestCallbackBuilder<P: IntoScriptPluginParams, L: IntoCallbackLabel> {
4344
}
4445

4546
impl<L: IntoCallbackLabel, P: IntoScriptPluginParams> TestCallbackBuilder<P, L> {
46-
fn build(script_id: impl Into<ScriptId>) -> SystemConfigs {
47+
fn build(script_id: impl Into<ScriptId>, expect_response: bool) -> SystemConfigs {
4748
let script_id = script_id.into();
4849
IntoSystem::into_system(
4950
move |world: &mut World,
5051
system_state: &mut SystemState<WithWorldGuard<HandlerContext<P>>>| {
5152
let with_guard = system_state.get_mut(world);
52-
run_test_callback::<P, L>(&script_id.clone(), with_guard);
53+
let _ = run_test_callback::<P, L>(&script_id.clone(), with_guard, expect_response);
54+
5355
system_state.apply(world);
5456
},
5557
)
@@ -103,13 +105,22 @@ pub fn execute_integration_test<
103105
*handle = server.load(script_id.to_owned());
104106
};
105107

108+
// tests can opt in to this via "__RETURN"
109+
let expect_callback_response = script_id.contains("__RETURN");
110+
106111
app.add_systems(Startup, load_system);
107-
app.add_systems(Update, TestCallbackBuilder::<P, OnTest>::build(script_id));
112+
app.add_systems(
113+
Update,
114+
TestCallbackBuilder::<P, OnTest>::build(script_id, expect_callback_response),
115+
);
108116
app.add_systems(
109117
PostUpdate,
110-
TestCallbackBuilder::<P, OnTestPostUpdate>::build(script_id),
118+
TestCallbackBuilder::<P, OnTestPostUpdate>::build(script_id, expect_callback_response),
119+
);
120+
app.add_systems(
121+
Last,
122+
TestCallbackBuilder::<P, OnTestLast>::build(script_id, expect_callback_response),
111123
);
112-
app.add_systems(Last, TestCallbackBuilder::<P, OnTestLast>::build(script_id));
113124
app.add_systems(Update, dummy_update_system);
114125
app.add_systems(Startup, dummy_startup_system::<String>);
115126

@@ -147,11 +158,12 @@ pub fn execute_integration_test<
147158
fn run_test_callback<P: IntoScriptPluginParams, C: IntoCallbackLabel>(
148159
script_id: &str,
149160
mut with_guard: WithWorldGuard<'_, '_, HandlerContext<'_, P>>,
150-
) {
161+
expect_response: bool,
162+
) -> Result<ScriptValue, ScriptError> {
151163
let (guard, handler_ctxt) = with_guard.get_mut();
152164

153165
if !handler_ctxt.is_script_fully_loaded(script_id.to_string().into()) {
154-
return;
166+
return Ok(ScriptValue::Unit);
155167
}
156168

157169
let res = handler_ctxt.call::<C>(
@@ -163,14 +175,20 @@ fn run_test_callback<P: IntoScriptPluginParams, C: IntoCallbackLabel>(
163175
let e = match res {
164176
Ok(ScriptValue::Error(e)) => e.into(),
165177
Err(e) => e,
166-
_ => {
167-
match guard.with_resource_mut(|mut events: Mut<Events<TestEventFinished>>| {
168-
events.send(TestEventFinished)
169-
}) {
170-
Ok(_) => return,
171-
Err(e) => e.into(),
178+
Ok(v) => {
179+
if expect_response && !matches!(v, ScriptValue::Bool(true)) {
180+
InteropError::external_error(format!("Response from callback {} was either not received or wasn't correct. Expected true, got: {v:?}", C::into_callback_label()).into()).into()
181+
} else {
182+
match guard.with_resource_mut(|mut events: Mut<Events<TestEventFinished>>| {
183+
events.send(TestEventFinished)
184+
}) {
185+
Ok(_) => return Ok(v),
186+
Err(e) => e.into(),
187+
}
172188
}
173189
}
174190
};
175-
handle_script_errors(guard, vec![e].into_iter())
191+
handle_script_errors(guard, vec![e.clone()].into_iter());
192+
193+
Err(e)
176194
}

0 commit comments

Comments
 (0)