Add simple Disabled marker (#17514)
# Objective We have default query filters now, but there is no first-party marker for entity disabling yet Fixes #17458 ## Solution Add the marker, cool recursive features and/or potential hook changes should be follow up work ## Testing Added a unit test to check that the new marker is enabled by default
This commit is contained in:
parent
75e8e8c0f6
commit
62285a47ba
@ -26,7 +26,17 @@ use crate::{
|
||||
component::{ComponentId, Components, StorageType},
|
||||
query::FilteredAccess,
|
||||
};
|
||||
use bevy_ecs_macros::Resource;
|
||||
use bevy_ecs_macros::{Component, Resource};
|
||||
|
||||
#[cfg(feature = "bevy_reflect")]
|
||||
use {crate::reflect::ReflectComponent, bevy_reflect::Reflect};
|
||||
|
||||
/// A marker component for disabled entities. See [the module docs] for more info.
|
||||
///
|
||||
/// [the module docs]: crate::entity_disabling
|
||||
#[derive(Component)]
|
||||
#[cfg_attr(feature = "bevy_reflect", derive(Reflect), reflect(Component))]
|
||||
pub struct Disabled;
|
||||
|
||||
/// The default filters for all queries, these are used to globally exclude entities from queries.
|
||||
/// See the [module docs](crate::entity_disabling) for more info.
|
||||
@ -37,10 +47,6 @@ pub struct DefaultQueryFilters {
|
||||
}
|
||||
|
||||
impl DefaultQueryFilters {
|
||||
#[cfg_attr(
|
||||
not(test),
|
||||
expect(dead_code, reason = "No Disabled component exist yet")
|
||||
)]
|
||||
/// Set the [`ComponentId`] for the entity disabling marker
|
||||
pub(crate) fn set_disabled(&mut self, component_id: ComponentId) -> Option<()> {
|
||||
if self.disabled.is_some() {
|
||||
|
@ -134,6 +134,7 @@ mod tests {
|
||||
change_detection::Ref,
|
||||
component::{require, Component, ComponentId, RequiredComponents, RequiredComponentsError},
|
||||
entity::Entity,
|
||||
entity_disabling::DefaultQueryFilters,
|
||||
prelude::Or,
|
||||
query::{Added, Changed, FilteredAccess, QueryFilter, With, Without},
|
||||
resource::Resource,
|
||||
@ -1530,6 +1531,8 @@ mod tests {
|
||||
#[test]
|
||||
fn filtered_query_access() {
|
||||
let mut world = World::new();
|
||||
// We remove entity disabling so it doesn't affect our query filters
|
||||
world.remove_resource::<DefaultQueryFilters>();
|
||||
let query = world.query_filtered::<&mut A, Changed<B>>();
|
||||
|
||||
let mut expected = FilteredAccess::<ComponentId>::default();
|
||||
|
@ -2552,15 +2552,15 @@ mod tests {
|
||||
|
||||
fn nothing() {}
|
||||
|
||||
assert!(world.iter_resources().count() == 0);
|
||||
let resources = world.iter_resources().count();
|
||||
let id = world.register_system_cached(nothing);
|
||||
assert!(world.iter_resources().count() == 1);
|
||||
assert_eq!(world.iter_resources().count(), resources + 1);
|
||||
assert!(world.get_entity(id.entity).is_ok());
|
||||
|
||||
let mut commands = Commands::new(&mut queue, &world);
|
||||
commands.unregister_system_cached(nothing);
|
||||
queue.apply(&mut world);
|
||||
assert!(world.iter_resources().count() == 0);
|
||||
assert_eq!(world.iter_resources().count(), resources);
|
||||
assert!(world.get_entity(id.entity).is_err());
|
||||
}
|
||||
|
||||
|
@ -40,6 +40,7 @@ use crate::{
|
||||
RequiredComponentsError, Tick,
|
||||
},
|
||||
entity::{AllocAtWithoutReplacement, Entities, Entity, EntityLocation},
|
||||
entity_disabling::{DefaultQueryFilters, Disabled},
|
||||
event::{Event, EventId, Events, SendBatchIds},
|
||||
observer::Observers,
|
||||
query::{DebugCheckedUnwrap, QueryData, QueryFilter, QueryState},
|
||||
@ -158,6 +159,11 @@ impl World {
|
||||
|
||||
let on_despawn = OnDespawn::register_component_id(self);
|
||||
assert_eq!(ON_DESPAWN, on_despawn);
|
||||
|
||||
let disabled = self.register_component::<Disabled>();
|
||||
let mut filters = DefaultQueryFilters::default();
|
||||
filters.set_disabled(disabled);
|
||||
self.insert_resource(filters);
|
||||
}
|
||||
/// Creates a new empty [`World`].
|
||||
///
|
||||
@ -3267,6 +3273,7 @@ impl World {
|
||||
/// # struct B(u32);
|
||||
/// #
|
||||
/// # let mut world = World::new();
|
||||
/// # world.remove_resource::<bevy_ecs::entity_disabling::DefaultQueryFilters>();
|
||||
/// # world.insert_resource(A(1));
|
||||
/// # world.insert_resource(B(2));
|
||||
/// let mut total = 0;
|
||||
@ -3765,6 +3772,7 @@ mod tests {
|
||||
change_detection::DetectChangesMut,
|
||||
component::{ComponentDescriptor, ComponentInfo, StorageType},
|
||||
entity::hash_set::EntityHashSet,
|
||||
entity_disabling::{DefaultQueryFilters, Disabled},
|
||||
ptr::OwningPtr,
|
||||
resource::Resource,
|
||||
world::error::EntityFetchError,
|
||||
@ -3954,6 +3962,8 @@ mod tests {
|
||||
#[test]
|
||||
fn iter_resources() {
|
||||
let mut world = World::new();
|
||||
// Remove DefaultQueryFilters so it doesn't show up in the iterator
|
||||
world.remove_resource::<DefaultQueryFilters>();
|
||||
world.insert_resource(TestResource(42));
|
||||
world.insert_resource(TestResource2("Hello, world!".to_string()));
|
||||
world.insert_resource(TestResource3);
|
||||
@ -3980,6 +3990,8 @@ mod tests {
|
||||
#[test]
|
||||
fn iter_resources_mut() {
|
||||
let mut world = World::new();
|
||||
// Remove DefaultQueryFilters so it doesn't show up in the iterator
|
||||
world.remove_resource::<DefaultQueryFilters>();
|
||||
world.insert_resource(TestResource(42));
|
||||
world.insert_resource(TestResource2("Hello, world!".to_string()));
|
||||
world.insert_resource(TestResource3);
|
||||
@ -4446,4 +4458,16 @@ mod tests {
|
||||
None
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn new_world_has_disabling() {
|
||||
let mut world = World::new();
|
||||
world.spawn(Foo);
|
||||
world.spawn((Foo, Disabled));
|
||||
assert_eq!(1, world.query::<&Foo>().iter(&world).count());
|
||||
|
||||
// If we explicitly remove the resource, no entities should be filtered anymore
|
||||
world.remove_resource::<DefaultQueryFilters>();
|
||||
assert_eq!(2, world.query::<&Foo>().iter(&world).count());
|
||||
}
|
||||
}
|
||||
|
@ -1,7 +1,10 @@
|
||||
use core::any::TypeId;
|
||||
|
||||
use crate::{DynamicEntity, DynamicScene, SceneFilter};
|
||||
use alloc::collections::BTreeMap;
|
||||
use bevy_ecs::{
|
||||
component::{Component, ComponentId},
|
||||
entity_disabling::DefaultQueryFilters,
|
||||
prelude::Entity,
|
||||
reflect::{AppTypeRegistry, ReflectComponent, ReflectResource},
|
||||
resource::Resource,
|
||||
@ -348,9 +351,17 @@ impl<'w> DynamicSceneBuilder<'w> {
|
||||
/// [`deny_resource`]: Self::deny_resource
|
||||
#[must_use]
|
||||
pub fn extract_resources(mut self) -> Self {
|
||||
let original_world_dqf_id = self
|
||||
.original_world
|
||||
.components()
|
||||
.get_resource_id(TypeId::of::<DefaultQueryFilters>());
|
||||
|
||||
let type_registry = self.original_world.resource::<AppTypeRegistry>().read();
|
||||
|
||||
for (component_id, _) in self.original_world.storages().resources.iter() {
|
||||
if Some(component_id) == original_world_dqf_id {
|
||||
continue;
|
||||
}
|
||||
let mut extract_and_push = || {
|
||||
let type_id = self
|
||||
.original_world
|
||||
|
@ -1,7 +1,10 @@
|
||||
use core::any::TypeId;
|
||||
|
||||
use crate::{DynamicScene, SceneSpawnError};
|
||||
use bevy_asset::Asset;
|
||||
use bevy_ecs::{
|
||||
entity::{hash_map::EntityHashMap, Entity, SceneEntityMapper},
|
||||
entity_disabling::DefaultQueryFilters,
|
||||
reflect::{AppTypeRegistry, ReflectComponent, ReflectMapEntities, ReflectResource},
|
||||
world::World,
|
||||
};
|
||||
@ -59,8 +62,16 @@ impl Scene {
|
||||
) -> Result<(), SceneSpawnError> {
|
||||
let type_registry = type_registry.read();
|
||||
|
||||
let self_dqf_id = self
|
||||
.world
|
||||
.components()
|
||||
.get_resource_id(TypeId::of::<DefaultQueryFilters>());
|
||||
|
||||
// Resources archetype
|
||||
for (component_id, resource_data) in self.world.storages().resources.iter() {
|
||||
if Some(component_id) == self_dqf_id {
|
||||
continue;
|
||||
}
|
||||
if !resource_data.is_present() {
|
||||
continue;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user