#![expect(unsafe_code, reason = "Unsafe code is used to improve performance.")]
use core::{marker::PhantomData, mem};
use bevy_ecs::{
bundle::{Bundle, DynamicBundle},
event::{EntityEvent, EventPattern},
system::IntoObserverSystem,
};
pub struct AddObserver<E, M, I>
where
E: EventPattern<Event: EntityEvent>,
I: IntoObserverSystem<E, M>,
{
observer: I,
marker: PhantomData<(E, M)>,
}
unsafe impl<E, M, I> Bundle for AddObserver<E, M, I>
where
E: EventPattern<Event: EntityEvent>,
M: Send + Sync + 'static,
I: IntoObserverSystem<E, M> + Send + Sync,
{
#[inline]
fn component_ids(
_components: &mut bevy_ecs::component::ComponentsRegistrator,
) -> impl Iterator<Item = bevy_ecs::component::ComponentId> + use<E, M, I> {
core::iter::empty()
}
#[inline]
fn get_component_ids(
_components: &bevy_ecs::component::Components,
) -> impl Iterator<Item = Option<bevy_ecs::component::ComponentId>> {
core::iter::empty()
}
}
impl<E, M, I> DynamicBundle for AddObserver<E, M, I>
where
E: EventPattern<Event: EntityEvent>,
I: IntoObserverSystem<E, M>,
{
type Effect = Self;
#[inline]
unsafe fn get_components(
ptr: bevy_ecs::ptr::MovingPtr<'_, Self>,
_func: &mut impl FnMut(bevy_ecs::component::StorageType, bevy_ecs::ptr::OwningPtr<'_>),
) {
mem::forget(ptr);
}
#[inline]
unsafe fn apply_effect(
ptr: bevy_ecs::ptr::MovingPtr<'_, mem::MaybeUninit<Self>>,
entity: &mut bevy_ecs::world::EntityWorldMut,
) {
let add_observer = unsafe { ptr.assume_init() };
if entity.is_despawned() {
return;
}
let add_observer = add_observer.read();
entity.observe(add_observer.observer);
}
}
pub fn observe<E, M, I>(observer: I) -> AddObserver<E, M, I>
where
E: EventPattern<Event: EntityEvent>,
I: IntoObserverSystem<E, M>,
{
AddObserver {
observer,
marker: PhantomData,
}
}