1use crate::archetype::index::ArchetypeIndex;
2use crate::archetype::{Archetype, ComponentInfo, EntityLocation};
3use crate::component::Component;
4use crate::entity::Entity;
5
6use std::any::TypeId;
7use std::collections::HashMap;
8use std::marker::PhantomData;
9use std::sync::RwLock;
10
11pub mod hooks;
12pub mod resources;
13
14pub use self::hooks::*;
15pub use self::resources::*;
16pub use crate::entity::allocator::Entities;
17
18pub struct World {
19 resources: HashMap<TypeId, RwLock<Box<dyn std::any::Any + Send + Sync>>>,
21
22 entity_locations: Vec<EntityLocation>,
25
26 pub(crate) archetype_index: ArchetypeIndex,
28
29 component_infos: HashMap<TypeId, ComponentInfo>,
31
32 pub(crate) component_hooks: HashMap<TypeId, ComponentHooks>,
33 pub(crate) sparse_sets: HashMap<TypeId, crate::archetype::sparse_set::ComponentSparseSet>,
34
35 despawn_hooks: Vec<DespawnHook>,
36 entities_to_despawn: Vec<Entity>,
37 is_despawning: bool,
38 pub(crate) entity_observers: HashMap<TypeId, Box<dyn std::any::Any + Send + Sync>>,
39 pub tick: u32,
40}
41
42impl World {
43 pub fn new() -> Self {
44 let mut world = Self {
45 resources: HashMap::new(),
46 entity_locations: Vec::new(),
47 archetype_index: ArchetypeIndex::new(),
48 component_infos: HashMap::new(),
49 component_hooks: HashMap::new(),
50 sparse_sets: HashMap::new(),
51 despawn_hooks: Vec::new(),
52 entities_to_despawn: Vec::new(),
53 is_despawning: false,
54 entity_observers: HashMap::new(),
55 tick: 1,
56 };
57 world.insert_resource(crate::commands::CommandQueue::new());
58 world.insert_resource(Entities::new());
59 world.insert_resource(Entities::new());
60 world
61 }
62
63 fn run_hooks<F>(&mut self, type_id: TypeId, mut f: F)
64 where
65 F: FnMut(&mut ComponentHooks, &mut World),
66 {
67 let mut hooks = self.component_hooks.remove(&type_id);
68 if let Some(ref mut h) = hooks {
69 f(h, self);
70 }
71 if let Some(h) = hooks {
72 if let Some(existing) = self.component_hooks.get_mut(&type_id) {
73 existing.on_add.extend(h.on_add);
74 existing.on_set.extend(h.on_set);
75 existing.on_remove.extend(h.on_remove);
76 } else {
77 self.component_hooks.insert(type_id, h);
78 }
79 }
80 }
81
82 pub fn increment_tick(&mut self) {
84 self.tick = self.tick.wrapping_add(1);
85 if self.tick == 0 {
86 self.tick = 1;
87 }
88
89 self.sort_archetype_hierarchy();
91 }
92
93 pub fn apply_commands(&mut self) {
96 let queue_opt = self
97 .get_resource::<crate::commands::CommandQueue>()
98 .map(|q| (*q).clone());
99 if let Some(queue) = queue_opt {
100 queue.apply(self);
101 }
102 }
103}
104
105impl Default for World {
106 fn default() -> Self {
107 Self::new()
108 }
109}
110
111impl World {
112 #[inline]
115 pub fn register_component_type<T: Component>(&mut self) {
116 let type_id = TypeId::of::<T>();
117 self.component_infos
118 .entry(type_id)
119 .or_insert_with(ComponentInfo::of::<T>);
120 }
121
122 pub fn add_observer<T: Component, F>(&mut self, mut system: F) -> &mut Self
124 where
125 F: FnMut(crate::observer::On<crate::observer::Insert, T>) + Send + Sync + 'static,
126 {
127 let type_id = TypeId::of::<T>();
128 let mut hooks = self.component_hooks.remove(&type_id).unwrap_or_default();
129
130 hooks.on_add.push(Box::new(move |_world, entity| {
131 let event = crate::observer::On {
132 event: crate::observer::Insert,
133 entity,
134 _marker: std::marker::PhantomData,
135 };
136 system(event);
137 }));
138
139 self.component_hooks.insert(type_id, hooks);
140 self
141 }
142
143 pub fn observe<E: crate::observer::EntityEvent, F>(&mut self, entity: Entity, listener: F) -> &mut Self
145 where
146 F: FnMut(crate::observer::On<E>) + Send + Sync + 'static,
147 {
148 let type_id = TypeId::of::<E>();
149 let map_any = self.entity_observers.entry(type_id).or_insert_with(|| {
150 Box::new(HashMap::<Entity, Vec<Box<dyn FnMut(crate::observer::On<E>) + Send + Sync + 'static>>>::new())
151 });
152
153 let map = map_any.downcast_mut::<HashMap<Entity, Vec<Box<dyn FnMut(crate::observer::On<E>) + Send + Sync + 'static>>>>().unwrap();
154 map.entry(entity).or_default().push(Box::new(listener));
155 self
156 }
157
158 pub fn trigger<E: crate::observer::EntityEvent>(&mut self, event: E) {
160 use crate::component::Parent;
161 let mut current_entity = event.target();
162
163 loop {
164 let mut hooks_to_run = Vec::new();
166
167 if let Some(map_any) = self.entity_observers.get_mut(&TypeId::of::<E>()) {
168 if let Some(map) = map_any.downcast_mut::<HashMap<Entity, Vec<Box<dyn FnMut(crate::observer::On<E>) + Send + Sync + 'static>>>>() {
169 if let Some(listeners) = map.remove(¤t_entity) {
170 hooks_to_run = listeners;
171 }
172 }
173 }
174
175 for mut listener in hooks_to_run.drain(..) {
176 let e = crate::observer::On {
177 event: event.clone(),
178 entity: current_entity,
179 _marker: std::marker::PhantomData,
180 };
181 listener(e);
182
183 if let Some(map_any) = self.entity_observers.get_mut(&TypeId::of::<E>()) {
185 if let Some(map) = map_any.downcast_mut::<HashMap<Entity, Vec<Box<dyn FnMut(crate::observer::On<E>) + Send + Sync + 'static>>>>() {
186 map.entry(current_entity).or_default().push(listener);
187 }
188 }
189 }
190
191 if !event.can_propagate() {
192 break;
193 }
194
195 if let Some(parent_ptr) = self.get_component_ptr(current_entity, TypeId::of::<Parent>()) {
197 current_entity = self.reconstruct_entity(unsafe { (*(parent_ptr as *const Parent)).0 }).unwrap();
198 } else {
199 break;
200 }
201 }
202 }
203
204 #[inline]
206 pub fn is_component_registered<T: Component>(&self) -> bool {
207 self.component_infos.contains_key(&TypeId::of::<T>())
208 }
209
210 #[inline]
212 pub fn registered_component_count(&self) -> usize {
213 self.component_infos.len()
214 }
215
216 pub fn register_on_add<T: Component>(&mut self, hook: AddHook) {
217 self.component_hooks
218 .entry(TypeId::of::<T>())
219 .or_default()
220 .on_add
221 .push(hook);
222 }
223
224 pub fn register_on_remove<T: Component>(&mut self, hook: RemoveHook) {
225 self.component_hooks
226 .entry(TypeId::of::<T>())
227 .or_default()
228 .on_remove
229 .push(hook);
230 }
231
232 pub fn register_on_set<T: Component>(&mut self, hook: SetHook) {
233 self.component_hooks
234 .entry(TypeId::of::<T>())
235 .or_default()
236 .on_set
237 .push(hook);
238 }
239
240 pub fn spawn(&mut self) -> Entity {
241 let entity = {
242 let entities = self
243 .get_resource::<Entities>()
244 .expect("Entities resource not initialized");
245 entities.reserve_entity()
246 };
247
248 self.flush_spawn(entity);
249 entity
250 }
251
252 pub fn spawn_bundle<B: crate::component::Bundle>(&mut self, bundle: B) -> Entity {
264 let entity = self.spawn();
265 bundle.apply(self, entity);
266 entity
267 }
268
269 pub fn flush_spawn(&mut self, entity: Entity) {
270 self.archetype_index.on_spawn(entity.id());
272
273 let eid = entity.id();
275 let loc_idx = eid as usize;
276 let row = self.archetype_index.archetypes[0].len() as u32 - 1;
277
278 if loc_idx >= self.entity_locations.len() {
279 self.entity_locations
280 .resize(loc_idx + 1, EntityLocation::INVALID);
281 }
282 self.entity_locations[loc_idx] = EntityLocation {
283 archetype_id: 0,
284 row,
285 };
286 }
287
288 pub fn get_entity(&self, id: u32) -> Option<Entity> {
291 let entities = self
292 .get_resource::<Entities>()
293 .expect("Entities resource not initialized");
294 let state = entities.state.lock().expect("Entities mutex poisoned");
295 if (id as usize) < state.generations.len() && !state.free_set.contains(&id) {
296 return Some(Entity::new(id, state.generations[id as usize]));
297 }
298 None
299 }
300
301 pub fn clone_entity(&mut self, source_id: u32, count: usize) -> Option<Vec<Entity>> {
304 if count == 0 {
305 return Some(Vec::new());
306 }
307
308 let loc = self.entity_locations.get(source_id as usize).copied()?;
309 if !loc.is_valid() {
310 return None;
311 }
312
313 let arch_id = loc.archetype_id as usize;
314 let row = loc.row as usize;
315
316 let mut new_entities = Vec::with_capacity(count);
318 let mut new_eids = Vec::with_capacity(count);
319
320 {
321 let entities_res = self
322 .get_resource::<Entities>()
323 .expect("Entities resource not initialized");
324 for _ in 0..count {
325 let e = entities_res.reserve_entity();
326 new_eids.push(e.id());
327 new_entities.push(e);
328 }
329 }
330
331 let arch = &mut self.archetype_index.archetypes[arch_id];
333 let tick = self.tick;
334 let new_rows = unsafe { arch.batch_clone_row(row, count, &new_eids, tick) };
335
336 for (i, &id) in new_eids.iter().enumerate() {
338 let row = new_rows[i];
339 let idx = id as usize;
340 if idx >= self.entity_locations.len() {
341 self.entity_locations
342 .resize(idx + 1, EntityLocation::INVALID);
343 }
344 self.entity_locations[idx] = EntityLocation {
345 archetype_id: arch_id as u32,
346 row,
347 };
348 self.archetype_index.entity_archetype.insert(id, arch_id);
349 }
352
353 Some(new_entities)
354 }
355
356 pub fn register_despawn_hook(&mut self, hook: DespawnHook) {
357 self.despawn_hooks.push(hook);
358 }
359
360
361 pub fn spawn_batch<I>(&mut self, iter: I) -> impl Iterator<Item = Entity>
362 where
363 I: IntoIterator,
364 I::Item: crate::component::Bundle,
365 {
366 let mut iter = iter.into_iter();
367 let mut entities = Vec::new();
368
369 let first_bundle = match iter.next() {
370 Some(b) => b,
371 None => return entities.into_iter(),
372 };
373
374 let first_entity = self.spawn_bundle(first_bundle);
375 entities.push(first_entity);
376
377 let loc = self.entity_locations[first_entity.id() as usize];
378 let target_arch_id = loc.archetype_id as usize;
379
380 for bundle in iter {
381 let entity = {
382 let e_res = self.get_resource::<crate::entity::allocator::Entities>().expect("Entities not init");
383 e_res.reserve_entity()
384 };
385 let eid = entity.id();
386
387 let new_row = {
388 let arch = &mut self.archetype_index.archetypes[target_arch_id];
389 let row = arch.push_entity(eid);
390 unsafe { crate::component::Bundle::write_to_archetype(bundle, arch, row as usize, self.tick); }
391 row
392 };
393
394 let loc_idx = eid as usize;
395 if loc_idx >= self.entity_locations.len() {
396 self.entity_locations.resize(loc_idx + 1, crate::archetype::EntityLocation::INVALID);
397 }
398 self.entity_locations[loc_idx] = crate::archetype::EntityLocation {
399 archetype_id: target_arch_id as u32,
400 row: new_row,
401 };
402 self.archetype_index.entity_archetype.insert(eid, target_arch_id);
403
404 entities.push(entity);
405 }
406
407 entities.into_iter()
408 }
409
410 pub fn clear_entities(&mut self) {
412 self.archetype_index.clear_entities();
413 self.entity_locations.clear();
414 self.entities_to_despawn.clear();
415
416 if let Some(entities) = self.get_resource::<Entities>() {
418 entities.clear();
419 }
420 }
421
422 pub fn despawn(&mut self, entity: Entity) {
423 self.entities_to_despawn.push(entity);
424 if self.is_despawning {
425 return;
426 }
427 self.is_despawning = true;
428
429 while let Some(e) = self.entities_to_despawn.pop() {
430 if !self.is_alive(e) {
431 continue;
432 }
433
434 let mut hooks = std::mem::take(&mut self.despawn_hooks);
435 for hook in &mut hooks {
436 hook(self, e);
437 }
438 self.despawn_hooks.extend(hooks);
439
440 let id = e.id();
441 let loc = self.entity_locations[id as usize];
442
443 if loc.is_valid() {
444 let comp_types = {
446 let arch = &self.archetype_index.archetypes[loc.archetype_id as usize];
447 arch.component_types()
448 };
449 for t in comp_types {
450 self.run_hooks(t, |h, w| {
451 for hook in &mut h.on_remove {
452 hook(w, e);
453 }
454 });
455 }
456
457 let loc = self.entity_locations[id as usize];
459 if loc.is_valid() {
460 if let Some(moved_eid) = self.archetype_index.archetypes
462 [loc.archetype_id as usize]
463 .swap_remove_entity(loc.row as usize)
464 {
465 self.entity_locations[moved_eid as usize].row = loc.row;
467 }
468 }
469 }
470
471 {
472 let entities = self
473 .get_resource::<Entities>()
474 .expect("Entities resource not initialized");
475 entities.free(e);
476 }
477
478 self.archetype_index.entity_archetype.remove(&id);
479 self.entity_locations[id as usize] = EntityLocation::INVALID;
480 }
481 self.is_despawning = false;
482 }
483
484 pub fn compact(&mut self) {
488 self.archetype_index
490 .gc_empty_archetypes(&mut self.entity_locations);
491
492 for arch in &mut self.archetype_index.archetypes {
494 arch.shrink_to_fit();
495 }
496
497 self.archetype_index.archetypes.shrink_to_fit();
498
499 self.entities_to_despawn.shrink_to_fit();
501 self.entity_locations.shrink_to_fit();
502
503 let entities = self
504 .get_resource::<Entities>()
505 .expect("Entities resource not initialized");
506 let mut state = entities.state.lock().expect("Entities mutex poisoned");
507 state.generations.shrink_to_fit();
508 state.free_ids.shrink_to_fit();
509 state.free_set.shrink_to_fit();
510 }
511
512 pub fn despawn_by_id(&mut self, id: u32) {
513 if let Some(entity) = self.get_entity(id) {
514 self.despawn(entity);
515 }
516 }
517
518 pub fn iter_alive_entities(&self) -> Vec<Entity> {
521 let entities = self
522 .get_resource::<Entities>()
523 .expect("Entities resource not initialized");
524 let state = entities.state.lock().expect("Entities mutex poisoned");
525 let mut alive = Vec::new();
526 for id in 0..state.next_entity_id {
527 if !state.free_set.contains(&id) {
528 alive.push(Entity::new(id, state.generations[id as usize]));
529 }
530 }
531 alive
532 }
533
534 #[inline]
535 pub fn is_alive(&self, entity: Entity) -> bool {
536 self.get_resource::<Entities>()
537 .expect("Entities resource not initialized")
538 .is_alive(entity)
539 }
540
541 pub fn add_bundle<B: crate::component::Bundle>(&mut self, entity: Entity, bundle: B) {
544 if !self.is_alive(entity) { return; }
545 let eid = entity.id();
546 let infos = B::get_infos();
547
548 for info in &infos {
549 self.component_infos.entry(info.type_id).or_insert_with(|| *info);
550 }
551
552 let old_arch_id = match self.archetype_index.entity_archetype.get(&eid) {
555 Some(&id) => id,
556 None => {
557 let _arch = &mut self.archetype_index.archetypes[0];
559 0
560 }
561 };
562
563 let mut new_types = self.archetype_index.archetypes[old_arch_id as usize].sorted_component_types();
564 for info in &infos {
565 if let Err(pos) = new_types.binary_search(&info.type_id) {
566 new_types.insert(pos, info.type_id);
567 }
568 }
569
570 let target_arch_id = if let Some(&id) = self.archetype_index.set_to_id.get(&new_types) {
571 id
572 } else {
573 let id = self.archetype_index.archetypes.len();
574 let mut new_infos = Vec::new();
575 for &t in &new_types {
576 new_infos.push(self.component_infos.get(&t).cloned().unwrap());
577 }
578 self.archetype_index.archetypes.push(crate::archetype::Archetype::new(id as u32, &new_infos));
579 self.archetype_index.set_to_id.insert(new_types, id);
580 id
581 };
582
583 if old_arch_id == target_arch_id {
584 let loc = self.entity_locations[eid as usize];
586 let arch = &mut self.archetype_index.archetypes[target_arch_id];
587 unsafe { bundle.write_to_archetype(arch, loc.row as usize, self.tick); }
588 return;
589 }
590
591 let old_loc = self.entity_locations[eid as usize];
592 let (new_row, moved_eid) = unsafe {
593 let old_arch_ptr = &mut self.archetype_index.archetypes[old_arch_id] as *mut crate::archetype::Archetype;
594 let target_arch_ptr = &mut self.archetype_index.archetypes[target_arch_id] as *mut crate::archetype::Archetype;
595 (&mut *old_arch_ptr).move_entity_to(old_loc.row as usize, &mut *target_arch_ptr)
596 };
597
598 if let Some(moved) = moved_eid {
599 self.entity_locations[moved as usize].row = old_loc.row;
600 }
601
602 let arch = &mut self.archetype_index.archetypes[target_arch_id];
603 unsafe { bundle.write_to_archetype(arch, new_row as usize, self.tick); }
604
605 self.entity_locations[eid as usize] = EntityLocation {
606 archetype_id: target_arch_id as u32,
607 row: new_row,
608 };
609 self.archetype_index.entity_archetype.insert(eid, target_arch_id);
610 }
611
612 pub fn remove_bundle<B: crate::component::Bundle>(&mut self, entity: Entity) {
613 if !self.is_alive(entity) { return; }
614 let eid = entity.id();
615 let infos = B::get_infos();
616
617 let old_arch_id = match self.archetype_index.entity_archetype.get(&eid) {
618 Some(&id) => id,
619 None => return,
620 };
621
622 let mut new_types = self.archetype_index.archetypes[old_arch_id as usize].sorted_component_types();
623 for info in &infos {
624 if let Ok(pos) = new_types.binary_search(&info.type_id) {
625 new_types.remove(pos);
626 }
627 }
628
629 let target_arch_id = if let Some(&id) = self.archetype_index.set_to_id.get(&new_types) {
630 id
631 } else {
632 let id = self.archetype_index.archetypes.len();
633 let mut new_infos = Vec::new();
634 for &t in &new_types {
635 new_infos.push(self.component_infos.get(&t).cloned().unwrap());
636 }
637 self.archetype_index.archetypes.push(crate::archetype::Archetype::new(id as u32, &new_infos));
638 self.archetype_index.set_to_id.insert(new_types, id);
639 id
640 };
641
642 if old_arch_id == target_arch_id { return; }
643
644 let old_loc = self.entity_locations[eid as usize];
645 let (new_row, moved_eid) = unsafe {
646 let old_arch_ptr = &mut self.archetype_index.archetypes[old_arch_id] as *mut crate::archetype::Archetype;
647 let target_arch_ptr = &mut self.archetype_index.archetypes[target_arch_id] as *mut crate::archetype::Archetype;
648 (&mut *old_arch_ptr).move_entity_to(old_loc.row as usize, &mut *target_arch_ptr)
649 };
650
651 if let Some(moved) = moved_eid {
652 self.entity_locations[moved as usize].row = old_loc.row;
653 }
654
655 self.entity_locations[eid as usize] = EntityLocation {
656 archetype_id: target_arch_id as u32,
657 row: new_row,
658 };
659 self.archetype_index.entity_archetype.insert(eid, target_arch_id);
660 }
661
662 pub fn add_component<T: Component>(&mut self, entity: Entity, component: T) {
663 if !self.is_alive(entity) { return; }
664 let eid = entity.id();
665 self.register_component_type::<T>();
666 let type_id = TypeId::of::<T>();
667
668 if T::storage_type() == crate::component::StorageType::SparseSet {
669 let info = self.component_infos.get(&type_id).copied().unwrap_or_else(|| ComponentInfo::of::<T>());
670 let set = self.sparse_sets.entry(type_id).or_insert_with(|| {
671 crate::archetype::sparse_set::ComponentSparseSet::new(info)
672 });
673 let ptr = &component as *const T as *const u8;
674 set.insert(eid, ptr, self.tick);
675 std::mem::forget(component);
676
677 self.run_hooks(type_id, |h, w| {
678 for hook in &mut h.on_add { hook(w, entity); }
679 for hook in &mut h.on_set { hook(w, entity); }
680 });
681 return;
682 }
683
684 let target_arch_id =
690 match self
691 .archetype_index
692 .get_add_component_target(eid, type_id, &self.component_infos)
693 {
694 Some(id) => id,
695 None => return,
696 };
697 let old_loc = self.entity_locations[eid as usize];
698
699 if old_loc.archetype_id == target_arch_id as u32 {
700 {
702 let arch = &self.archetype_index.archetypes[target_arch_id];
703 let col = arch
704 .get_column_mut(type_id)
705 .expect("component column missing in current archetype");
706 unsafe {
707 let ptr = col.get_ptr(old_loc.row as usize) as *mut T;
708 *ptr = component;
709 col.ticks_ptr_mut()
710 .add(old_loc.row as usize)
711 .write(crate::archetype::ComponentTicks::new(self.tick));
712 }
713 }
714 let mut hooks = self.component_hooks.remove(&type_id);
716 if let Some(ref mut h) = hooks {
717 for hook in &mut h.on_set {
718 hook(self, entity);
719 }
720 }
721 if let Some(h) = hooks {
722 if let Some(existing) = self.component_hooks.get_mut(&type_id) {
723 existing.on_add.extend(h.on_add);
724 existing.on_set.extend(h.on_set);
725 existing.on_remove.extend(h.on_remove);
726 } else {
727 self.component_hooks.insert(type_id, h);
728 }
729 }
730 return;
731 }
732
733 let (eid, old_arch_id, old_row) = (
735 entity.id(),
736 old_loc.archetype_id as usize,
737 old_loc.row as usize,
738 );
739
740 let (new_row, moved_eid) = unsafe {
741 let old_arch_ptr = &mut self.archetype_index.archetypes[old_arch_id] as *mut Archetype;
743 let target_arch_ptr =
744 &mut self.archetype_index.archetypes[target_arch_id] as *mut Archetype;
745
746 (&mut *old_arch_ptr).move_entity_to(old_row, &mut *target_arch_ptr)
747 };
748
749 if let Some(moved) = moved_eid {
750 self.entity_locations[moved as usize].row = old_row as u32;
751 }
752
753 {
755 let arch = &self.archetype_index.archetypes[target_arch_id];
756 let col = arch
757 .get_column_mut(type_id)
758 .expect("Mandatory component column missing");
759 unsafe {
760 let ptr = col.get_ptr(new_row as usize) as *mut T;
761 std::ptr::write(ptr, component);
762 col.ticks_ptr_mut()
763 .add(new_row as usize)
764 .write(crate::archetype::ComponentTicks::new(self.tick));
765 }
766 }
767
768 self.entity_locations[eid as usize] = EntityLocation {
770 archetype_id: target_arch_id as u32,
771 row: new_row,
772 };
773 self.archetype_index
774 .entity_archetype
775 .insert(eid, target_arch_id);
776
777 let mut hooks = self.component_hooks.remove(&type_id);
778 if let Some(ref mut h) = hooks {
779 for hook in &mut h.on_add {
780 hook(self, entity);
781 }
782 for hook in &mut h.on_set {
783 hook(self, entity);
784 }
785 }
786 if let Some(h) = hooks {
787 if let Some(existing) = self.component_hooks.get_mut(&type_id) {
788 existing.on_add.extend(h.on_add);
789 existing.on_set.extend(h.on_set);
790 existing.on_remove.extend(h.on_remove);
791 } else {
792 self.component_hooks.insert(type_id, h);
793 }
794 }
795 }
796
797 pub fn get_entity_component_types(&self, entity: Entity) -> Vec<TypeId> {
799 if !self.is_alive(entity) {
800 return Vec::new();
801 }
802 if let Some(&loc) = self.entity_locations.get(entity.id() as usize) {
803 if loc.is_valid() {
804 let arch = &self.archetype_index.archetypes[loc.archetype_id as usize];
805 return arch.component_types();
806 }
807 }
808 Vec::new()
809 }
810
811 pub fn get_component_ptr(&self, entity: Entity, type_id: TypeId) -> Option<*const u8> {
813 let loc = self.entity_locations.get(entity.id() as usize).copied()?;
814 if !loc.is_valid() {
815 return None;
816 }
817 let arch = &self.archetype_index.archetypes[loc.archetype_id as usize];
818 let col = arch.get_column(type_id)?;
819 Some(unsafe { col.get_ptr(loc.row as usize) })
820 }
821
822 pub fn get_component_mut_ptr(&mut self, entity: Entity, type_id: TypeId) -> Option<*mut u8> {
824 let loc = self.entity_locations.get(entity.id() as usize).copied()?;
825 if !loc.is_valid() {
826 return None;
827 }
828 let arch = &mut self.archetype_index.archetypes[loc.archetype_id as usize];
829 let col = arch.get_column_mut(type_id)?;
830 Some(unsafe { col.get_mut_ptr(loc.row as usize) })
831 }
832
833 pub fn reconstruct_entity(&self, id: u32) -> Option<Entity> {
835 if id as usize >= self.entity_locations.len() || !self.entity_locations[id as usize].is_valid() {
836 return None;
837 }
838 let entities = self.get_resource::<Entities>()?;
839 let state = entities.state.lock().unwrap();
840 if id as usize >= state.generations.len() || state.free_set.contains(&id) {
841 return None;
842 }
843 Some(Entity::new(id, state.generations[id as usize]))
844 }
845
846 pub fn remove_component<T: Component>(&mut self, entity: Entity) {
848 if !self.is_alive(entity) { return; }
849 let eid = entity.id();
850 let type_id = TypeId::of::<T>();
851
852 if T::storage_type() == crate::component::StorageType::SparseSet {
853 if let Some(set) = self.sparse_sets.get_mut(&type_id) {
854 if set.remove(eid) {
855 self.run_hooks(type_id, |h, w| {
856 for hook in &mut h.on_remove { hook(w, entity); }
857 });
858 }
859 }
860 return;
861 }
862
863
864 let old_loc = self.entity_locations[eid as usize];
865
866 let target_arch_id_opt =
868 self.archetype_index
869 .get_remove_component_target(eid, type_id, &self.component_infos);
870 let target_arch_id = match target_arch_id_opt {
871 Some(id) => id,
872 None => return, };
874
875 if old_loc.archetype_id == target_arch_id as u32 {
876 return; }
878
879 let (new_row, moved_eid) = unsafe {
881 let old_arch_ptr = &mut self.archetype_index.archetypes[old_loc.archetype_id as usize]
882 as *mut Archetype;
883 let target_arch_ptr =
884 &mut self.archetype_index.archetypes[target_arch_id] as *mut Archetype;
885 (&mut *old_arch_ptr).move_entity_to(old_loc.row as usize, &mut *target_arch_ptr)
886 };
887
888 if let Some(moved) = moved_eid {
889 self.entity_locations[moved as usize].row = old_loc.row;
890 }
891
892 self.entity_locations[eid as usize] = EntityLocation {
894 archetype_id: target_arch_id as u32,
895 row: new_row,
896 };
897 self.archetype_index
898 .entity_archetype
899 .insert(eid, target_arch_id);
900
901 self.run_hooks(type_id, |h, w| {
902 for hook in &mut h.on_remove {
903 hook(w, entity);
904 }
905 });
906 }
907
908
909
910 pub fn query<'w, Q: crate::query::WorldQuery>(&'w self) -> Option<crate::query::Query<'w, Q>> {
915 crate::query::Query::new(self)
916 }
917
918 #[inline]
920 pub fn borrow<'w, T: Component>(&'w self) -> crate::query::Query<'w, &'w T> {
921 self.query::<&T>().expect("Failed to create borrow Query")
922 }
923
924 #[inline]
926 pub fn borrow_mut<'w, T: Component>(&'w self) -> crate::query::Query<'w, crate::query::Mut<'w, T>> {
927 self.query::<crate::query::Mut<T>>().expect("Failed to create borrow_mut Query")
928 }
929
930 pub fn query_cached<'w, Q: crate::query::WorldQuery>(
933 &'w mut self,
934 ) -> Option<crate::query::Query<'w, Q>> {
935 crate::query::Query::new_cached(self)
936 }
937
938 pub fn insert_batch<T: Component + Clone>(&mut self, entities: &[Entity], component: T) {
949 if T::storage_type() == crate::component::StorageType::SparseSet {
950 for &e in entities {
951 self.add_component(e, component.clone());
952 }
953 return;
954 }
955
956 self.register_component_type::<T>();
957 let type_id = TypeId::of::<T>();
958
959 let mut groups: std::collections::HashMap<u32, Vec<Entity>> = std::collections::HashMap::new();
961
962 for &e in entities {
963 if !self.is_alive(e) { continue; }
964 let loc = self.entity_locations[e.id() as usize];
965 if !loc.is_valid() { continue; }
966 groups.entry(loc.archetype_id).or_default().push(e);
967 }
968
969 for (source_arch_id, group_entities) in groups {
970 let target_arch_id = match self.archetype_index.get_add_component_target(
971 group_entities[0].id(), type_id, &self.component_infos
972 ) {
973 Some(id) => id,
974 None => continue,
975 };
976
977 if source_arch_id == target_arch_id as u32 {
978 let arch = &self.archetype_index.archetypes[target_arch_id];
979 let col = arch.get_column_mut(type_id).unwrap();
980 for e in &group_entities {
981 let row = self.entity_locations[e.id() as usize].row as usize;
982 unsafe {
983 std::ptr::write(col.get_ptr(row) as *mut T, component.clone());
984 col.ticks_ptr_mut().add(row).write(crate::archetype::ComponentTicks::new(self.tick));
985 }
986 }
987 self.run_hooks(type_id, |h, w| {
988 for e in &group_entities {
989 for hook in &mut h.on_set {
990 hook(w, *e);
991 }
992 }
993 });
994 continue;
995 }
996
997 for e in &group_entities {
998 let eid = e.id();
999 let old_loc = self.entity_locations[eid as usize];
1000 let old_row = old_loc.row as usize;
1001
1002 let (new_row, moved_eid) = unsafe {
1003 let old_arch_ptr = &mut self.archetype_index.archetypes[source_arch_id as usize] as *mut Archetype;
1004 let target_arch_ptr = &mut self.archetype_index.archetypes[target_arch_id] as *mut Archetype;
1005 (&mut *old_arch_ptr).move_entity_to(old_row, &mut *target_arch_ptr)
1006 };
1007
1008 if let Some(moved) = moved_eid {
1009 self.entity_locations[moved as usize].row = old_row as u32;
1010 }
1011
1012 {
1013 let arch = &self.archetype_index.archetypes[target_arch_id];
1014 let col = arch.get_column_mut(type_id).unwrap();
1015 unsafe {
1016 std::ptr::write(col.get_ptr(new_row as usize) as *mut T, component.clone());
1017 col.ticks_ptr_mut().add(new_row as usize).write(crate::archetype::ComponentTicks::new(self.tick));
1018 }
1019 }
1020
1021 self.entity_locations[eid as usize] = EntityLocation {
1022 archetype_id: target_arch_id as u32,
1023 row: new_row,
1024 };
1025 self.archetype_index.entity_archetype.insert(eid, target_arch_id);
1026 }
1027
1028 self.run_hooks(type_id, |h, w| {
1029 for e in &group_entities {
1030 for hook in &mut h.on_add { hook(w, *e); }
1031 for hook in &mut h.on_set { hook(w, *e); }
1032 }
1033 });
1034 }
1035 }
1036
1037 pub fn remove_batch<T: Component>(&mut self, entities: &[Entity]) {
1039 if T::storage_type() == crate::component::StorageType::SparseSet {
1040 for &e in entities {
1041 self.remove_component::<T>(e);
1042 }
1043 return;
1044 }
1045
1046 let type_id = TypeId::of::<T>();
1047 let mut groups: std::collections::HashMap<u32, Vec<Entity>> = std::collections::HashMap::new();
1048
1049 for &e in entities {
1050 if !self.is_alive(e) { continue; }
1051 let loc = self.entity_locations[e.id() as usize];
1052 if !loc.is_valid() { continue; }
1053 groups.entry(loc.archetype_id).or_default().push(e);
1054 }
1055
1056 for (source_arch_id, group_entities) in groups {
1057 let target_arch_id = match self.archetype_index.get_remove_component_target(
1058 group_entities[0].id(), type_id, &self.component_infos
1059 ) {
1060 Some(id) => id,
1061 None => continue,
1062 };
1063
1064 if source_arch_id == target_arch_id as u32 {
1065 continue;
1066 }
1067
1068 for e in &group_entities {
1069 let eid = e.id();
1070 let old_loc = self.entity_locations[eid as usize];
1071
1072 let (new_row, moved_eid) = unsafe {
1073 let old_arch_ptr = &mut self.archetype_index.archetypes[source_arch_id as usize] as *mut Archetype;
1074 let target_arch_ptr = &mut self.archetype_index.archetypes[target_arch_id] as *mut Archetype;
1075 (&mut *old_arch_ptr).move_entity_to(old_loc.row as usize, &mut *target_arch_ptr)
1076 };
1077
1078 if let Some(moved) = moved_eid {
1079 self.entity_locations[moved as usize].row = old_loc.row;
1080 }
1081
1082 self.entity_locations[eid as usize] = EntityLocation {
1083 archetype_id: target_arch_id as u32,
1084 row: new_row,
1085 };
1086 self.archetype_index.entity_archetype.insert(eid, target_arch_id);
1087 }
1088
1089 self.run_hooks(type_id, |h, w| {
1090 for e in &group_entities {
1091 for hook in &mut h.on_remove { hook(w, *e); }
1092 }
1093 });
1094 }
1095 }
1096
1097 pub fn query_entity_mut<'w, Q: crate::query::WorldQuery>(
1098 &'w mut self,
1099 entity_id: u32,
1100 ) -> Option<Q::Item<'w>> {
1101 let loc = self.entity_location(entity_id);
1102 if !loc.is_valid() {
1103 return None;
1104 }
1105 let arch = &self.archetype_index.archetypes[loc.archetype_id as usize];
1106 if !Q::matches_archetype(arch) {
1107 return None;
1108 }
1109 unsafe {
1110 let fetch = Q::fetch_raw(self, arch, self.tick)?;
1111 if !Q::filter_row(fetch, loc.row as usize, entity_id, self.tick) {
1112 return None;
1113 }
1114 Some(Q::get_item(fetch, loc.row as usize, entity_id))
1115 }
1116 }
1117
1118 pub fn query_entity<'w, Q: crate::query::WorldQuery>(
1120 &'w self,
1121 entity_id: u32,
1122 ) -> Option<Q::Item<'w>> {
1123 let loc = self.entity_location(entity_id);
1124 if !loc.is_valid() {
1125 return None;
1126 }
1127 let arch = &self.archetype_index.archetypes[loc.archetype_id as usize];
1128 if !Q::matches_archetype(arch) {
1129 return None;
1130 }
1131 unsafe {
1132 let fetch = Q::fetch_raw(self, arch, self.tick)?;
1133 if !Q::filter_row(fetch, loc.row as usize, entity_id, self.tick) {
1134 return None;
1135 }
1136 Some(Q::get_item(fetch, loc.row as usize, entity_id))
1137 }
1138 }
1139
1140 #[inline]
1142 pub fn entity_location(&self, entity_id: u32) -> EntityLocation {
1143 let loc_idx = entity_id as usize;
1144 if loc_idx < self.entity_locations.len() {
1145 self.entity_locations[loc_idx]
1146 } else {
1147 EntityLocation::INVALID
1148 }
1149 }
1150
1151 #[inline]
1153 pub fn entity_count(&self) -> u32 {
1154 let entities = self
1155 .get_resource::<Entities>()
1156 .expect("Entities resource not initialized");
1157 let state = entities.state.lock().expect("Entities mutex poisoned");
1158 state
1159 .next_entity_id
1160 .saturating_sub(state.free_ids.len() as u32)
1161 }
1162
1163 pub fn insert_resource<T: Send + Sync + 'static>(&mut self, resource: T) {
1169 let type_id = TypeId::of::<T>();
1170 self.resources
1171 .insert(type_id, RwLock::new(Box::new(resource)));
1172 }
1173
1174 pub fn get_resource<T: 'static>(&self) -> Option<ResourceReadGuard<'_, T>> {
1176 self.try_get_resource::<T>().ok()
1177 }
1178
1179 pub fn get_resource_mut<T: 'static>(&self) -> Option<ResourceWriteGuard<'_, T>> {
1181 self.try_get_resource_mut::<T>().ok()
1182 }
1183
1184 pub fn try_get_resource<T: 'static>(
1186 &self,
1187 ) -> Result<ResourceReadGuard<'_, T>, ResourceFetchError> {
1188 let type_id = TypeId::of::<T>();
1189 let storage = self
1190 .resources
1191 .get(&type_id)
1192 .ok_or(ResourceFetchError::NotFound(type_id))?;
1193 let guard = storage
1194 .try_read()
1195 .map_err(|_| ResourceFetchError::BorrowConflict(type_id))?;
1196 Ok(ResourceReadGuard {
1197 guard,
1198 _marker: PhantomData,
1199 })
1200 }
1201
1202 pub fn try_get_resource_mut<T: 'static>(
1204 &self,
1205 ) -> Result<ResourceWriteGuard<'_, T>, ResourceFetchError> {
1206 let type_id = TypeId::of::<T>();
1207 let storage = self
1208 .resources
1209 .get(&type_id)
1210 .ok_or(ResourceFetchError::NotFound(type_id))?;
1211 let guard = storage
1212 .try_write()
1213 .map_err(|_| ResourceFetchError::BorrowConflict(type_id))?;
1214 Ok(ResourceWriteGuard {
1215 guard,
1216 _marker: PhantomData,
1217 })
1218 }
1219
1220 pub fn get_resource_mut_or_default<T: Default + Send + Sync + 'static>(
1223 &mut self,
1224 ) -> ResourceWriteGuard<'_, T> {
1225 let type_id = TypeId::of::<T>();
1226 self.resources
1227 .entry(type_id)
1228 .or_insert_with(|| RwLock::new(Box::new(T::default())));
1229
1230 let storage = self
1231 .resources
1232 .get(&type_id)
1233 .expect("resource just inserted");
1234 let guard = storage.write().expect("resource write lock poisoned");
1235 ResourceWriteGuard {
1236 guard,
1237 _marker: PhantomData,
1238 }
1239 }
1240
1241 pub fn remove_resource<T: 'static>(&mut self) -> Option<T> {
1243 let type_id = TypeId::of::<T>();
1244 let cell = self.resources.remove(&type_id)?;
1245 let boxed_any = cell.into_inner().ok()?;
1246 match boxed_any.downcast::<T>() {
1247 Ok(boxed_t) => Some(*boxed_t),
1248 Err(_) => None,
1249 }
1250 }
1251
1252 pub fn resource_scope<T: Send + Sync + 'static, U, F>(&mut self, f: F) -> Option<U>
1263 where
1264 F: FnOnce(&mut World, &mut T) -> U,
1265 {
1266 let resource = self.remove_resource::<T>()?;
1267
1268 struct Guard<'a, T: Send + Sync + 'static> {
1271 world: *mut World,
1272 resource: Option<T>,
1273 _marker: std::marker::PhantomData<&'a mut World>,
1274 }
1275 impl<'a, T: Send + Sync + 'static> Drop for Guard<'a, T> {
1276 fn drop(&mut self) {
1277 if let Some(resource) = self.resource.take() {
1278 unsafe { &mut *self.world }.insert_resource(resource);
1280 }
1281 }
1282 }
1283
1284 let mut guard = Guard::<T> {
1285 world: self as *mut World,
1286 resource: Some(resource),
1287 _marker: std::marker::PhantomData,
1288 };
1289
1290 let result = f(self, guard.resource.as_mut().unwrap());
1291
1292 Some(result)
1294 }
1295
1296 pub fn swap_archetype_rows(&mut self, arch_id: u32, row_a: usize, row_b: usize) {
1298 if row_a == row_b {
1299 return;
1300 }
1301
1302 let arch = &self.archetype_index.archetypes[arch_id as usize];
1303 if row_a >= arch.len() || row_b >= arch.len() {
1304 return;
1305 }
1306
1307 let entity_a = arch.entities()[row_a];
1308 let entity_b = arch.entities()[row_b];
1309
1310 unsafe {
1311 let mut_arch = &mut self.archetype_index.archetypes[arch_id as usize];
1312 mut_arch.swap_rows(row_a, row_b);
1313 }
1314
1315 self.entity_locations[entity_a as usize].row = row_b as u32;
1316 self.entity_locations[entity_b as usize].row = row_a as u32;
1317 }
1318
1319 pub fn sort_archetype_hierarchy(&mut self) {
1321 let type_id = std::any::TypeId::of::<crate::component::Children>();
1322 let mut arches_to_sort: Vec<usize> = Vec::new();
1323
1324 for (idx, arch) in self.archetype_index.archetypes.iter().enumerate() {
1325 if arch.has_component(type_id) {
1326 arches_to_sort.push(idx);
1327 }
1328 }
1329
1330 for arch_idx in arches_to_sort {
1331 let arch_len = self.archetype_index.archetypes[arch_idx].len();
1332 if arch_len <= 1 {
1333 continue;
1334 }
1335
1336 let mut visited = std::collections::HashSet::new();
1337
1338 for row in 0..arch_len {
1339 let parent_entity_id = self.archetype_index.archetypes[arch_idx].entities()[row];
1340
1341 if visited.contains(&parent_entity_id) {
1342 continue;
1343 }
1344 visited.insert(parent_entity_id);
1345
1346 let children_opt = {
1347 let fetch = unsafe {
1348 <&crate::component::Children as crate::query::FetchComponent>::fetch_raw(self, &self.archetype_index.archetypes[arch_idx], self.tick)
1349 };
1350 fetch.map(|f| unsafe {
1351 <&crate::component::Children as crate::query::FetchComponent>::get_item(f, row, parent_entity_id)
1352 })
1353 };
1354
1355 let children_list = match children_opt {
1356 Some(c) => c.0.clone(),
1357 None => continue,
1358 };
1359
1360 let mut current_insert_row = row + 1;
1361 for child_id in children_list {
1362 let loc = self.entity_location(child_id);
1363 if loc.is_valid() && loc.archetype_id == arch_idx as u32 {
1364 let child_row = loc.row as usize;
1365 if child_row > current_insert_row {
1366 self.swap_archetype_rows(
1367 arch_idx as u32,
1368 current_insert_row,
1369 child_row,
1370 );
1371 visited.insert(child_id);
1372 current_insert_row += 1;
1373 } else if child_row == current_insert_row {
1374 visited.insert(child_id);
1375 current_insert_row += 1;
1376 }
1377 }
1378 }
1379 }
1380 }
1381 }
1382}
1383
1384#[cfg(test)]
1385mod tests {
1386 use super::*;
1387 use crate::component::Children;
1388
1389 #[derive(Clone, PartialEq, Debug)]
1390 struct Transform(f32);
1391 impl crate::component::Component for Transform {}
1392
1393 #[test]
1394 fn test_sort_archetype_hierarchy() {
1395 let mut world = World::new();
1396
1397 let e0 = world.spawn();
1399 let e1 = world.spawn();
1400 let e2 = world.spawn();
1401 let e3 = world.spawn();
1402 let e4 = world.spawn();
1403
1404 world.add_component(e0, Transform(0.0));
1407 world.add_component(e1, Transform(1.0));
1408 world.add_component(e2, Transform(2.0));
1409 world.add_component(e3, Transform(3.0));
1410 world.add_component(e4, Transform(4.0));
1411
1412 world.add_component(e0, Children(vec![e3.id(), e4.id()]));
1415
1416 world.add_component(e1, Children(vec![]));
1419 world.add_component(e2, Children(vec![]));
1420 world.add_component(e3, Children(vec![]));
1421 world.add_component(e4, Children(vec![]));
1422
1423 world.sort_archetype_hierarchy();
1428
1429 let loc0 = world.entity_location(e0.id());
1431 let loc3 = world.entity_location(e3.id());
1432 let loc4 = world.entity_location(e4.id());
1433
1434 assert_eq!(
1435 loc0.row + 1,
1436 loc3.row,
1437 "e3 (child), e0 (parent)'dan hemen sonra gelmeli"
1438 );
1439 assert_eq!(
1440 loc0.row + 2,
1441 loc4.row,
1442 "e4 (child), e3'ten hemen sonra gelmeli"
1443 );
1444
1445 let loc1 = world.entity_location(e1.id());
1447 let loc2 = world.entity_location(e2.id());
1448 assert!(
1449 loc1.row > loc4.row || loc2.row > loc4.row,
1450 "Bağımsız entityler sona itilmeli"
1451 );
1452 }
1453
1454 #[test]
1455 fn test_sort_archetype_hierarchy_deep() {
1456 let mut world = World::new();
1457
1458 let e0 = world.spawn();
1459 let e1 = world.spawn();
1460 let e2 = world.spawn();
1461 let e3 = world.spawn();
1462
1463 world.add_component(e0, Transform(0.0));
1464 world.add_component(e1, Transform(1.0));
1465 world.add_component(e2, Transform(2.0));
1466 world.add_component(e3, Transform(3.0));
1467
1468 world.add_component(e0, Children(vec![e1.id()]));
1470 world.add_component(e1, Children(vec![e2.id()]));
1471 world.add_component(e2, Children(vec![e3.id()]));
1472 world.add_component(e3, Children(vec![]));
1473
1474 world.sort_archetype_hierarchy();
1475
1476 let l0 = world.entity_location(e0.id());
1477 let l1 = world.entity_location(e1.id());
1478 let l2 = world.entity_location(e2.id());
1479 let l3 = world.entity_location(e3.id());
1480
1481 assert_eq!(l0.row + 1, l1.row);
1482 assert_eq!(l1.row + 1, l2.row);
1486 assert_eq!(l2.row + 1, l3.row);
1487 }
1488
1489
1490 #[test]
1491 fn spawn_despawn_generation() {
1492 let mut world = World::new();
1493 let e1 = world.spawn();
1494 world.despawn(e1);
1495
1496 let e2 = world.spawn(); assert_eq!(e1.id(), e2.id());
1498 assert_ne!(e1.generation(), e2.generation());
1499
1500 assert!(!world.is_alive(e1));
1502 assert!(world.is_alive(e2));
1503 }
1504
1505 #[test]
1506 fn despawn_updates_swapped_entity_location() {
1507 #[derive(Clone)]
1508 struct TestComp(i32);
1509 impl crate::component::Component for TestComp {}
1510
1511 let mut world = World::new();
1512 world.register_component_type::<TestComp>();
1513
1514 let e1 = world.spawn(); world.add_component(e1, TestComp(1));
1515 let e2 = world.spawn(); world.add_component(e2, TestComp(2));
1516 let e3 = world.spawn(); world.add_component(e3, TestComp(3));
1517
1518 world.despawn(e2);
1520
1521 let comps = world.borrow::<TestComp>();
1523 let val = comps.get(e3.id()).unwrap();
1524 assert_eq!(val.0, 3);
1525 }
1526
1527 #[test]
1528 fn add_component_migrates_archetype() {
1529 #[derive(Clone, Debug, PartialEq)]
1530 struct TestCompI32(i32);
1531 impl crate::component::Component for TestCompI32 {}
1532
1533 #[derive(Clone, Debug, PartialEq)]
1534 struct TestCompF32(f32);
1535 impl crate::component::Component for TestCompF32 {}
1536
1537 let mut world = World::new();
1538 world.register_component_type::<TestCompI32>();
1539 world.register_component_type::<TestCompF32>();
1540
1541 let e = world.spawn();
1542 world.add_component(e, TestCompI32(10));
1543
1544 let loc1 = world.entity_location(e.id());
1545
1546 world.add_component(e, TestCompF32(3.14));
1547
1548 let loc2 = world.entity_location(e.id());
1549 assert_ne!(loc1.archetype_id, loc2.archetype_id);
1550
1551 assert_eq!(world.borrow::<TestCompI32>().get(e.id()).unwrap().0, 10);
1552 assert_eq!(world.borrow::<TestCompF32>().get(e.id()).unwrap().0, 3.14);
1553 }
1554
1555 #[test]
1556 fn add_same_component_overwrites() {
1557 #[derive(Clone, Debug, PartialEq)]
1558 struct TestCompI32(i32);
1559 impl crate::component::Component for TestCompI32 {}
1560
1561 let mut world = World::new();
1562 world.register_component_type::<TestCompI32>();
1563
1564 let e = world.spawn();
1565 world.add_component(e, TestCompI32(1));
1566 world.add_component(e, TestCompI32(99)); assert_eq!(world.borrow::<TestCompI32>().get(e.id()).unwrap().0, 99);
1569 }
1570
1571 #[test]
1572 fn archetype_graph_reuses_archetypes() {
1573 #[derive(Clone, Debug, PartialEq)]
1574 struct TestCompI32(i32);
1575 impl crate::component::Component for TestCompI32 {}
1576
1577 #[derive(Clone, Debug, PartialEq)]
1578 struct TestCompF32(f32);
1579 impl crate::component::Component for TestCompF32 {}
1580
1581 let mut world = World::new();
1582 world.register_component_type::<TestCompI32>();
1583 world.register_component_type::<TestCompF32>();
1584
1585 let e1 = world.spawn(); world.add_component(e1, TestCompI32(1)); world.add_component(e1, TestCompF32(1.0));
1586 let e2 = world.spawn(); world.add_component(e2, TestCompI32(2)); world.add_component(e2, TestCompF32(2.0));
1587
1588 let loc1 = world.entity_location(e1.id());
1589 let loc2 = world.entity_location(e2.id());
1590 assert_eq!(loc1.archetype_id, loc2.archetype_id);
1591
1592 assert!(world.archetype_index.archetypes.len() < 5);
1593 }
1594
1595 #[test]
1596 fn query_finds_matching_archetypes() {
1597 #[derive(Clone)]
1598 struct TestCompI32(i32);
1599 impl crate::component::Component for TestCompI32 {}
1600
1601 #[derive(Clone)]
1602 struct TestCompF32(f32);
1603 impl crate::component::Component for TestCompF32 {}
1604
1605 #[derive(Clone)]
1606 struct TestCompBool(bool);
1607 impl crate::component::Component for TestCompBool {}
1608
1609 let mut world = World::new();
1610 world.register_component_type::<TestCompI32>();
1611 world.register_component_type::<TestCompF32>();
1612 world.register_component_type::<TestCompBool>();
1613
1614 let e1 = world.spawn(); world.add_component(e1, TestCompI32(1)); world.add_component(e1, TestCompF32(1.0));
1615 let e2 = world.spawn(); world.add_component(e2, TestCompI32(2)); world.add_component(e2, TestCompBool(true));
1616 let e3 = world.spawn(); world.add_component(e3, TestCompI32(3)); let count = world.query::<&TestCompI32>().unwrap().iter().count();
1620 assert_eq!(count, 3);
1621
1622 let count = world.query::<(&TestCompI32, &TestCompF32)>().unwrap().iter().count();
1624 assert_eq!(count, 1);
1625 }
1626
1627 #[test]
1628 fn query_mut_modifies_data() {
1629 #[derive(Clone)]
1630 struct TestCompI32(i32);
1631 impl crate::component::Component for TestCompI32 {}
1632
1633 let mut world = World::new();
1634 world.register_component_type::<TestCompI32>();
1635
1636 let e1 = world.spawn(); world.add_component(e1, TestCompI32(1));
1637 let e2 = world.spawn(); world.add_component(e2, TestCompI32(2));
1638
1639 if let Some(mut q) = world.query::<crate::query::Mut<TestCompI32>>() {
1641 for (_, mut val) in q.iter_mut() {
1642 val.0 *= 2;
1643 }
1644 }
1645
1646 assert_eq!(world.borrow::<TestCompI32>().get(e1.id()).unwrap().0, 2);
1647 assert_eq!(world.borrow::<TestCompI32>().get(e2.id()).unwrap().0, 4);
1648 }
1649
1650 #[test]
1651 fn query_skips_non_matching() {
1652 #[derive(Clone)]
1653 struct CompA;
1654 impl crate::component::Component for CompA {}
1655 #[derive(Clone)]
1656 struct CompB;
1657 impl crate::component::Component for CompB {}
1658
1659 let mut world = World::new();
1660 world.register_component_type::<CompA>();
1661 world.register_component_type::<CompB>();
1662
1663 for _ in 0..100 {
1664 let e = world.spawn();
1665 world.add_component(e, CompA);
1666 }
1667
1668 for _ in 0..50 {
1669 let e = world.spawn();
1670 world.add_component(e, CompB);
1671 }
1672
1673 let a_count = world.query::<&CompA>().unwrap().iter().count();
1674 let b_count = world.query::<&CompB>().unwrap().iter().count();
1675 let both_count = world.query::<(&CompA, &CompB)>().unwrap().iter().count();
1676
1677 assert_eq!(a_count, 100);
1678 assert_eq!(b_count, 50);
1679 assert_eq!(both_count, 0);
1680 }
1681
1682 #[test]
1683 fn spawn_despawn_10k_entities_archetype_stability() {
1684 #[derive(Clone)]
1685 struct CompA(i32);
1686 impl crate::component::Component for CompA {}
1687 #[derive(Clone)]
1688 struct CompB(f32);
1689 impl crate::component::Component for CompB {}
1690
1691 let mut world = World::new();
1692 world.register_component_type::<CompA>();
1693 world.register_component_type::<CompB>();
1694
1695 let initial_archetypes = world.archetype_index.archetypes.len();
1696
1697 let mut entities = Vec::new();
1699 for i in 0..10_000 {
1700 let e = world.spawn();
1701 world.add_component(e, CompA(i as i32));
1702 if i % 2 == 0 {
1703 world.add_component(e, CompB(i as f32));
1704 }
1705 entities.push(e);
1706 }
1707
1708 for e in entities {
1710 world.despawn(e);
1711 }
1712
1713 let final_archetypes = world.archetype_index.archetypes.len();
1715 assert!(final_archetypes <= initial_archetypes + 2);
1717 }
1718}