use crate::event::SetEntityEventTarget;
use crate::{
component::ComponentId,
entity::Entity,
event::{EntityEvent, Event},
observer::{CachedObservers, TriggerContext},
traversal::Traversal,
world::DeferredWorld,
};
use bevy_ptr::PtrMut;
use core::{fmt, marker::PhantomData};
pub unsafe trait Trigger<E: Event> {
unsafe fn trigger(
&mut self,
world: DeferredWorld,
observers: &CachedObservers,
trigger_context: &TriggerContext,
event: &mut E,
);
}
#[derive(Default, Debug)]
pub struct GlobalTrigger;
unsafe impl<E: for<'a> Event<Trigger<'a> = Self>> Trigger<E> for GlobalTrigger {
unsafe fn trigger(
&mut self,
world: DeferredWorld,
observers: &CachedObservers,
trigger_context: &TriggerContext,
event: &mut E,
) {
unsafe {
self.trigger_internal(world, observers, trigger_context, event.into());
}
}
}
impl GlobalTrigger {
unsafe fn trigger_internal(
&mut self,
mut world: DeferredWorld,
observers: &CachedObservers,
trigger_context: &TriggerContext,
mut event: PtrMut,
) {
unsafe {
world.as_unsafe_world_cell().increment_trigger_id();
}
for (observer, runner) in observers.global_observers() {
unsafe {
(runner)(
world.reborrow(),
*observer,
trigger_context,
event.reborrow(),
self.into(),
);
}
}
}
}
#[derive(Default, Debug)]
pub struct EntityTrigger;
unsafe impl<E: EntityEvent + for<'a> Event<Trigger<'a> = Self>> Trigger<E> for EntityTrigger {
unsafe fn trigger(
&mut self,
world: DeferredWorld,
observers: &CachedObservers,
trigger_context: &TriggerContext,
event: &mut E,
) {
let entity = event.event_target();
unsafe {
trigger_entity_internal(
world,
observers,
event.into(),
self.into(),
entity,
trigger_context,
);
}
}
}
#[inline(never)]
pub unsafe fn trigger_entity_internal(
mut world: DeferredWorld,
observers: &CachedObservers,
mut event: PtrMut,
mut trigger: PtrMut,
target_entity: Entity,
trigger_context: &TriggerContext,
) {
unsafe {
world.as_unsafe_world_cell().increment_trigger_id();
}
for (observer, runner) in observers.global_observers() {
unsafe {
(runner)(
world.reborrow(),
*observer,
trigger_context,
event.reborrow(),
trigger.reborrow(),
);
}
}
if let Some(map) = observers.entity_observers().get(&target_entity) {
for (observer, runner) in map {
unsafe {
(runner)(
world.reborrow(),
*observer,
trigger_context,
event.reborrow(),
trigger.reborrow(),
);
}
}
}
}
pub struct PropagateEntityTrigger<const AUTO_PROPAGATE: bool, E: EntityEvent, T: Traversal<E>> {
pub original_event_target: Entity,
pub propagate: bool,
_marker: PhantomData<(E, T)>,
}
impl<const AUTO_PROPAGATE: bool, E: EntityEvent, T: Traversal<E>> Default
for PropagateEntityTrigger<AUTO_PROPAGATE, E, T>
{
fn default() -> Self {
Self {
original_event_target: Entity::PLACEHOLDER,
propagate: AUTO_PROPAGATE,
_marker: Default::default(),
}
}
}
impl<const AUTO_PROPAGATE: bool, E: EntityEvent, T: Traversal<E>> fmt::Debug
for PropagateEntityTrigger<AUTO_PROPAGATE, E, T>
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("PropagateEntityTrigger")
.field("original_event_target", &self.original_event_target)
.field("propagate", &self.propagate)
.field("_marker", &self._marker)
.finish()
}
}
unsafe impl<
const AUTO_PROPAGATE: bool,
E: EntityEvent + SetEntityEventTarget + for<'a> Event<Trigger<'a> = Self>,
T: Traversal<E>,
> Trigger<E> for PropagateEntityTrigger<AUTO_PROPAGATE, E, T>
{
unsafe fn trigger(
&mut self,
mut world: DeferredWorld,
observers: &CachedObservers,
trigger_context: &TriggerContext,
event: &mut E,
) {
let mut current_entity = event.event_target();
self.original_event_target = current_entity;
unsafe {
trigger_entity_internal(
world.reborrow(),
observers,
event.into(),
self.into(),
current_entity,
trigger_context,
);
}
loop {
if !self.propagate {
return;
}
if let Ok(entity) = world.get_entity(current_entity)
&& let Ok(item) = entity.get_components::<T>()
&& let Some(traverse_to) = T::traverse(item, event)
{
current_entity = traverse_to;
} else {
break;
}
event.set_event_target(current_entity);
unsafe {
trigger_entity_internal(
world.reborrow(),
observers,
event.into(),
self.into(),
current_entity,
trigger_context,
);
}
}
}
}
#[derive(Default)]
pub struct EntityComponentsTrigger<'a> {
pub components: &'a [ComponentId],
}
unsafe impl<'a, E: EntityEvent + Event<Trigger<'a> = EntityComponentsTrigger<'a>>> Trigger<E>
for EntityComponentsTrigger<'a>
{
unsafe fn trigger(
&mut self,
world: DeferredWorld,
observers: &CachedObservers,
trigger_context: &TriggerContext,
event: &mut E,
) {
let entity = event.event_target();
unsafe {
self.trigger_internal(world, observers, event.into(), entity, trigger_context);
}
}
}
impl<'a> EntityComponentsTrigger<'a> {
#[inline(never)]
unsafe fn trigger_internal(
&mut self,
mut world: DeferredWorld,
observers: &CachedObservers,
mut event: PtrMut,
entity: Entity,
trigger_context: &TriggerContext,
) {
unsafe {
trigger_entity_internal(
world.reborrow(),
observers,
event.reborrow(),
self.into(),
entity,
trigger_context,
);
}
for id in self.components {
if let Some(component_observers) = observers.component_observers().get(id) {
for (observer, runner) in component_observers.global_observers() {
unsafe {
(runner)(
world.reborrow(),
*observer,
trigger_context,
event.reborrow(),
self.into(),
);
}
}
if let Some(map) = component_observers
.entity_component_observers()
.get(&entity)
{
for (observer, runner) in map {
unsafe {
(runner)(
world.reborrow(),
*observer,
trigger_context,
event.reborrow(),
self.into(),
);
}
}
}
}
}
}
}