mirror of
https://github.com/bevyengine/bevy
synced 2024-11-21 20:23:28 +00:00
Move EntityHash
related types into bevy_ecs
(#11498)
# Objective Reduce the size of `bevy_utils` (https://github.com/bevyengine/bevy/issues/11478) ## Solution Move `EntityHash` related types into `bevy_ecs`. This also allows us access to `Entity`, which means we no longer need `EntityHashMap`'s first generic argument. --- ## Changelog - Moved `bevy::utils::{EntityHash, EntityHasher, EntityHashMap, EntityHashSet}` into `bevy::ecs::entity::hash` . - Removed `EntityHashMap`'s first generic argument. It is now hardcoded to always be `Entity`. ## Migration Guide - Uses of `bevy::utils::{EntityHash, EntityHasher, EntityHashMap, EntityHashSet}` now have to be imported from `bevy::ecs::entity::hash`. - Uses of `EntityHashMap` no longer have to specify the first generic parameter. It is now hardcoded to always be `Entity`.
This commit is contained in:
parent
c1a4e29a1e
commit
1c67e020f7
35 changed files with 262 additions and 229 deletions
|
@ -63,6 +63,6 @@ path = "benches/bevy_math/bezier.rs"
|
|||
harness = false
|
||||
|
||||
[[bench]]
|
||||
name = "utils"
|
||||
path = "benches/bevy_utils/entity_hash.rs"
|
||||
name = "entity_hash"
|
||||
path = "benches/bevy_ecs/world/entity_hash.rs"
|
||||
harness = false
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
use bevy_ecs::entity::Entity;
|
||||
use bevy_utils::EntityHashSet;
|
||||
use bevy_ecs::entity::{Entity, EntityHashMap, EntityHashSet};
|
||||
use criterion::{criterion_group, criterion_main, BenchmarkId, Criterion, Throughput};
|
||||
use rand::{Rng, SeedableRng};
|
||||
use rand_chacha::ChaCha8Rng;
|
||||
|
@ -28,7 +27,7 @@ fn make_entity(rng: &mut impl Rng, size: usize) -> Entity {
|
|||
e
|
||||
}
|
||||
|
||||
fn entity_set_build_and_lookup(c: &mut Criterion) {
|
||||
pub fn entity_set_build_and_lookup(c: &mut Criterion) {
|
||||
let mut group = c.benchmark_group("entity_hash");
|
||||
for size in SIZES {
|
||||
// Get some random-but-consistent entities to use for all the benches below.
|
|
@ -1,13 +1,17 @@
|
|||
use criterion::criterion_group;
|
||||
|
||||
mod commands;
|
||||
mod spawn;
|
||||
mod world_get;
|
||||
|
||||
use commands::*;
|
||||
|
||||
mod spawn;
|
||||
use spawn::*;
|
||||
|
||||
mod world_get;
|
||||
use world_get::*;
|
||||
|
||||
mod entity_hash;
|
||||
use entity_hash::*;
|
||||
|
||||
criterion_group!(
|
||||
world_benches,
|
||||
empty_commands,
|
||||
|
@ -30,4 +34,5 @@ criterion_group!(
|
|||
query_get_many::<2>,
|
||||
query_get_many::<5>,
|
||||
query_get_many::<10>,
|
||||
entity_set_build_and_lookup
|
||||
);
|
||||
|
|
|
@ -32,6 +32,7 @@ thiserror = "1.0"
|
|||
|
||||
[dev-dependencies]
|
||||
rand = "0.8"
|
||||
static_assertions = "1.1.0"
|
||||
|
||||
[[example]]
|
||||
name = "events"
|
||||
|
|
99
crates/bevy_ecs/src/entity/hash.rs
Normal file
99
crates/bevy_ecs/src/entity/hash.rs
Normal file
|
@ -0,0 +1,99 @@
|
|||
use std::hash::{BuildHasher, Hasher};
|
||||
|
||||
#[cfg(feature = "bevy_reflect")]
|
||||
use bevy_reflect::Reflect;
|
||||
use bevy_utils::hashbrown;
|
||||
|
||||
use super::Entity;
|
||||
|
||||
/// A [`BuildHasher`] that results in a [`EntityHasher`].
|
||||
#[derive(Default, Clone)]
|
||||
#[cfg_attr(feature = "bevy_reflect", derive(Reflect))]
|
||||
pub struct EntityHash;
|
||||
|
||||
impl BuildHasher for EntityHash {
|
||||
type Hasher = EntityHasher;
|
||||
|
||||
fn build_hasher(&self) -> Self::Hasher {
|
||||
Self::Hasher::default()
|
||||
}
|
||||
}
|
||||
|
||||
/// A very fast hash that is only designed to work on generational indices
|
||||
/// like [`Entity`]. It will panic if attempting to hash a type containing
|
||||
/// non-u64 fields.
|
||||
///
|
||||
/// This is heavily optimized for typical cases, where you have mostly live
|
||||
/// entities, and works particularly well for contiguous indices.
|
||||
///
|
||||
/// If you have an unusual case -- say all your indices are multiples of 256
|
||||
/// or most of the entities are dead generations -- then you might want also to
|
||||
/// try [`AHasher`](bevy_utils::AHasher) for a slower hash computation but fewer lookup conflicts.
|
||||
#[derive(Debug, Default)]
|
||||
pub struct EntityHasher {
|
||||
hash: u64,
|
||||
}
|
||||
|
||||
impl Hasher for EntityHasher {
|
||||
#[inline]
|
||||
fn finish(&self) -> u64 {
|
||||
self.hash
|
||||
}
|
||||
|
||||
fn write(&mut self, _bytes: &[u8]) {
|
||||
panic!("EntityHasher can only hash u64 fields.");
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn write_u64(&mut self, bits: u64) {
|
||||
// SwissTable (and thus `hashbrown`) cares about two things from the hash:
|
||||
// - H1: low bits (masked by `2ⁿ-1`) to pick the slot in which to store the item
|
||||
// - H2: high 7 bits are used to SIMD optimize hash collision probing
|
||||
// For more see <https://abseil.io/about/design/swisstables#metadata-layout>
|
||||
|
||||
// This hash function assumes that the entity ids are still well-distributed,
|
||||
// so for H1 leaves the entity id alone in the low bits so that id locality
|
||||
// will also give memory locality for things spawned together.
|
||||
// For H2, take advantage of the fact that while multiplication doesn't
|
||||
// spread entropy to the low bits, it's incredibly good at spreading it
|
||||
// upward, which is exactly where we need it the most.
|
||||
|
||||
// While this does include the generation in the output, it doesn't do so
|
||||
// *usefully*. H1 won't care until you have over 3 billion entities in
|
||||
// the table, and H2 won't care until something hits generation 33 million.
|
||||
// Thus the comment suggesting that this is best for live entities,
|
||||
// where there won't be generation conflicts where it would matter.
|
||||
|
||||
// The high 32 bits of this are ⅟φ for Fibonacci hashing. That works
|
||||
// particularly well for hashing for the same reason as described in
|
||||
// <https://extremelearning.com.au/unreasonable-effectiveness-of-quasirandom-sequences/>
|
||||
// It loses no information because it has a modular inverse.
|
||||
// (Specifically, `0x144c_bc89_u32 * 0x9e37_79b9_u32 == 1`.)
|
||||
//
|
||||
// The low 32 bits make that part of the just product a pass-through.
|
||||
const UPPER_PHI: u64 = 0x9e37_79b9_0000_0001;
|
||||
|
||||
// This is `(MAGIC * index + generation) << 32 + index`, in a single instruction.
|
||||
self.hash = bits.wrapping_mul(UPPER_PHI);
|
||||
}
|
||||
}
|
||||
|
||||
/// A [`HashMap`](hashbrown::HashMap) pre-configured to use [`EntityHash`] hashing.
|
||||
pub type EntityHashMap<V> = hashbrown::HashMap<Entity, V, EntityHash>;
|
||||
|
||||
/// A [`HashSet`](hashbrown::HashSet) pre-configured to use [`EntityHash`] hashing.
|
||||
pub type EntityHashSet = hashbrown::HashSet<Entity, EntityHash>;
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
#[cfg(feature = "bevy_reflect")]
|
||||
use bevy_reflect::Reflect;
|
||||
use static_assertions::assert_impl_all;
|
||||
|
||||
// Check that the HashMaps are Clone if the key/values are Clone
|
||||
assert_impl_all!(EntityHashMap::<usize>: Clone);
|
||||
// EntityHashMap should implement Reflect
|
||||
#[cfg(feature = "bevy_reflect")]
|
||||
assert_impl_all!(EntityHashMap::<i32>: Reflect);
|
||||
}
|
|
@ -3,7 +3,8 @@ use crate::{
|
|||
identifier::masks::{IdentifierMask, HIGH_MASK},
|
||||
world::World,
|
||||
};
|
||||
use bevy_utils::EntityHashMap;
|
||||
|
||||
use super::EntityHashMap;
|
||||
|
||||
/// Operation to map all contained [`Entity`] fields in a type to new values.
|
||||
///
|
||||
|
@ -11,7 +12,7 @@ use bevy_utils::EntityHashMap;
|
|||
/// as references in components copied from another world will be invalid. This trait
|
||||
/// allows defining custom mappings for these references via [`EntityMappers`](EntityMapper), which
|
||||
/// inject the entity mapping strategy between your `MapEntities` type and the current world
|
||||
/// (usually by using an [`EntityHashMap<Entity, Entity>`] between source entities and entities in the
|
||||
/// (usually by using an [`EntityHashMap<Entity>`] between source entities and entities in the
|
||||
/// current world).
|
||||
///
|
||||
/// Implementing this trait correctly is required for properly loading components
|
||||
|
@ -47,7 +48,7 @@ pub trait MapEntities {
|
|||
|
||||
/// An implementor of this trait knows how to map an [`Entity`] into another [`Entity`].
|
||||
///
|
||||
/// Usually this is done by using an [`EntityHashMap<Entity, Entity>`] to map source entities
|
||||
/// Usually this is done by using an [`EntityHashMap<Entity>`] to map source entities
|
||||
/// (mapper inputs) to the current world's entities (mapper outputs).
|
||||
///
|
||||
/// More generally, this can be used to map [`Entity`] references between any two [`Worlds`](World).
|
||||
|
@ -56,10 +57,10 @@ pub trait MapEntities {
|
|||
///
|
||||
/// ```
|
||||
/// # use bevy_ecs::entity::{Entity, EntityMapper};
|
||||
/// # use bevy_utils::EntityHashMap;
|
||||
/// # use bevy_ecs::entity::EntityHashMap;
|
||||
/// #
|
||||
/// pub struct SimpleEntityMapper {
|
||||
/// map: EntityHashMap<Entity, Entity>,
|
||||
/// map: EntityHashMap<Entity>,
|
||||
/// }
|
||||
///
|
||||
/// // Example implementation of EntityMapper where we map an entity to another entity if it exists
|
||||
|
@ -97,7 +98,7 @@ impl EntityMapper for SceneEntityMapper<'_> {
|
|||
}
|
||||
}
|
||||
|
||||
/// A wrapper for [`EntityHashMap<Entity, Entity>`], augmenting it with the ability to allocate new [`Entity`] references in a destination
|
||||
/// A wrapper for [`EntityHashMap<Entity>`], augmenting it with the ability to allocate new [`Entity`] references in a destination
|
||||
/// world. These newly allocated references are guaranteed to never point to any living entity in that world.
|
||||
///
|
||||
/// References are allocated by returning increasing generations starting from an internally initialized base
|
||||
|
@ -110,9 +111,9 @@ pub struct SceneEntityMapper<'m> {
|
|||
/// or over the network. This is required as [`Entity`] identifiers are opaque; you cannot and do not want to reuse
|
||||
/// identifiers directly.
|
||||
///
|
||||
/// On its own, a [`EntityHashMap<Entity, Entity>`] is not capable of allocating new entity identifiers, which is needed to map references
|
||||
/// On its own, a [`EntityHashMap<Entity>`] is not capable of allocating new entity identifiers, which is needed to map references
|
||||
/// to entities that lie outside the source entity set. This functionality can be accessed through [`SceneEntityMapper::world_scope()`].
|
||||
map: &'m mut EntityHashMap<Entity, Entity>,
|
||||
map: &'m mut EntityHashMap<Entity>,
|
||||
/// A base [`Entity`] used to allocate new references.
|
||||
dead_start: Entity,
|
||||
/// The number of generations this mapper has allocated thus far.
|
||||
|
@ -129,18 +130,18 @@ impl<'m> SceneEntityMapper<'m> {
|
|||
self.map_entity(entity)
|
||||
}
|
||||
|
||||
/// Gets a reference to the underlying [`EntityHashMap<Entity, Entity>`].
|
||||
pub fn get_map(&'m self) -> &'m EntityHashMap<Entity, Entity> {
|
||||
/// Gets a reference to the underlying [`EntityHashMap<Entity>`].
|
||||
pub fn get_map(&'m self) -> &'m EntityHashMap<Entity> {
|
||||
self.map
|
||||
}
|
||||
|
||||
/// Gets a mutable reference to the underlying [`EntityHashMap<Entity, Entity>`].
|
||||
pub fn get_map_mut(&'m mut self) -> &'m mut EntityHashMap<Entity, Entity> {
|
||||
/// Gets a mutable reference to the underlying [`EntityHashMap<Entity>`].
|
||||
pub fn get_map_mut(&'m mut self) -> &'m mut EntityHashMap<Entity> {
|
||||
self.map
|
||||
}
|
||||
|
||||
/// Creates a new [`SceneEntityMapper`], spawning a temporary base [`Entity`] in the provided [`World`]
|
||||
fn new(map: &'m mut EntityHashMap<Entity, Entity>, world: &mut World) -> Self {
|
||||
fn new(map: &'m mut EntityHashMap<Entity>, world: &mut World) -> Self {
|
||||
Self {
|
||||
map,
|
||||
// SAFETY: Entities data is kept in a valid state via `EntityMapper::world_scope`
|
||||
|
@ -160,14 +161,14 @@ impl<'m> SceneEntityMapper<'m> {
|
|||
assert!(entities.reserve_generations(self.dead_start.index(), self.generations));
|
||||
}
|
||||
|
||||
/// Creates an [`SceneEntityMapper`] from a provided [`World`] and [`EntityHashMap<Entity, Entity>`], then calls the
|
||||
/// Creates an [`SceneEntityMapper`] from a provided [`World`] and [`EntityHashMap<Entity>`], then calls the
|
||||
/// provided function with it. This allows one to allocate new entity references in this [`World`] that are
|
||||
/// guaranteed to never point at a living entity now or in the future. This functionality is useful for safely
|
||||
/// mapping entity identifiers that point at entities outside the source world. The passed function, `f`, is called
|
||||
/// within the scope of this world. Its return value is then returned from `world_scope` as the generic type
|
||||
/// parameter `R`.
|
||||
pub fn world_scope<R>(
|
||||
entity_map: &'m mut EntityHashMap<Entity, Entity>,
|
||||
entity_map: &'m mut EntityHashMap<Entity>,
|
||||
world: &mut World,
|
||||
f: impl FnOnce(&mut World, &mut Self) -> R,
|
||||
) -> R {
|
||||
|
@ -180,10 +181,8 @@ impl<'m> SceneEntityMapper<'m> {
|
|||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use bevy_utils::EntityHashMap;
|
||||
|
||||
use crate::{
|
||||
entity::{Entity, EntityMapper, SceneEntityMapper},
|
||||
entity::{Entity, EntityHashMap, EntityMapper, SceneEntityMapper},
|
||||
world::World,
|
||||
};
|
||||
|
||||
|
|
|
@ -36,9 +36,14 @@
|
|||
//! [`EntityWorldMut::insert`]: crate::world::EntityWorldMut::insert
|
||||
//! [`EntityWorldMut::remove`]: crate::world::EntityWorldMut::remove
|
||||
mod map_entities;
|
||||
#[cfg(feature = "bevy_reflect")]
|
||||
use bevy_reflect::{Reflect, ReflectDeserialize, ReflectSerialize};
|
||||
pub use map_entities::*;
|
||||
|
||||
mod hash;
|
||||
pub use hash::*;
|
||||
|
||||
use bevy_utils::tracing::warn;
|
||||
pub use map_entities::*;
|
||||
|
||||
use crate::{
|
||||
archetype::{ArchetypeId, ArchetypeRow},
|
||||
|
@ -123,6 +128,11 @@ type IdCursor = isize;
|
|||
/// [`Query::get`]: crate::system::Query::get
|
||||
/// [`World`]: crate::world::World
|
||||
#[derive(Clone, Copy)]
|
||||
#[cfg_attr(feature = "bevy_reflect", derive(Reflect))]
|
||||
#[cfg_attr(
|
||||
feature = "bevy_reflect",
|
||||
reflect_value(Hash, PartialEq, Serialize, Deserialize)
|
||||
)]
|
||||
// Alignment repr necessary to allow LLVM to better output
|
||||
// optimised codegen for `to_bits`, `PartialEq` and `Ord`.
|
||||
#[repr(C, align(8))]
|
||||
|
@ -218,7 +228,7 @@ impl Entity {
|
|||
/// // ... replace the entities with valid ones.
|
||||
/// ```
|
||||
///
|
||||
/// Deriving [`Reflect`](bevy_reflect::Reflect) for a component that has an `Entity` field:
|
||||
/// Deriving [`Reflect`] for a component that has an `Entity` field:
|
||||
///
|
||||
/// ```no_run
|
||||
/// # use bevy_ecs::{prelude::*, component::*};
|
||||
|
@ -1092,7 +1102,7 @@ mod tests {
|
|||
#[test]
|
||||
fn entity_hash_keeps_similar_ids_together() {
|
||||
use std::hash::BuildHasher;
|
||||
let hash = bevy_utils::EntityHash;
|
||||
let hash = EntityHash;
|
||||
|
||||
let first_id = 0xC0FFEE << 8;
|
||||
let first_hash = hash.hash_one(Entity::from_raw(first_id));
|
||||
|
@ -1107,7 +1117,8 @@ mod tests {
|
|||
#[test]
|
||||
fn entity_hash_id_bitflip_affects_high_7_bits() {
|
||||
use std::hash::BuildHasher;
|
||||
let hash = bevy_utils::EntityHash;
|
||||
|
||||
let hash = EntityHash;
|
||||
|
||||
let first_id = 0xC0FFEE;
|
||||
let first_hash = hash.hash_one(Entity::from_raw(first_id)) >> 57;
|
||||
|
|
|
@ -1,10 +1,9 @@
|
|||
use crate::{
|
||||
component::Component,
|
||||
entity::{Entity, MapEntities, SceneEntityMapper},
|
||||
entity::{Entity, EntityHashMap, MapEntities, SceneEntityMapper},
|
||||
world::World,
|
||||
};
|
||||
use bevy_reflect::FromType;
|
||||
use bevy_utils::EntityHashMap;
|
||||
|
||||
/// For a specific type of component, this maps any fields with values of type [`Entity`] to a new world.
|
||||
/// Since a given `Entity` ID is only valid for the world it came from, when performing deserialization
|
||||
|
@ -18,33 +17,29 @@ pub struct ReflectMapEntities {
|
|||
}
|
||||
|
||||
impl ReflectMapEntities {
|
||||
/// A general method for applying [`MapEntities`] behavior to all elements in an [`EntityHashMap<Entity, Entity>`].
|
||||
/// A general method for applying [`MapEntities`] behavior to all elements in an [`EntityHashMap<Entity>`].
|
||||
///
|
||||
/// Be mindful in its usage: Works best in situations where the entities in the [`EntityHashMap<Entity, Entity>`] are newly
|
||||
/// Be mindful in its usage: Works best in situations where the entities in the [`EntityHashMap<Entity>`] are newly
|
||||
/// created, before systems have a chance to add new components. If some of the entities referred to
|
||||
/// by the [`EntityHashMap<Entity, Entity>`] might already contain valid entity references, you should use [`map_entities`](Self::map_entities).
|
||||
/// by the [`EntityHashMap<Entity>`] might already contain valid entity references, you should use [`map_entities`](Self::map_entities).
|
||||
///
|
||||
/// An example of this: A scene can be loaded with `Parent` components, but then a `Parent` component can be added
|
||||
/// to these entities after they have been loaded. If you reload the scene using [`map_all_entities`](Self::map_all_entities), those `Parent`
|
||||
/// components with already valid entity references could be updated to point at something else entirely.
|
||||
pub fn map_all_entities(
|
||||
&self,
|
||||
world: &mut World,
|
||||
entity_map: &mut EntityHashMap<Entity, Entity>,
|
||||
) {
|
||||
pub fn map_all_entities(&self, world: &mut World, entity_map: &mut EntityHashMap<Entity>) {
|
||||
SceneEntityMapper::world_scope(entity_map, world, self.map_all_entities);
|
||||
}
|
||||
|
||||
/// A general method for applying [`MapEntities`] behavior to elements in an [`EntityHashMap<Entity, Entity>`]. Unlike
|
||||
/// A general method for applying [`MapEntities`] behavior to elements in an [`EntityHashMap<Entity>`]. Unlike
|
||||
/// [`map_all_entities`](Self::map_all_entities), this is applied to specific entities, not all values
|
||||
/// in the [`EntityHashMap<Entity, Entity>`].
|
||||
/// in the [`EntityHashMap<Entity>`].
|
||||
///
|
||||
/// This is useful mostly for when you need to be careful not to update components that already contain valid entity
|
||||
/// values. See [`map_all_entities`](Self::map_all_entities) for more details.
|
||||
pub fn map_entities(
|
||||
&self,
|
||||
world: &mut World,
|
||||
entity_map: &mut EntityHashMap<Entity, Entity>,
|
||||
entity_map: &mut EntityHashMap<Entity>,
|
||||
entities: &[Entity],
|
||||
) {
|
||||
SceneEntityMapper::world_scope(entity_map, world, |world, mapper| {
|
||||
|
|
|
@ -3,8 +3,8 @@
|
|||
use std::ops::{Deref, DerefMut};
|
||||
|
||||
use crate as bevy_ecs;
|
||||
use crate::{entity::Entity, system::Resource};
|
||||
use bevy_reflect::{impl_reflect_value, ReflectDeserialize, ReflectSerialize, TypeRegistryArc};
|
||||
use crate::system::Resource;
|
||||
use bevy_reflect::TypeRegistryArc;
|
||||
|
||||
mod bundle;
|
||||
mod component;
|
||||
|
@ -40,5 +40,3 @@ impl DerefMut for AppTypeRegistry {
|
|||
&mut self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl_reflect_value!((in bevy_ecs) Entity(Hash, PartialEq, Serialize, Deserialize));
|
||||
|
|
|
@ -4,6 +4,7 @@ use bevy_asset::{
|
|||
};
|
||||
use bevy_core::Name;
|
||||
use bevy_core_pipeline::prelude::Camera3dBundle;
|
||||
use bevy_ecs::entity::EntityHashMap;
|
||||
use bevy_ecs::{entity::Entity, world::World};
|
||||
use bevy_hierarchy::{BuildWorldChildren, WorldChildBuilder};
|
||||
use bevy_log::{error, warn};
|
||||
|
@ -33,7 +34,7 @@ use bevy_scene::Scene;
|
|||
#[cfg(not(target_arch = "wasm32"))]
|
||||
use bevy_tasks::IoTaskPool;
|
||||
use bevy_transform::components::Transform;
|
||||
use bevy_utils::{EntityHashMap, HashMap, HashSet};
|
||||
use bevy_utils::{HashMap, HashSet};
|
||||
use gltf::{
|
||||
accessor::Iter,
|
||||
mesh::{util::ReadIndices, Mode},
|
||||
|
@ -930,7 +931,7 @@ fn load_node(
|
|||
load_context: &mut LoadContext,
|
||||
settings: &GltfLoaderSettings,
|
||||
node_index_to_entity_map: &mut HashMap<usize, Entity>,
|
||||
entity_to_skin_index_map: &mut EntityHashMap<Entity, usize>,
|
||||
entity_to_skin_index_map: &mut EntityHashMap<usize>,
|
||||
active_camera_found: &mut bool,
|
||||
parent_transform: &Transform,
|
||||
) -> Result<(), GltfError> {
|
||||
|
|
|
@ -3,7 +3,8 @@ use crate::{
|
|||
StandardMaterial,
|
||||
};
|
||||
use bevy_asset::Handle;
|
||||
use bevy_ecs::{bundle::Bundle, component::Component, prelude::Entity, reflect::ReflectComponent};
|
||||
use bevy_ecs::entity::EntityHashMap;
|
||||
use bevy_ecs::{bundle::Bundle, component::Component, reflect::ReflectComponent};
|
||||
use bevy_reflect::Reflect;
|
||||
use bevy_render::{
|
||||
mesh::Mesh,
|
||||
|
@ -11,7 +12,6 @@ use bevy_render::{
|
|||
view::{InheritedVisibility, ViewVisibility, Visibility, VisibleEntities},
|
||||
};
|
||||
use bevy_transform::components::{GlobalTransform, Transform};
|
||||
use bevy_utils::EntityHashMap;
|
||||
|
||||
/// A component bundle for PBR entities with a [`Mesh`] and a [`StandardMaterial`].
|
||||
pub type PbrBundle = MaterialMeshBundle<StandardMaterial>;
|
||||
|
@ -75,7 +75,7 @@ impl CubemapVisibleEntities {
|
|||
pub struct CascadesVisibleEntities {
|
||||
/// Map of view entity to the visible entities for each cascade frustum.
|
||||
#[reflect(ignore)]
|
||||
pub entities: EntityHashMap<Entity, Vec<VisibleEntities>>,
|
||||
pub entities: EntityHashMap<Vec<VisibleEntities>>,
|
||||
}
|
||||
|
||||
/// A component bundle for [`PointLight`] entities.
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
use std::collections::HashSet;
|
||||
|
||||
use bevy_ecs::entity::EntityHashMap;
|
||||
use bevy_ecs::prelude::*;
|
||||
use bevy_math::{
|
||||
AspectRatio, Mat4, UVec2, UVec3, Vec2, Vec3, Vec3A, Vec3Swizzles, Vec4, Vec4Swizzles,
|
||||
|
@ -16,7 +17,7 @@ use bevy_render::{
|
|||
view::{InheritedVisibility, RenderLayers, ViewVisibility, VisibleEntities},
|
||||
};
|
||||
use bevy_transform::components::{GlobalTransform, Transform};
|
||||
use bevy_utils::{tracing::warn, EntityHashMap};
|
||||
use bevy_utils::tracing::warn;
|
||||
|
||||
use crate::*;
|
||||
|
||||
|
@ -390,7 +391,7 @@ impl From<CascadeShadowConfigBuilder> for CascadeShadowConfig {
|
|||
#[reflect(Component)]
|
||||
pub struct Cascades {
|
||||
/// Map from a view to the configuration of each of its [`Cascade`]s.
|
||||
pub(crate) cascades: EntityHashMap<Entity, Vec<Cascade>>,
|
||||
pub(crate) cascades: EntityHashMap<Vec<Cascade>>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Default, Reflect)]
|
||||
|
|
|
@ -159,6 +159,7 @@ pub struct LightProbesUniform {
|
|||
intensity_for_view: f32,
|
||||
}
|
||||
|
||||
/// A GPU buffer that stores information about all light probes.
|
||||
#[derive(Resource, Default, Deref, DerefMut)]
|
||||
pub struct LightProbesBuffer(DynamicUniformBuffer<LightProbesUniform>);
|
||||
|
||||
|
|
|
@ -30,6 +30,7 @@
|
|||
|
||||
use bevy_app::{App, Plugin};
|
||||
use bevy_asset::{load_internal_asset, AssetId, Handle};
|
||||
use bevy_ecs::entity::EntityHashMap;
|
||||
use bevy_ecs::{
|
||||
component::Component,
|
||||
entity::Entity,
|
||||
|
@ -43,7 +44,7 @@ use bevy_render::{
|
|||
mesh::Mesh, render_asset::RenderAssets, render_resource::Shader, texture::Image,
|
||||
view::ViewVisibility, Extract, ExtractSchedule, RenderApp,
|
||||
};
|
||||
use bevy_utils::{EntityHashMap, HashSet};
|
||||
use bevy_utils::HashSet;
|
||||
|
||||
use crate::RenderMeshInstances;
|
||||
|
||||
|
@ -104,7 +105,7 @@ pub struct RenderLightmaps {
|
|||
///
|
||||
/// Entities without lightmaps, or for which the mesh or lightmap isn't
|
||||
/// loaded, won't have entries in this table.
|
||||
pub(crate) render_lightmaps: EntityHashMap<Entity, RenderLightmap>,
|
||||
pub(crate) render_lightmaps: EntityHashMap<RenderLightmap>,
|
||||
|
||||
/// All active lightmap images in the scene.
|
||||
///
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
use bevy_core_pipeline::core_3d::{Transparent3d, CORE_3D_DEPTH_FORMAT};
|
||||
use bevy_ecs::entity::EntityHashMap;
|
||||
use bevy_ecs::prelude::*;
|
||||
use bevy_math::{Mat4, UVec3, UVec4, Vec2, Vec3, Vec3Swizzles, Vec4, Vec4Swizzles};
|
||||
use bevy_render::{
|
||||
|
@ -21,7 +22,6 @@ use bevy_utils::tracing::info_span;
|
|||
use bevy_utils::{
|
||||
nonmax::NonMaxU32,
|
||||
tracing::{error, warn},
|
||||
EntityHashMap,
|
||||
};
|
||||
use std::{hash::Hash, num::NonZeroU64, ops::Range};
|
||||
|
||||
|
@ -50,8 +50,8 @@ pub struct ExtractedDirectionalLight {
|
|||
shadow_depth_bias: f32,
|
||||
shadow_normal_bias: f32,
|
||||
cascade_shadow_config: CascadeShadowConfig,
|
||||
cascades: EntityHashMap<Entity, Vec<Cascade>>,
|
||||
frusta: EntityHashMap<Entity, Vec<Frustum>>,
|
||||
cascades: EntityHashMap<Vec<Cascade>>,
|
||||
frusta: EntityHashMap<Vec<Frustum>>,
|
||||
render_layers: RenderLayers,
|
||||
}
|
||||
|
||||
|
@ -586,7 +586,7 @@ pub const CLUSTERED_FORWARD_STORAGE_BUFFER_COUNT: u32 = 3;
|
|||
#[derive(Resource)]
|
||||
pub struct GlobalLightMeta {
|
||||
pub gpu_point_lights: GpuPointLights,
|
||||
pub entity_to_index: EntityHashMap<Entity, usize>,
|
||||
pub entity_to_index: EntityHashMap<usize>,
|
||||
}
|
||||
|
||||
impl FromWorld for GlobalLightMeta {
|
||||
|
|
|
@ -10,6 +10,7 @@ use bevy_core_pipeline::{
|
|||
deferred::{AlphaMask3dDeferred, Opaque3dDeferred},
|
||||
};
|
||||
use bevy_derive::{Deref, DerefMut};
|
||||
use bevy_ecs::entity::EntityHashMap;
|
||||
use bevy_ecs::{
|
||||
prelude::*,
|
||||
query::ROQueryItem,
|
||||
|
@ -33,7 +34,7 @@ use bevy_render::{
|
|||
Extract, ExtractSchedule, Render, RenderApp, RenderSet,
|
||||
};
|
||||
use bevy_transform::components::GlobalTransform;
|
||||
use bevy_utils::{tracing::error, EntityHashMap, Entry, HashMap, Hashed};
|
||||
use bevy_utils::{tracing::error, Entry, HashMap, Hashed};
|
||||
use std::cell::Cell;
|
||||
use thread_local::ThreadLocal;
|
||||
|
||||
|
@ -254,7 +255,7 @@ pub struct RenderMeshInstance {
|
|||
}
|
||||
|
||||
#[derive(Default, Resource, Deref, DerefMut)]
|
||||
pub struct RenderMeshInstances(EntityHashMap<Entity, RenderMeshInstance>);
|
||||
pub struct RenderMeshInstances(EntityHashMap<RenderMeshInstance>);
|
||||
|
||||
pub fn extract_meshes(
|
||||
mut render_mesh_instances: ResMut<RenderMeshInstances>,
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
use std::{iter, mem};
|
||||
|
||||
use bevy_derive::{Deref, DerefMut};
|
||||
use bevy_ecs::entity::EntityHashMap;
|
||||
use bevy_ecs::prelude::*;
|
||||
use bevy_render::{
|
||||
batching::NoAutomaticBatching,
|
||||
|
@ -10,7 +11,6 @@ use bevy_render::{
|
|||
view::ViewVisibility,
|
||||
Extract,
|
||||
};
|
||||
use bevy_utils::EntityHashMap;
|
||||
use bytemuck::Pod;
|
||||
|
||||
#[derive(Component)]
|
||||
|
@ -19,7 +19,7 @@ pub struct MorphIndex {
|
|||
}
|
||||
|
||||
#[derive(Default, Resource, Deref, DerefMut)]
|
||||
pub struct MorphIndices(EntityHashMap<Entity, MorphIndex>);
|
||||
pub struct MorphIndices(EntityHashMap<MorphIndex>);
|
||||
|
||||
#[derive(Resource)]
|
||||
pub struct MorphUniform {
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
use bevy_asset::Assets;
|
||||
use bevy_derive::{Deref, DerefMut};
|
||||
use bevy_ecs::entity::EntityHashMap;
|
||||
use bevy_ecs::prelude::*;
|
||||
use bevy_math::Mat4;
|
||||
use bevy_render::{
|
||||
|
@ -11,7 +12,6 @@ use bevy_render::{
|
|||
Extract,
|
||||
};
|
||||
use bevy_transform::prelude::GlobalTransform;
|
||||
use bevy_utils::EntityHashMap;
|
||||
|
||||
/// Maximum number of joints supported for skinned meshes.
|
||||
pub const MAX_JOINTS: usize = 256;
|
||||
|
@ -31,7 +31,7 @@ impl SkinIndex {
|
|||
}
|
||||
|
||||
#[derive(Default, Resource, Deref, DerefMut)]
|
||||
pub struct SkinIndices(EntityHashMap<Entity, SkinIndex>);
|
||||
pub struct SkinIndices(EntityHashMap<SkinIndex>);
|
||||
|
||||
// Notes on implementation: see comment on top of the `extract_skins` system.
|
||||
#[derive(Resource)]
|
||||
|
|
|
@ -80,7 +80,6 @@ impl_reflect_value!(isize(
|
|||
impl_reflect_value!(f32(Debug, PartialEq, Serialize, Deserialize, Default));
|
||||
impl_reflect_value!(f64(Debug, PartialEq, Serialize, Deserialize, Default));
|
||||
impl_type_path!(str);
|
||||
impl_type_path!(::bevy_utils::EntityHash);
|
||||
impl_reflect_value!(::alloc::string::String(
|
||||
Debug,
|
||||
Hash,
|
||||
|
@ -1655,15 +1654,12 @@ mod tests {
|
|||
Enum, FromReflect, Reflect, ReflectSerialize, TypeInfo, TypeRegistry, Typed, VariantInfo,
|
||||
VariantType,
|
||||
};
|
||||
use bevy_utils::HashMap;
|
||||
use bevy_utils::{Duration, Instant};
|
||||
use bevy_utils::{EntityHashMap, HashMap};
|
||||
use static_assertions::assert_impl_all;
|
||||
use std::f32::consts::{PI, TAU};
|
||||
use std::path::Path;
|
||||
|
||||
// EntityHashMap should implement Reflect
|
||||
assert_impl_all!(EntityHashMap<i32, i32>: Reflect);
|
||||
|
||||
#[test]
|
||||
fn can_serialize_duration() {
|
||||
let mut type_registry = TypeRegistry::default();
|
||||
|
|
|
@ -10,11 +10,11 @@ use bevy_app::{App, Plugin};
|
|||
use bevy_asset::{Asset, AssetId, Handle};
|
||||
use bevy_derive::{Deref, DerefMut};
|
||||
use bevy_ecs::{
|
||||
entity::EntityHashMap,
|
||||
prelude::Entity,
|
||||
query::{QueryFilter, QueryItem, ReadOnlyQueryData},
|
||||
system::{lifetimeless::Read, Query, ResMut, Resource},
|
||||
};
|
||||
use bevy_utils::EntityHashMap;
|
||||
|
||||
use crate::{prelude::ViewVisibility, Extract, ExtractSchedule, RenderApp};
|
||||
|
||||
|
@ -53,7 +53,7 @@ where
|
|||
|
||||
/// Stores all extract instances of a type in the render world.
|
||||
#[derive(Resource, Deref, DerefMut)]
|
||||
pub struct ExtractedInstances<EI>(EntityHashMap<Entity, EI>)
|
||||
pub struct ExtractedInstances<EI>(EntityHashMap<EI>)
|
||||
where
|
||||
EI: ExtractInstance;
|
||||
|
||||
|
|
|
@ -1,9 +1,8 @@
|
|||
use std::borrow::Borrow;
|
||||
|
||||
use bevy_ecs::{component::Component, prelude::Entity, reflect::ReflectComponent};
|
||||
use bevy_ecs::{component::Component, entity::EntityHashMap, reflect::ReflectComponent};
|
||||
use bevy_math::{Affine3A, Mat3A, Mat4, Vec3, Vec3A, Vec4, Vec4Swizzles};
|
||||
use bevy_reflect::Reflect;
|
||||
use bevy_utils::EntityHashMap;
|
||||
|
||||
/// An axis-aligned bounding box, defined by:
|
||||
/// - a center,
|
||||
|
@ -323,7 +322,7 @@ impl CubemapFrusta {
|
|||
#[reflect(Component)]
|
||||
pub struct CascadesFrusta {
|
||||
#[reflect(ignore)]
|
||||
pub frusta: EntityHashMap<Entity, Vec<Frustum>>,
|
||||
pub frusta: EntityHashMap<Vec<Frustum>>,
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
|
|
@ -7,8 +7,8 @@ use crate::{
|
|||
Extract, ExtractSchedule, Render, RenderApp, RenderSet,
|
||||
};
|
||||
use bevy_app::{App, Plugin};
|
||||
use bevy_ecs::prelude::*;
|
||||
use bevy_utils::{default, tracing::debug, EntityHashMap, HashSet};
|
||||
use bevy_ecs::{entity::EntityHashMap, prelude::*};
|
||||
use bevy_utils::{default, tracing::debug, HashSet};
|
||||
use bevy_window::{
|
||||
CompositeAlphaMode, PresentMode, PrimaryWindow, RawHandleWrapper, Window, WindowClosed,
|
||||
};
|
||||
|
@ -92,11 +92,11 @@ impl ExtractedWindow {
|
|||
#[derive(Default, Resource)]
|
||||
pub struct ExtractedWindows {
|
||||
pub primary: Option<Entity>,
|
||||
pub windows: EntityHashMap<Entity, ExtractedWindow>,
|
||||
pub windows: EntityHashMap<ExtractedWindow>,
|
||||
}
|
||||
|
||||
impl Deref for ExtractedWindows {
|
||||
type Target = EntityHashMap<Entity, ExtractedWindow>;
|
||||
type Target = EntityHashMap<ExtractedWindow>;
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.windows
|
||||
|
@ -203,7 +203,7 @@ struct SurfaceData {
|
|||
|
||||
#[derive(Resource, Default)]
|
||||
pub struct WindowSurfaces {
|
||||
surfaces: EntityHashMap<Entity, SurfaceData>,
|
||||
surfaces: EntityHashMap<SurfaceData>,
|
||||
/// List of windows that we have already called the initial `configure_surface` for
|
||||
configured_windows: HashSet<Entity>,
|
||||
}
|
||||
|
|
|
@ -2,10 +2,9 @@ use std::{borrow::Cow, path::Path, sync::PoisonError};
|
|||
|
||||
use bevy_app::Plugin;
|
||||
use bevy_asset::{load_internal_asset, Handle};
|
||||
use bevy_ecs::prelude::*;
|
||||
use bevy_ecs::{entity::EntityHashMap, prelude::*};
|
||||
use bevy_log::{error, info, info_span};
|
||||
use bevy_tasks::AsyncComputeTaskPool;
|
||||
use bevy_utils::EntityHashMap;
|
||||
use std::sync::Mutex;
|
||||
use thiserror::Error;
|
||||
use wgpu::{
|
||||
|
@ -33,7 +32,7 @@ pub type ScreenshotFn = Box<dyn FnOnce(Image) + Send + Sync>;
|
|||
#[derive(Resource, Default)]
|
||||
pub struct ScreenshotManager {
|
||||
// this is in a mutex to enable extraction with only an immutable reference
|
||||
pub(crate) callbacks: Mutex<EntityHashMap<Entity, ScreenshotFn>>,
|
||||
pub(crate) callbacks: Mutex<EntityHashMap<ScreenshotFn>>,
|
||||
}
|
||||
|
||||
#[derive(Error, Debug)]
|
||||
|
|
|
@ -1,11 +1,12 @@
|
|||
use crate::{ron, DynamicSceneBuilder, Scene, SceneSpawnError};
|
||||
use bevy_ecs::entity::EntityHashMap;
|
||||
use bevy_ecs::{
|
||||
entity::Entity,
|
||||
reflect::{AppTypeRegistry, ReflectComponent, ReflectMapEntities},
|
||||
world::World,
|
||||
};
|
||||
use bevy_reflect::{Reflect, TypePath, TypeRegistryArc};
|
||||
use bevy_utils::{EntityHashMap, TypeIdMap};
|
||||
use bevy_utils::TypeIdMap;
|
||||
|
||||
#[cfg(feature = "serialize")]
|
||||
use crate::serde::SceneSerializer;
|
||||
|
@ -65,7 +66,7 @@ impl DynamicScene {
|
|||
pub fn write_to_world_with(
|
||||
&self,
|
||||
world: &mut World,
|
||||
entity_map: &mut EntityHashMap<Entity, Entity>,
|
||||
entity_map: &mut EntityHashMap<Entity>,
|
||||
type_registry: &AppTypeRegistry,
|
||||
) -> Result<(), SceneSpawnError> {
|
||||
let type_registry = type_registry.read();
|
||||
|
@ -163,7 +164,7 @@ impl DynamicScene {
|
|||
pub fn write_to_world(
|
||||
&self,
|
||||
world: &mut World,
|
||||
entity_map: &mut EntityHashMap<Entity, Entity>,
|
||||
entity_map: &mut EntityHashMap<Entity>,
|
||||
) -> Result<(), SceneSpawnError> {
|
||||
let registry = world.resource::<AppTypeRegistry>().clone();
|
||||
self.write_to_world_with(world, entity_map, ®istry)
|
||||
|
@ -191,9 +192,9 @@ where
|
|||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use bevy_ecs::entity::EntityHashMap;
|
||||
use bevy_ecs::{reflect::AppTypeRegistry, system::Command, world::World};
|
||||
use bevy_hierarchy::{Parent, PushChild};
|
||||
use bevy_utils::EntityHashMap;
|
||||
|
||||
use crate::dynamic_scene_builder::DynamicSceneBuilder;
|
||||
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
use crate::{DynamicScene, InstanceInfo, SceneSpawnError};
|
||||
use bevy_asset::Asset;
|
||||
use bevy_ecs::entity::EntityHashMap;
|
||||
use bevy_ecs::{
|
||||
reflect::{AppTypeRegistry, ReflectComponent, ReflectMapEntities, ReflectResource},
|
||||
world::World,
|
||||
};
|
||||
use bevy_reflect::TypePath;
|
||||
use bevy_utils::EntityHashMap;
|
||||
|
||||
/// To spawn a scene, you can use either:
|
||||
/// * [`SceneSpawner::spawn`](crate::SceneSpawner::spawn)
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
use crate::{DynamicScene, Scene};
|
||||
use bevy_asset::{AssetEvent, AssetId, Assets, Handle};
|
||||
use bevy_ecs::entity::EntityHashMap;
|
||||
use bevy_ecs::{
|
||||
entity::Entity,
|
||||
event::{Event, Events, ManualEventReader},
|
||||
|
@ -8,7 +9,7 @@ use bevy_ecs::{
|
|||
world::{Mut, World},
|
||||
};
|
||||
use bevy_hierarchy::{Parent, PushChild};
|
||||
use bevy_utils::{tracing::error, EntityHashMap, HashMap, HashSet};
|
||||
use bevy_utils::{tracing::error, HashMap, HashSet};
|
||||
use thiserror::Error;
|
||||
use uuid::Uuid;
|
||||
|
||||
|
@ -25,7 +26,7 @@ pub struct SceneInstanceReady {
|
|||
#[derive(Debug)]
|
||||
pub struct InstanceInfo {
|
||||
/// Mapping of entities from the scene world to the instance world.
|
||||
pub entity_map: EntityHashMap<Entity, Entity>,
|
||||
pub entity_map: EntityHashMap<Entity>,
|
||||
}
|
||||
|
||||
/// Unique id identifying a scene instance.
|
||||
|
@ -213,7 +214,7 @@ impl SceneSpawner {
|
|||
fn spawn_dynamic_internal(
|
||||
world: &mut World,
|
||||
id: AssetId<DynamicScene>,
|
||||
entity_map: &mut EntityHashMap<Entity, Entity>,
|
||||
entity_map: &mut EntityHashMap<Entity>,
|
||||
) -> Result<(), SceneSpawnError> {
|
||||
world.resource_scope(|world, scenes: Mut<Assets<DynamicScene>>| {
|
||||
let scene = scenes
|
||||
|
|
|
@ -499,13 +499,13 @@ mod tests {
|
|||
use crate::ron;
|
||||
use crate::serde::{SceneDeserializer, SceneSerializer};
|
||||
use crate::{DynamicScene, DynamicSceneBuilder};
|
||||
use bevy_ecs::entity::EntityHashMap;
|
||||
use bevy_ecs::entity::{Entity, EntityMapper, MapEntities};
|
||||
use bevy_ecs::prelude::{Component, ReflectComponent, ReflectResource, Resource, World};
|
||||
use bevy_ecs::query::{With, Without};
|
||||
use bevy_ecs::reflect::{AppTypeRegistry, ReflectMapEntities};
|
||||
use bevy_ecs::world::FromWorld;
|
||||
use bevy_reflect::{Reflect, ReflectSerialize};
|
||||
use bevy_utils::EntityHashMap;
|
||||
use bincode::Options;
|
||||
use serde::de::DeserializeSeed;
|
||||
use serde::Serialize;
|
||||
|
|
|
@ -5,6 +5,7 @@ use bevy_core_pipeline::{
|
|||
tonemapping::{DebandDither, Tonemapping},
|
||||
};
|
||||
use bevy_derive::{Deref, DerefMut};
|
||||
use bevy_ecs::entity::EntityHashMap;
|
||||
use bevy_ecs::{
|
||||
prelude::*,
|
||||
system::{lifetimeless::SRes, SystemParamItem},
|
||||
|
@ -29,7 +30,7 @@ use bevy_render::{
|
|||
Extract, ExtractSchedule, Render, RenderApp, RenderSet,
|
||||
};
|
||||
use bevy_transform::components::{GlobalTransform, Transform};
|
||||
use bevy_utils::{EntityHashMap, FloatOrd, HashMap, HashSet};
|
||||
use bevy_utils::{FloatOrd, HashMap, HashSet};
|
||||
use std::hash::Hash;
|
||||
use std::marker::PhantomData;
|
||||
|
||||
|
@ -180,7 +181,7 @@ where
|
|||
}
|
||||
|
||||
#[derive(Resource, Deref, DerefMut)]
|
||||
pub struct RenderMaterial2dInstances<M: Material2d>(EntityHashMap<Entity, AssetId<M>>);
|
||||
pub struct RenderMaterial2dInstances<M: Material2d>(EntityHashMap<AssetId<M>>);
|
||||
|
||||
impl<M: Material2d> Default for RenderMaterial2dInstances<M> {
|
||||
fn default() -> Self {
|
||||
|
|
|
@ -3,6 +3,7 @@ use bevy_asset::{load_internal_asset, AssetId, Handle};
|
|||
|
||||
use bevy_core_pipeline::core_2d::Transparent2d;
|
||||
use bevy_derive::{Deref, DerefMut};
|
||||
use bevy_ecs::entity::EntityHashMap;
|
||||
use bevy_ecs::{
|
||||
prelude::*,
|
||||
query::ROQueryItem,
|
||||
|
@ -30,7 +31,6 @@ use bevy_render::{
|
|||
Extract, ExtractSchedule, Render, RenderApp, RenderSet,
|
||||
};
|
||||
use bevy_transform::components::GlobalTransform;
|
||||
use bevy_utils::EntityHashMap;
|
||||
|
||||
use crate::Material2dBindGroupId;
|
||||
|
||||
|
@ -192,7 +192,7 @@ pub struct RenderMesh2dInstance {
|
|||
}
|
||||
|
||||
#[derive(Default, Resource, Deref, DerefMut)]
|
||||
pub struct RenderMesh2dInstances(EntityHashMap<Entity, RenderMesh2dInstance>);
|
||||
pub struct RenderMesh2dInstances(EntityHashMap<RenderMesh2dInstance>);
|
||||
|
||||
#[derive(Component)]
|
||||
pub struct Mesh2d;
|
||||
|
|
|
@ -9,6 +9,7 @@ use bevy_core_pipeline::{
|
|||
core_2d::Transparent2d,
|
||||
tonemapping::{DebandDither, Tonemapping},
|
||||
};
|
||||
use bevy_ecs::entity::EntityHashMap;
|
||||
use bevy_ecs::{
|
||||
prelude::*,
|
||||
system::{lifetimeless::*, SystemParamItem, SystemState},
|
||||
|
@ -36,7 +37,7 @@ use bevy_render::{
|
|||
Extract,
|
||||
};
|
||||
use bevy_transform::components::GlobalTransform;
|
||||
use bevy_utils::{EntityHashMap, FloatOrd, HashMap};
|
||||
use bevy_utils::{FloatOrd, HashMap};
|
||||
use bytemuck::{Pod, Zeroable};
|
||||
use fixedbitset::FixedBitSet;
|
||||
|
||||
|
@ -312,7 +313,7 @@ pub struct ExtractedSprite {
|
|||
|
||||
#[derive(Resource, Default)]
|
||||
pub struct ExtractedSprites {
|
||||
pub sprites: EntityHashMap<Entity, ExtractedSprite>,
|
||||
pub sprites: EntityHashMap<ExtractedSprite>,
|
||||
}
|
||||
|
||||
#[derive(Resource, Default)]
|
||||
|
|
|
@ -2,6 +2,7 @@ mod convert;
|
|||
pub mod debug;
|
||||
|
||||
use crate::{ContentSize, DefaultUiCamera, Node, Outline, Style, TargetCamera, UiScale};
|
||||
use bevy_ecs::entity::EntityHashMap;
|
||||
use bevy_ecs::{
|
||||
change_detection::{DetectChanges, DetectChangesMut},
|
||||
entity::Entity,
|
||||
|
@ -16,7 +17,7 @@ use bevy_log::warn;
|
|||
use bevy_math::{UVec2, Vec2};
|
||||
use bevy_render::camera::{Camera, NormalizedRenderTarget};
|
||||
use bevy_transform::components::Transform;
|
||||
use bevy_utils::{default, EntityHashMap, HashMap, HashSet};
|
||||
use bevy_utils::{default, HashMap, HashSet};
|
||||
use bevy_window::{PrimaryWindow, Window, WindowScaleFactorChanged};
|
||||
use std::fmt;
|
||||
use taffy::{tree::LayoutTree, Taffy};
|
||||
|
@ -51,14 +52,14 @@ struct RootNodePair {
|
|||
|
||||
#[derive(Resource)]
|
||||
pub struct UiSurface {
|
||||
entity_to_taffy: EntityHashMap<Entity, taffy::node::Node>,
|
||||
camera_roots: EntityHashMap<Entity, Vec<RootNodePair>>,
|
||||
entity_to_taffy: EntityHashMap<taffy::node::Node>,
|
||||
camera_roots: EntityHashMap<Vec<RootNodePair>>,
|
||||
taffy: Taffy,
|
||||
}
|
||||
|
||||
fn _assert_send_sync_ui_surface_impl_safe() {
|
||||
fn _assert_send_sync<T: Send + Sync>() {}
|
||||
_assert_send_sync::<EntityHashMap<Entity, taffy::node::Node>>();
|
||||
_assert_send_sync::<EntityHashMap<taffy::node::Node>>();
|
||||
_assert_send_sync::<Taffy>();
|
||||
_assert_send_sync::<UiSurface>();
|
||||
}
|
||||
|
|
|
@ -23,6 +23,7 @@ use crate::{
|
|||
|
||||
use bevy_app::prelude::*;
|
||||
use bevy_asset::{load_internal_asset, AssetEvent, AssetId, Assets, Handle};
|
||||
use bevy_ecs::entity::EntityHashMap;
|
||||
use bevy_ecs::prelude::*;
|
||||
use bevy_math::{Mat4, Rect, URect, UVec4, Vec2, Vec3, Vec4Swizzles};
|
||||
use bevy_render::{
|
||||
|
@ -41,7 +42,7 @@ use bevy_sprite::TextureAtlasLayout;
|
|||
#[cfg(feature = "bevy_text")]
|
||||
use bevy_text::{PositionedGlyph, Text, TextLayoutInfo};
|
||||
use bevy_transform::components::GlobalTransform;
|
||||
use bevy_utils::{EntityHashMap, FloatOrd, HashMap};
|
||||
use bevy_utils::{FloatOrd, HashMap};
|
||||
use bytemuck::{Pod, Zeroable};
|
||||
use std::ops::Range;
|
||||
|
||||
|
@ -147,7 +148,7 @@ pub struct ExtractedUiNode {
|
|||
|
||||
#[derive(Resource, Default)]
|
||||
pub struct ExtractedUiNodes {
|
||||
pub uinodes: EntityHashMap<Entity, ExtractedUiNode>,
|
||||
pub uinodes: EntityHashMap<ExtractedUiNode>,
|
||||
}
|
||||
|
||||
pub(crate) fn resolve_border_thickness(value: Val, parent_width: f32, viewport_size: Vec2) -> f32 {
|
||||
|
|
|
@ -265,124 +265,6 @@ impl<K: Hash + Eq + PartialEq + Clone, V> PreHashMapExt<K, V> for PreHashMap<K,
|
|||
}
|
||||
}
|
||||
|
||||
/// A [`BuildHasher`] that results in a [`EntityHasher`].
|
||||
#[derive(Default, Clone)]
|
||||
pub struct EntityHash;
|
||||
|
||||
impl BuildHasher for EntityHash {
|
||||
type Hasher = EntityHasher;
|
||||
|
||||
fn build_hasher(&self) -> Self::Hasher {
|
||||
EntityHasher::default()
|
||||
}
|
||||
}
|
||||
|
||||
/// A very fast hash that is only designed to work on generational indices
|
||||
/// like `Entity`. It will panic if attempting to hash a type containing
|
||||
/// non-u64 fields.
|
||||
///
|
||||
/// This is heavily optimized for typical cases, where you have mostly live
|
||||
/// entities, and works particularly well for contiguous indices.
|
||||
///
|
||||
/// If you have an unusual case -- say all your indices are multiples of 256
|
||||
/// or most of the entities are dead generations -- then you might want also to
|
||||
/// try [`AHasher`] for a slower hash computation but fewer lookup conflicts.
|
||||
#[derive(Debug, Default)]
|
||||
pub struct EntityHasher {
|
||||
hash: u64,
|
||||
}
|
||||
|
||||
impl Hasher for EntityHasher {
|
||||
#[inline]
|
||||
fn finish(&self) -> u64 {
|
||||
self.hash
|
||||
}
|
||||
|
||||
fn write(&mut self, _bytes: &[u8]) {
|
||||
panic!("can only hash u64 using EntityHasher");
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn write_u64(&mut self, bits: u64) {
|
||||
// SwissTable (and thus `hashbrown`) cares about two things from the hash:
|
||||
// - H1: low bits (masked by `2ⁿ-1`) to pick the slot in which to store the item
|
||||
// - H2: high 7 bits are used to SIMD optimize hash collision probing
|
||||
// For more see <https://abseil.io/about/design/swisstables#metadata-layout>
|
||||
|
||||
// This hash function assumes that the entity ids are still well-distributed,
|
||||
// so for H1 leaves the entity id alone in the low bits so that id locality
|
||||
// will also give memory locality for things spawned together.
|
||||
// For H2, take advantage of the fact that while multiplication doesn't
|
||||
// spread entropy to the low bits, it's incredibly good at spreading it
|
||||
// upward, which is exactly where we need it the most.
|
||||
|
||||
// While this does include the generation in the output, it doesn't do so
|
||||
// *usefully*. H1 won't care until you have over 3 billion entities in
|
||||
// the table, and H2 won't care until something hits generation 33 million.
|
||||
// Thus the comment suggesting that this is best for live entities,
|
||||
// where there won't be generation conflicts where it would matter.
|
||||
|
||||
// The high 32 bits of this are ⅟φ for Fibonacci hashing. That works
|
||||
// particularly well for hashing for the same reason as described in
|
||||
// <https://extremelearning.com.au/unreasonable-effectiveness-of-quasirandom-sequences/>
|
||||
// It loses no information because it has a modular inverse.
|
||||
// (Specifically, `0x144c_bc89_u32 * 0x9e37_79b9_u32 == 1`.)
|
||||
//
|
||||
// The low 32 bits make that part of the just product a pass-through.
|
||||
const UPPER_PHI: u64 = 0x9e37_79b9_0000_0001;
|
||||
|
||||
// This is `(MAGIC * index + generation) << 32 + index`, in a single instruction.
|
||||
self.hash = bits.wrapping_mul(UPPER_PHI);
|
||||
}
|
||||
}
|
||||
|
||||
/// A [`HashMap`] pre-configured to use [`EntityHash`] hashing.
|
||||
/// Iteration order only depends on the order of insertions and deletions.
|
||||
pub type EntityHashMap<K, V> = hashbrown::HashMap<K, V, EntityHash>;
|
||||
|
||||
/// A [`HashSet`] pre-configured to use [`EntityHash`] hashing.
|
||||
/// Iteration order only depends on the order of insertions and deletions.
|
||||
pub type EntityHashSet<T> = hashbrown::HashSet<T, EntityHash>;
|
||||
|
||||
/// A specialized hashmap type with Key of [`TypeId`]
|
||||
/// Iteration order only depends on the order of insertions and deletions.
|
||||
pub type TypeIdMap<V> = hashbrown::HashMap<TypeId, V, NoOpTypeIdHash>;
|
||||
|
||||
/// [`BuildHasher`] for [`TypeId`]s.
|
||||
#[derive(Default)]
|
||||
pub struct NoOpTypeIdHash;
|
||||
|
||||
impl BuildHasher for NoOpTypeIdHash {
|
||||
type Hasher = NoOpTypeIdHasher;
|
||||
|
||||
fn build_hasher(&self) -> Self::Hasher {
|
||||
NoOpTypeIdHasher(0)
|
||||
}
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
pub struct NoOpTypeIdHasher(u64);
|
||||
|
||||
// TypeId already contains a high-quality hash, so skip re-hashing that hash.
|
||||
impl std::hash::Hasher for NoOpTypeIdHasher {
|
||||
fn finish(&self) -> u64 {
|
||||
self.0
|
||||
}
|
||||
|
||||
fn write(&mut self, bytes: &[u8]) {
|
||||
// This will never be called: TypeId always just calls write_u64 once!
|
||||
// This is a known trick and unlikely to change, but isn't officially guaranteed.
|
||||
// Don't break applications (slower fallback, just check in test):
|
||||
self.0 = bytes.iter().fold(self.0, |hash, b| {
|
||||
hash.rotate_left(8).wrapping_add(*b as u64)
|
||||
});
|
||||
}
|
||||
|
||||
fn write_u64(&mut self, i: u64) {
|
||||
self.0 = i;
|
||||
}
|
||||
}
|
||||
|
||||
/// A type which calls a function when dropped.
|
||||
/// This can be used to ensure that cleanup code is run even in case of a panic.
|
||||
///
|
||||
|
@ -438,6 +320,45 @@ impl<F: FnOnce()> Drop for OnDrop<F> {
|
|||
}
|
||||
}
|
||||
|
||||
/// A specialized hashmap type with Key of [`TypeId`]
|
||||
/// Iteration order only depends on the order of insertions and deletions.
|
||||
pub type TypeIdMap<V> = hashbrown::HashMap<TypeId, V, NoOpTypeIdHash>;
|
||||
|
||||
/// [`BuildHasher`] for [`TypeId`]s.
|
||||
#[derive(Default)]
|
||||
pub struct NoOpTypeIdHash;
|
||||
|
||||
impl BuildHasher for NoOpTypeIdHash {
|
||||
type Hasher = NoOpTypeIdHasher;
|
||||
|
||||
fn build_hasher(&self) -> Self::Hasher {
|
||||
NoOpTypeIdHasher(0)
|
||||
}
|
||||
}
|
||||
#[doc(hidden)]
|
||||
#[derive(Default)]
|
||||
pub struct NoOpTypeIdHasher(pub u64);
|
||||
|
||||
// TypeId already contains a high-quality hash, so skip re-hashing that hash.
|
||||
impl std::hash::Hasher for NoOpTypeIdHasher {
|
||||
fn finish(&self) -> u64 {
|
||||
self.0
|
||||
}
|
||||
|
||||
fn write(&mut self, bytes: &[u8]) {
|
||||
// This will never be called: TypeId always just calls write_u64 once!
|
||||
// This is a known trick and unlikely to change, but isn't officially guaranteed.
|
||||
// Don't break applications (slower fallback, just check in test):
|
||||
self.0 = bytes.iter().fold(self.0, |hash, b| {
|
||||
hash.rotate_left(8).wrapping_add(*b as u64)
|
||||
});
|
||||
}
|
||||
|
||||
fn write_u64(&mut self, i: u64) {
|
||||
self.0 = i;
|
||||
}
|
||||
}
|
||||
|
||||
/// Calls the [`tracing::info!`] macro on a value.
|
||||
pub fn info<T: Debug>(data: T) {
|
||||
tracing::info!("{:?}", data);
|
||||
|
@ -478,7 +399,6 @@ mod tests {
|
|||
use static_assertions::assert_impl_all;
|
||||
|
||||
// Check that the HashMaps are Clone if the key/values are Clone
|
||||
assert_impl_all!(EntityHashMap::<u64, usize>: Clone);
|
||||
assert_impl_all!(PreHashMap::<u64, usize>: Clone);
|
||||
|
||||
#[test]
|
||||
|
|
|
@ -15,6 +15,7 @@ use bevy_a11y::{
|
|||
use bevy_a11y::{ActionRequest as ActionRequestWrapper, ManageAccessibilityUpdates};
|
||||
use bevy_app::{App, Plugin, PostUpdate};
|
||||
use bevy_derive::{Deref, DerefMut};
|
||||
use bevy_ecs::entity::EntityHashMap;
|
||||
use bevy_ecs::{
|
||||
prelude::{DetectChanges, Entity, EventReader, EventWriter},
|
||||
query::With,
|
||||
|
@ -22,16 +23,15 @@ use bevy_ecs::{
|
|||
system::{NonSend, NonSendMut, Query, Res, ResMut, Resource},
|
||||
};
|
||||
use bevy_hierarchy::{Children, Parent};
|
||||
use bevy_utils::EntityHashMap;
|
||||
use bevy_window::{PrimaryWindow, Window, WindowClosed};
|
||||
|
||||
/// Maps window entities to their `AccessKit` [`Adapter`]s.
|
||||
#[derive(Default, Deref, DerefMut)]
|
||||
pub struct AccessKitAdapters(pub EntityHashMap<Entity, Adapter>);
|
||||
pub struct AccessKitAdapters(pub EntityHashMap<Adapter>);
|
||||
|
||||
/// Maps window entities to their respective [`WinitActionHandler`]s.
|
||||
#[derive(Resource, Default, Deref, DerefMut)]
|
||||
pub struct WinitActionHandlers(pub EntityHashMap<Entity, WinitActionHandler>);
|
||||
pub struct WinitActionHandlers(pub EntityHashMap<WinitActionHandler>);
|
||||
|
||||
/// Forwards `AccessKit` [`ActionRequest`]s from winit to an event channel.
|
||||
#[derive(Clone, Default, Deref, DerefMut)]
|
||||
|
|
|
@ -5,7 +5,8 @@ use bevy_a11y::{
|
|||
};
|
||||
use bevy_ecs::entity::Entity;
|
||||
|
||||
use bevy_utils::{tracing::warn, EntityHashMap, HashMap};
|
||||
use bevy_ecs::entity::EntityHashMap;
|
||||
use bevy_utils::{tracing::warn, HashMap};
|
||||
use bevy_window::{CursorGrabMode, Window, WindowMode, WindowPosition, WindowResolution};
|
||||
|
||||
use winit::{
|
||||
|
@ -25,7 +26,7 @@ pub struct WinitWindows {
|
|||
/// Stores [`winit`] windows by window identifier.
|
||||
pub windows: HashMap<winit::window::WindowId, winit::window::Window>,
|
||||
/// Maps entities to `winit` window identifiers.
|
||||
pub entity_to_winit: EntityHashMap<Entity, winit::window::WindowId>,
|
||||
pub entity_to_winit: EntityHashMap<winit::window::WindowId>,
|
||||
/// Maps `winit` window identifiers to entities.
|
||||
pub winit_to_entity: HashMap<winit::window::WindowId, Entity>,
|
||||
// Many `winit` window functions (e.g. `set_window_icon`) can only be called on the main thread.
|
||||
|
|
Loading…
Reference in a new issue