Skip to content

Commit 06a9b62

Browse files
committed
disabling
1 parent 473b032 commit 06a9b62

File tree

4 files changed

+139
-11
lines changed

4 files changed

+139
-11
lines changed

crates/bevy_ecs/src/archetype.rs

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -327,6 +327,7 @@ impl Edges {
327327
}
328328

329329
/// Metadata about an [`Entity`] in a [`Archetype`].
330+
#[derive(Clone, Copy)]
330331
pub struct ArchetypeEntity {
331332
entity: Entity,
332333
table_row: TableRow,
@@ -634,6 +635,52 @@ impl Archetype {
634635
self.entities.reserve(additional);
635636
}
636637

638+
/// Disables the entity at `row` by swapping it with the first enabled
639+
/// entity. Returns the swapped entities with their respective table and
640+
/// archetype rows, or `None` if no swap occurred.
641+
///
642+
/// # Panics
643+
/// This function will panic if `row >= self.entities.len()`
644+
#[inline]
645+
pub(crate) fn swap_disable(
646+
&mut self,
647+
row: ArchetypeRow,
648+
) -> (
649+
(ArchetypeEntity, ArchetypeRow),
650+
Option<(ArchetypeEntity, ArchetypeRow)>,
651+
) {
652+
debug_assert!(row.index_u32() < self.len());
653+
debug_assert!(row.index_u32() >= self.disabled_entities);
654+
655+
if row.index_u32() == self.disabled_entities {
656+
// no need to swap, just increment the disabled count
657+
self.disabled_entities += 1;
658+
659+
// SAFETY: `row` is guaranteed to be in-bounds.
660+
(
661+
(unsafe { *self.entities.get_unchecked(row.index()) }, row),
662+
None,
663+
)
664+
} else {
665+
// SAFETY: `self.disabled_entities` is always less than `u32::MAX`, as guaranteed by `allocate`.
666+
let disabled_row =
667+
ArchetypeRow::new(unsafe { NonMaxU32::new_unchecked(self.disabled_entities) });
668+
669+
self.entities.swap(row.index(), disabled_row.index());
670+
671+
// SAFETY: Both `row` and `other` are guaranteed to be in-bounds.
672+
unsafe {
673+
(
674+
(
675+
*self.entities.get_unchecked(disabled_row.index()),
676+
disabled_row,
677+
),
678+
Some((*self.entities.get_unchecked(row.index()), row)),
679+
)
680+
}
681+
}
682+
}
683+
637684
/// Removes the entity at `row` by swapping it out. Returns the table row the entity is stored
638685
/// in.
639686
///

crates/bevy_ecs/src/storage/table/mod.rs

Lines changed: 14 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -224,29 +224,33 @@ impl Table {
224224
pub(crate) unsafe fn swap_disable_unchecked(
225225
&mut self,
226226
row: TableRow,
227-
) -> Option<((Entity, TableRow), (Entity, TableRow))> {
227+
) -> ((Entity, TableRow), Option<(Entity, TableRow)>) {
228228
debug_assert!(row.index_u32() < self.len());
229229
debug_assert!(row.index_u32() >= self.disabled_entities);
230230

231-
if row.index_u32() != 0 {
231+
if row.index_u32() != self.disabled_entities {
232232
// SAFETY: `self.disabled_entities` is always less than `u32::MAX`,
233233
// as guaranteed by `allocate`.
234-
let other = TableRow::new(unsafe { NonMaxU32::new_unchecked(self.disabled_entities) });
234+
let disabled_row =
235+
TableRow::new(unsafe { NonMaxU32::new_unchecked(self.disabled_entities) });
235236

236237
for col in self.columns.values_mut() {
237-
col.swap_unchecked(row, other);
238+
col.swap_unchecked(row, disabled_row);
238239
}
239240

240-
self.entities.swap(row.index(), other.index());
241+
self.entities.swap(row.index(), disabled_row.index());
241242
self.disabled_entities += 1;
242243

243-
Some((
244-
(*self.entities.get_unchecked(other.index()), other),
245-
(*self.entities.get_unchecked(row.index()), row),
246-
))
244+
(
245+
(
246+
*self.entities.get_unchecked(disabled_row.index()),
247+
disabled_row,
248+
),
249+
Some((*self.entities.get_unchecked(row.index()), row)),
250+
)
247251
} else {
248252
self.disabled_entities += 1;
249-
None
253+
((*self.entities.get_unchecked(row.index()), row), None)
250254
}
251255
}
252256

crates/bevy_ecs/src/world/entity_ref.rs

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2562,6 +2562,76 @@ impl<'w> EntityWorldMut<'w> {
25622562
self.despawn_with_caller(MaybeLocation::caller());
25632563
}
25642564

2565+
/// Disable the current entity.
2566+
///
2567+
pub fn disable(self) -> EntityLocation {
2568+
let world = self.world;
2569+
2570+
let location = world
2571+
.entities
2572+
.get(self.entity)
2573+
.expect("entity should exist at this point.");
2574+
2575+
let location = {
2576+
let archetype = &mut world.archetypes[location.archetype_id];
2577+
let ((disabled_arch, archetype_row), swapped_archetype) =
2578+
archetype.swap_disable(location.archetype_row);
2579+
2580+
// set the correct entity location for the swapped entity; the disabled is set to `None`
2581+
if let Some((entity, archetype_row)) = swapped_archetype {
2582+
let entity = entity.id();
2583+
let swapped_location = world.entities.get(entity).unwrap();
2584+
2585+
// SAFETY: TODO
2586+
unsafe {
2587+
world.entities.set(
2588+
entity.index(),
2589+
Some(EntityLocation {
2590+
archetype_row,
2591+
..swapped_location
2592+
}),
2593+
);
2594+
}
2595+
}
2596+
2597+
// SAFETY: TODO
2598+
let ((disabled_table, table_row), swapped_table) = unsafe {
2599+
world.storages.tables[archetype.table_id()]
2600+
.swap_disable_unchecked(disabled_arch.table_row())
2601+
};
2602+
2603+
if let Some((entity, table_row)) = swapped_table {
2604+
let swapped_location = world.entities.get(entity).unwrap();
2605+
2606+
// SAFETY: TODO
2607+
unsafe {
2608+
world.entities.set(
2609+
entity.index(),
2610+
Some(EntityLocation {
2611+
table_row,
2612+
..swapped_location
2613+
}),
2614+
);
2615+
}
2616+
}
2617+
2618+
assert_eq!(disabled_table, disabled_arch.id());
2619+
2620+
EntityLocation {
2621+
archetype_row,
2622+
table_row,
2623+
..location
2624+
}
2625+
};
2626+
2627+
// SAFETY: TODO
2628+
unsafe {
2629+
world.entities.set(self.entity.index(), None);
2630+
}
2631+
2632+
location
2633+
}
2634+
25652635
pub(crate) fn despawn_with_caller(self, caller: MaybeLocation) {
25662636
let location = self.location();
25672637
let world = self.world;

crates/bevy_ecs/src/world/mod.rs

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ use crate::{
4141
ComponentTicks, Components, ComponentsQueuedRegistrator, ComponentsRegistrator, Mutable,
4242
RequiredComponents, RequiredComponentsError, Tick,
4343
},
44-
entity::{Entities, Entity, EntityDoesNotExistError},
44+
entity::{Entities, Entity, EntityDoesNotExistError, EntityLocation},
4545
entity_disabling::DefaultQueryFilters,
4646
error::{DefaultErrorHandler, ErrorHandler},
4747
lifecycle::{ComponentHooks, RemovedComponentMessages, ADD, DESPAWN, INSERT, REMOVE, REPLACE},
@@ -1439,6 +1439,13 @@ impl World {
14391439
Ok(())
14401440
}
14411441

1442+
pub fn disable(&mut self, entity: Entity) -> Result<EntityLocation, EntityMutableFetchError> {
1443+
self.flush();
1444+
1445+
let entity = self.get_entity_mut(entity)?;
1446+
Ok(entity.disable())
1447+
}
1448+
14421449
/// Clears the internal component tracker state.
14431450
///
14441451
/// The world maintains some internal state about changed and removed components. This state

0 commit comments

Comments
 (0)