bevy_ecs/observer/
runner.rs1use core::any::Any;
4
5use crate::{
6 error::ErrorContext,
7 event::Event,
8 observer::TriggerContext,
9 prelude::*,
10 query::DebugCheckedUnwrap,
11 system::{ObserverSystem, RunSystemError},
12 world::DeferredWorld,
13};
14use bevy_ptr::PtrMut;
15
16pub type ObserverRunner =
23 unsafe fn(DeferredWorld, observer: Entity, &TriggerContext, event: PtrMut, trigger: PtrMut);
24
25pub(super) unsafe fn observer_system_runner<E: Event, B: Bundle, S: ObserverSystem<E, B>>(
36 mut world: DeferredWorld,
37 observer: Entity,
38 trigger_context: &TriggerContext,
39 event_ptr: PtrMut,
40 trigger_ptr: PtrMut,
41) {
42 let world = world.as_unsafe_world_cell();
43
44 let observer_cell = unsafe { world.get_entity(observer).debug_checked_unwrap() };
46 let mut state = unsafe { observer_cell.get_mut::<Observer>().debug_checked_unwrap() };
48
49 let last_trigger = world.last_trigger_id();
51 if state.last_trigger_id == last_trigger {
52 return;
53 }
54 state.last_trigger_id = last_trigger;
55
56 let mut should_run = true;
61 for condition in state.conditions.iter_mut() {
62 should_run &= unsafe { condition.check(world) };
64 }
65
66 if !should_run {
67 return;
68 }
69
70 let trigger: &mut E::Trigger<'_> = unsafe { trigger_ptr.deref_mut() };
78
79 let on: On<E, B> = On::new(
80 unsafe { event_ptr.deref_mut() },
82 observer,
83 trigger,
84 trigger_context,
85 );
86
87 let system: *mut dyn ObserverSystem<E, B> = unsafe {
91 let system: &mut dyn Any = state.system.as_mut();
92 let system = system.downcast_mut::<S>().debug_checked_unwrap();
93 &mut *system
94 };
95
96 unsafe {
102 #[cfg(feature = "hotpatching")]
103 if world
104 .get_resource_ref::<crate::HotPatchChanges>()
105 .is_none_or(|r| r.is_changed_after((*system).get_last_run()))
106 {
107 (*system).refresh_hotpatch();
108 };
109
110 if let Err(RunSystemError::Failed(err)) = (*system).run_unsafe(on, world) {
111 let handler = state
112 .error_handler
113 .unwrap_or_else(|| world.fallback_error_handler());
114 handler(
115 err,
116 ErrorContext::Observer {
117 name: (*system).name(),
118 last_run: (*system).get_last_run(),
119 },
120 );
121 };
122 (*system).queue_deferred(world.into_deferred());
123 }
124}
125
126#[cfg(test)]
127mod tests {
128 use super::*;
129 use crate::{
130 error::{ignore, FallbackErrorHandler},
131 event::Event,
132 observer::On,
133 };
134
135 #[derive(Event)]
136 struct TriggerEvent;
137
138 #[test]
139 #[should_panic(expected = "I failed!")]
140 fn test_fallible_observer() {
141 fn system(_: On<TriggerEvent>) -> Result {
142 Err("I failed!".into())
143 }
144
145 let mut world = World::default();
146 world.add_observer(system);
147 Schedule::default().run(&mut world);
148 world.trigger(TriggerEvent);
149 }
150
151 #[test]
152 fn test_fallible_observer_ignored_errors() {
153 #[derive(Resource, Default)]
154 struct Ran(bool);
155
156 fn system(_: On<TriggerEvent>, mut ran: ResMut<Ran>) -> Result {
157 ran.0 = true;
158 Err("I failed!".into())
159 }
160
161 let mut world = World::default();
163 world.init_resource::<Ran>();
164 world.spawn(Observer::new(system).with_error_handler(ignore));
165 world.trigger(TriggerEvent);
166 assert!(world.resource::<Ran>().0);
167
168 let mut world = World::default();
170 world.init_resource::<Ran>();
171 world.spawn(Observer::new(system));
172 world.insert_resource(FallbackErrorHandler(ignore));
175 world.trigger(TriggerEvent);
176 assert!(world.resource::<Ran>().0);
177 }
178
179 #[test]
180 #[should_panic]
181 fn exclusive_system_cannot_be_observer() {
182 fn system(_: On<TriggerEvent>, _world: &mut World) {}
183 let mut world = World::default();
184 world.add_observer(system);
185 }
186}