mirror of
https://github.com/bevyengine/bevy
synced 2024-12-24 20:13:07 +00:00
858 lines
31 KiB
Rust
858 lines
31 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},
|
||
|
component::{
|
||
|
Component, ComponentDescriptor, ComponentFlags, ComponentId, Components, ComponentsError,
|
||
|
StorageType,
|
||
|
},
|
||
|
entity::{Entities, Entity},
|
||
|
query::{FilterFetch, QueryState, WorldQuery},
|
||
|
storage::{Column, SparseSet, Storages},
|
||
|
};
|
||
|
use std::{any::TypeId, fmt};
|
||
|
|
||
|
#[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].
|
||
|
#[derive(Default)]
|
||
|
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,
|
||
|
}
|
||
|
|
||
|
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
|
||
|
// SAFE: archetype tables always exist
|
||
|
let table = self.storages.tables.get_unchecked_mut(archetype.table_id());
|
||
|
// SAFE: no components are allocated by archetype.allocate() because the archetype is empty
|
||
|
let location = archetype.allocate(entity, table.allocate(entity));
|
||
|
// 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 all component tracker state, such as "added", "mutated", and "removed".
|
||
|
pub fn clear_trackers(&mut self) {
|
||
|
self.storages.tables.clear_flags();
|
||
|
self.storages.sparse_sets.clear_flags();
|
||
|
for entities in self.removed_components.values_mut() {
|
||
|
entities.clear();
|
||
|
}
|
||
|
|
||
|
let resource_archetype = self.archetypes.resource_mut();
|
||
|
for column in resource_archetype.unique_components.values_mut() {
|
||
|
column.clear_flags();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/// Returns [QueryState] for the given [WorldQuery], which is used to efficiently
|
||
|
/// run queries on the [World].
|
||
|
/// ```
|
||
|
///
|
||
|
/// 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 });
|
||
|
/// ```
|
||
|
#[inline]
|
||
|
pub fn query<Q: WorldQuery>(&mut self) -> QueryState<Q, ()> {
|
||
|
QueryState::new(self)
|
||
|
}
|
||
|
|
||
|
/// Returns [QueryState] for the given [WorldQuery] and filter, which is used to efficiently
|
||
|
/// run filtered queries on the [World].
|
||
|
/// ```
|
||
|
/// 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> {
|
||
|
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) }
|
||
|
}
|
||
|
|
||
|
/// 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(|mut a: Mut<A>, world| {
|
||
|
/// 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<T>, &mut World) -> U,
|
||
|
) -> U {
|
||
|
let component_id = self
|
||
|
.components
|
||
|
.get_resource_id(TypeId::of::<T>())
|
||
|
.expect("resource does not exist");
|
||
|
let (ptr, mut flags) = {
|
||
|
let resource_archetype = self.archetypes.resource_mut();
|
||
|
let unique_components = resource_archetype.unique_components_mut();
|
||
|
let column = unique_components
|
||
|
.get_mut(component_id)
|
||
|
.expect("resource does not exist");
|
||
|
if column.is_empty() {
|
||
|
panic!("resource does not exist");
|
||
|
}
|
||
|
// 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>() },
|
||
|
flags: &mut flags,
|
||
|
};
|
||
|
let result = f(value, self);
|
||
|
let resource_archetype = self.archetypes.resource_mut();
|
||
|
let unique_components = resource_archetype.unique_components_mut();
|
||
|
let column = unique_components
|
||
|
.get_mut(component_id)
|
||
|
.expect("resource does not exist");
|
||
|
// SAFE: new location is immediately written to below
|
||
|
let row = unsafe { column.push_uninit() };
|
||
|
// SAFE: row was just allocated above
|
||
|
unsafe { column.set_unchecked(row, ptr) };
|
||
|
// SAFE: row was just allocated above
|
||
|
unsafe { *column.get_flags_unchecked_mut(row) = flags };
|
||
|
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_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_ptr().as_ptr().cast::<T>(),
|
||
|
flags: &mut *column.get_flags_mut_ptr(),
|
||
|
})
|
||
|
}
|
||
|
|
||
|
/// # 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 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>();
|
||
|
// SAFE: new location is immediately written to below
|
||
|
let row = column.push_uninit();
|
||
|
// SAFE: index was just allocated above
|
||
|
column.set_unchecked(row, data);
|
||
|
std::mem::forget(value);
|
||
|
column
|
||
|
.get_flags_unchecked_mut(row)
|
||
|
.set(ComponentFlags::ADDED, true);
|
||
|
} else {
|
||
|
// SAFE: column is of type T and has already been allocated
|
||
|
*column.get_unchecked(0).cast::<T>() = value;
|
||
|
column
|
||
|
.get_flags_unchecked_mut(0)
|
||
|
.set(ComponentFlags::MUTATED, true);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/// # 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)
|
||
|
}
|
||
|
})
|
||
|
}
|
||
|
|
||
|
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 {
|
||
|
// SAFE: archetype tables always exist
|
||
|
let table = self
|
||
|
.storages
|
||
|
.tables
|
||
|
.get_unchecked_mut(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));
|
||
|
});
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
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(),
|
||
|
}
|
||
|
}
|
||
|
}
|