mirror of
https://github.com/bevyengine/bevy
synced 2024-12-25 20:43:07 +00:00
1214ddabb7
Continuing the work on reducing the safety footguns in the code, I've removed one extra `UnsafeCell` in favour of safe `Cell` usage inisde `ComponentTicks`. That change led to discovery of misbehaving component insert logic, where data wasn't properly dropped when overwritten. Apart from that being fixed, some method names were changed to better convey the "initialize new allocation" and "replace existing allocation" semantic. Depends on #2221, I will rebase this PR after the dependency is merged. For now, review just the last commit. Co-authored-by: Carter Anderson <mcanders1@gmail.com>
968 lines
35 KiB
Rust
968 lines
35 KiB
Rust
mod entity_ref;
|
|
mod pointer;
|
|
mod spawn_batch;
|
|
mod world_cell;
|
|
|
|
pub use entity_ref::*;
|
|
pub use pointer::*;
|
|
pub use spawn_batch::*;
|
|
pub use world_cell::*;
|
|
|
|
use crate::{
|
|
archetype::{ArchetypeComponentId, ArchetypeComponentInfo, ArchetypeId, Archetypes},
|
|
bundle::{Bundle, Bundles},
|
|
change_detection::Ticks,
|
|
component::{
|
|
Component, ComponentDescriptor, ComponentId, ComponentTicks, Components, ComponentsError,
|
|
StorageType,
|
|
},
|
|
entity::{Entities, Entity},
|
|
query::{FilterFetch, QueryState, WorldQuery},
|
|
storage::{Column, SparseSet, Storages},
|
|
};
|
|
use std::{
|
|
any::TypeId,
|
|
fmt,
|
|
sync::atomic::{AtomicU32, Ordering},
|
|
};
|
|
|
|
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
|
|
pub struct WorldId(u64);
|
|
|
|
impl Default for WorldId {
|
|
fn default() -> Self {
|
|
WorldId(rand::random())
|
|
}
|
|
}
|
|
|
|
/// [World] stores and exposes operations on [entities](Entity), [components](Component),
|
|
/// and their associated metadata.
|
|
/// Each [Entity] has a set of components. Each component can have up to one instance of each
|
|
/// component type. Entity components can be created, updated, removed, and queried using a given
|
|
/// [World].
|
|
pub struct World {
|
|
id: WorldId,
|
|
pub(crate) entities: Entities,
|
|
pub(crate) components: Components,
|
|
pub(crate) archetypes: Archetypes,
|
|
pub(crate) storages: Storages,
|
|
pub(crate) bundles: Bundles,
|
|
pub(crate) removed_components: SparseSet<ComponentId, Vec<Entity>>,
|
|
/// Access cache used by [WorldCell].
|
|
pub(crate) archetype_component_access: ArchetypeComponentAccess,
|
|
main_thread_validator: MainThreadValidator,
|
|
pub(crate) change_tick: AtomicU32,
|
|
pub(crate) last_change_tick: u32,
|
|
}
|
|
|
|
impl Default for World {
|
|
fn default() -> Self {
|
|
Self {
|
|
id: Default::default(),
|
|
entities: Default::default(),
|
|
components: Default::default(),
|
|
archetypes: Default::default(),
|
|
storages: Default::default(),
|
|
bundles: Default::default(),
|
|
removed_components: Default::default(),
|
|
archetype_component_access: Default::default(),
|
|
main_thread_validator: Default::default(),
|
|
// Default value is `1`, and `last_change_tick`s default to `0`, such that changes
|
|
// are detected on first system runs and for direct world queries.
|
|
change_tick: AtomicU32::new(1),
|
|
last_change_tick: 0,
|
|
}
|
|
}
|
|
}
|
|
|
|
impl World {
|
|
/// Creates a new empty [World]
|
|
#[inline]
|
|
pub fn new() -> World {
|
|
World::default()
|
|
}
|
|
|
|
/// Retrieves this world's unique ID
|
|
#[inline]
|
|
pub fn id(&self) -> WorldId {
|
|
self.id
|
|
}
|
|
|
|
/// Retrieves this world's [Entities] collection
|
|
#[inline]
|
|
pub fn entities(&self) -> &Entities {
|
|
&self.entities
|
|
}
|
|
|
|
/// Retrieves this world's [Archetypes] collection
|
|
#[inline]
|
|
pub fn archetypes(&self) -> &Archetypes {
|
|
&self.archetypes
|
|
}
|
|
|
|
/// Retrieves this world's [Components] collection
|
|
#[inline]
|
|
pub fn components(&self) -> &Components {
|
|
&self.components
|
|
}
|
|
|
|
/// Retrieves a mutable reference to this world's [Components] collection
|
|
#[inline]
|
|
pub fn components_mut(&mut self) -> &mut Components {
|
|
&mut self.components
|
|
}
|
|
|
|
/// Retrieves this world's [Storages] collection
|
|
#[inline]
|
|
pub fn storages(&self) -> &Storages {
|
|
&self.storages
|
|
}
|
|
|
|
/// Retrieves this world's [Bundles] collection
|
|
#[inline]
|
|
pub fn bundles(&self) -> &Bundles {
|
|
&self.bundles
|
|
}
|
|
|
|
/// Retrieves a [WorldCell], which safely enables multiple mutable World accesses at the same
|
|
/// time, provided those accesses do not conflict with each other.
|
|
#[inline]
|
|
pub fn cell(&mut self) -> WorldCell<'_> {
|
|
WorldCell::new(self)
|
|
}
|
|
|
|
/// Registers a new component using the given [ComponentDescriptor]. Components do not need to
|
|
/// be manually registered. This just provides a way to override default configuration.
|
|
/// Attempting to register a component with a type that has already been used by [World]
|
|
/// will result in an error.
|
|
///
|
|
/// The default component storage type can be overridden like this:
|
|
///
|
|
/// ```
|
|
/// use bevy_ecs::{component::{ComponentDescriptor, StorageType}, world::World};
|
|
///
|
|
/// struct Position {
|
|
/// x: f32,
|
|
/// y: f32,
|
|
/// }
|
|
///
|
|
/// let mut world = World::new();
|
|
/// world.register_component(ComponentDescriptor::new::<Position>(StorageType::SparseSet)).unwrap();
|
|
/// ```
|
|
pub fn register_component(
|
|
&mut self,
|
|
descriptor: ComponentDescriptor,
|
|
) -> Result<ComponentId, ComponentsError> {
|
|
let storage_type = descriptor.storage_type();
|
|
let component_id = self.components.add(descriptor)?;
|
|
// ensure sparse set is created for SparseSet components
|
|
if storage_type == StorageType::SparseSet {
|
|
// SAFE: just created
|
|
let info = unsafe { self.components.get_info_unchecked(component_id) };
|
|
self.storages.sparse_sets.get_or_insert(info);
|
|
}
|
|
|
|
Ok(component_id)
|
|
}
|
|
|
|
/// Retrieves an [EntityRef] that exposes read-only operations for the given `entity`.
|
|
/// This will panic if the `entity` does not exist. Use [World::get_entity] if you want
|
|
/// to check for entity existence instead of implicitly panic-ing.
|
|
///
|
|
/// ```
|
|
/// use bevy_ecs::world::World;
|
|
///
|
|
/// struct Position {
|
|
/// x: f32,
|
|
/// y: f32,
|
|
/// }
|
|
///
|
|
/// let mut world = World::new();
|
|
/// let entity = world.spawn()
|
|
/// .insert(Position { x: 0.0, y: 0.0 })
|
|
/// .id();
|
|
///
|
|
/// let position = world.entity(entity).get::<Position>().unwrap();
|
|
/// assert_eq!(position.x, 0.0);
|
|
/// ```
|
|
#[inline]
|
|
pub fn entity(&self, entity: Entity) -> EntityRef {
|
|
self.get_entity(entity).expect("Entity does not exist")
|
|
}
|
|
|
|
/// Retrieves an [EntityMut] that exposes read and write operations for the given `entity`.
|
|
/// This will panic if the `entity` does not exist. Use [World::get_entity_mut] if you want
|
|
/// to check for entity existence instead of implicitly panic-ing.
|
|
///
|
|
/// ```
|
|
/// use bevy_ecs::world::World;
|
|
///
|
|
/// struct Position {
|
|
/// x: f32,
|
|
/// y: f32,
|
|
/// }
|
|
///
|
|
/// let mut world = World::new();
|
|
/// let entity = world.spawn()
|
|
/// .insert(Position { x: 0.0, y: 0.0 })
|
|
/// .id();
|
|
///
|
|
/// let mut position = world.entity_mut(entity).get_mut::<Position>().unwrap();
|
|
/// position.x = 1.0;
|
|
/// ```
|
|
#[inline]
|
|
pub fn entity_mut(&mut self, entity: Entity) -> EntityMut {
|
|
self.get_entity_mut(entity).expect("Entity does not exist")
|
|
}
|
|
|
|
/// Retrieves an [EntityRef] that exposes read-only operations for the given `entity`.
|
|
/// Returns [None] if the `entity` does not exist. Use [World::entity] if you don't want
|
|
/// to unwrap the [EntityRef] yourself.
|
|
///
|
|
/// ```
|
|
/// use bevy_ecs::world::World;
|
|
///
|
|
/// struct Position {
|
|
/// x: f32,
|
|
/// y: f32,
|
|
/// }
|
|
///
|
|
/// let mut world = World::new();
|
|
/// let entity = world.spawn()
|
|
/// .insert(Position { x: 0.0, y: 0.0 })
|
|
/// .id();
|
|
///
|
|
/// let entity_ref = world.get_entity(entity).unwrap();
|
|
/// let position = entity_ref.get::<Position>().unwrap();
|
|
/// assert_eq!(position.x, 0.0);
|
|
/// ```
|
|
#[inline]
|
|
pub fn get_entity(&self, entity: Entity) -> Option<EntityRef> {
|
|
let location = self.entities.get(entity)?;
|
|
Some(EntityRef::new(self, entity, location))
|
|
}
|
|
|
|
/// Retrieves an [EntityMut] that exposes read and write operations for the given `entity`.
|
|
/// Returns [None] if the `entity` does not exist. Use [World::entity_mut] if you don't want
|
|
/// to unwrap the [EntityMut] yourself.
|
|
///
|
|
/// ```
|
|
/// use bevy_ecs::world::World;
|
|
///
|
|
/// struct Position {
|
|
/// x: f32,
|
|
/// y: f32,
|
|
/// }
|
|
///
|
|
/// let mut world = World::new();
|
|
/// let entity = world.spawn()
|
|
/// .insert(Position { x: 0.0, y: 0.0 })
|
|
/// .id();
|
|
///
|
|
/// let mut entity_mut = world.get_entity_mut(entity).unwrap();
|
|
/// let mut position = entity_mut.get_mut::<Position>().unwrap();
|
|
/// position.x = 1.0;
|
|
/// ```
|
|
#[inline]
|
|
pub fn get_entity_mut(&mut self, entity: Entity) -> Option<EntityMut> {
|
|
let location = self.entities.get(entity)?;
|
|
// SAFE: `entity` exists and `location` is that entity's location
|
|
Some(unsafe { EntityMut::new(self, entity, location) })
|
|
}
|
|
|
|
/// Spawns a new [Entity] and returns a corresponding [EntityMut], which can be used
|
|
/// to add components to the entity or retrieve its id.
|
|
///
|
|
/// ```
|
|
/// use bevy_ecs::world::World;
|
|
///
|
|
/// struct Position {
|
|
/// x: f32,
|
|
/// y: f32,
|
|
/// }
|
|
///
|
|
/// let mut world = World::new();
|
|
/// let entity = world.spawn()
|
|
/// .insert(Position { x: 0.0, y: 0.0 }) // add a single component
|
|
/// .insert_bundle((1, 2.0, "hello")) // add a bundle of components
|
|
/// .id();
|
|
///
|
|
/// let position = world.entity(entity).get::<Position>().unwrap();
|
|
/// assert_eq!(position.x, 0.0);
|
|
/// ```
|
|
pub fn spawn(&mut self) -> EntityMut {
|
|
self.flush();
|
|
let entity = self.entities.alloc();
|
|
let archetype = self.archetypes.empty_mut();
|
|
unsafe {
|
|
// PERF: consider avoiding allocating entities in the empty archetype unless needed
|
|
let table_row = self.storages.tables[archetype.table_id()].allocate(entity);
|
|
// SAFE: no components are allocated by archetype.allocate() because the archetype is
|
|
// empty
|
|
let location = archetype.allocate(entity, table_row);
|
|
// SAFE: entity index was just allocated
|
|
self.entities
|
|
.meta
|
|
.get_unchecked_mut(entity.id() as usize)
|
|
.location = location;
|
|
EntityMut::new(self, entity, location)
|
|
}
|
|
}
|
|
|
|
/// Spawns a batch of entities with the same component [Bundle] type. Takes a given [Bundle]
|
|
/// iterator and returns a corresponding [Entity] iterator.
|
|
/// This is more efficient than spawning entities and adding components to them individually,
|
|
/// but it is limited to spawning entities with the same [Bundle] type, whereas spawning
|
|
/// individually is more flexible.
|
|
///
|
|
/// ```
|
|
/// use bevy_ecs::{entity::Entity, world::World};
|
|
///
|
|
/// let mut world = World::new();
|
|
/// let entities = world.spawn_batch(vec![
|
|
/// ("a", 0.0), // the first entity
|
|
/// ("b", 1.0), // the second entity
|
|
/// ]).collect::<Vec<Entity>>();
|
|
///
|
|
/// assert_eq!(entities.len(), 2);
|
|
/// ```
|
|
pub fn spawn_batch<I>(&mut self, iter: I) -> SpawnBatchIter<'_, I::IntoIter>
|
|
where
|
|
I: IntoIterator,
|
|
I::Item: Bundle,
|
|
{
|
|
SpawnBatchIter::new(self, iter.into_iter())
|
|
}
|
|
|
|
/// Retrieves a reference to the given `entity`'s [Component] of the given type.
|
|
/// Returns [None] if the `entity` does not have a [Component] of the given type.
|
|
/// ```
|
|
/// use bevy_ecs::world::World;
|
|
///
|
|
/// struct Position {
|
|
/// x: f32,
|
|
/// y: f32,
|
|
/// }
|
|
///
|
|
/// let mut world = World::new();
|
|
/// let entity = world.spawn()
|
|
/// .insert(Position { x: 0.0, y: 0.0 })
|
|
/// .id();
|
|
/// let position = world.get::<Position>(entity).unwrap();
|
|
/// assert_eq!(position.x, 0.0);
|
|
#[inline]
|
|
pub fn get<T: Component>(&self, entity: Entity) -> Option<&T> {
|
|
self.get_entity(entity)?.get()
|
|
}
|
|
|
|
/// Retrieves a mutable reference to the given `entity`'s [Component] of the given type.
|
|
/// Returns [None] if the `entity` does not have a [Component] of the given type.
|
|
/// ```
|
|
/// use bevy_ecs::world::World;
|
|
///
|
|
/// struct Position {
|
|
/// x: f32,
|
|
/// y: f32,
|
|
/// }
|
|
///
|
|
/// let mut world = World::new();
|
|
/// let entity = world.spawn()
|
|
/// .insert(Position { x: 0.0, y: 0.0 })
|
|
/// .id();
|
|
/// let mut position = world.get_mut::<Position>(entity).unwrap();
|
|
/// position.x = 1.0;
|
|
#[inline]
|
|
pub fn get_mut<T: Component>(&mut self, entity: Entity) -> Option<Mut<T>> {
|
|
self.get_entity_mut(entity)?.get_mut()
|
|
}
|
|
|
|
/// Despawns the given `entity`, if it exists. This will also remove all of the entity's
|
|
/// [Component]s. Returns `true` if the `entity` is successfully despawned and `false` if
|
|
/// the `entity` does not exist.
|
|
/// ```
|
|
/// use bevy_ecs::world::World;
|
|
///
|
|
/// struct Position {
|
|
/// x: f32,
|
|
/// y: f32,
|
|
/// }
|
|
///
|
|
/// let mut world = World::new();
|
|
/// let entity = world.spawn()
|
|
/// .insert(Position { x: 0.0, y: 0.0 })
|
|
/// .id();
|
|
/// assert!(world.despawn(entity));
|
|
/// assert!(world.get_entity(entity).is_none());
|
|
/// assert!(world.get::<Position>(entity).is_none());
|
|
/// ```
|
|
#[inline]
|
|
pub fn despawn(&mut self, entity: Entity) -> bool {
|
|
self.get_entity_mut(entity)
|
|
.map(|e| {
|
|
e.despawn();
|
|
true
|
|
})
|
|
.unwrap_or(false)
|
|
}
|
|
|
|
/// Clears component tracker state
|
|
pub fn clear_trackers(&mut self) {
|
|
for entities in self.removed_components.values_mut() {
|
|
entities.clear();
|
|
}
|
|
|
|
self.last_change_tick = self.increment_change_tick();
|
|
}
|
|
|
|
/// Returns [QueryState] for the given [WorldQuery], which is used to efficiently
|
|
/// run queries on the [World] by storing and reusing the [QueryState].
|
|
/// ```
|
|
/// use bevy_ecs::{entity::Entity, world::World};
|
|
///
|
|
/// #[derive(Debug, PartialEq)]
|
|
/// struct Position {
|
|
/// x: f32,
|
|
/// y: f32,
|
|
/// }
|
|
///
|
|
/// struct Velocity {
|
|
/// x: f32,
|
|
/// y: f32,
|
|
/// }
|
|
///
|
|
/// let mut world = World::new();
|
|
/// let entities = world.spawn_batch(vec![
|
|
/// (Position { x: 0.0, y: 0.0}, Velocity { x: 1.0, y: 0.0 }),
|
|
/// (Position { x: 0.0, y: 0.0}, Velocity { x: 0.0, y: 1.0 }),
|
|
/// ]).collect::<Vec<Entity>>();
|
|
///
|
|
/// let mut query = world.query::<(&mut Position, &Velocity)>();
|
|
/// for (mut position, velocity) in query.iter_mut(&mut world) {
|
|
/// position.x += velocity.x;
|
|
/// position.y += velocity.y;
|
|
/// }
|
|
///
|
|
/// assert_eq!(world.get::<Position>(entities[0]).unwrap(), &Position { x: 1.0, y: 0.0 });
|
|
/// assert_eq!(world.get::<Position>(entities[1]).unwrap(), &Position { x: 0.0, y: 1.0 });
|
|
/// ```
|
|
///
|
|
/// To iterate over entities in a deterministic order,
|
|
/// sort the results of the query using the desired component as a key.
|
|
/// Note that this requires fetching the whole result set from the query
|
|
/// and allocation of a [Vec] to store it.
|
|
///
|
|
/// ```
|
|
/// use bevy_ecs::{entity::Entity, world::World};
|
|
/// let mut world = World::new();
|
|
/// let a = world.spawn().insert_bundle((2, 4.0)).id();
|
|
/// let b = world.spawn().insert_bundle((3, 5.0)).id();
|
|
/// let c = world.spawn().insert_bundle((1, 6.0)).id();
|
|
/// let mut entities = world.query::<(Entity, &i32, &f64)>()
|
|
/// .iter(&world)
|
|
/// .collect::<Vec<_>>();
|
|
/// // Sort the query results by their `i32` component before comparing
|
|
/// // to expected results. Query iteration order should not be relied on.
|
|
/// entities.sort_by_key(|e| e.1);
|
|
/// assert_eq!(entities, vec![(c, &1, &6.0), (a, &2, &4.0), (b, &3, &5.0)]);
|
|
/// ```
|
|
#[inline]
|
|
pub fn query<Q: WorldQuery>(&mut self) -> QueryState<Q, ()> {
|
|
QueryState::new(self)
|
|
}
|
|
|
|
/// Returns [QueryState] for the given filtered [WorldQuery], which is used to efficiently
|
|
/// run queries on the [World] by storing and reusing the [QueryState].
|
|
/// ```
|
|
/// use bevy_ecs::{entity::Entity, world::World, query::With};
|
|
///
|
|
/// struct A;
|
|
/// struct B;
|
|
///
|
|
/// let mut world = World::new();
|
|
/// let e1 = world.spawn().insert(A).id();
|
|
/// let e2 = world.spawn().insert_bundle((A, B)).id();
|
|
///
|
|
/// let mut query = world.query_filtered::<Entity, With<B>>();
|
|
/// let matching_entities = query.iter(&world).collect::<Vec<Entity>>();
|
|
///
|
|
/// assert_eq!(matching_entities, vec![e2]);
|
|
/// ```
|
|
#[inline]
|
|
pub fn query_filtered<Q: WorldQuery, F: WorldQuery>(&mut self) -> QueryState<Q, F>
|
|
where
|
|
F::Fetch: FilterFetch,
|
|
{
|
|
QueryState::new(self)
|
|
}
|
|
|
|
/// Returns an iterator of entities that had components of type `T` removed
|
|
/// since the last call to [World::clear_trackers].
|
|
pub fn removed<T: Component>(&self) -> std::iter::Cloned<std::slice::Iter<'_, Entity>> {
|
|
if let Some(component_id) = self.components.get_id(TypeId::of::<T>()) {
|
|
self.removed_with_id(component_id)
|
|
} else {
|
|
[].iter().cloned()
|
|
}
|
|
}
|
|
|
|
/// Returns an iterator of entities that had components with the given `component_id` removed
|
|
/// since the last call to [World::clear_trackers].
|
|
pub fn removed_with_id(
|
|
&self,
|
|
component_id: ComponentId,
|
|
) -> std::iter::Cloned<std::slice::Iter<'_, Entity>> {
|
|
if let Some(removed) = self.removed_components.get(component_id) {
|
|
removed.iter().cloned()
|
|
} else {
|
|
[].iter().cloned()
|
|
}
|
|
}
|
|
|
|
/// Inserts a new resource with the given `value`.
|
|
/// Resources are "unique" data of a given type.
|
|
#[inline]
|
|
pub fn insert_resource<T: Component>(&mut self, value: T) {
|
|
let component_id = self.components.get_or_insert_resource_id::<T>();
|
|
// SAFE: component_id just initialized and corresponds to resource of type T
|
|
unsafe { self.insert_resource_with_id(component_id, value) };
|
|
}
|
|
|
|
/// Inserts a new non-send resource with the given `value`.
|
|
/// Resources are "unique" data of a given type.
|
|
#[inline]
|
|
pub fn insert_non_send<T: 'static>(&mut self, value: T) {
|
|
self.validate_non_send_access::<T>();
|
|
let component_id = self.components.get_or_insert_non_send_resource_id::<T>();
|
|
// SAFE: component_id just initialized and corresponds to resource of type T
|
|
unsafe { self.insert_resource_with_id(component_id, value) };
|
|
}
|
|
|
|
/// Removes the resource of a given type and returns it, if it exists. Otherwise returns [None].
|
|
/// Resources are "unique" data of a given type.
|
|
#[inline]
|
|
pub fn remove_resource<T: Component>(&mut self) -> Option<T> {
|
|
// SAFE: T is Send + Sync
|
|
unsafe { self.remove_resource_unchecked() }
|
|
}
|
|
|
|
#[inline]
|
|
pub fn remove_non_send<T: 'static>(&mut self) -> Option<T> {
|
|
self.validate_non_send_access::<T>();
|
|
// SAFE: we are on main thread
|
|
unsafe { self.remove_resource_unchecked() }
|
|
}
|
|
|
|
#[inline]
|
|
/// # Safety
|
|
/// make sure you're on main thread if T isn't Send + Sync
|
|
#[allow(unused_unsafe)]
|
|
pub unsafe fn remove_resource_unchecked<T: 'static>(&mut self) -> Option<T> {
|
|
let component_id = self.components.get_resource_id(TypeId::of::<T>())?;
|
|
let resource_archetype = self.archetypes.resource_mut();
|
|
let unique_components = resource_archetype.unique_components_mut();
|
|
let column = unique_components.get_mut(component_id)?;
|
|
if column.is_empty() {
|
|
return None;
|
|
}
|
|
// SAFE: if a resource column exists, row 0 exists as well. caller takes ownership of the
|
|
// ptr value / drop is called when T is dropped
|
|
let (ptr, _) = unsafe { column.swap_remove_and_forget_unchecked(0) };
|
|
// SAFE: column is of type T
|
|
Some(unsafe { ptr.cast::<T>().read() })
|
|
}
|
|
|
|
/// Returns `true` if a resource of type `T` exists. Otherwise returns `false`.
|
|
#[inline]
|
|
pub fn contains_resource<T: Component>(&self) -> bool {
|
|
let component_id =
|
|
if let Some(component_id) = self.components.get_resource_id(TypeId::of::<T>()) {
|
|
component_id
|
|
} else {
|
|
return false;
|
|
};
|
|
self.get_populated_resource_column(component_id).is_some()
|
|
}
|
|
|
|
/// Gets a reference to the resource of the given type, if it exists. Otherwise returns [None]
|
|
/// Resources are "unique" data of a given type.
|
|
#[inline]
|
|
pub fn get_resource<T: Component>(&self) -> Option<&T> {
|
|
let component_id = self.components.get_resource_id(TypeId::of::<T>())?;
|
|
unsafe { self.get_resource_with_id(component_id) }
|
|
}
|
|
|
|
pub fn is_resource_added<T: Component>(&self) -> bool {
|
|
let component_id = self.components.get_resource_id(TypeId::of::<T>()).unwrap();
|
|
let column = self.get_populated_resource_column(component_id).unwrap();
|
|
// SAFE: resources table always have row 0
|
|
let ticks = unsafe { column.get_ticks_unchecked(0) };
|
|
ticks.is_added(self.last_change_tick(), self.read_change_tick())
|
|
}
|
|
|
|
pub fn is_resource_changed<T: Component>(&self) -> bool {
|
|
let component_id = self.components.get_resource_id(TypeId::of::<T>()).unwrap();
|
|
let column = self.get_populated_resource_column(component_id).unwrap();
|
|
// SAFE: resources table always have row 0
|
|
let ticks = unsafe { column.get_ticks_unchecked(0) };
|
|
ticks.is_changed(self.last_change_tick(), self.read_change_tick())
|
|
}
|
|
|
|
/// Gets a mutable reference to the resource of the given type, if it exists. Otherwise returns
|
|
/// [None] Resources are "unique" data of a given type.
|
|
#[inline]
|
|
pub fn get_resource_mut<T: Component>(&mut self) -> Option<Mut<'_, T>> {
|
|
// SAFE: unique world access
|
|
unsafe { self.get_resource_unchecked_mut() }
|
|
}
|
|
|
|
// PERF: optimize this to avoid redundant lookups
|
|
/// Gets a resource of type `T` if it exists, otherwise inserts the resource using the result of
|
|
/// calling `func`.
|
|
#[inline]
|
|
pub fn get_resource_or_insert_with<T: Component>(
|
|
&mut self,
|
|
func: impl FnOnce() -> T,
|
|
) -> Mut<'_, T> {
|
|
if !self.contains_resource::<T>() {
|
|
self.insert_resource(func());
|
|
}
|
|
self.get_resource_mut().unwrap()
|
|
}
|
|
|
|
/// Gets a mutable reference to the resource of the given type, if it exists. Otherwise returns
|
|
/// [None] Resources are "unique" data of a given type.
|
|
///
|
|
/// # Safety
|
|
/// This will allow aliased mutable access to the given resource type. The caller must ensure
|
|
/// that only one mutable access exists at a time.
|
|
#[inline]
|
|
pub unsafe fn get_resource_unchecked_mut<T: Component>(&self) -> Option<Mut<'_, T>> {
|
|
let component_id = self.components.get_resource_id(TypeId::of::<T>())?;
|
|
self.get_resource_unchecked_mut_with_id(component_id)
|
|
}
|
|
|
|
/// Gets a reference to the non-send resource of the given type, if it exists. Otherwise returns
|
|
/// [None] Resources are "unique" data of a given type.
|
|
#[inline]
|
|
pub fn get_non_send_resource<T: 'static>(&self) -> Option<&T> {
|
|
let component_id = self.components.get_resource_id(TypeId::of::<T>())?;
|
|
// SAFE: component id matches type T
|
|
unsafe { self.get_non_send_with_id(component_id) }
|
|
}
|
|
|
|
/// Gets a mutable reference to the non-send resource of the given type, if it exists. Otherwise
|
|
/// returns [None] Resources are "unique" data of a given type.
|
|
#[inline]
|
|
pub fn get_non_send_resource_mut<T: 'static>(&mut self) -> Option<Mut<'_, T>> {
|
|
// SAFE: unique world access
|
|
unsafe { self.get_non_send_resource_unchecked_mut() }
|
|
}
|
|
|
|
/// Gets a mutable reference to the non-send resource of the given type, if it exists. Otherwise
|
|
/// returns [None] Resources are "unique" data of a given type.
|
|
///
|
|
/// # Safety
|
|
/// This will allow aliased mutable access to the given non-send resource type. The caller must
|
|
/// ensure that only one mutable access exists at a time.
|
|
#[inline]
|
|
pub unsafe fn get_non_send_resource_unchecked_mut<T: 'static>(&self) -> Option<Mut<'_, T>> {
|
|
let component_id = self.components.get_resource_id(TypeId::of::<T>())?;
|
|
self.get_non_send_unchecked_mut_with_id(component_id)
|
|
}
|
|
|
|
/// Temporarily removes the requested resource from this [World], then re-adds it before
|
|
/// returning. This enables safe mutable access to a resource while still providing mutable
|
|
/// world access
|
|
/// ```
|
|
/// use bevy_ecs::world::{World, Mut};
|
|
/// struct A(u32);
|
|
/// struct B(u32);
|
|
/// let mut world = World::new();
|
|
/// world.insert_resource(A(1));
|
|
/// let entity = world.spawn().insert(B(1)).id();
|
|
///
|
|
/// world.resource_scope(|world, mut a: Mut<A>| {
|
|
/// let b = world.get_mut::<B>(entity).unwrap();
|
|
/// a.0 += b.0;
|
|
/// });
|
|
/// assert_eq!(world.get_resource::<A>().unwrap().0, 2);
|
|
/// ```
|
|
pub fn resource_scope<T: Component, U>(
|
|
&mut self,
|
|
f: impl FnOnce(&mut World, Mut<T>) -> U,
|
|
) -> U {
|
|
let component_id = self
|
|
.components
|
|
.get_resource_id(TypeId::of::<T>())
|
|
.unwrap_or_else(|| panic!("resource does not exist: {}", std::any::type_name::<T>()));
|
|
let (ptr, mut ticks) = {
|
|
let resource_archetype = self.archetypes.resource_mut();
|
|
let unique_components = resource_archetype.unique_components_mut();
|
|
let column = unique_components.get_mut(component_id).unwrap_or_else(|| {
|
|
panic!("resource does not exist: {}", std::any::type_name::<T>())
|
|
});
|
|
if column.is_empty() {
|
|
panic!("resource does not exist: {}", std::any::type_name::<T>());
|
|
}
|
|
// SAFE: if a resource column exists, row 0 exists as well. caller takes ownership of
|
|
// the ptr value / drop is called when T is dropped
|
|
unsafe { column.swap_remove_and_forget_unchecked(0) }
|
|
};
|
|
// SAFE: pointer is of type T
|
|
let value = Mut {
|
|
value: unsafe { &mut *ptr.cast::<T>() },
|
|
ticks: Ticks {
|
|
component_ticks: &mut ticks,
|
|
last_change_tick: self.last_change_tick(),
|
|
change_tick: self.change_tick(),
|
|
},
|
|
};
|
|
let result = f(self, value);
|
|
let resource_archetype = self.archetypes.resource_mut();
|
|
let unique_components = resource_archetype.unique_components_mut();
|
|
let column = unique_components
|
|
.get_mut(component_id)
|
|
.unwrap_or_else(|| panic!("resource does not exist: {}", std::any::type_name::<T>()));
|
|
unsafe {
|
|
// SAFE: pointer is of type T
|
|
column.push(ptr, ticks);
|
|
}
|
|
result
|
|
}
|
|
|
|
/// # Safety
|
|
/// `component_id` must be assigned to a component of type T
|
|
#[inline]
|
|
pub(crate) unsafe fn get_resource_with_id<T: 'static>(
|
|
&self,
|
|
component_id: ComponentId,
|
|
) -> Option<&T> {
|
|
let column = self.get_populated_resource_column(component_id)?;
|
|
Some(&*column.get_data_ptr().as_ptr().cast::<T>())
|
|
}
|
|
|
|
/// # Safety
|
|
/// `component_id` must be assigned to a component of type T.
|
|
/// Caller must ensure this doesn't violate Rust mutability rules for the given resource.
|
|
#[inline]
|
|
pub(crate) unsafe fn get_resource_unchecked_mut_with_id<T>(
|
|
&self,
|
|
component_id: ComponentId,
|
|
) -> Option<Mut<'_, T>> {
|
|
let column = self.get_populated_resource_column(component_id)?;
|
|
Some(Mut {
|
|
value: &mut *column.get_data_ptr().cast::<T>().as_ptr(),
|
|
ticks: Ticks {
|
|
component_ticks: &mut *column.get_ticks_mut_ptr_unchecked(0),
|
|
last_change_tick: self.last_change_tick(),
|
|
change_tick: self.read_change_tick(),
|
|
},
|
|
})
|
|
}
|
|
|
|
/// # Safety
|
|
/// `component_id` must be assigned to a component of type T
|
|
#[inline]
|
|
pub(crate) unsafe fn get_non_send_with_id<T: 'static>(
|
|
&self,
|
|
component_id: ComponentId,
|
|
) -> Option<&T> {
|
|
self.validate_non_send_access::<T>();
|
|
self.get_resource_with_id(component_id)
|
|
}
|
|
|
|
/// # Safety
|
|
/// `component_id` must be assigned to a component of type T.
|
|
/// Caller must ensure this doesn't violate Rust mutability rules for the given resource.
|
|
#[inline]
|
|
pub(crate) unsafe fn get_non_send_unchecked_mut_with_id<T: 'static>(
|
|
&self,
|
|
component_id: ComponentId,
|
|
) -> Option<Mut<'_, T>> {
|
|
self.validate_non_send_access::<T>();
|
|
self.get_resource_unchecked_mut_with_id(component_id)
|
|
}
|
|
|
|
/// # Safety
|
|
/// `component_id` must be valid and correspond to a resource component of type T
|
|
#[inline]
|
|
unsafe fn insert_resource_with_id<T>(&mut self, component_id: ComponentId, mut value: T) {
|
|
let change_tick = self.change_tick();
|
|
let column = self.initialize_resource_internal(component_id);
|
|
if column.is_empty() {
|
|
// SAFE: column is of type T and has been allocated above
|
|
let data = (&mut value as *mut T).cast::<u8>();
|
|
std::mem::forget(value);
|
|
column.push(data, ComponentTicks::new(change_tick));
|
|
} else {
|
|
// SAFE: column is of type T and has already been allocated
|
|
*column.get_data_unchecked(0).cast::<T>() = value;
|
|
column.get_ticks_unchecked_mut(0).set_changed(change_tick);
|
|
}
|
|
}
|
|
|
|
/// # Safety
|
|
/// `component_id` must be valid and correspond to a resource component of type T
|
|
#[inline]
|
|
unsafe fn initialize_resource_internal(&mut self, component_id: ComponentId) -> &mut Column {
|
|
// SAFE: resource archetype always exists
|
|
let resource_archetype = self
|
|
.archetypes
|
|
.archetypes
|
|
.get_unchecked_mut(ArchetypeId::resource().index());
|
|
let resource_archetype_components = &mut resource_archetype.components;
|
|
let archetype_component_count = &mut self.archetypes.archetype_component_count;
|
|
let components = &self.components;
|
|
resource_archetype
|
|
.unique_components
|
|
.get_or_insert_with(component_id, || {
|
|
resource_archetype_components.insert(
|
|
component_id,
|
|
ArchetypeComponentInfo {
|
|
archetype_component_id: ArchetypeComponentId::new(
|
|
*archetype_component_count,
|
|
),
|
|
storage_type: StorageType::Table,
|
|
},
|
|
);
|
|
*archetype_component_count += 1;
|
|
let component_info = components.get_info_unchecked(component_id);
|
|
Column::with_capacity(component_info, 1)
|
|
})
|
|
}
|
|
|
|
pub(crate) fn initialize_resource<T: Component>(&mut self) -> ComponentId {
|
|
let component_id = self.components.get_or_insert_resource_id::<T>();
|
|
// SAFE: resource initialized above
|
|
unsafe { self.initialize_resource_internal(component_id) };
|
|
component_id
|
|
}
|
|
|
|
pub(crate) fn initialize_non_send_resource<T: 'static>(&mut self) -> ComponentId {
|
|
let component_id = self.components.get_or_insert_non_send_resource_id::<T>();
|
|
// SAFE: resource initialized above
|
|
unsafe { self.initialize_resource_internal(component_id) };
|
|
component_id
|
|
}
|
|
|
|
/// returns the resource column if the requested resource exists
|
|
pub(crate) fn get_populated_resource_column(
|
|
&self,
|
|
component_id: ComponentId,
|
|
) -> Option<&Column> {
|
|
let resource_archetype = self.archetypes.resource();
|
|
let unique_components = resource_archetype.unique_components();
|
|
unique_components.get(component_id).and_then(|column| {
|
|
if column.is_empty() {
|
|
None
|
|
} else {
|
|
Some(column)
|
|
}
|
|
})
|
|
}
|
|
|
|
pub(crate) fn validate_non_send_access<T: 'static>(&self) {
|
|
if !self.main_thread_validator.is_main_thread() {
|
|
panic!(
|
|
"attempted to access NonSend resource {} off of the main thread",
|
|
std::any::type_name::<T>()
|
|
);
|
|
}
|
|
}
|
|
|
|
/// Empties queued entities and adds them to the empty [Archetype].
|
|
/// This should be called before doing operations that might operate on queued entities,
|
|
/// such as inserting a [Component].
|
|
pub(crate) fn flush(&mut self) {
|
|
let empty_archetype = self.archetypes.empty_mut();
|
|
unsafe {
|
|
let table = &mut self.storages.tables[empty_archetype.table_id()];
|
|
// PERF: consider pre-allocating space for flushed entities
|
|
self.entities.flush(|entity, location| {
|
|
// SAFE: no components are allocated by archetype.allocate() because the archetype
|
|
// is empty
|
|
*location = empty_archetype.allocate(entity, table.allocate(entity));
|
|
});
|
|
}
|
|
}
|
|
|
|
#[inline]
|
|
pub fn increment_change_tick(&self) -> u32 {
|
|
self.change_tick.fetch_add(1, Ordering::AcqRel)
|
|
}
|
|
|
|
#[inline]
|
|
pub fn read_change_tick(&self) -> u32 {
|
|
self.change_tick.load(Ordering::Acquire)
|
|
}
|
|
|
|
#[inline]
|
|
pub fn change_tick(&mut self) -> u32 {
|
|
*self.change_tick.get_mut()
|
|
}
|
|
|
|
#[inline]
|
|
pub fn last_change_tick(&self) -> u32 {
|
|
self.last_change_tick
|
|
}
|
|
|
|
pub fn check_change_ticks(&mut self) {
|
|
// Iterate over all component change ticks, clamping their age to max age
|
|
// PERF: parallelize
|
|
let change_tick = self.change_tick();
|
|
self.storages.tables.check_change_ticks(change_tick);
|
|
self.storages.sparse_sets.check_change_ticks(change_tick);
|
|
let resource_archetype = self.archetypes.resource_mut();
|
|
for column in resource_archetype.unique_components.values_mut() {
|
|
column.check_change_ticks(change_tick);
|
|
}
|
|
}
|
|
}
|
|
|
|
impl fmt::Debug for World {
|
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
f.debug_struct("World")
|
|
.field("id", &self.id)
|
|
.field("entity_count", &self.entities.len())
|
|
.field("archetype_count", &self.archetypes.len())
|
|
.field("component_count", &self.components.len())
|
|
.field(
|
|
"resource_count",
|
|
&self.archetypes.resource().unique_components.len(),
|
|
)
|
|
.finish()
|
|
}
|
|
}
|
|
|
|
unsafe impl Send for World {}
|
|
unsafe impl Sync for World {}
|
|
|
|
/// Creates `Self` using data from the given [World]
|
|
pub trait FromWorld {
|
|
/// Creates `Self` using data from the given [World]
|
|
fn from_world(world: &mut World) -> Self;
|
|
}
|
|
|
|
impl<T: Default> FromWorld for T {
|
|
fn from_world(_world: &mut World) -> Self {
|
|
T::default()
|
|
}
|
|
}
|
|
|
|
struct MainThreadValidator {
|
|
main_thread: std::thread::ThreadId,
|
|
}
|
|
|
|
impl MainThreadValidator {
|
|
fn is_main_thread(&self) -> bool {
|
|
self.main_thread == std::thread::current().id()
|
|
}
|
|
}
|
|
|
|
impl Default for MainThreadValidator {
|
|
fn default() -> Self {
|
|
Self {
|
|
main_thread: std::thread::current().id(),
|
|
}
|
|
}
|
|
}
|