Support non-Vec data structures in relations (#17447)
# Objective
The existing `RelationshipSourceCollection` uses `Vec` as the only
possible backing for our relationships. While a reasonable choice,
benchmarking use cases might reveal that a different data type is better
or faster.
For example:
- Not all relationships require a stable ordering between the
relationship sources (i.e. children). In cases where we a) have many
such relations and b) don't care about the ordering between them, a hash
set is likely a better datastructure than a `Vec`.
- The number of children-like entities may be small on average, and a
`smallvec` may be faster
## Solution
- Implement `RelationshipSourceCollection` for `EntityHashSet`, our
custom entity-optimized `HashSet`.
-~~Implement `DoubleEndedIterator` for `EntityHashSet` to make things
compile.~~
- This implementation was cursed and very surprising.
- Instead, by moving the iterator type on `RelationshipSourceCollection`
from an erased RPTIT to an explicit associated type we can add a trait
bound on the offending methods!
- Implement `RelationshipSourceCollection` for `SmallVec`
## Testing
I've added a pair of new tests to make sure this pattern compiles
successfully in practice!
## Migration Guide
`EntityHashSet` and `EntityHashMap` are no longer re-exported in
`bevy_ecs::entity` directly. If you were not using `bevy_ecs` / `bevy`'s
`prelude`, you can access them through their now-public modules,
`hash_set` and `hash_map` instead.
## Notes to reviewers
The `EntityHashSet::Iter` type needs to be public for this impl to be
allowed. I initially renamed it to something that wasn't ambiguous and
re-exported it, but as @Victoronz pointed out, that was somewhat
unidiomatic.
In
1a8564898f
,
I instead made the `entity_hash_set` public (and its `entity_hash_set`)
sister public, and removed the re-export. I prefer this design (give me
module docs please), but it leads to a lot of churn in this PR.
Let me know which you'd prefer, and if you'd like me to split that
change out into its own micro PR.
This commit is contained in:
parent
1dd30a620a
commit
5a9bc28502
@ -1,4 +1,4 @@
|
||||
use bevy_ecs::entity::{Entity, EntityHashSet};
|
||||
use bevy_ecs::entity::{hash_set::EntityHashSet, Entity};
|
||||
use criterion::{BenchmarkId, Criterion, Throughput};
|
||||
use rand::{Rng, SeedableRng};
|
||||
use rand_chacha::ChaCha8Rng;
|
||||
|
@ -6,7 +6,7 @@ use bevy_app::Plugin;
|
||||
use bevy_asset::{load_internal_asset, Handle};
|
||||
use bevy_derive::Deref;
|
||||
use bevy_ecs::{
|
||||
entity::{EntityHashMap, EntityHashSet},
|
||||
entity::{hash_map::EntityHashMap, hash_set::EntityHashSet},
|
||||
prelude::*,
|
||||
};
|
||||
use bevy_image::BevyDefault as _;
|
||||
|
@ -125,7 +125,7 @@ derive_more = { version = "1", default-features = false, features = [
|
||||
] }
|
||||
nonmax = { version = "0.5", default-features = false }
|
||||
arrayvec = { version = "0.7.4", default-features = false, optional = true }
|
||||
smallvec = { version = "1", features = ["union"] }
|
||||
smallvec = { version = "1", features = ["union", "const_generics"] }
|
||||
indexmap = { version = "2.5.0", default-features = false }
|
||||
variadics_please = { version = "1.1", default-features = false }
|
||||
spin = { version = "0.9.8", default-features = false, features = [
|
||||
|
@ -1,3 +1,7 @@
|
||||
//! Contains the [`EntityHashMap`] type, a [`HashMap`] pre-configured to use [`EntityHash`] hashing.
|
||||
//!
|
||||
//! This module is a lightweight wrapper around [`hashbrown`](bevy_utils::hashbrown)'s [`HashMap`] that is more performant for [`Entity`] keys.
|
||||
|
||||
use core::{
|
||||
fmt::{self, Debug, Formatter},
|
||||
iter::FusedIterator,
|
||||
|
@ -1,3 +1,7 @@
|
||||
//! Contains the [`EntityHashSet`] type, a [`HashSet`] pre-configured to use [`EntityHash`] hashing.
|
||||
//!
|
||||
//! This module is a lightweight wrapper around [`hashbrown`](bevy_utils::hashbrown)'s [`HashSet`] that is more performant for [`Entity`] keys.
|
||||
|
||||
use core::{
|
||||
fmt::{self, Debug, Formatter},
|
||||
iter::FusedIterator,
|
||||
@ -38,6 +42,16 @@ impl EntityHashSet {
|
||||
Self(HashSet::with_capacity_and_hasher(n, EntityHash))
|
||||
}
|
||||
|
||||
/// Returns the number of elements in the set.
|
||||
pub fn len(&self) -> usize {
|
||||
self.0.len()
|
||||
}
|
||||
|
||||
/// Returns `true` if the set contains no elements.
|
||||
pub fn is_empty(&self) -> bool {
|
||||
self.0.is_empty()
|
||||
}
|
||||
|
||||
/// Returns the inner [`HashSet`].
|
||||
pub fn into_inner(self) -> HashSet<Entity, EntityHash> {
|
||||
self.0
|
||||
|
@ -4,7 +4,7 @@ use crate::{
|
||||
world::World,
|
||||
};
|
||||
|
||||
use super::{EntityHashMap, VisitEntitiesMut};
|
||||
use super::{hash_map::EntityHashMap, VisitEntitiesMut};
|
||||
|
||||
/// Operation to map all contained [`Entity`] fields in a type to new values.
|
||||
///
|
||||
@ -71,7 +71,7 @@ impl<T: VisitEntitiesMut> MapEntities for T {
|
||||
///
|
||||
/// ```
|
||||
/// # use bevy_ecs::entity::{Entity, EntityMapper};
|
||||
/// # use bevy_ecs::entity::EntityHashMap;
|
||||
/// # use bevy_ecs::entity::hash_map::EntityHashMap;
|
||||
/// #
|
||||
/// pub struct SimpleEntityMapper {
|
||||
/// map: EntityHashMap<Entity>,
|
||||
@ -194,7 +194,7 @@ impl<'m> SceneEntityMapper<'m> {
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::{
|
||||
entity::{Entity, EntityHashMap, EntityMapper, SceneEntityMapper},
|
||||
entity::{hash_map::EntityHashMap, Entity, EntityMapper, SceneEntityMapper},
|
||||
world::World,
|
||||
};
|
||||
|
||||
|
@ -53,11 +53,8 @@ pub use visit_entities::*;
|
||||
mod hash;
|
||||
pub use hash::*;
|
||||
|
||||
mod hash_map;
|
||||
mod hash_set;
|
||||
|
||||
pub use hash_map::EntityHashMap;
|
||||
pub use hash_set::EntityHashSet;
|
||||
pub mod hash_map;
|
||||
pub mod hash_set;
|
||||
|
||||
use crate::{
|
||||
archetype::{ArchetypeId, ArchetypeRow},
|
||||
|
@ -58,7 +58,7 @@ impl VisitEntitiesMut for Entity {
|
||||
mod tests {
|
||||
use crate::{
|
||||
self as bevy_ecs,
|
||||
entity::{EntityHashMap, MapEntities, SceneEntityMapper},
|
||||
entity::{hash_map::EntityHashMap, MapEntities, SceneEntityMapper},
|
||||
world::World,
|
||||
};
|
||||
use alloc::{string::String, vec, vec::Vec};
|
||||
|
@ -9,7 +9,7 @@ pub use runner::*;
|
||||
use crate::{
|
||||
archetype::ArchetypeFlags,
|
||||
component::ComponentId,
|
||||
entity::EntityHashMap,
|
||||
entity::hash_map::EntityHashMap,
|
||||
prelude::*,
|
||||
system::IntoObserverSystem,
|
||||
world::{DeferredWorld, *},
|
||||
|
@ -130,12 +130,22 @@ pub trait Relationship: Component + Sized {
|
||||
}
|
||||
}
|
||||
|
||||
/// The iterator type for the source entities in a [`RelationshipTarget`] collection,
|
||||
/// as defined in the [`RelationshipSourceCollection`] trait.
|
||||
pub type SourceIter<'w, R> =
|
||||
<<R as RelationshipTarget>::Collection as RelationshipSourceCollection>::SourceIter<'w>;
|
||||
|
||||
/// A [`Component`] containing the collection of entities that relate to this [`Entity`] via the associated `Relationship` type.
|
||||
/// See the [`Relationship`] documentation for more information.
|
||||
pub trait RelationshipTarget: Component<Mutability = Mutable> + Sized {
|
||||
/// The [`Relationship`] that populates this [`RelationshipTarget`] collection.
|
||||
type Relationship: Relationship<RelationshipTarget = Self>;
|
||||
/// The collection type that stores the "source" entities for this [`RelationshipTarget`] component.
|
||||
///
|
||||
/// Check the list of types which implement [`RelationshipSourceCollection`] for the data structures that can be used inside of your component.
|
||||
/// If you need a new collection type, you can implement the [`RelationshipSourceCollection`] trait
|
||||
/// for a type you own which wraps the collection you want to use (to avoid the orphan rule),
|
||||
/// or open an issue on the Bevy repository to request first-party support for your collection type.
|
||||
type Collection: RelationshipSourceCollection;
|
||||
|
||||
/// Returns a reference to the stored [`RelationshipTarget::Collection`].
|
||||
@ -210,7 +220,7 @@ pub trait RelationshipTarget: Component<Mutability = Mutable> + Sized {
|
||||
|
||||
/// Iterates the entities stored in this collection.
|
||||
#[inline]
|
||||
fn iter(&self) -> impl DoubleEndedIterator<Item = Entity> {
|
||||
fn iter(&self) -> SourceIter<'_, Self> {
|
||||
self.collection().iter()
|
||||
}
|
||||
|
||||
|
@ -7,6 +7,8 @@ use crate::{
|
||||
use alloc::collections::VecDeque;
|
||||
use smallvec::SmallVec;
|
||||
|
||||
use super::SourceIter;
|
||||
|
||||
impl<'w, 's, D: QueryData, F: QueryFilter> Query<'w, 's, D, F> {
|
||||
/// If the given `entity` contains the `R` [`Relationship`] component, returns the
|
||||
/// target entity of that relationship.
|
||||
@ -59,6 +61,7 @@ impl<'w, 's, D: QueryData, F: QueryFilter> Query<'w, 's, D, F> {
|
||||
) -> impl Iterator<Item = Entity> + 'w
|
||||
where
|
||||
<D as QueryData>::ReadOnly: WorldQuery<Item<'w> = &'w S>,
|
||||
SourceIter<'w, S>: DoubleEndedIterator,
|
||||
{
|
||||
self.iter_descendants_depth_first(entity).filter(|entity| {
|
||||
self.get(*entity)
|
||||
@ -114,6 +117,7 @@ impl<'w, 's, D: QueryData, F: QueryFilter> Query<'w, 's, D, F> {
|
||||
) -> DescendantDepthFirstIter<'w, 's, D, F, S>
|
||||
where
|
||||
D::ReadOnly: WorldQuery<Item<'w> = &'w S>,
|
||||
SourceIter<'w, S>: DoubleEndedIterator,
|
||||
{
|
||||
DescendantDepthFirstIter::new(self, entity)
|
||||
}
|
||||
@ -195,6 +199,7 @@ impl<'w, 's, D: QueryData, F: QueryFilter, S: RelationshipTarget>
|
||||
DescendantDepthFirstIter<'w, 's, D, F, S>
|
||||
where
|
||||
D::ReadOnly: WorldQuery<Item<'w> = &'w S>,
|
||||
SourceIter<'w, S>: DoubleEndedIterator,
|
||||
{
|
||||
/// Returns a new [`DescendantDepthFirstIter`].
|
||||
pub fn new(children_query: &'w Query<'w, 's, D, F>, entity: Entity) -> Self {
|
||||
@ -211,6 +216,7 @@ impl<'w, 's, D: QueryData, F: QueryFilter, S: RelationshipTarget> Iterator
|
||||
for DescendantDepthFirstIter<'w, 's, D, F, S>
|
||||
where
|
||||
D::ReadOnly: WorldQuery<Item<'w> = &'w S>,
|
||||
SourceIter<'w, S>: DoubleEndedIterator,
|
||||
{
|
||||
type Item = Entity;
|
||||
|
||||
|
@ -1,9 +1,21 @@
|
||||
use crate::entity::Entity;
|
||||
use crate::entity::{hash_set::EntityHashSet, Entity};
|
||||
use alloc::vec::Vec;
|
||||
use smallvec::SmallVec;
|
||||
|
||||
/// The internal [`Entity`] collection used by a [`RelationshipTarget`](crate::relationship::RelationshipTarget) component.
|
||||
/// This is not intended to be modified directly by users, as it could invalidate the correctness of relationships.
|
||||
pub trait RelationshipSourceCollection {
|
||||
/// The type of iterator returned by the `iter` method.
|
||||
///
|
||||
/// This is an associated type (rather than using a method that returns an opaque return-position impl trait)
|
||||
/// to ensure that all methods and traits (like [`DoubleEndedIterator`]) of the underlying collection's iterator
|
||||
/// are available to the user when implemented without unduly restricting the possible collections.
|
||||
///
|
||||
/// The [`SourceIter`](super::SourceIter) type alias can be helpful to reduce confusion when working with this associated type.
|
||||
type SourceIter<'a>: Iterator<Item = Entity>
|
||||
where
|
||||
Self: 'a;
|
||||
|
||||
/// Returns an instance with the given pre-allocated entity `capacity`.
|
||||
fn with_capacity(capacity: usize) -> Self;
|
||||
|
||||
@ -14,7 +26,7 @@ pub trait RelationshipSourceCollection {
|
||||
fn remove(&mut self, entity: Entity);
|
||||
|
||||
/// Iterates all entities in the collection.
|
||||
fn iter(&self) -> impl DoubleEndedIterator<Item = Entity>;
|
||||
fn iter(&self) -> Self::SourceIter<'_>;
|
||||
|
||||
/// Returns the current length of the collection.
|
||||
fn len(&self) -> usize;
|
||||
@ -27,6 +39,8 @@ pub trait RelationshipSourceCollection {
|
||||
}
|
||||
|
||||
impl RelationshipSourceCollection for Vec<Entity> {
|
||||
type SourceIter<'a> = core::iter::Copied<core::slice::Iter<'a, Entity>>;
|
||||
|
||||
fn with_capacity(capacity: usize) -> Self {
|
||||
Vec::with_capacity(capacity)
|
||||
}
|
||||
@ -41,7 +55,7 @@ impl RelationshipSourceCollection for Vec<Entity> {
|
||||
}
|
||||
}
|
||||
|
||||
fn iter(&self) -> impl DoubleEndedIterator<Item = Entity> {
|
||||
fn iter(&self) -> Self::SourceIter<'_> {
|
||||
<[Entity]>::iter(self).copied()
|
||||
}
|
||||
|
||||
@ -49,3 +63,126 @@ impl RelationshipSourceCollection for Vec<Entity> {
|
||||
Vec::len(self)
|
||||
}
|
||||
}
|
||||
|
||||
impl RelationshipSourceCollection for EntityHashSet {
|
||||
type SourceIter<'a> = core::iter::Copied<crate::entity::hash_set::Iter<'a>>;
|
||||
|
||||
fn with_capacity(capacity: usize) -> Self {
|
||||
EntityHashSet::with_capacity(capacity)
|
||||
}
|
||||
|
||||
fn add(&mut self, entity: Entity) {
|
||||
self.insert(entity);
|
||||
}
|
||||
|
||||
fn remove(&mut self, entity: Entity) {
|
||||
// We need to call the remove method on the underlying hash set,
|
||||
// which takes its argument by reference
|
||||
self.0.remove(&entity);
|
||||
}
|
||||
|
||||
fn iter(&self) -> Self::SourceIter<'_> {
|
||||
self.iter().copied()
|
||||
}
|
||||
|
||||
fn len(&self) -> usize {
|
||||
self.len()
|
||||
}
|
||||
}
|
||||
|
||||
impl<const N: usize> RelationshipSourceCollection for SmallVec<[Entity; N]> {
|
||||
type SourceIter<'a> = core::iter::Copied<core::slice::Iter<'a, Entity>>;
|
||||
|
||||
fn with_capacity(capacity: usize) -> Self {
|
||||
SmallVec::with_capacity(capacity)
|
||||
}
|
||||
|
||||
fn add(&mut self, entity: Entity) {
|
||||
SmallVec::push(self, entity);
|
||||
}
|
||||
|
||||
fn remove(&mut self, entity: Entity) {
|
||||
if let Some(index) = <[Entity]>::iter(self).position(|e| *e == entity) {
|
||||
SmallVec::remove(self, index);
|
||||
}
|
||||
}
|
||||
|
||||
fn iter(&self) -> Self::SourceIter<'_> {
|
||||
<[Entity]>::iter(self).copied()
|
||||
}
|
||||
|
||||
fn len(&self) -> usize {
|
||||
SmallVec::len(self)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate as bevy_ecs;
|
||||
use crate::prelude::{Component, World};
|
||||
use crate::relationship::RelationshipTarget;
|
||||
|
||||
#[test]
|
||||
fn vec_relationship_source_collection() {
|
||||
#[derive(Component)]
|
||||
#[relationship(relationship_target = RelTarget)]
|
||||
struct Rel(Entity);
|
||||
|
||||
#[derive(Component)]
|
||||
#[relationship_target(relationship = Rel, despawn_descendants)]
|
||||
struct RelTarget(Vec<Entity>);
|
||||
|
||||
let mut world = World::new();
|
||||
let a = world.spawn_empty().id();
|
||||
let b = world.spawn_empty().id();
|
||||
|
||||
world.entity_mut(a).insert(Rel(b));
|
||||
|
||||
let rel_target = world.get::<RelTarget>(b).unwrap();
|
||||
let collection = rel_target.collection();
|
||||
assert_eq!(collection, &alloc::vec!(a));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn entity_hash_set_relationship_source_collection() {
|
||||
#[derive(Component)]
|
||||
#[relationship(relationship_target = RelTarget)]
|
||||
struct Rel(Entity);
|
||||
|
||||
#[derive(Component)]
|
||||
#[relationship_target(relationship = Rel, despawn_descendants)]
|
||||
struct RelTarget(EntityHashSet);
|
||||
|
||||
let mut world = World::new();
|
||||
let a = world.spawn_empty().id();
|
||||
let b = world.spawn_empty().id();
|
||||
|
||||
world.entity_mut(a).insert(Rel(b));
|
||||
|
||||
let rel_target = world.get::<RelTarget>(b).unwrap();
|
||||
let collection = rel_target.collection();
|
||||
assert_eq!(collection, &EntityHashSet::from([a]));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn smallvec_relationship_source_collection() {
|
||||
#[derive(Component)]
|
||||
#[relationship(relationship_target = RelTarget)]
|
||||
struct Rel(Entity);
|
||||
|
||||
#[derive(Component)]
|
||||
#[relationship_target(relationship = Rel, despawn_descendants)]
|
||||
struct RelTarget(SmallVec<[Entity; 4]>);
|
||||
|
||||
let mut world = World::new();
|
||||
let a = world.spawn_empty().id();
|
||||
let b = world.spawn_empty().id();
|
||||
|
||||
world.entity_mut(a).insert(Rel(b));
|
||||
|
||||
let rel_target = world.get::<RelTarget>(b).unwrap();
|
||||
let collection = rel_target.collection();
|
||||
assert_eq!(collection, &SmallVec::from_buf([a]));
|
||||
}
|
||||
}
|
||||
|
@ -189,8 +189,8 @@ impl<'w> DeferredWorld<'w> {
|
||||
/// For examples, see [`DeferredWorld::entity_mut`].
|
||||
///
|
||||
/// [`EntityMut`]: crate::world::EntityMut
|
||||
/// [`&EntityHashSet`]: crate::entity::EntityHashSet
|
||||
/// [`EntityHashMap<EntityMut>`]: crate::entity::EntityHashMap
|
||||
/// [`&EntityHashSet`]: crate::entity::hash_set::EntityHashSet
|
||||
/// [`EntityHashMap<EntityMut>`]: crate::entity::hash_map::EntityHashMap
|
||||
/// [`Vec<EntityMut>`]: alloc::vec::Vec
|
||||
#[inline]
|
||||
pub fn get_entity_mut<F: WorldEntityFetch>(
|
||||
@ -298,7 +298,7 @@ impl<'w> DeferredWorld<'w> {
|
||||
/// ## [`&EntityHashSet`]
|
||||
///
|
||||
/// ```
|
||||
/// # use bevy_ecs::{prelude::*, entity::EntityHashSet, world::DeferredWorld};
|
||||
/// # use bevy_ecs::{prelude::*, entity::hash_set::EntityHashSet, world::DeferredWorld};
|
||||
/// #[derive(Component)]
|
||||
/// struct Position {
|
||||
/// x: f32,
|
||||
@ -321,8 +321,8 @@ impl<'w> DeferredWorld<'w> {
|
||||
/// ```
|
||||
///
|
||||
/// [`EntityMut`]: crate::world::EntityMut
|
||||
/// [`&EntityHashSet`]: crate::entity::EntityHashSet
|
||||
/// [`EntityHashMap<EntityMut>`]: crate::entity::EntityHashMap
|
||||
/// [`&EntityHashSet`]: crate::entity::hash_set::EntityHashSet
|
||||
/// [`EntityHashMap<EntityMut>`]: crate::entity::hash_map::EntityHashMap
|
||||
/// [`Vec<EntityMut>`]: alloc::vec::Vec
|
||||
#[inline]
|
||||
pub fn entity_mut<F: WorldEntityFetch>(&mut self, entities: F) -> F::DeferredMut<'_> {
|
||||
|
@ -2,7 +2,7 @@ use alloc::vec::Vec;
|
||||
use core::mem::MaybeUninit;
|
||||
|
||||
use crate::{
|
||||
entity::{Entity, EntityHashMap, EntityHashSet},
|
||||
entity::{hash_map::EntityHashMap, hash_set::EntityHashSet, Entity},
|
||||
world::{
|
||||
error::EntityFetchError, unsafe_world_cell::UnsafeWorldCell, EntityMut, EntityRef,
|
||||
EntityWorldMut,
|
||||
|
@ -647,10 +647,10 @@ impl World {
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// ## [`EntityHashSet`](crate::entity::EntityHashMap)
|
||||
/// ## [`EntityHashSet`](crate::entity::hash_map::EntityHashMap)
|
||||
///
|
||||
/// ```
|
||||
/// # use bevy_ecs::{prelude::*, entity::EntityHashSet};
|
||||
/// # use bevy_ecs::{prelude::*, entity::hash_set::EntityHashSet};
|
||||
/// #[derive(Component)]
|
||||
/// struct Position {
|
||||
/// x: f32,
|
||||
@ -668,7 +668,7 @@ impl World {
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// [`EntityHashSet`]: crate::entity::EntityHashSet
|
||||
/// [`EntityHashSet`]: crate::entity::hash_set::EntityHashSet
|
||||
#[inline]
|
||||
#[track_caller]
|
||||
pub fn entity<F: WorldEntityFetch>(&self, entities: F) -> F::Ref<'_> {
|
||||
@ -699,8 +699,8 @@ impl World {
|
||||
/// such as adding or removing components, or despawning the entity.
|
||||
/// - Pass a slice of [`Entity`]s to receive a [`Vec<EntityMut>`].
|
||||
/// - Pass an array of [`Entity`]s to receive an equally-sized array of [`EntityMut`]s.
|
||||
/// - Pass a reference to a [`EntityHashSet`](crate::entity::EntityHashMap) to receive an
|
||||
/// [`EntityHashMap<EntityMut>`](crate::entity::EntityHashMap).
|
||||
/// - Pass a reference to a [`EntityHashSet`](crate::entity::hash_map::EntityHashMap) to receive an
|
||||
/// [`EntityHashMap<EntityMut>`](crate::entity::hash_map::EntityHashMap).
|
||||
///
|
||||
/// In order to perform structural changes on the returned entity reference,
|
||||
/// such as adding or removing components, or despawning the entity, only a
|
||||
@ -781,10 +781,10 @@ impl World {
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// ## [`EntityHashSet`](crate::entity::EntityHashMap)
|
||||
/// ## [`EntityHashSet`](crate::entity::hash_map::EntityHashMap)
|
||||
///
|
||||
/// ```
|
||||
/// # use bevy_ecs::{prelude::*, entity::EntityHashSet};
|
||||
/// # use bevy_ecs::{prelude::*, entity::hash_set::EntityHashSet};
|
||||
/// #[derive(Component)]
|
||||
/// struct Position {
|
||||
/// x: f32,
|
||||
@ -804,7 +804,7 @@ impl World {
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// [`EntityHashSet`]: crate::entity::EntityHashSet
|
||||
/// [`EntityHashSet`]: crate::entity::hash_set::EntityHashSet
|
||||
#[inline]
|
||||
#[track_caller]
|
||||
pub fn entity_mut<F: WorldEntityFetch>(&mut self, entities: F) -> F::Mut<'_> {
|
||||
@ -853,8 +853,8 @@ impl World {
|
||||
/// - Pass an [`Entity`] to receive a single [`EntityRef`].
|
||||
/// - Pass a slice of [`Entity`]s to receive a [`Vec<EntityRef>`].
|
||||
/// - Pass an array of [`Entity`]s to receive an equally-sized array of [`EntityRef`]s.
|
||||
/// - Pass a reference to a [`EntityHashSet`](crate::entity::EntityHashMap) to receive an
|
||||
/// [`EntityHashMap<EntityRef>`](crate::entity::EntityHashMap).
|
||||
/// - Pass a reference to a [`EntityHashSet`](crate::entity::hash_map::EntityHashMap) to receive an
|
||||
/// [`EntityHashMap<EntityRef>`](crate::entity::hash_map::EntityHashMap).
|
||||
///
|
||||
/// # Errors
|
||||
///
|
||||
@ -865,7 +865,7 @@ impl World {
|
||||
///
|
||||
/// For examples, see [`World::entity`].
|
||||
///
|
||||
/// [`EntityHashSet`]: crate::entity::EntityHashSet
|
||||
/// [`EntityHashSet`]: crate::entity::hash_set::EntityHashSet
|
||||
#[inline]
|
||||
pub fn get_entity<F: WorldEntityFetch>(&self, entities: F) -> Result<F::Ref<'_>, Entity> {
|
||||
let cell = self.as_unsafe_world_cell_readonly();
|
||||
@ -884,8 +884,8 @@ impl World {
|
||||
/// such as adding or removing components, or despawning the entity.
|
||||
/// - Pass a slice of [`Entity`]s to receive a [`Vec<EntityMut>`].
|
||||
/// - Pass an array of [`Entity`]s to receive an equally-sized array of [`EntityMut`]s.
|
||||
/// - Pass a reference to a [`EntityHashSet`](crate::entity::EntityHashMap) to receive an
|
||||
/// [`EntityHashMap<EntityMut>`](crate::entity::EntityHashMap).
|
||||
/// - Pass a reference to a [`EntityHashSet`](crate::entity::hash_map::EntityHashMap) to receive an
|
||||
/// [`EntityHashMap<EntityMut>`](crate::entity::hash_map::EntityHashMap).
|
||||
///
|
||||
/// In order to perform structural changes on the returned entity reference,
|
||||
/// such as adding or removing components, or despawning the entity, only a
|
||||
@ -903,7 +903,7 @@ impl World {
|
||||
///
|
||||
/// For examples, see [`World::entity_mut`].
|
||||
///
|
||||
/// [`EntityHashSet`]: crate::entity::EntityHashSet
|
||||
/// [`EntityHashSet`]: crate::entity::hash_set::EntityHashSet
|
||||
#[inline]
|
||||
pub fn get_entity_mut<F: WorldEntityFetch>(
|
||||
&mut self,
|
||||
@ -3696,7 +3696,7 @@ mod tests {
|
||||
use crate::{
|
||||
change_detection::DetectChangesMut,
|
||||
component::{ComponentDescriptor, ComponentInfo, StorageType},
|
||||
entity::EntityHashSet,
|
||||
entity::hash_set::EntityHashSet,
|
||||
ptr::OwningPtr,
|
||||
system::Resource,
|
||||
world::error::EntityFetchError,
|
||||
|
@ -15,7 +15,7 @@ mod gilrs_system;
|
||||
mod rumble;
|
||||
|
||||
use bevy_app::{App, Plugin, PostUpdate, PreStartup, PreUpdate};
|
||||
use bevy_ecs::entity::EntityHashMap;
|
||||
use bevy_ecs::entity::hash_map::EntityHashMap;
|
||||
use bevy_ecs::prelude::*;
|
||||
use bevy_input::InputSystem;
|
||||
use bevy_utils::{synccell::SyncCell, HashMap};
|
||||
|
@ -10,7 +10,7 @@ use bevy_asset::{
|
||||
use bevy_color::{Color, LinearRgba};
|
||||
use bevy_core_pipeline::prelude::Camera3d;
|
||||
use bevy_ecs::{
|
||||
entity::{Entity, EntityHashMap},
|
||||
entity::{hash_map::EntityHashMap, Entity},
|
||||
hierarchy::ChildSpawner,
|
||||
name::Name,
|
||||
world::World,
|
||||
|
@ -17,7 +17,7 @@
|
||||
|
||||
use bevy_app::prelude::*;
|
||||
use bevy_ecs::{
|
||||
entity::{EntityHashMap, EntityHashSet},
|
||||
entity::{hash_map::EntityHashMap, hash_set::EntityHashSet},
|
||||
prelude::*,
|
||||
system::SystemParam,
|
||||
};
|
||||
|
@ -5,7 +5,7 @@ use core::num::NonZero;
|
||||
use bevy_core_pipeline::core_3d::Camera3d;
|
||||
use bevy_ecs::{
|
||||
component::Component,
|
||||
entity::{Entity, EntityHashMap},
|
||||
entity::{hash_map::EntityHashMap, Entity},
|
||||
query::{With, Without},
|
||||
reflect::ReflectComponent,
|
||||
system::{Commands, Query, Res, Resource},
|
||||
|
@ -1,6 +1,6 @@
|
||||
use bevy_derive::{Deref, DerefMut};
|
||||
use bevy_ecs::component::Component;
|
||||
use bevy_ecs::entity::{Entity, EntityHashMap};
|
||||
use bevy_ecs::entity::{hash_map::EntityHashMap, Entity};
|
||||
use bevy_ecs::reflect::ReflectComponent;
|
||||
use bevy_reflect::{std_traits::ReflectDefault, Reflect};
|
||||
use bevy_render::sync_world::MainEntity;
|
||||
|
@ -1,7 +1,7 @@
|
||||
use core::ops::DerefMut;
|
||||
|
||||
use bevy_ecs::{
|
||||
entity::{EntityHashMap, EntityHashSet},
|
||||
entity::{hash_map::EntityHashMap, hash_set::EntityHashSet},
|
||||
prelude::*,
|
||||
};
|
||||
use bevy_math::{ops, Mat4, Vec3A, Vec4};
|
||||
|
@ -5,7 +5,7 @@ use crate::{
|
||||
};
|
||||
use bevy_asset::{AssetEvent, AssetServer, Assets, UntypedAssetId};
|
||||
use bevy_ecs::{
|
||||
entity::{Entities, Entity, EntityHashMap},
|
||||
entity::{hash_map::EntityHashMap, Entities, Entity},
|
||||
event::EventReader,
|
||||
query::Has,
|
||||
system::{Local, Query, Res, ResMut, Resource, SystemState},
|
||||
|
@ -7,7 +7,7 @@ use bevy_core_pipeline::{
|
||||
};
|
||||
use bevy_ecs::{
|
||||
component::Component,
|
||||
entity::{Entity, EntityHashMap},
|
||||
entity::{hash_map::EntityHashMap, Entity},
|
||||
query::AnyOf,
|
||||
system::{Commands, Query, Res, ResMut, Resource},
|
||||
};
|
||||
|
@ -6,7 +6,7 @@ use bevy_color::ColorToComponents;
|
||||
use bevy_core_pipeline::core_3d::{Camera3d, CORE_3D_DEPTH_FORMAT};
|
||||
use bevy_derive::{Deref, DerefMut};
|
||||
use bevy_ecs::{
|
||||
entity::{EntityHashMap, EntityHashSet},
|
||||
entity::{hash_map::EntityHashMap, hash_set::EntityHashSet},
|
||||
prelude::*,
|
||||
system::lifetimeless::Read,
|
||||
};
|
||||
|
@ -4,7 +4,7 @@ use core::any::TypeId;
|
||||
|
||||
use bevy_app::{App, Plugin};
|
||||
use bevy_ecs::{
|
||||
entity::{Entity, EntityHashMap},
|
||||
entity::{hash_map::EntityHashMap, Entity},
|
||||
query::{Has, With},
|
||||
schedule::IntoSystemConfigs as _,
|
||||
system::{Query, Res, ResMut, Resource, StaticSystemParam},
|
||||
|
@ -1,6 +1,6 @@
|
||||
use core::borrow::Borrow;
|
||||
|
||||
use bevy_ecs::{component::Component, entity::EntityHashMap, reflect::ReflectComponent};
|
||||
use bevy_ecs::{component::Component, entity::hash_map::EntityHashMap, reflect::ReflectComponent};
|
||||
use bevy_math::{Affine3A, Mat3A, Mat4, Vec3, Vec3A, Vec4, Vec4Swizzles};
|
||||
use bevy_reflect::prelude::*;
|
||||
|
||||
|
@ -4,7 +4,7 @@ mod render_layers;
|
||||
use core::any::TypeId;
|
||||
|
||||
use bevy_ecs::component::ComponentId;
|
||||
use bevy_ecs::entity::EntityHashSet;
|
||||
use bevy_ecs::entity::hash_set::EntityHashSet;
|
||||
use bevy_ecs::world::DeferredWorld;
|
||||
use derive_more::derive::{Deref, DerefMut};
|
||||
pub use range::*;
|
||||
|
@ -9,7 +9,7 @@ use core::{
|
||||
use bevy_app::{App, Plugin, PostUpdate};
|
||||
use bevy_ecs::{
|
||||
component::Component,
|
||||
entity::{Entity, EntityHashMap},
|
||||
entity::{hash_map::EntityHashMap, Entity},
|
||||
query::{Changed, With},
|
||||
reflect::ReflectComponent,
|
||||
removal_detection::RemovedComponents,
|
||||
|
@ -4,7 +4,7 @@ use crate::{
|
||||
Extract, ExtractSchedule, Render, RenderApp, RenderSet, WgpuWrapper,
|
||||
};
|
||||
use bevy_app::{App, Plugin};
|
||||
use bevy_ecs::{entity::EntityHashMap, prelude::*};
|
||||
use bevy_ecs::{entity::hash_map::EntityHashMap, prelude::*};
|
||||
use bevy_utils::{default, HashSet};
|
||||
use bevy_window::{
|
||||
CompositeAlphaMode, PresentMode, PrimaryWindow, RawHandleWrapper, Window, WindowClosing,
|
||||
|
@ -20,7 +20,7 @@ use bevy_app::{First, Plugin, Update};
|
||||
use bevy_asset::{load_internal_asset, Handle};
|
||||
use bevy_derive::{Deref, DerefMut};
|
||||
use bevy_ecs::{
|
||||
entity::EntityHashMap, event::event_update_system, prelude::*, system::SystemState,
|
||||
entity::hash_map::EntityHashMap, event::event_update_system, prelude::*, system::SystemState,
|
||||
};
|
||||
use bevy_image::{Image, TextureFormatPixelInfo};
|
||||
use bevy_reflect::Reflect;
|
||||
|
@ -2,7 +2,7 @@ use crate::{ron, DynamicSceneBuilder, Scene, SceneSpawnError};
|
||||
use bevy_asset::Asset;
|
||||
use bevy_ecs::reflect::ReflectResource;
|
||||
use bevy_ecs::{
|
||||
entity::{Entity, EntityHashMap, SceneEntityMapper},
|
||||
entity::{hash_map::EntityHashMap, Entity, SceneEntityMapper},
|
||||
reflect::{AppTypeRegistry, ReflectComponent, ReflectMapEntities},
|
||||
world::World,
|
||||
};
|
||||
@ -200,7 +200,8 @@ mod tests {
|
||||
use bevy_ecs::{
|
||||
component::Component,
|
||||
entity::{
|
||||
Entity, EntityHashMap, EntityMapper, MapEntities, VisitEntities, VisitEntitiesMut,
|
||||
hash_map::EntityHashMap, Entity, EntityMapper, MapEntities, VisitEntities,
|
||||
VisitEntitiesMut,
|
||||
},
|
||||
hierarchy::Parent,
|
||||
reflect::{AppTypeRegistry, ReflectComponent, ReflectMapEntities, ReflectResource},
|
||||
|
@ -1,7 +1,7 @@
|
||||
use crate::{DynamicScene, SceneSpawnError};
|
||||
use bevy_asset::Asset;
|
||||
use bevy_ecs::{
|
||||
entity::{Entity, EntityHashMap, SceneEntityMapper},
|
||||
entity::{hash_map::EntityHashMap, Entity, SceneEntityMapper},
|
||||
reflect::{AppTypeRegistry, ReflectComponent, ReflectMapEntities, ReflectResource},
|
||||
world::World,
|
||||
};
|
||||
|
@ -1,7 +1,7 @@
|
||||
use crate::{DynamicScene, Scene};
|
||||
use bevy_asset::{AssetEvent, AssetId, Assets, Handle};
|
||||
use bevy_ecs::{
|
||||
entity::{Entity, EntityHashMap},
|
||||
entity::{hash_map::EntityHashMap, Entity},
|
||||
event::{Event, EventCursor, Events},
|
||||
hierarchy::Parent,
|
||||
reflect::AppTypeRegistry,
|
||||
|
@ -515,7 +515,7 @@ mod tests {
|
||||
DynamicScene, DynamicSceneBuilder,
|
||||
};
|
||||
use bevy_ecs::{
|
||||
entity::{Entity, EntityHashMap, VisitEntities, VisitEntitiesMut},
|
||||
entity::{hash_map::EntityHashMap, Entity, VisitEntities, VisitEntitiesMut},
|
||||
prelude::{Component, ReflectComponent, ReflectResource, Resource, World},
|
||||
query::{With, Without},
|
||||
reflect::{AppTypeRegistry, ReflectMapEntities},
|
||||
|
@ -7,7 +7,7 @@ use crate::{
|
||||
use bevy_asset::Assets;
|
||||
use bevy_color::LinearRgba;
|
||||
use bevy_derive::{Deref, DerefMut};
|
||||
use bevy_ecs::entity::EntityHashSet;
|
||||
use bevy_ecs::entity::hash_set::EntityHashSet;
|
||||
use bevy_ecs::{
|
||||
change_detection::{DetectChanges, Ref},
|
||||
component::{require, Component},
|
||||
|
@ -4,7 +4,7 @@ use crate::{
|
||||
OverflowAxis, ScrollPosition, UiScale, UiTargetCamera, Val,
|
||||
};
|
||||
use bevy_ecs::{
|
||||
entity::{EntityHashMap, EntityHashSet},
|
||||
entity::{hash_map::EntityHashMap, hash_set::EntityHashSet},
|
||||
prelude::*,
|
||||
system::SystemParam,
|
||||
};
|
||||
|
@ -3,7 +3,7 @@ use core::fmt;
|
||||
use taffy::TaffyTree;
|
||||
|
||||
use bevy_ecs::{
|
||||
entity::{Entity, EntityHashMap},
|
||||
entity::{hash_map::EntityHashMap, Entity},
|
||||
prelude::Resource,
|
||||
};
|
||||
use bevy_math::{UVec2, Vec2};
|
||||
|
@ -18,7 +18,7 @@ use bevy_color::{Alpha, ColorToComponents, LinearRgba};
|
||||
use bevy_core_pipeline::core_2d::graph::{Core2d, Node2d};
|
||||
use bevy_core_pipeline::core_3d::graph::{Core3d, Node3d};
|
||||
use bevy_core_pipeline::{core_2d::Camera2d, core_3d::Camera3d};
|
||||
use bevy_ecs::entity::EntityHashMap;
|
||||
use bevy_ecs::entity::hash_map::EntityHashMap;
|
||||
use bevy_ecs::prelude::*;
|
||||
use bevy_image::prelude::*;
|
||||
use bevy_math::{FloatOrd, Mat4, Rect, UVec4, Vec2, Vec3, Vec3Swizzles, Vec4Swizzles};
|
||||
|
@ -7,7 +7,7 @@ use bevy_color::Color;
|
||||
use bevy_derive::{Deref, DerefMut};
|
||||
use bevy_ecs::{
|
||||
change_detection::DetectChanges,
|
||||
entity::{Entity, EntityHashMap},
|
||||
entity::{hash_map::EntityHashMap, Entity},
|
||||
prelude::{require, Component},
|
||||
query::With,
|
||||
reflect::ReflectComponent,
|
||||
|
@ -15,7 +15,7 @@ use bevy_a11y::{
|
||||
};
|
||||
use bevy_app::{App, Plugin, PostUpdate};
|
||||
use bevy_derive::{Deref, DerefMut};
|
||||
use bevy_ecs::{entity::EntityHashMap, prelude::*};
|
||||
use bevy_ecs::{entity::hash_map::EntityHashMap, prelude::*};
|
||||
use bevy_window::{PrimaryWindow, Window, WindowClosed};
|
||||
|
||||
/// Maps window entities to their `AccessKit` [`Adapter`]s.
|
||||
|
@ -1,7 +1,7 @@
|
||||
use bevy_a11y::AccessibilityRequested;
|
||||
use bevy_ecs::entity::Entity;
|
||||
|
||||
use bevy_ecs::entity::EntityHashMap;
|
||||
use bevy_ecs::entity::hash_map::EntityHashMap;
|
||||
use bevy_utils::HashMap;
|
||||
use bevy_window::{
|
||||
CursorGrabMode, MonitorSelection, Window, WindowMode, WindowPosition, WindowResolution,
|
||||
|
@ -1,7 +1,9 @@
|
||||
//! Control animations of entities in the loaded scene.
|
||||
use std::collections::HashMap;
|
||||
|
||||
use bevy::{animation::AnimationTarget, ecs::entity::EntityHashMap, gltf::Gltf, prelude::*};
|
||||
use bevy::{
|
||||
animation::AnimationTarget, ecs::entity::hash_map::EntityHashMap, gltf::Gltf, prelude::*,
|
||||
};
|
||||
|
||||
use crate::scene_viewer_plugin::SceneHandle;
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user