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
@ -63,6 +63,6 @@ path = "benches/bevy_math/bezier.rs"
|
|||||||
harness = false
|
harness = false
|
||||||
|
|
||||||
[[bench]]
|
[[bench]]
|
||||||
name = "utils"
|
name = "entity_hash"
|
||||||
path = "benches/bevy_utils/entity_hash.rs"
|
path = "benches/bevy_ecs/world/entity_hash.rs"
|
||||||
harness = false
|
harness = false
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
use bevy_ecs::entity::Entity;
|
use bevy_ecs::entity::{Entity, EntityHashMap, EntityHashSet};
|
||||||
use bevy_utils::EntityHashSet;
|
|
||||||
use criterion::{criterion_group, criterion_main, BenchmarkId, Criterion, Throughput};
|
use criterion::{criterion_group, criterion_main, BenchmarkId, Criterion, Throughput};
|
||||||
use rand::{Rng, SeedableRng};
|
use rand::{Rng, SeedableRng};
|
||||||
use rand_chacha::ChaCha8Rng;
|
use rand_chacha::ChaCha8Rng;
|
||||||
@ -28,7 +27,7 @@ fn make_entity(rng: &mut impl Rng, size: usize) -> Entity {
|
|||||||
e
|
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");
|
let mut group = c.benchmark_group("entity_hash");
|
||||||
for size in SIZES {
|
for size in SIZES {
|
||||||
// Get some random-but-consistent entities to use for all the benches below.
|
// Get some random-but-consistent entities to use for all the benches below.
|
@ -1,13 +1,17 @@
|
|||||||
use criterion::criterion_group;
|
use criterion::criterion_group;
|
||||||
|
|
||||||
mod commands;
|
mod commands;
|
||||||
mod spawn;
|
|
||||||
mod world_get;
|
|
||||||
|
|
||||||
use commands::*;
|
use commands::*;
|
||||||
|
|
||||||
|
mod spawn;
|
||||||
use spawn::*;
|
use spawn::*;
|
||||||
|
|
||||||
|
mod world_get;
|
||||||
use world_get::*;
|
use world_get::*;
|
||||||
|
|
||||||
|
mod entity_hash;
|
||||||
|
use entity_hash::*;
|
||||||
|
|
||||||
criterion_group!(
|
criterion_group!(
|
||||||
world_benches,
|
world_benches,
|
||||||
empty_commands,
|
empty_commands,
|
||||||
@ -30,4 +34,5 @@ criterion_group!(
|
|||||||
query_get_many::<2>,
|
query_get_many::<2>,
|
||||||
query_get_many::<5>,
|
query_get_many::<5>,
|
||||||
query_get_many::<10>,
|
query_get_many::<10>,
|
||||||
|
entity_set_build_and_lookup
|
||||||
);
|
);
|
||||||
|
@ -32,6 +32,7 @@ thiserror = "1.0"
|
|||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
rand = "0.8"
|
rand = "0.8"
|
||||||
|
static_assertions = "1.1.0"
|
||||||
|
|
||||||
[[example]]
|
[[example]]
|
||||||
name = "events"
|
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},
|
identifier::masks::{IdentifierMask, HIGH_MASK},
|
||||||
world::World,
|
world::World,
|
||||||
};
|
};
|
||||||
use bevy_utils::EntityHashMap;
|
|
||||||
|
use super::EntityHashMap;
|
||||||
|
|
||||||
/// Operation to map all contained [`Entity`] fields in a type to new values.
|
/// 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
|
/// as references in components copied from another world will be invalid. This trait
|
||||||
/// allows defining custom mappings for these references via [`EntityMappers`](EntityMapper), which
|
/// allows defining custom mappings for these references via [`EntityMappers`](EntityMapper), which
|
||||||
/// inject the entity mapping strategy between your `MapEntities` type and the current world
|
/// 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).
|
/// current world).
|
||||||
///
|
///
|
||||||
/// Implementing this trait correctly is required for properly loading components
|
/// 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`].
|
/// 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).
|
/// (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).
|
/// 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_ecs::entity::{Entity, EntityMapper};
|
||||||
/// # use bevy_utils::EntityHashMap;
|
/// # use bevy_ecs::entity::EntityHashMap;
|
||||||
/// #
|
/// #
|
||||||
/// pub struct SimpleEntityMapper {
|
/// 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
|
/// // 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.
|
/// 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
|
/// 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
|
/// or over the network. This is required as [`Entity`] identifiers are opaque; you cannot and do not want to reuse
|
||||||
/// identifiers directly.
|
/// 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()`].
|
/// 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.
|
/// A base [`Entity`] used to allocate new references.
|
||||||
dead_start: Entity,
|
dead_start: Entity,
|
||||||
/// The number of generations this mapper has allocated thus far.
|
/// The number of generations this mapper has allocated thus far.
|
||||||
@ -129,18 +130,18 @@ impl<'m> SceneEntityMapper<'m> {
|
|||||||
self.map_entity(entity)
|
self.map_entity(entity)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Gets a reference to the underlying [`EntityHashMap<Entity, Entity>`].
|
/// Gets a reference to the underlying [`EntityHashMap<Entity>`].
|
||||||
pub fn get_map(&'m self) -> &'m EntityHashMap<Entity, Entity> {
|
pub fn get_map(&'m self) -> &'m EntityHashMap<Entity> {
|
||||||
self.map
|
self.map
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Gets a mutable reference to the underlying [`EntityHashMap<Entity, Entity>`].
|
/// Gets a mutable reference to the underlying [`EntityHashMap<Entity>`].
|
||||||
pub fn get_map_mut(&'m mut self) -> &'m mut EntityHashMap<Entity, Entity> {
|
pub fn get_map_mut(&'m mut self) -> &'m mut EntityHashMap<Entity> {
|
||||||
self.map
|
self.map
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Creates a new [`SceneEntityMapper`], spawning a temporary base [`Entity`] in the provided [`World`]
|
/// 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 {
|
Self {
|
||||||
map,
|
map,
|
||||||
// SAFETY: Entities data is kept in a valid state via `EntityMapper::world_scope`
|
// 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));
|
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
|
/// 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
|
/// 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
|
/// 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
|
/// within the scope of this world. Its return value is then returned from `world_scope` as the generic type
|
||||||
/// parameter `R`.
|
/// parameter `R`.
|
||||||
pub fn world_scope<R>(
|
pub fn world_scope<R>(
|
||||||
entity_map: &'m mut EntityHashMap<Entity, Entity>,
|
entity_map: &'m mut EntityHashMap<Entity>,
|
||||||
world: &mut World,
|
world: &mut World,
|
||||||
f: impl FnOnce(&mut World, &mut Self) -> R,
|
f: impl FnOnce(&mut World, &mut Self) -> R,
|
||||||
) -> R {
|
) -> R {
|
||||||
@ -180,10 +181,8 @@ impl<'m> SceneEntityMapper<'m> {
|
|||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use bevy_utils::EntityHashMap;
|
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
entity::{Entity, EntityMapper, SceneEntityMapper},
|
entity::{Entity, EntityHashMap, EntityMapper, SceneEntityMapper},
|
||||||
world::World,
|
world::World,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -36,9 +36,14 @@
|
|||||||
//! [`EntityWorldMut::insert`]: crate::world::EntityWorldMut::insert
|
//! [`EntityWorldMut::insert`]: crate::world::EntityWorldMut::insert
|
||||||
//! [`EntityWorldMut::remove`]: crate::world::EntityWorldMut::remove
|
//! [`EntityWorldMut::remove`]: crate::world::EntityWorldMut::remove
|
||||||
mod map_entities;
|
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;
|
use bevy_utils::tracing::warn;
|
||||||
pub use map_entities::*;
|
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
archetype::{ArchetypeId, ArchetypeRow},
|
archetype::{ArchetypeId, ArchetypeRow},
|
||||||
@ -123,6 +128,11 @@ type IdCursor = isize;
|
|||||||
/// [`Query::get`]: crate::system::Query::get
|
/// [`Query::get`]: crate::system::Query::get
|
||||||
/// [`World`]: crate::world::World
|
/// [`World`]: crate::world::World
|
||||||
#[derive(Clone, Copy)]
|
#[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
|
// Alignment repr necessary to allow LLVM to better output
|
||||||
// optimised codegen for `to_bits`, `PartialEq` and `Ord`.
|
// optimised codegen for `to_bits`, `PartialEq` and `Ord`.
|
||||||
#[repr(C, align(8))]
|
#[repr(C, align(8))]
|
||||||
@ -218,7 +228,7 @@ impl Entity {
|
|||||||
/// // ... replace the entities with valid ones.
|
/// // ... 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
|
/// ```no_run
|
||||||
/// # use bevy_ecs::{prelude::*, component::*};
|
/// # use bevy_ecs::{prelude::*, component::*};
|
||||||
@ -1092,7 +1102,7 @@ mod tests {
|
|||||||
#[test]
|
#[test]
|
||||||
fn entity_hash_keeps_similar_ids_together() {
|
fn entity_hash_keeps_similar_ids_together() {
|
||||||
use std::hash::BuildHasher;
|
use std::hash::BuildHasher;
|
||||||
let hash = bevy_utils::EntityHash;
|
let hash = EntityHash;
|
||||||
|
|
||||||
let first_id = 0xC0FFEE << 8;
|
let first_id = 0xC0FFEE << 8;
|
||||||
let first_hash = hash.hash_one(Entity::from_raw(first_id));
|
let first_hash = hash.hash_one(Entity::from_raw(first_id));
|
||||||
@ -1107,7 +1117,8 @@ mod tests {
|
|||||||
#[test]
|
#[test]
|
||||||
fn entity_hash_id_bitflip_affects_high_7_bits() {
|
fn entity_hash_id_bitflip_affects_high_7_bits() {
|
||||||
use std::hash::BuildHasher;
|
use std::hash::BuildHasher;
|
||||||
let hash = bevy_utils::EntityHash;
|
|
||||||
|
let hash = EntityHash;
|
||||||
|
|
||||||
let first_id = 0xC0FFEE;
|
let first_id = 0xC0FFEE;
|
||||||
let first_hash = hash.hash_one(Entity::from_raw(first_id)) >> 57;
|
let first_hash = hash.hash_one(Entity::from_raw(first_id)) >> 57;
|
||||||
|
@ -1,10 +1,9 @@
|
|||||||
use crate::{
|
use crate::{
|
||||||
component::Component,
|
component::Component,
|
||||||
entity::{Entity, MapEntities, SceneEntityMapper},
|
entity::{Entity, EntityHashMap, MapEntities, SceneEntityMapper},
|
||||||
world::World,
|
world::World,
|
||||||
};
|
};
|
||||||
use bevy_reflect::FromType;
|
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.
|
/// 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
|
/// 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 {
|
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
|
/// 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
|
/// 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`
|
/// 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.
|
/// components with already valid entity references could be updated to point at something else entirely.
|
||||||
pub fn map_all_entities(
|
pub fn map_all_entities(&self, world: &mut World, entity_map: &mut EntityHashMap<Entity>) {
|
||||||
&self,
|
|
||||||
world: &mut World,
|
|
||||||
entity_map: &mut EntityHashMap<Entity, Entity>,
|
|
||||||
) {
|
|
||||||
SceneEntityMapper::world_scope(entity_map, world, self.map_all_entities);
|
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
|
/// [`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
|
/// 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.
|
/// values. See [`map_all_entities`](Self::map_all_entities) for more details.
|
||||||
pub fn map_entities(
|
pub fn map_entities(
|
||||||
&self,
|
&self,
|
||||||
world: &mut World,
|
world: &mut World,
|
||||||
entity_map: &mut EntityHashMap<Entity, Entity>,
|
entity_map: &mut EntityHashMap<Entity>,
|
||||||
entities: &[Entity],
|
entities: &[Entity],
|
||||||
) {
|
) {
|
||||||
SceneEntityMapper::world_scope(entity_map, world, |world, mapper| {
|
SceneEntityMapper::world_scope(entity_map, world, |world, mapper| {
|
||||||
|
@ -3,8 +3,8 @@
|
|||||||
use std::ops::{Deref, DerefMut};
|
use std::ops::{Deref, DerefMut};
|
||||||
|
|
||||||
use crate as bevy_ecs;
|
use crate as bevy_ecs;
|
||||||
use crate::{entity::Entity, system::Resource};
|
use crate::system::Resource;
|
||||||
use bevy_reflect::{impl_reflect_value, ReflectDeserialize, ReflectSerialize, TypeRegistryArc};
|
use bevy_reflect::TypeRegistryArc;
|
||||||
|
|
||||||
mod bundle;
|
mod bundle;
|
||||||
mod component;
|
mod component;
|
||||||
@ -40,5 +40,3 @@ impl DerefMut for AppTypeRegistry {
|
|||||||
&mut self.0
|
&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::Name;
|
||||||
use bevy_core_pipeline::prelude::Camera3dBundle;
|
use bevy_core_pipeline::prelude::Camera3dBundle;
|
||||||
|
use bevy_ecs::entity::EntityHashMap;
|
||||||
use bevy_ecs::{entity::Entity, world::World};
|
use bevy_ecs::{entity::Entity, world::World};
|
||||||
use bevy_hierarchy::{BuildWorldChildren, WorldChildBuilder};
|
use bevy_hierarchy::{BuildWorldChildren, WorldChildBuilder};
|
||||||
use bevy_log::{error, warn};
|
use bevy_log::{error, warn};
|
||||||
@ -33,7 +34,7 @@ use bevy_scene::Scene;
|
|||||||
#[cfg(not(target_arch = "wasm32"))]
|
#[cfg(not(target_arch = "wasm32"))]
|
||||||
use bevy_tasks::IoTaskPool;
|
use bevy_tasks::IoTaskPool;
|
||||||
use bevy_transform::components::Transform;
|
use bevy_transform::components::Transform;
|
||||||
use bevy_utils::{EntityHashMap, HashMap, HashSet};
|
use bevy_utils::{HashMap, HashSet};
|
||||||
use gltf::{
|
use gltf::{
|
||||||
accessor::Iter,
|
accessor::Iter,
|
||||||
mesh::{util::ReadIndices, Mode},
|
mesh::{util::ReadIndices, Mode},
|
||||||
@ -930,7 +931,7 @@ fn load_node(
|
|||||||
load_context: &mut LoadContext,
|
load_context: &mut LoadContext,
|
||||||
settings: &GltfLoaderSettings,
|
settings: &GltfLoaderSettings,
|
||||||
node_index_to_entity_map: &mut HashMap<usize, Entity>,
|
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,
|
active_camera_found: &mut bool,
|
||||||
parent_transform: &Transform,
|
parent_transform: &Transform,
|
||||||
) -> Result<(), GltfError> {
|
) -> Result<(), GltfError> {
|
||||||
|
@ -3,7 +3,8 @@ use crate::{
|
|||||||
StandardMaterial,
|
StandardMaterial,
|
||||||
};
|
};
|
||||||
use bevy_asset::Handle;
|
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_reflect::Reflect;
|
||||||
use bevy_render::{
|
use bevy_render::{
|
||||||
mesh::Mesh,
|
mesh::Mesh,
|
||||||
@ -11,7 +12,6 @@ use bevy_render::{
|
|||||||
view::{InheritedVisibility, ViewVisibility, Visibility, VisibleEntities},
|
view::{InheritedVisibility, ViewVisibility, Visibility, VisibleEntities},
|
||||||
};
|
};
|
||||||
use bevy_transform::components::{GlobalTransform, Transform};
|
use bevy_transform::components::{GlobalTransform, Transform};
|
||||||
use bevy_utils::EntityHashMap;
|
|
||||||
|
|
||||||
/// A component bundle for PBR entities with a [`Mesh`] and a [`StandardMaterial`].
|
/// A component bundle for PBR entities with a [`Mesh`] and a [`StandardMaterial`].
|
||||||
pub type PbrBundle = MaterialMeshBundle<StandardMaterial>;
|
pub type PbrBundle = MaterialMeshBundle<StandardMaterial>;
|
||||||
@ -75,7 +75,7 @@ impl CubemapVisibleEntities {
|
|||||||
pub struct CascadesVisibleEntities {
|
pub struct CascadesVisibleEntities {
|
||||||
/// Map of view entity to the visible entities for each cascade frustum.
|
/// Map of view entity to the visible entities for each cascade frustum.
|
||||||
#[reflect(ignore)]
|
#[reflect(ignore)]
|
||||||
pub entities: EntityHashMap<Entity, Vec<VisibleEntities>>,
|
pub entities: EntityHashMap<Vec<VisibleEntities>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A component bundle for [`PointLight`] entities.
|
/// A component bundle for [`PointLight`] entities.
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
use std::collections::HashSet;
|
use std::collections::HashSet;
|
||||||
|
|
||||||
|
use bevy_ecs::entity::EntityHashMap;
|
||||||
use bevy_ecs::prelude::*;
|
use bevy_ecs::prelude::*;
|
||||||
use bevy_math::{
|
use bevy_math::{
|
||||||
AspectRatio, Mat4, UVec2, UVec3, Vec2, Vec3, Vec3A, Vec3Swizzles, Vec4, Vec4Swizzles,
|
AspectRatio, Mat4, UVec2, UVec3, Vec2, Vec3, Vec3A, Vec3Swizzles, Vec4, Vec4Swizzles,
|
||||||
@ -16,7 +17,7 @@ use bevy_render::{
|
|||||||
view::{InheritedVisibility, RenderLayers, ViewVisibility, VisibleEntities},
|
view::{InheritedVisibility, RenderLayers, ViewVisibility, VisibleEntities},
|
||||||
};
|
};
|
||||||
use bevy_transform::components::{GlobalTransform, Transform};
|
use bevy_transform::components::{GlobalTransform, Transform};
|
||||||
use bevy_utils::{tracing::warn, EntityHashMap};
|
use bevy_utils::tracing::warn;
|
||||||
|
|
||||||
use crate::*;
|
use crate::*;
|
||||||
|
|
||||||
@ -390,7 +391,7 @@ impl From<CascadeShadowConfigBuilder> for CascadeShadowConfig {
|
|||||||
#[reflect(Component)]
|
#[reflect(Component)]
|
||||||
pub struct Cascades {
|
pub struct Cascades {
|
||||||
/// Map from a view to the configuration of each of its [`Cascade`]s.
|
/// 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)]
|
#[derive(Clone, Debug, Default, Reflect)]
|
||||||
|
@ -159,6 +159,7 @@ pub struct LightProbesUniform {
|
|||||||
intensity_for_view: f32,
|
intensity_for_view: f32,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// A GPU buffer that stores information about all light probes.
|
||||||
#[derive(Resource, Default, Deref, DerefMut)]
|
#[derive(Resource, Default, Deref, DerefMut)]
|
||||||
pub struct LightProbesBuffer(DynamicUniformBuffer<LightProbesUniform>);
|
pub struct LightProbesBuffer(DynamicUniformBuffer<LightProbesUniform>);
|
||||||
|
|
||||||
|
@ -30,6 +30,7 @@
|
|||||||
|
|
||||||
use bevy_app::{App, Plugin};
|
use bevy_app::{App, Plugin};
|
||||||
use bevy_asset::{load_internal_asset, AssetId, Handle};
|
use bevy_asset::{load_internal_asset, AssetId, Handle};
|
||||||
|
use bevy_ecs::entity::EntityHashMap;
|
||||||
use bevy_ecs::{
|
use bevy_ecs::{
|
||||||
component::Component,
|
component::Component,
|
||||||
entity::Entity,
|
entity::Entity,
|
||||||
@ -43,7 +44,7 @@ use bevy_render::{
|
|||||||
mesh::Mesh, render_asset::RenderAssets, render_resource::Shader, texture::Image,
|
mesh::Mesh, render_asset::RenderAssets, render_resource::Shader, texture::Image,
|
||||||
view::ViewVisibility, Extract, ExtractSchedule, RenderApp,
|
view::ViewVisibility, Extract, ExtractSchedule, RenderApp,
|
||||||
};
|
};
|
||||||
use bevy_utils::{EntityHashMap, HashSet};
|
use bevy_utils::HashSet;
|
||||||
|
|
||||||
use crate::RenderMeshInstances;
|
use crate::RenderMeshInstances;
|
||||||
|
|
||||||
@ -104,7 +105,7 @@ pub struct RenderLightmaps {
|
|||||||
///
|
///
|
||||||
/// Entities without lightmaps, or for which the mesh or lightmap isn't
|
/// Entities without lightmaps, or for which the mesh or lightmap isn't
|
||||||
/// loaded, won't have entries in this table.
|
/// 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.
|
/// All active lightmap images in the scene.
|
||||||
///
|
///
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
use bevy_core_pipeline::core_3d::{Transparent3d, CORE_3D_DEPTH_FORMAT};
|
use bevy_core_pipeline::core_3d::{Transparent3d, CORE_3D_DEPTH_FORMAT};
|
||||||
|
use bevy_ecs::entity::EntityHashMap;
|
||||||
use bevy_ecs::prelude::*;
|
use bevy_ecs::prelude::*;
|
||||||
use bevy_math::{Mat4, UVec3, UVec4, Vec2, Vec3, Vec3Swizzles, Vec4, Vec4Swizzles};
|
use bevy_math::{Mat4, UVec3, UVec4, Vec2, Vec3, Vec3Swizzles, Vec4, Vec4Swizzles};
|
||||||
use bevy_render::{
|
use bevy_render::{
|
||||||
@ -21,7 +22,6 @@ use bevy_utils::tracing::info_span;
|
|||||||
use bevy_utils::{
|
use bevy_utils::{
|
||||||
nonmax::NonMaxU32,
|
nonmax::NonMaxU32,
|
||||||
tracing::{error, warn},
|
tracing::{error, warn},
|
||||||
EntityHashMap,
|
|
||||||
};
|
};
|
||||||
use std::{hash::Hash, num::NonZeroU64, ops::Range};
|
use std::{hash::Hash, num::NonZeroU64, ops::Range};
|
||||||
|
|
||||||
@ -50,8 +50,8 @@ pub struct ExtractedDirectionalLight {
|
|||||||
shadow_depth_bias: f32,
|
shadow_depth_bias: f32,
|
||||||
shadow_normal_bias: f32,
|
shadow_normal_bias: f32,
|
||||||
cascade_shadow_config: CascadeShadowConfig,
|
cascade_shadow_config: CascadeShadowConfig,
|
||||||
cascades: EntityHashMap<Entity, Vec<Cascade>>,
|
cascades: EntityHashMap<Vec<Cascade>>,
|
||||||
frusta: EntityHashMap<Entity, Vec<Frustum>>,
|
frusta: EntityHashMap<Vec<Frustum>>,
|
||||||
render_layers: RenderLayers,
|
render_layers: RenderLayers,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -586,7 +586,7 @@ pub const CLUSTERED_FORWARD_STORAGE_BUFFER_COUNT: u32 = 3;
|
|||||||
#[derive(Resource)]
|
#[derive(Resource)]
|
||||||
pub struct GlobalLightMeta {
|
pub struct GlobalLightMeta {
|
||||||
pub gpu_point_lights: GpuPointLights,
|
pub gpu_point_lights: GpuPointLights,
|
||||||
pub entity_to_index: EntityHashMap<Entity, usize>,
|
pub entity_to_index: EntityHashMap<usize>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FromWorld for GlobalLightMeta {
|
impl FromWorld for GlobalLightMeta {
|
||||||
|
@ -10,6 +10,7 @@ use bevy_core_pipeline::{
|
|||||||
deferred::{AlphaMask3dDeferred, Opaque3dDeferred},
|
deferred::{AlphaMask3dDeferred, Opaque3dDeferred},
|
||||||
};
|
};
|
||||||
use bevy_derive::{Deref, DerefMut};
|
use bevy_derive::{Deref, DerefMut};
|
||||||
|
use bevy_ecs::entity::EntityHashMap;
|
||||||
use bevy_ecs::{
|
use bevy_ecs::{
|
||||||
prelude::*,
|
prelude::*,
|
||||||
query::ROQueryItem,
|
query::ROQueryItem,
|
||||||
@ -33,7 +34,7 @@ use bevy_render::{
|
|||||||
Extract, ExtractSchedule, Render, RenderApp, RenderSet,
|
Extract, ExtractSchedule, Render, RenderApp, RenderSet,
|
||||||
};
|
};
|
||||||
use bevy_transform::components::GlobalTransform;
|
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 std::cell::Cell;
|
||||||
use thread_local::ThreadLocal;
|
use thread_local::ThreadLocal;
|
||||||
|
|
||||||
@ -254,7 +255,7 @@ pub struct RenderMeshInstance {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Default, Resource, Deref, DerefMut)]
|
#[derive(Default, Resource, Deref, DerefMut)]
|
||||||
pub struct RenderMeshInstances(EntityHashMap<Entity, RenderMeshInstance>);
|
pub struct RenderMeshInstances(EntityHashMap<RenderMeshInstance>);
|
||||||
|
|
||||||
pub fn extract_meshes(
|
pub fn extract_meshes(
|
||||||
mut render_mesh_instances: ResMut<RenderMeshInstances>,
|
mut render_mesh_instances: ResMut<RenderMeshInstances>,
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
use std::{iter, mem};
|
use std::{iter, mem};
|
||||||
|
|
||||||
use bevy_derive::{Deref, DerefMut};
|
use bevy_derive::{Deref, DerefMut};
|
||||||
|
use bevy_ecs::entity::EntityHashMap;
|
||||||
use bevy_ecs::prelude::*;
|
use bevy_ecs::prelude::*;
|
||||||
use bevy_render::{
|
use bevy_render::{
|
||||||
batching::NoAutomaticBatching,
|
batching::NoAutomaticBatching,
|
||||||
@ -10,7 +11,6 @@ use bevy_render::{
|
|||||||
view::ViewVisibility,
|
view::ViewVisibility,
|
||||||
Extract,
|
Extract,
|
||||||
};
|
};
|
||||||
use bevy_utils::EntityHashMap;
|
|
||||||
use bytemuck::Pod;
|
use bytemuck::Pod;
|
||||||
|
|
||||||
#[derive(Component)]
|
#[derive(Component)]
|
||||||
@ -19,7 +19,7 @@ pub struct MorphIndex {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Default, Resource, Deref, DerefMut)]
|
#[derive(Default, Resource, Deref, DerefMut)]
|
||||||
pub struct MorphIndices(EntityHashMap<Entity, MorphIndex>);
|
pub struct MorphIndices(EntityHashMap<MorphIndex>);
|
||||||
|
|
||||||
#[derive(Resource)]
|
#[derive(Resource)]
|
||||||
pub struct MorphUniform {
|
pub struct MorphUniform {
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
use bevy_asset::Assets;
|
use bevy_asset::Assets;
|
||||||
use bevy_derive::{Deref, DerefMut};
|
use bevy_derive::{Deref, DerefMut};
|
||||||
|
use bevy_ecs::entity::EntityHashMap;
|
||||||
use bevy_ecs::prelude::*;
|
use bevy_ecs::prelude::*;
|
||||||
use bevy_math::Mat4;
|
use bevy_math::Mat4;
|
||||||
use bevy_render::{
|
use bevy_render::{
|
||||||
@ -11,7 +12,6 @@ use bevy_render::{
|
|||||||
Extract,
|
Extract,
|
||||||
};
|
};
|
||||||
use bevy_transform::prelude::GlobalTransform;
|
use bevy_transform::prelude::GlobalTransform;
|
||||||
use bevy_utils::EntityHashMap;
|
|
||||||
|
|
||||||
/// Maximum number of joints supported for skinned meshes.
|
/// Maximum number of joints supported for skinned meshes.
|
||||||
pub const MAX_JOINTS: usize = 256;
|
pub const MAX_JOINTS: usize = 256;
|
||||||
@ -31,7 +31,7 @@ impl SkinIndex {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Default, Resource, Deref, DerefMut)]
|
#[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.
|
// Notes on implementation: see comment on top of the `extract_skins` system.
|
||||||
#[derive(Resource)]
|
#[derive(Resource)]
|
||||||
|
@ -80,7 +80,6 @@ impl_reflect_value!(isize(
|
|||||||
impl_reflect_value!(f32(Debug, PartialEq, Serialize, Deserialize, Default));
|
impl_reflect_value!(f32(Debug, PartialEq, Serialize, Deserialize, Default));
|
||||||
impl_reflect_value!(f64(Debug, PartialEq, Serialize, Deserialize, Default));
|
impl_reflect_value!(f64(Debug, PartialEq, Serialize, Deserialize, Default));
|
||||||
impl_type_path!(str);
|
impl_type_path!(str);
|
||||||
impl_type_path!(::bevy_utils::EntityHash);
|
|
||||||
impl_reflect_value!(::alloc::string::String(
|
impl_reflect_value!(::alloc::string::String(
|
||||||
Debug,
|
Debug,
|
||||||
Hash,
|
Hash,
|
||||||
@ -1655,15 +1654,12 @@ mod tests {
|
|||||||
Enum, FromReflect, Reflect, ReflectSerialize, TypeInfo, TypeRegistry, Typed, VariantInfo,
|
Enum, FromReflect, Reflect, ReflectSerialize, TypeInfo, TypeRegistry, Typed, VariantInfo,
|
||||||
VariantType,
|
VariantType,
|
||||||
};
|
};
|
||||||
|
use bevy_utils::HashMap;
|
||||||
use bevy_utils::{Duration, Instant};
|
use bevy_utils::{Duration, Instant};
|
||||||
use bevy_utils::{EntityHashMap, HashMap};
|
|
||||||
use static_assertions::assert_impl_all;
|
use static_assertions::assert_impl_all;
|
||||||
use std::f32::consts::{PI, TAU};
|
use std::f32::consts::{PI, TAU};
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
|
|
||||||
// EntityHashMap should implement Reflect
|
|
||||||
assert_impl_all!(EntityHashMap<i32, i32>: Reflect);
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn can_serialize_duration() {
|
fn can_serialize_duration() {
|
||||||
let mut type_registry = TypeRegistry::default();
|
let mut type_registry = TypeRegistry::default();
|
||||||
|
@ -10,11 +10,11 @@ use bevy_app::{App, Plugin};
|
|||||||
use bevy_asset::{Asset, AssetId, Handle};
|
use bevy_asset::{Asset, AssetId, Handle};
|
||||||
use bevy_derive::{Deref, DerefMut};
|
use bevy_derive::{Deref, DerefMut};
|
||||||
use bevy_ecs::{
|
use bevy_ecs::{
|
||||||
|
entity::EntityHashMap,
|
||||||
prelude::Entity,
|
prelude::Entity,
|
||||||
query::{QueryFilter, QueryItem, ReadOnlyQueryData},
|
query::{QueryFilter, QueryItem, ReadOnlyQueryData},
|
||||||
system::{lifetimeless::Read, Query, ResMut, Resource},
|
system::{lifetimeless::Read, Query, ResMut, Resource},
|
||||||
};
|
};
|
||||||
use bevy_utils::EntityHashMap;
|
|
||||||
|
|
||||||
use crate::{prelude::ViewVisibility, Extract, ExtractSchedule, RenderApp};
|
use crate::{prelude::ViewVisibility, Extract, ExtractSchedule, RenderApp};
|
||||||
|
|
||||||
@ -53,7 +53,7 @@ where
|
|||||||
|
|
||||||
/// Stores all extract instances of a type in the render world.
|
/// Stores all extract instances of a type in the render world.
|
||||||
#[derive(Resource, Deref, DerefMut)]
|
#[derive(Resource, Deref, DerefMut)]
|
||||||
pub struct ExtractedInstances<EI>(EntityHashMap<Entity, EI>)
|
pub struct ExtractedInstances<EI>(EntityHashMap<EI>)
|
||||||
where
|
where
|
||||||
EI: ExtractInstance;
|
EI: ExtractInstance;
|
||||||
|
|
||||||
|
@ -1,9 +1,8 @@
|
|||||||
use std::borrow::Borrow;
|
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_math::{Affine3A, Mat3A, Mat4, Vec3, Vec3A, Vec4, Vec4Swizzles};
|
||||||
use bevy_reflect::Reflect;
|
use bevy_reflect::Reflect;
|
||||||
use bevy_utils::EntityHashMap;
|
|
||||||
|
|
||||||
/// An axis-aligned bounding box, defined by:
|
/// An axis-aligned bounding box, defined by:
|
||||||
/// - a center,
|
/// - a center,
|
||||||
@ -323,7 +322,7 @@ impl CubemapFrusta {
|
|||||||
#[reflect(Component)]
|
#[reflect(Component)]
|
||||||
pub struct CascadesFrusta {
|
pub struct CascadesFrusta {
|
||||||
#[reflect(ignore)]
|
#[reflect(ignore)]
|
||||||
pub frusta: EntityHashMap<Entity, Vec<Frustum>>,
|
pub frusta: EntityHashMap<Vec<Frustum>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
|
@ -7,8 +7,8 @@ use crate::{
|
|||||||
Extract, ExtractSchedule, Render, RenderApp, RenderSet,
|
Extract, ExtractSchedule, Render, RenderApp, RenderSet,
|
||||||
};
|
};
|
||||||
use bevy_app::{App, Plugin};
|
use bevy_app::{App, Plugin};
|
||||||
use bevy_ecs::prelude::*;
|
use bevy_ecs::{entity::EntityHashMap, prelude::*};
|
||||||
use bevy_utils::{default, tracing::debug, EntityHashMap, HashSet};
|
use bevy_utils::{default, tracing::debug, HashSet};
|
||||||
use bevy_window::{
|
use bevy_window::{
|
||||||
CompositeAlphaMode, PresentMode, PrimaryWindow, RawHandleWrapper, Window, WindowClosed,
|
CompositeAlphaMode, PresentMode, PrimaryWindow, RawHandleWrapper, Window, WindowClosed,
|
||||||
};
|
};
|
||||||
@ -92,11 +92,11 @@ impl ExtractedWindow {
|
|||||||
#[derive(Default, Resource)]
|
#[derive(Default, Resource)]
|
||||||
pub struct ExtractedWindows {
|
pub struct ExtractedWindows {
|
||||||
pub primary: Option<Entity>,
|
pub primary: Option<Entity>,
|
||||||
pub windows: EntityHashMap<Entity, ExtractedWindow>,
|
pub windows: EntityHashMap<ExtractedWindow>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Deref for ExtractedWindows {
|
impl Deref for ExtractedWindows {
|
||||||
type Target = EntityHashMap<Entity, ExtractedWindow>;
|
type Target = EntityHashMap<ExtractedWindow>;
|
||||||
|
|
||||||
fn deref(&self) -> &Self::Target {
|
fn deref(&self) -> &Self::Target {
|
||||||
&self.windows
|
&self.windows
|
||||||
@ -203,7 +203,7 @@ struct SurfaceData {
|
|||||||
|
|
||||||
#[derive(Resource, Default)]
|
#[derive(Resource, Default)]
|
||||||
pub struct WindowSurfaces {
|
pub struct WindowSurfaces {
|
||||||
surfaces: EntityHashMap<Entity, SurfaceData>,
|
surfaces: EntityHashMap<SurfaceData>,
|
||||||
/// List of windows that we have already called the initial `configure_surface` for
|
/// List of windows that we have already called the initial `configure_surface` for
|
||||||
configured_windows: HashSet<Entity>,
|
configured_windows: HashSet<Entity>,
|
||||||
}
|
}
|
||||||
|
@ -2,10 +2,9 @@ use std::{borrow::Cow, path::Path, sync::PoisonError};
|
|||||||
|
|
||||||
use bevy_app::Plugin;
|
use bevy_app::Plugin;
|
||||||
use bevy_asset::{load_internal_asset, Handle};
|
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_log::{error, info, info_span};
|
||||||
use bevy_tasks::AsyncComputeTaskPool;
|
use bevy_tasks::AsyncComputeTaskPool;
|
||||||
use bevy_utils::EntityHashMap;
|
|
||||||
use std::sync::Mutex;
|
use std::sync::Mutex;
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
use wgpu::{
|
use wgpu::{
|
||||||
@ -33,7 +32,7 @@ pub type ScreenshotFn = Box<dyn FnOnce(Image) + Send + Sync>;
|
|||||||
#[derive(Resource, Default)]
|
#[derive(Resource, Default)]
|
||||||
pub struct ScreenshotManager {
|
pub struct ScreenshotManager {
|
||||||
// this is in a mutex to enable extraction with only an immutable reference
|
// 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)]
|
#[derive(Error, Debug)]
|
||||||
|
@ -1,11 +1,12 @@
|
|||||||
use crate::{ron, DynamicSceneBuilder, Scene, SceneSpawnError};
|
use crate::{ron, DynamicSceneBuilder, Scene, SceneSpawnError};
|
||||||
|
use bevy_ecs::entity::EntityHashMap;
|
||||||
use bevy_ecs::{
|
use bevy_ecs::{
|
||||||
entity::Entity,
|
entity::Entity,
|
||||||
reflect::{AppTypeRegistry, ReflectComponent, ReflectMapEntities},
|
reflect::{AppTypeRegistry, ReflectComponent, ReflectMapEntities},
|
||||||
world::World,
|
world::World,
|
||||||
};
|
};
|
||||||
use bevy_reflect::{Reflect, TypePath, TypeRegistryArc};
|
use bevy_reflect::{Reflect, TypePath, TypeRegistryArc};
|
||||||
use bevy_utils::{EntityHashMap, TypeIdMap};
|
use bevy_utils::TypeIdMap;
|
||||||
|
|
||||||
#[cfg(feature = "serialize")]
|
#[cfg(feature = "serialize")]
|
||||||
use crate::serde::SceneSerializer;
|
use crate::serde::SceneSerializer;
|
||||||
@ -65,7 +66,7 @@ impl DynamicScene {
|
|||||||
pub fn write_to_world_with(
|
pub fn write_to_world_with(
|
||||||
&self,
|
&self,
|
||||||
world: &mut World,
|
world: &mut World,
|
||||||
entity_map: &mut EntityHashMap<Entity, Entity>,
|
entity_map: &mut EntityHashMap<Entity>,
|
||||||
type_registry: &AppTypeRegistry,
|
type_registry: &AppTypeRegistry,
|
||||||
) -> Result<(), SceneSpawnError> {
|
) -> Result<(), SceneSpawnError> {
|
||||||
let type_registry = type_registry.read();
|
let type_registry = type_registry.read();
|
||||||
@ -163,7 +164,7 @@ impl DynamicScene {
|
|||||||
pub fn write_to_world(
|
pub fn write_to_world(
|
||||||
&self,
|
&self,
|
||||||
world: &mut World,
|
world: &mut World,
|
||||||
entity_map: &mut EntityHashMap<Entity, Entity>,
|
entity_map: &mut EntityHashMap<Entity>,
|
||||||
) -> Result<(), SceneSpawnError> {
|
) -> Result<(), SceneSpawnError> {
|
||||||
let registry = world.resource::<AppTypeRegistry>().clone();
|
let registry = world.resource::<AppTypeRegistry>().clone();
|
||||||
self.write_to_world_with(world, entity_map, ®istry)
|
self.write_to_world_with(world, entity_map, ®istry)
|
||||||
@ -191,9 +192,9 @@ where
|
|||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
|
use bevy_ecs::entity::EntityHashMap;
|
||||||
use bevy_ecs::{reflect::AppTypeRegistry, system::Command, world::World};
|
use bevy_ecs::{reflect::AppTypeRegistry, system::Command, world::World};
|
||||||
use bevy_hierarchy::{Parent, PushChild};
|
use bevy_hierarchy::{Parent, PushChild};
|
||||||
use bevy_utils::EntityHashMap;
|
|
||||||
|
|
||||||
use crate::dynamic_scene_builder::DynamicSceneBuilder;
|
use crate::dynamic_scene_builder::DynamicSceneBuilder;
|
||||||
|
|
||||||
|
@ -1,11 +1,11 @@
|
|||||||
use crate::{DynamicScene, InstanceInfo, SceneSpawnError};
|
use crate::{DynamicScene, InstanceInfo, SceneSpawnError};
|
||||||
use bevy_asset::Asset;
|
use bevy_asset::Asset;
|
||||||
|
use bevy_ecs::entity::EntityHashMap;
|
||||||
use bevy_ecs::{
|
use bevy_ecs::{
|
||||||
reflect::{AppTypeRegistry, ReflectComponent, ReflectMapEntities, ReflectResource},
|
reflect::{AppTypeRegistry, ReflectComponent, ReflectMapEntities, ReflectResource},
|
||||||
world::World,
|
world::World,
|
||||||
};
|
};
|
||||||
use bevy_reflect::TypePath;
|
use bevy_reflect::TypePath;
|
||||||
use bevy_utils::EntityHashMap;
|
|
||||||
|
|
||||||
/// To spawn a scene, you can use either:
|
/// To spawn a scene, you can use either:
|
||||||
/// * [`SceneSpawner::spawn`](crate::SceneSpawner::spawn)
|
/// * [`SceneSpawner::spawn`](crate::SceneSpawner::spawn)
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
use crate::{DynamicScene, Scene};
|
use crate::{DynamicScene, Scene};
|
||||||
use bevy_asset::{AssetEvent, AssetId, Assets, Handle};
|
use bevy_asset::{AssetEvent, AssetId, Assets, Handle};
|
||||||
|
use bevy_ecs::entity::EntityHashMap;
|
||||||
use bevy_ecs::{
|
use bevy_ecs::{
|
||||||
entity::Entity,
|
entity::Entity,
|
||||||
event::{Event, Events, ManualEventReader},
|
event::{Event, Events, ManualEventReader},
|
||||||
@ -8,7 +9,7 @@ use bevy_ecs::{
|
|||||||
world::{Mut, World},
|
world::{Mut, World},
|
||||||
};
|
};
|
||||||
use bevy_hierarchy::{Parent, PushChild};
|
use bevy_hierarchy::{Parent, PushChild};
|
||||||
use bevy_utils::{tracing::error, EntityHashMap, HashMap, HashSet};
|
use bevy_utils::{tracing::error, HashMap, HashSet};
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
use uuid::Uuid;
|
use uuid::Uuid;
|
||||||
|
|
||||||
@ -25,7 +26,7 @@ pub struct SceneInstanceReady {
|
|||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct InstanceInfo {
|
pub struct InstanceInfo {
|
||||||
/// Mapping of entities from the scene world to the instance world.
|
/// 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.
|
/// Unique id identifying a scene instance.
|
||||||
@ -213,7 +214,7 @@ impl SceneSpawner {
|
|||||||
fn spawn_dynamic_internal(
|
fn spawn_dynamic_internal(
|
||||||
world: &mut World,
|
world: &mut World,
|
||||||
id: AssetId<DynamicScene>,
|
id: AssetId<DynamicScene>,
|
||||||
entity_map: &mut EntityHashMap<Entity, Entity>,
|
entity_map: &mut EntityHashMap<Entity>,
|
||||||
) -> Result<(), SceneSpawnError> {
|
) -> Result<(), SceneSpawnError> {
|
||||||
world.resource_scope(|world, scenes: Mut<Assets<DynamicScene>>| {
|
world.resource_scope(|world, scenes: Mut<Assets<DynamicScene>>| {
|
||||||
let scene = scenes
|
let scene = scenes
|
||||||
|
@ -499,13 +499,13 @@ mod tests {
|
|||||||
use crate::ron;
|
use crate::ron;
|
||||||
use crate::serde::{SceneDeserializer, SceneSerializer};
|
use crate::serde::{SceneDeserializer, SceneSerializer};
|
||||||
use crate::{DynamicScene, DynamicSceneBuilder};
|
use crate::{DynamicScene, DynamicSceneBuilder};
|
||||||
|
use bevy_ecs::entity::EntityHashMap;
|
||||||
use bevy_ecs::entity::{Entity, EntityMapper, MapEntities};
|
use bevy_ecs::entity::{Entity, EntityMapper, MapEntities};
|
||||||
use bevy_ecs::prelude::{Component, ReflectComponent, ReflectResource, Resource, World};
|
use bevy_ecs::prelude::{Component, ReflectComponent, ReflectResource, Resource, World};
|
||||||
use bevy_ecs::query::{With, Without};
|
use bevy_ecs::query::{With, Without};
|
||||||
use bevy_ecs::reflect::{AppTypeRegistry, ReflectMapEntities};
|
use bevy_ecs::reflect::{AppTypeRegistry, ReflectMapEntities};
|
||||||
use bevy_ecs::world::FromWorld;
|
use bevy_ecs::world::FromWorld;
|
||||||
use bevy_reflect::{Reflect, ReflectSerialize};
|
use bevy_reflect::{Reflect, ReflectSerialize};
|
||||||
use bevy_utils::EntityHashMap;
|
|
||||||
use bincode::Options;
|
use bincode::Options;
|
||||||
use serde::de::DeserializeSeed;
|
use serde::de::DeserializeSeed;
|
||||||
use serde::Serialize;
|
use serde::Serialize;
|
||||||
|
@ -5,6 +5,7 @@ use bevy_core_pipeline::{
|
|||||||
tonemapping::{DebandDither, Tonemapping},
|
tonemapping::{DebandDither, Tonemapping},
|
||||||
};
|
};
|
||||||
use bevy_derive::{Deref, DerefMut};
|
use bevy_derive::{Deref, DerefMut};
|
||||||
|
use bevy_ecs::entity::EntityHashMap;
|
||||||
use bevy_ecs::{
|
use bevy_ecs::{
|
||||||
prelude::*,
|
prelude::*,
|
||||||
system::{lifetimeless::SRes, SystemParamItem},
|
system::{lifetimeless::SRes, SystemParamItem},
|
||||||
@ -29,7 +30,7 @@ use bevy_render::{
|
|||||||
Extract, ExtractSchedule, Render, RenderApp, RenderSet,
|
Extract, ExtractSchedule, Render, RenderApp, RenderSet,
|
||||||
};
|
};
|
||||||
use bevy_transform::components::{GlobalTransform, Transform};
|
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::hash::Hash;
|
||||||
use std::marker::PhantomData;
|
use std::marker::PhantomData;
|
||||||
|
|
||||||
@ -180,7 +181,7 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Resource, Deref, DerefMut)]
|
#[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> {
|
impl<M: Material2d> Default for RenderMaterial2dInstances<M> {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
|
@ -3,6 +3,7 @@ use bevy_asset::{load_internal_asset, AssetId, Handle};
|
|||||||
|
|
||||||
use bevy_core_pipeline::core_2d::Transparent2d;
|
use bevy_core_pipeline::core_2d::Transparent2d;
|
||||||
use bevy_derive::{Deref, DerefMut};
|
use bevy_derive::{Deref, DerefMut};
|
||||||
|
use bevy_ecs::entity::EntityHashMap;
|
||||||
use bevy_ecs::{
|
use bevy_ecs::{
|
||||||
prelude::*,
|
prelude::*,
|
||||||
query::ROQueryItem,
|
query::ROQueryItem,
|
||||||
@ -30,7 +31,6 @@ use bevy_render::{
|
|||||||
Extract, ExtractSchedule, Render, RenderApp, RenderSet,
|
Extract, ExtractSchedule, Render, RenderApp, RenderSet,
|
||||||
};
|
};
|
||||||
use bevy_transform::components::GlobalTransform;
|
use bevy_transform::components::GlobalTransform;
|
||||||
use bevy_utils::EntityHashMap;
|
|
||||||
|
|
||||||
use crate::Material2dBindGroupId;
|
use crate::Material2dBindGroupId;
|
||||||
|
|
||||||
@ -192,7 +192,7 @@ pub struct RenderMesh2dInstance {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Default, Resource, Deref, DerefMut)]
|
#[derive(Default, Resource, Deref, DerefMut)]
|
||||||
pub struct RenderMesh2dInstances(EntityHashMap<Entity, RenderMesh2dInstance>);
|
pub struct RenderMesh2dInstances(EntityHashMap<RenderMesh2dInstance>);
|
||||||
|
|
||||||
#[derive(Component)]
|
#[derive(Component)]
|
||||||
pub struct Mesh2d;
|
pub struct Mesh2d;
|
||||||
|
@ -9,6 +9,7 @@ use bevy_core_pipeline::{
|
|||||||
core_2d::Transparent2d,
|
core_2d::Transparent2d,
|
||||||
tonemapping::{DebandDither, Tonemapping},
|
tonemapping::{DebandDither, Tonemapping},
|
||||||
};
|
};
|
||||||
|
use bevy_ecs::entity::EntityHashMap;
|
||||||
use bevy_ecs::{
|
use bevy_ecs::{
|
||||||
prelude::*,
|
prelude::*,
|
||||||
system::{lifetimeless::*, SystemParamItem, SystemState},
|
system::{lifetimeless::*, SystemParamItem, SystemState},
|
||||||
@ -36,7 +37,7 @@ use bevy_render::{
|
|||||||
Extract,
|
Extract,
|
||||||
};
|
};
|
||||||
use bevy_transform::components::GlobalTransform;
|
use bevy_transform::components::GlobalTransform;
|
||||||
use bevy_utils::{EntityHashMap, FloatOrd, HashMap};
|
use bevy_utils::{FloatOrd, HashMap};
|
||||||
use bytemuck::{Pod, Zeroable};
|
use bytemuck::{Pod, Zeroable};
|
||||||
use fixedbitset::FixedBitSet;
|
use fixedbitset::FixedBitSet;
|
||||||
|
|
||||||
@ -312,7 +313,7 @@ pub struct ExtractedSprite {
|
|||||||
|
|
||||||
#[derive(Resource, Default)]
|
#[derive(Resource, Default)]
|
||||||
pub struct ExtractedSprites {
|
pub struct ExtractedSprites {
|
||||||
pub sprites: EntityHashMap<Entity, ExtractedSprite>,
|
pub sprites: EntityHashMap<ExtractedSprite>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Resource, Default)]
|
#[derive(Resource, Default)]
|
||||||
|
@ -2,6 +2,7 @@ mod convert;
|
|||||||
pub mod debug;
|
pub mod debug;
|
||||||
|
|
||||||
use crate::{ContentSize, DefaultUiCamera, Node, Outline, Style, TargetCamera, UiScale};
|
use crate::{ContentSize, DefaultUiCamera, Node, Outline, Style, TargetCamera, UiScale};
|
||||||
|
use bevy_ecs::entity::EntityHashMap;
|
||||||
use bevy_ecs::{
|
use bevy_ecs::{
|
||||||
change_detection::{DetectChanges, DetectChangesMut},
|
change_detection::{DetectChanges, DetectChangesMut},
|
||||||
entity::Entity,
|
entity::Entity,
|
||||||
@ -16,7 +17,7 @@ use bevy_log::warn;
|
|||||||
use bevy_math::{UVec2, Vec2};
|
use bevy_math::{UVec2, Vec2};
|
||||||
use bevy_render::camera::{Camera, NormalizedRenderTarget};
|
use bevy_render::camera::{Camera, NormalizedRenderTarget};
|
||||||
use bevy_transform::components::Transform;
|
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 bevy_window::{PrimaryWindow, Window, WindowScaleFactorChanged};
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use taffy::{tree::LayoutTree, Taffy};
|
use taffy::{tree::LayoutTree, Taffy};
|
||||||
@ -51,14 +52,14 @@ struct RootNodePair {
|
|||||||
|
|
||||||
#[derive(Resource)]
|
#[derive(Resource)]
|
||||||
pub struct UiSurface {
|
pub struct UiSurface {
|
||||||
entity_to_taffy: EntityHashMap<Entity, taffy::node::Node>,
|
entity_to_taffy: EntityHashMap<taffy::node::Node>,
|
||||||
camera_roots: EntityHashMap<Entity, Vec<RootNodePair>>,
|
camera_roots: EntityHashMap<Vec<RootNodePair>>,
|
||||||
taffy: Taffy,
|
taffy: Taffy,
|
||||||
}
|
}
|
||||||
|
|
||||||
fn _assert_send_sync_ui_surface_impl_safe() {
|
fn _assert_send_sync_ui_surface_impl_safe() {
|
||||||
fn _assert_send_sync<T: Send + Sync>() {}
|
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::<Taffy>();
|
||||||
_assert_send_sync::<UiSurface>();
|
_assert_send_sync::<UiSurface>();
|
||||||
}
|
}
|
||||||
|
@ -23,6 +23,7 @@ use crate::{
|
|||||||
|
|
||||||
use bevy_app::prelude::*;
|
use bevy_app::prelude::*;
|
||||||
use bevy_asset::{load_internal_asset, AssetEvent, AssetId, Assets, Handle};
|
use bevy_asset::{load_internal_asset, AssetEvent, AssetId, Assets, Handle};
|
||||||
|
use bevy_ecs::entity::EntityHashMap;
|
||||||
use bevy_ecs::prelude::*;
|
use bevy_ecs::prelude::*;
|
||||||
use bevy_math::{Mat4, Rect, URect, UVec4, Vec2, Vec3, Vec4Swizzles};
|
use bevy_math::{Mat4, Rect, URect, UVec4, Vec2, Vec3, Vec4Swizzles};
|
||||||
use bevy_render::{
|
use bevy_render::{
|
||||||
@ -41,7 +42,7 @@ use bevy_sprite::TextureAtlasLayout;
|
|||||||
#[cfg(feature = "bevy_text")]
|
#[cfg(feature = "bevy_text")]
|
||||||
use bevy_text::{PositionedGlyph, Text, TextLayoutInfo};
|
use bevy_text::{PositionedGlyph, Text, TextLayoutInfo};
|
||||||
use bevy_transform::components::GlobalTransform;
|
use bevy_transform::components::GlobalTransform;
|
||||||
use bevy_utils::{EntityHashMap, FloatOrd, HashMap};
|
use bevy_utils::{FloatOrd, HashMap};
|
||||||
use bytemuck::{Pod, Zeroable};
|
use bytemuck::{Pod, Zeroable};
|
||||||
use std::ops::Range;
|
use std::ops::Range;
|
||||||
|
|
||||||
@ -147,7 +148,7 @@ pub struct ExtractedUiNode {
|
|||||||
|
|
||||||
#[derive(Resource, Default)]
|
#[derive(Resource, Default)]
|
||||||
pub struct ExtractedUiNodes {
|
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 {
|
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.
|
/// 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.
|
/// 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.
|
/// Calls the [`tracing::info!`] macro on a value.
|
||||||
pub fn info<T: Debug>(data: T) {
|
pub fn info<T: Debug>(data: T) {
|
||||||
tracing::info!("{:?}", data);
|
tracing::info!("{:?}", data);
|
||||||
@ -478,7 +399,6 @@ mod tests {
|
|||||||
use static_assertions::assert_impl_all;
|
use static_assertions::assert_impl_all;
|
||||||
|
|
||||||
// Check that the HashMaps are Clone if the key/values are Clone
|
// 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);
|
assert_impl_all!(PreHashMap::<u64, usize>: Clone);
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -15,6 +15,7 @@ use bevy_a11y::{
|
|||||||
use bevy_a11y::{ActionRequest as ActionRequestWrapper, ManageAccessibilityUpdates};
|
use bevy_a11y::{ActionRequest as ActionRequestWrapper, ManageAccessibilityUpdates};
|
||||||
use bevy_app::{App, Plugin, PostUpdate};
|
use bevy_app::{App, Plugin, PostUpdate};
|
||||||
use bevy_derive::{Deref, DerefMut};
|
use bevy_derive::{Deref, DerefMut};
|
||||||
|
use bevy_ecs::entity::EntityHashMap;
|
||||||
use bevy_ecs::{
|
use bevy_ecs::{
|
||||||
prelude::{DetectChanges, Entity, EventReader, EventWriter},
|
prelude::{DetectChanges, Entity, EventReader, EventWriter},
|
||||||
query::With,
|
query::With,
|
||||||
@ -22,16 +23,15 @@ use bevy_ecs::{
|
|||||||
system::{NonSend, NonSendMut, Query, Res, ResMut, Resource},
|
system::{NonSend, NonSendMut, Query, Res, ResMut, Resource},
|
||||||
};
|
};
|
||||||
use bevy_hierarchy::{Children, Parent};
|
use bevy_hierarchy::{Children, Parent};
|
||||||
use bevy_utils::EntityHashMap;
|
|
||||||
use bevy_window::{PrimaryWindow, Window, WindowClosed};
|
use bevy_window::{PrimaryWindow, Window, WindowClosed};
|
||||||
|
|
||||||
/// Maps window entities to their `AccessKit` [`Adapter`]s.
|
/// Maps window entities to their `AccessKit` [`Adapter`]s.
|
||||||
#[derive(Default, Deref, DerefMut)]
|
#[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.
|
/// Maps window entities to their respective [`WinitActionHandler`]s.
|
||||||
#[derive(Resource, Default, Deref, DerefMut)]
|
#[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.
|
/// Forwards `AccessKit` [`ActionRequest`]s from winit to an event channel.
|
||||||
#[derive(Clone, Default, Deref, DerefMut)]
|
#[derive(Clone, Default, Deref, DerefMut)]
|
||||||
|
@ -5,7 +5,8 @@ use bevy_a11y::{
|
|||||||
};
|
};
|
||||||
use bevy_ecs::entity::Entity;
|
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 bevy_window::{CursorGrabMode, Window, WindowMode, WindowPosition, WindowResolution};
|
||||||
|
|
||||||
use winit::{
|
use winit::{
|
||||||
@ -25,7 +26,7 @@ pub struct WinitWindows {
|
|||||||
/// Stores [`winit`] windows by window identifier.
|
/// Stores [`winit`] windows by window identifier.
|
||||||
pub windows: HashMap<winit::window::WindowId, winit::window::Window>,
|
pub windows: HashMap<winit::window::WindowId, winit::window::Window>,
|
||||||
/// Maps entities to `winit` window identifiers.
|
/// 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.
|
/// Maps `winit` window identifiers to entities.
|
||||||
pub winit_to_entity: HashMap<winit::window::WindowId, Entity>,
|
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.
|
// Many `winit` window functions (e.g. `set_window_icon`) can only be called on the main thread.
|
||||||
|
Loading…
Reference in New Issue
Block a user