Skip to content

Commit 1eb54d0

Browse files
committed
fix safety boundaries
1 parent 950b41b commit 1eb54d0

File tree

2 files changed

+54
-19
lines changed

2 files changed

+54
-19
lines changed

crates/bevy_mod_scripting_core/src/extractors.rs

Lines changed: 46 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,11 @@ pub fn with_handler_system_state<
5353
///
5454
/// This is useful for interacting with scripts, since [`WithWorldGuard`] will ensure scripts cannot gain exclusive access to the world if *any* reads or writes
5555
/// are claimed on the world. Removing the resource from the world lets you access it in the context of running scripts without blocking exclusive world access.
56-
pub struct ResScope<'state, T: Resource + Default>(pub &'state mut T);
56+
///
57+
/// # Safety
58+
/// - Because the resource is removed during the `get_param` call, if there is a conflicting resource access, this will be unsafe
59+
/// - You must ensure you're only using this in combination with system parameters which will not read or write to this resource in `get_param`
60+
pub(crate) struct ResScope<'state, T: Resource + Default>(pub &'state mut T);
5761

5862
impl<T: Resource + Default> Deref for ResScope<'_, T> {
5963
type Target = T;
@@ -108,8 +112,12 @@ unsafe impl<T: Resource + Default> SystemParam for ResScope<'_, T> {
108112
}
109113

110114
/// A version of [`bevy::ecs::event::EventReader`] which behaves just like [`ResScope`].
115+
///
116+
/// # Safety
117+
/// - unsafe to use this in a way which violates the invariants on [`ResScope`].
111118
#[derive(SystemParam)]
112-
pub struct EventReaderScope<'s, T: Event> {
119+
#[doc(hidden)]
120+
pub(crate) struct EventReaderScope<'s, T: Event> {
113121
events: ResScope<'s, Events<T>>,
114122
reader: Local<'s, EventCursor<T>>,
115123
}
@@ -125,20 +133,50 @@ impl<T: Event> EventReaderScope<'_, T> {
125133
#[derive(SystemParam)]
126134
pub struct HandlerContext<'s, P: IntoScriptPluginParams> {
127135
/// Settings for callbacks
128-
pub callback_settings: ResScope<'s, CallbackSettings<P>>,
136+
pub(crate) callback_settings: ResScope<'s, CallbackSettings<P>>,
129137
/// Settings for loading contexts
130-
pub context_loading_settings: ResScope<'s, ContextLoadingSettings<P>>,
138+
pub(crate) context_loading_settings: ResScope<'s, ContextLoadingSettings<P>>,
131139
/// Scripts
132-
pub scripts: ResScope<'s, Scripts>,
140+
pub(crate) scripts: ResScope<'s, Scripts>,
133141
/// The runtime container
134-
pub runtime_container: ResScope<'s, RuntimeContainer<P>>,
142+
pub(crate) runtime_container: ResScope<'s, RuntimeContainer<P>>,
135143
/// The script contexts
136-
pub script_contexts: ResScope<'s, ScriptContexts<P>>,
144+
pub(crate) script_contexts: ResScope<'s, ScriptContexts<P>>,
137145
/// List of static scripts
138-
pub static_scripts: ResScope<'s, StaticScripts>,
146+
pub(crate) static_scripts: ResScope<'s, StaticScripts>,
139147
}
140148

141149
impl<P: IntoScriptPluginParams> HandlerContext<'_, P> {
150+
/// Get the callback settings
151+
pub fn callback_settings(&mut self) -> &mut CallbackSettings<P> {
152+
&mut self.callback_settings
153+
}
154+
155+
/// Get the context loading settings
156+
pub fn context_loading_settings(&mut self) -> &mut ContextLoadingSettings<P> {
157+
&mut self.context_loading_settings
158+
}
159+
160+
/// Get the scripts
161+
pub fn scripts(&mut self) -> &mut Scripts {
162+
&mut self.scripts
163+
}
164+
165+
/// Get the runtime container
166+
pub fn runtime_container(&mut self) -> &mut RuntimeContainer<P> {
167+
&mut self.runtime_container
168+
}
169+
170+
/// Get the script contexts
171+
pub fn script_contexts(&mut self) -> &mut ScriptContexts<P> {
172+
&mut self.script_contexts
173+
}
174+
175+
/// Get the static scripts
176+
pub fn static_scripts(&mut self) -> &mut StaticScripts {
177+
&mut self.static_scripts
178+
}
179+
142180
/// checks if the script is loaded such that it can be executed.
143181
pub fn is_script_fully_loaded(&self, script_id: ScriptId) -> bool {
144182
// check script exists in scripts and contexts

crates/bevy_mod_scripting_core/src/handler.rs

Lines changed: 8 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ use bevy::{
1919
system::{Local, Resource, SystemState},
2020
world::{Mut, World},
2121
},
22-
log::{self, trace_once},
22+
log::trace_once,
2323
prelude::{Events, Ref},
2424
};
2525

@@ -106,6 +106,10 @@ macro_rules! push_err_and_continue {
106106
/// Passes events with the specified label to the script callback with the same name and runs the callback.
107107
///
108108
/// If any of the resources required for the handler are missing, the system will log this issue and do nothing.
109+
#[allow(
110+
private_interfaces,
111+
reason = "people should not need to use this as a function, they only need the type signature"
112+
)]
109113
pub fn event_handler<L: IntoCallbackLabel, P: IntoScriptPluginParams>(
110114
world: &mut World,
111115
state: &mut SystemState<(
@@ -130,12 +134,7 @@ fn event_handler_inner<L: IntoCallbackLabel, P: IntoScriptPluginParams>(
130134
mut handler_ctxt: WithWorldGuard<HandlerContext<P>>,
131135
) {
132136
let (guard, handler_ctxt) = handler_ctxt.get_mut();
133-
// bevy::log::debug!(
134-
// "{}: scripts:{} contexts:{}",
135-
// P::LANGUAGE,
136-
// handler_ctxt.scripts.scripts.len(),
137-
// handler_ctxt.script_contexts.contexts.len()
138-
// );
137+
139138
let mut errors = Vec::default();
140139

141140
let events = script_events.read().cloned().collect::<Vec<_>>();
@@ -568,15 +567,13 @@ mod test {
568567

569568
assert!(app
570569
.world()
571-
.get_resource::<Events<ScriptCallbackEvent>>()
572-
.is_some());
570+
.contains_resource::<Events<ScriptCallbackEvent>>());
573571

574572
let mut local = SystemState::from_world(app.world_mut());
575573

576574
assert!(!app
577575
.world()
578-
.get_resource::<Events<ScriptCallbackEvent>>()
579-
.is_some());
576+
.contains_resource::<Events<ScriptCallbackEvent>>());
580577

581578
event_handler::<OnTestCallback, TestPlugin>(app.world_mut(), &mut local);
582579

0 commit comments

Comments
 (0)