Skip to content

Commit 4c04775

Browse files
authored
Internal Entities (#20204)
# Objective As we move more stuff to entities, it's a good idea to keep these entities quasi-private. We do not want to confuse users by having to explain everything as being an entity. This came out of #19711. ## Solution This PR introduces the concept of internal entities, entities marked by the `Internal` component, that are filtered out by queries through `DefaultQureyFilters` and also don't show up for `World::entity_count()`. ## Testing Added a test.
1 parent 2b3ee67 commit 4c04775

File tree

4 files changed

+74
-3
lines changed

4 files changed

+74
-3
lines changed

crates/bevy_ecs/src/entity_disabling.rs

Lines changed: 42 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,27 @@ use {
105105
// This component is registered as a disabling component during World::bootstrap
106106
pub struct Disabled;
107107

108+
/// A marker component for internal entities.
109+
///
110+
/// This component is used to mark entities as being internal to the engine.
111+
/// These entities should be hidden from the developer's view by default,
112+
/// as they are both noisy and expose confusing implementation details.
113+
/// Internal entities are hidden from queries using [`DefaultQueryFilters`].
114+
/// For more information, see [the module docs].
115+
/// We strongly advise against altering, removing or relying on entities tagged with this component in any way.
116+
/// These are "internal implementation details", and may not be robust to these changes or stable across minor Bevy versions.
117+
///
118+
/// [the module docs]: crate::entity_disabling
119+
#[derive(Component, Clone, Debug, Default)]
120+
#[cfg_attr(
121+
feature = "bevy_reflect",
122+
derive(Reflect),
123+
reflect(Component),
124+
reflect(Debug, Clone, Default)
125+
)]
126+
// This component is registered as a disabling component during World::bootstrap
127+
pub struct Internal;
128+
108129
/// Default query filters work by excluding entities with certain components from most queries.
109130
///
110131
/// If a query does not explicitly mention a given disabling component, it will not include entities with that component.
@@ -143,6 +164,8 @@ impl FromWorld for DefaultQueryFilters {
143164
let mut filters = DefaultQueryFilters::empty();
144165
let disabled_component_id = world.register_component::<Disabled>();
145166
filters.register_disabling_component(disabled_component_id);
167+
let internal_component_id = world.register_component::<Internal>();
168+
filters.register_disabling_component(internal_component_id);
146169
filters
147170
}
148171
}
@@ -205,7 +228,7 @@ mod tests {
205228

206229
use super::*;
207230
use crate::{
208-
prelude::{EntityMut, EntityRef, World},
231+
prelude::{Add, EntityMut, EntityRef, On, World},
209232
query::{Has, With},
210233
};
211234
use alloc::{vec, vec::Vec};
@@ -316,4 +339,22 @@ mod tests {
316339
let mut query = world.query::<Option<&Disabled>>();
317340
assert_eq!(1, query.iter(&world).count());
318341
}
342+
343+
#[test]
344+
fn internal_entities() {
345+
let mut world = World::default();
346+
world.register_system(|| {});
347+
let mut query = world.query::<()>();
348+
assert_eq!(query.iter(&world).count(), 0);
349+
let mut query = world.query_filtered::<(), With<Internal>>();
350+
assert_eq!(query.iter(&world).count(), 1);
351+
352+
#[derive(Component)]
353+
struct A;
354+
world.add_observer(|_: On<Add, A>| {});
355+
let mut query = world.query::<()>();
356+
assert_eq!(query.iter(&world).count(), 0);
357+
let mut query = world.query_filtered::<(), With<Internal>>();
358+
assert_eq!(query.iter(&world).count(), 2);
359+
}
319360
}

crates/bevy_ecs/src/observer/distributed_storage.rs

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,12 @@
1212
use core::any::Any;
1313

1414
use crate::{
15-
component::{ComponentCloneBehavior, ComponentId, Mutable, StorageType},
15+
component::{
16+
ComponentCloneBehavior, ComponentId, ComponentsRegistrator, Mutable, RequiredComponents,
17+
StorageType,
18+
},
1619
entity::Entity,
20+
entity_disabling::Internal,
1721
error::{ErrorContext, ErrorHandler},
1822
lifecycle::{ComponentHook, HookContext},
1923
observer::{observer_system_runner, ObserverRunner},
@@ -342,6 +346,21 @@ impl Component for Observer {
342346
});
343347
})
344348
}
349+
350+
fn register_required_components(
351+
_component_id: ComponentId,
352+
components: &mut ComponentsRegistrator,
353+
required_components: &mut RequiredComponents,
354+
inheritance_depth: u16,
355+
recursion_check_stack: &mut Vec<ComponentId>,
356+
) {
357+
components.register_required_components_manual::<Self, Internal>(
358+
required_components,
359+
Internal::default,
360+
inheritance_depth,
361+
recursion_check_stack,
362+
);
363+
}
345364
}
346365

347366
/// Store information about what an [`Observer`] observes.

crates/bevy_ecs/src/system/system_registry.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ use crate::{change_detection::DetectChanges, HotPatchChanges};
55
use crate::{
66
change_detection::Mut,
77
entity::Entity,
8+
entity_disabling::Internal,
89
error::BevyError,
910
system::{
1011
input::SystemInput, BoxedSystem, IntoSystem, RunSystemError, SystemParamValidationError,
@@ -20,7 +21,7 @@ use thiserror::Error;
2021

2122
/// A small wrapper for [`BoxedSystem`] that also keeps track whether or not the system has been initialized.
2223
#[derive(Component)]
23-
#[require(SystemIdMarker)]
24+
#[require(SystemIdMarker, Internal)]
2425
pub(crate) struct RegisteredSystem<I, O> {
2526
initialized: bool,
2627
system: BoxedSystem<I, O>,
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
---
2+
title: Internal Entities
3+
pull_requests: [20204]
4+
---
5+
6+
Bevy 0.17 introduces internal entities. Entities tagged by the `Internal` component that are hidden from most queries using [`DefaultQueryFilters`](https://docs.rs/bevy/latest/bevy/ecs/entity_disabling/index.html).
7+
8+
Currently, both [`Observer`s](https://docs.rs/bevy/latest/bevy/ecs/observer/struct.Observer.html) and systems that are registered through [`World::register_system`](https://docs.rs/bevy/latest/bevy/prelude/struct.World.html#method.register_system) are considered internal entities.
9+
10+
If you queried them before, add the `Allows<Internal>` filter to the query to bypass the default filter.

0 commit comments

Comments
 (0)