diff --git a/crates/bevy_mod_scripting_core/src/handler.rs b/crates/bevy_mod_scripting_core/src/handler.rs index 322ea6adf..f75f6c973 100644 --- a/crates/bevy_mod_scripting_core/src/handler.rs +++ b/crates/bevy_mod_scripting_core/src/handler.rs @@ -1,4 +1,5 @@ //! Contains the logic for handling script callback events +use crate::script::ScriptExecutionOrder; use crate::{ bindings::{ pretty_print::DisplayWithWorld, script_value::ScriptValue, ThreadWorldContainer, @@ -129,7 +130,14 @@ pub fn event_handler( #[allow(deprecated)] pub(crate) type EventHandlerSystemState<'w, 's, P> = SystemState<( - Local<'s, QueryState<(Entity, Ref<'w, ScriptComponent>)>>, + Local< + 's, + QueryState<( + Entity, + Ref<'w, ScriptComponent>, + Option>, + )>, + >, crate::extractors::EventReaderScope<'s, ScriptCallbackEvent>, WithWorldGuard<'w, 's, HandlerContext<'s, P>>, )>; @@ -138,7 +146,13 @@ pub(crate) type EventHandlerSystemState<'w, 's, P> = SystemState<( #[allow(deprecated)] pub(crate) fn event_handler_inner( callback_label: CallbackLabel, - mut entity_query_state: Local)>>, + mut entity_query_state: Local< + QueryState<( + Entity, + Ref, + Option>, + )>, + >, mut script_events: crate::extractors::EventReaderScope, mut handler_ctxt: WithWorldGuard>, ) { @@ -152,13 +166,27 @@ pub(crate) fn event_handler_inner( let entity_and_static_scripts = guard.with_global_access(|world| { entity_query_state .iter(world) - .map(|(e, s)| (e, s.0.clone())) + // sort entity iteration by script execution order, if present + .sort_unstable_by_key::>, i32>(|e| match e { + None => 0, + Some(order) => order.0, + }) + .map(|(e, s, o)| { + ( + e, + s.0.clone(), + match o { + None => None, + Some(o) => Some(o.clone()), + }, + ) + }) .chain( handler_ctxt .static_scripts .scripts .iter() - .map(|s| (Entity::from_raw(0), vec![s.clone()])), + .map(|s| (Entity::from_raw(0), vec![s.clone()], None)), ) .collect::>() }); @@ -176,7 +204,7 @@ pub(crate) fn event_handler_inner( }; for event in events.into_iter().filter(|e| e.label == callback_label) { - for (entity, entity_scripts) in entity_and_static_scripts.iter() { + for (entity, entity_scripts, order) in entity_and_static_scripts.iter() { for script_id in entity_scripts.iter() { match &event.recipients { crate::event::Recipients::Script(target_script_id) diff --git a/crates/bevy_mod_scripting_core/src/script.rs b/crates/bevy_mod_scripting_core/src/script.rs index d5b0fe46a..7514d618a 100644 --- a/crates/bevy_mod_scripting_core/src/script.rs +++ b/crates/bevy_mod_scripting_core/src/script.rs @@ -18,6 +18,17 @@ pub type ScriptId = Cow<'static, str>; /// Event handlers search for components with this component to figure out which scripts to run and on which entities. pub struct ScriptComponent(pub Vec); +/// Specifies the order in which an entity's [ScriptComponent]'s +/// script callbacks are executed +/// relative to the script components on other entities. +/// +/// Higher values mean later execution. +/// Equal values have non-deterministic execution order. +/// If this is not present, a value of 0 is assumed. +#[derive(bevy::ecs::component::Component, Reflect, Clone, Copy, Ord, PartialOrd, Eq, PartialEq)] +#[reflect(Component)] +pub struct ScriptExecutionOrder(pub i32); + impl Deref for ScriptComponent { type Target = Vec;