1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
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 {
/// Registers the runtime metadata of a given component type.
/// It is used to create columns during the archetype storage migration stages.
#[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>);
}
/// Registers a Component hook (Observer) for `OnInsert`.
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
}
/// Entity-based Observer registration for custom EntityEvents
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
}
/// Triggers an Event and propagates it upwards through the hierarchy (bubble-up)
pub fn trigger<E: crate::observer::EntityEvent>(&mut self, event: E) {
use crate::component::Parent;
let mut current_entity = event.target();
loop {
// Observer'ları bu entity için bul ve çalıştır
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);
// Geri koy
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;
}
// Propagate to parent
if let Some(parent_ptr) = self.get_component_ptr(current_entity, TypeId::of::<Parent>()) {
// `Parent` stores a bare id with no generation; a plain `despawn(parent)`
// (not despawn_recursive) leaves children with a dangling `Parent(id)`.
// Resolve it safely — a dead id stops propagation instead of panicking.
let parent_id = unsafe { (*(parent_ptr as *const Parent)).0 };
match self.entity(parent_id) {
Some(e) => current_entity = e,
None => break,
}
} else {
break;
}
}
}
/// Is a given component type registered?
#[inline]
pub fn is_component_registered<T: Component>(&self) -> bool {
self.component_infos.contains_key(&TypeId::of::<T>())
}
/// The number of registered component metadata entries.
#[inline]
pub fn registered_component_count(&self) -> usize {
self.component_infos.len()
}
/// Appends a hook fired when `T` becomes newly present on an entity — not when an
/// existing value is overwritten. See [`AddHook`] for exactly when in the insert it
/// runs.
///
/// Hooks accumulate: registering the same closure twice makes it fire twice, and there
/// is no unregister. Within a type they run in registration order — except for one
/// registered from inside that same type's dispatch, whose position afterwards is not
/// guaranteed (see [`ComponentHooks`](crate::world::ComponentHooks)) — and all `on_add`
/// hooks precede that insert's `on_set` hooks.
pub fn register_on_add<T: Component>(&mut self, hook: AddHook) {
self.component_hooks
.entry(TypeId::of::<T>())
.or_default()
.on_add
.push(hook);
}
/// Appends a hook fired when `T` is detached from an entity, whether explicitly or
/// because the entity was despawned. Same accumulate-and-never-unregister rules as
/// [`World::register_on_add`].
///
/// Read [`RemoveHook`] before relying on it: whether the component is still readable
/// when the hook runs depends on the removal path and on `T`'s storage type, and
/// `World::remove_bundle` does not fire it for Table-storage components at all.
pub fn register_on_remove<T: Component>(&mut self, hook: RemoveHook) {
self.component_hooks
.entry(TypeId::of::<T>())
.or_default()
.on_remove
.push(hook);
}
/// Appends a hook fired on every write of `T`: the initial insert (right after the
/// `on_add` hooks) and every later overwrite of the same entity's value. Same
/// accumulate-and-never-unregister rules as [`World::register_on_add`].
///
/// It is a *write* notification, not a change notification — the hook fires even when
/// the new value equals the old one, and it cannot see either value except by reading
/// the entity out of the `&mut World` it is handed.
pub fn register_on_set<T: Component>(&mut self, hook: SetHook) {
self.component_hooks
.entry(TypeId::of::<T>())
.or_default()
.on_set
.push(hook);
}
/// Appends a hook fired once for every entity [`World::despawn`] actually destroys,
/// whatever components it carries — the place for teardown that no single component owns.
/// Handles that are already dead when despawn reaches them are skipped, so a double
/// despawn fires the hook once, not twice.
///
/// Unlike the `on_*` hooks this one is global, not keyed by component type. It runs
/// before any `on_remove` hook and before the id is freed, so the entity is still alive
/// and fully readable. Hooks accumulate and cannot be unregistered; one registered from
/// inside a despawn hook does not run for the entity currently being despawned.
pub fn register_despawn_hook(&mut self, hook: DespawnHook) {
self.despawn_hooks.push(hook);
}
}