use super::{AddHook, DespawnHook, RemoveHook, SetHook, World};
use crate::archetype::ComponentInfo;
use crate::component::Component;
use crate::entity::Entity;
use std::any::TypeId;
use std::collections::HashMap;
impl World {
#[inline]
pub fn register_component_type<T: Component>(&mut self) {
let type_id = TypeId::of::<T>();
self.component_infos
.entry(type_id)
.or_insert_with(ComponentInfo::of::<T>);
}
pub fn add_observer<T: Component, F>(&mut self, mut system: F) -> &mut Self
where
F: FnMut(crate::observer::On<crate::observer::Insert, T>) + Send + Sync + 'static,
{
let type_id = TypeId::of::<T>();
let mut hooks = self.component_hooks.remove(&type_id).unwrap_or_default();
hooks.on_add.push(Box::new(move |_world, entity| {
let event = crate::observer::On {
event: crate::observer::Insert,
entity,
_marker: std::marker::PhantomData,
};
system(event);
}));
self.component_hooks.insert(type_id, hooks);
self
}
pub fn observe<E: crate::observer::EntityEvent, F>(&mut self, entity: Entity, listener: F) -> &mut Self
where
F: FnMut(crate::observer::On<E>) + Send + Sync + 'static,
{
let type_id = TypeId::of::<E>();
let map_any = self.entity_observers.entry(type_id).or_insert_with(|| {
Box::new(HashMap::<Entity, Vec<Box<dyn FnMut(crate::observer::On<E>) + Send + Sync + 'static>>>::new())
});
let map = map_any.downcast_mut::<HashMap<Entity, Vec<Box<dyn FnMut(crate::observer::On<E>) + Send + Sync + 'static>>>>().unwrap();
map.entry(entity).or_default().push(Box::new(listener));
self
}
pub fn trigger<E: crate::observer::EntityEvent>(&mut self, event: E) {
use crate::component::Parent;
let mut current_entity = event.target();
loop {
let mut hooks_to_run = Vec::new();
if let Some(map_any) = self.entity_observers.get_mut(&TypeId::of::<E>()) {
if let Some(map) = map_any.downcast_mut::<HashMap<Entity, Vec<Box<dyn FnMut(crate::observer::On<E>) + Send + Sync + 'static>>>>() {
if let Some(listeners) = map.remove(¤t_entity) {
hooks_to_run = listeners;
}
}
}
for mut listener in hooks_to_run.drain(..) {
let e = crate::observer::On {
event: event.clone(),
entity: current_entity,
_marker: std::marker::PhantomData,
};
listener(e);
if let Some(map_any) = self.entity_observers.get_mut(&TypeId::of::<E>()) {
if let Some(map) = map_any.downcast_mut::<HashMap<Entity, Vec<Box<dyn FnMut(crate::observer::On<E>) + Send + Sync + 'static>>>>() {
map.entry(current_entity).or_default().push(listener);
}
}
}
if !event.can_propagate() {
break;
}
if let Some(parent_ptr) = self.get_component_ptr(current_entity, TypeId::of::<Parent>()) {
let parent_id = unsafe { (*(parent_ptr as *const Parent)).0 };
match self.entity(parent_id) {
Some(e) => current_entity = e,
None => break,
}
} else {
break;
}
}
}
#[inline]
pub fn is_component_registered<T: Component>(&self) -> bool {
self.component_infos.contains_key(&TypeId::of::<T>())
}
#[inline]
pub fn registered_component_count(&self) -> usize {
self.component_infos.len()
}
pub fn register_on_add<T: Component>(&mut self, hook: AddHook) {
self.component_hooks
.entry(TypeId::of::<T>())
.or_default()
.on_add
.push(hook);
}
pub fn register_on_remove<T: Component>(&mut self, hook: RemoveHook) {
self.component_hooks
.entry(TypeId::of::<T>())
.or_default()
.on_remove
.push(hook);
}
pub fn register_on_set<T: Component>(&mut self, hook: SetHook) {
self.component_hooks
.entry(TypeId::of::<T>())
.or_default()
.on_set
.push(hook);
}
pub fn register_despawn_hook(&mut self, hook: DespawnHook) {
self.despawn_hooks.push(hook);
}
}