bevy/crates/bevy_ecs/src/world/mod.rs
Daniel McNab aca7fc1854 Remove outdated perf comments (#4374)
# Objective

- The perf comments, added (by me) in https://github.com/bevyengine/bevy/pull/1349, became outdated once the initialisation call started to take an exclusive reference, (presumably in https://github.com/bevyengine/bevy/pull/1525).
- They have been naïvely transferred along ever since

## Solution

- Remove them
2022-03-31 20:43:00 +00:00

1466 lines
53 KiB
Rust

mod entity_ref;
mod spawn_batch;
mod world_cell;
pub use crate::change_detection::Mut;
pub use entity_ref::*;
pub use spawn_batch::*;
pub use world_cell::*;
use crate::{
archetype::{ArchetypeComponentId, ArchetypeComponentInfo, ArchetypeId, Archetypes},
bundle::{Bundle, BundleInserter, BundleSpawner, Bundles},
change_detection::Ticks,
component::{Component, ComponentId, ComponentTicks, Components, StorageType},
entity::{AllocAtWithoutReplacement, Entities, Entity},
query::{FilterFetch, QueryState, WorldQuery},
storage::{Column, SparseSet, Storages},
system::Resource,
};
use std::{
any::TypeId,
fmt,
mem::ManuallyDrop,
sync::atomic::{AtomicU32, Ordering},
};
mod identifier;
pub use identifier::WorldId;
/// Stores and exposes operations on [entities](Entity), [components](Component), resources,
/// 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].
///
/// For complex access patterns involving [`SystemParam`](crate::system::SystemParam),
/// consider using [`SystemState`](crate::system::SystemState).
///
/// To mutate different parts of the world simultaneously,
/// use [`World::resource_scope`] or [`SystemState`](crate::system::SystemState).
///
/// # Resources
///
/// Worlds can also store *resources*, which are unique instances of a given type that don't
/// belong to a specific Entity. There are also *non send resources*, which can only be
/// accessed on the main thread.
///
/// ## Usage of global resources
///
/// 1. Insert the resource into the `World`, using [`World::insert_resource`].
/// 2. Fetch the resource from a system, using [`Res`](crate::system::Res) or [`ResMut`](crate::system::ResMut).
///
/// ```
/// # let mut world = World::default();
/// # let mut schedule = Schedule::default();
/// # schedule.add_stage("update", SystemStage::parallel());
/// # use bevy_ecs::prelude::*;
/// #
/// struct MyResource { value: u32 }
///
/// world.insert_resource(MyResource { value: 42 });
///
/// fn read_resource_system(resource: Res<MyResource>) {
/// assert_eq!(resource.value, 42);
/// }
///
/// fn write_resource_system(mut resource: ResMut<MyResource>) {
/// assert_eq!(resource.value, 42);
/// resource.value = 0;
/// assert_eq!(resource.value, 0);
/// }
/// #
/// # schedule.add_system_to_stage("update", read_resource_system.label("first"));
/// # schedule.add_system_to_stage("update", write_resource_system.after("first"));
/// # schedule.run_once(&mut 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: WorldId::new().expect("More `bevy` `World`s have been created than is supported"),
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]
/// # Panics
///
/// If [`usize::MAX`] [`World`]s have been created.
/// This guarantee allows System Parameters to safely uniquely identify a [`World`],
/// since its [`WorldId`] is unique
#[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 [Entities] collection mutably
///
/// # Safety
/// Mutable reference must not be used to put the [`Entities`] data
/// in an invalid state for this [`World`]
#[inline]
pub unsafe fn entities_mut(&mut self) -> &mut Entities {
&mut 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 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)
}
pub fn init_component<T: Component>(&mut self) -> ComponentId {
self.components.init_component::<T>(&mut self.storages)
}
/// 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::{component::Component, world::World};
///
/// #[derive(Component)]
/// 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 {
// Lazily evaluate panic!() via unwrap_or_else() to avoid allocation unless failure
self.get_entity(entity)
.unwrap_or_else(|| panic!("Entity {:?} does not exist", entity))
}
/// 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::{component::Component, world::World};
///
/// #[derive(Component)]
/// 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 {
// Lazily evaluate panic!() via unwrap_or_else() to avoid allocation unless failure
self.get_entity_mut(entity)
.unwrap_or_else(|| panic!("Entity {:?} does not exist", entity))
}
/// Returns an [`EntityMut`] for the given `entity` (if it exists) or spawns one if it doesn't exist.
/// This will return [`None`] if the `entity` exists with a different generation.
///
/// # Note
/// Spawning a specific `entity` value is rarely the right choice. Most apps should favor [`World::spawn`].
/// This method should generally only be used for sharing entities across apps, and only when they have a
/// scheme worked out to share an ID space (which doesn't happen by default).
#[inline]
pub fn get_or_spawn(&mut self, entity: Entity) -> Option<EntityMut> {
self.flush();
match self.entities.alloc_at_without_replacement(entity) {
AllocAtWithoutReplacement::Exists(location) => {
// SAFE: `entity` exists and `location` is that entity's location
Some(unsafe { EntityMut::new(self, entity, location) })
}
AllocAtWithoutReplacement::DidNotExist => {
// SAFE: entity was just allocated
Some(unsafe { self.spawn_at_internal(entity) })
}
AllocAtWithoutReplacement::ExistsWithWrongGeneration => None,
}
}
/// 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::{component::Component, world::World};
///
/// #[derive(Component)]
/// 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::{component::Component, world::World};
///
/// #[derive(Component)]
/// 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::{component::Component, world::World};
///
/// #[derive(Component)]
/// struct Position {
/// x: f32,
/// y: f32,
/// }
/// #[derive(Component)]
/// struct Label(&'static str);
/// #[derive(Component)]
/// struct Num(u32);
///
/// let mut world = World::new();
/// let entity = world.spawn()
/// .insert(Position { x: 0.0, y: 0.0 }) // add a single component
/// .insert_bundle((Num(1), Label("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();
// SAFE: entity was just allocated
unsafe { self.spawn_at_internal(entity) }
}
/// # Safety
/// must be called on an entity that was just allocated
unsafe fn spawn_at_internal(&mut self, entity: Entity) -> EntityMut {
let archetype = self.archetypes.empty_mut();
// 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::{component::Component, entity::Entity, world::World};
///
/// #[derive(Component)]
/// struct Str(&'static str);
/// #[derive(Component)]
/// struct Num(u32);
///
/// let mut world = World::new();
/// let entities = world.spawn_batch(vec![
/// (Str("a"), Num(0)), // the first entity
/// (Str("b"), Num(1)), // 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::{component::Component, world::World};
///
/// #[derive(Component)]
/// 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::{component::Component, world::World};
///
/// #[derive(Component)]
/// 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::{component::Component, world::World};
///
/// #[derive(Component)]
/// 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::{component::Component, entity::Entity, world::World};
///
/// #[derive(Component, Debug, PartialEq)]
/// struct Position {
/// x: f32,
/// y: f32,
/// }
///
/// #[derive(Component)]
/// 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::{component::Component, entity::Entity, world::World};
///
/// #[derive(Component, PartialEq, Eq, PartialOrd, Ord, Debug)]
/// struct Order(i32);
/// #[derive(Component, PartialEq, Debug)]
/// struct Label(&'static str);
///
/// let mut world = World::new();
/// let a = world.spawn().insert_bundle((Order(2), Label("second"))).id();
/// let b = world.spawn().insert_bundle((Order(3), Label("third"))).id();
/// let c = world.spawn().insert_bundle((Order(1), Label("first"))).id();
/// let mut entities = world.query::<(Entity, &Order, &Label)>()
/// .iter(&world)
/// .collect::<Vec<_>>();
/// // Sort the query results by their `Order` 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, &Order(1), &Label("first")),
/// (a, &Order(2), &Label("second")),
/// (b, &Order(3), &Label("third")),
/// ]);
/// ```
#[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::{component::Component, entity::Entity, world::World, query::With};
///
/// #[derive(Component)]
/// struct A;
/// #[derive(Component)]
/// 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 standard starting values.
///
/// If the resource already exists, nothing happens.
///
/// The value given by the [`FromWorld::from_world`] method will be used.
/// Note that any resource with the `Default` trait automatically implements `FromWorld`,
/// and those default values will be here instead.
#[inline]
pub fn init_resource<R: Resource + FromWorld>(&mut self) {
if !self.contains_resource::<R>() {
let resource = R::from_world(self);
self.insert_resource(resource);
}
}
/// Inserts a new resource with the given `value`.
///
/// Resources are "unique" data of a given type.
/// If you insert a resource of a type that already exists,
/// you will overwrite any existing data.
#[inline]
pub fn insert_resource<R: Resource>(&mut self, value: R) {
let component_id = self.components.init_resource::<R>();
// 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 standard starting values.
///
/// If the resource already exists, nothing happens.
///
/// The value given by the [`FromWorld::from_world`] method will be used.
/// Note that any resource with the `Default` trait automatically implements `FromWorld`,
/// and those default values will be here instead.
#[inline]
pub fn init_non_send_resource<R: 'static + FromWorld>(&mut self) {
if !self.contains_resource::<R>() {
let resource = R::from_world(self);
self.insert_non_send_resource(resource);
}
}
/// Inserts a new non-send resource with the given `value`.
///
/// `NonSend` resources cannot be sent across threads,
/// and do not need the `Send + Sync` bounds.
/// Systems with `NonSend` resources are always scheduled on the main thread.
#[inline]
pub fn insert_non_send_resource<R: 'static>(&mut self, value: R) {
self.validate_non_send_access::<R>();
let component_id = self.components.init_non_send::<R>();
// SAFE: component_id just initialized and corresponds to resource of type R
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].
#[inline]
pub fn remove_resource<R: Resource>(&mut self) -> Option<R> {
// SAFE: R is Send + Sync
unsafe { self.remove_resource_unchecked() }
}
#[inline]
pub fn remove_non_send_resource<R: 'static>(&mut self) -> Option<R> {
self.validate_non_send_access::<R>();
// SAFE: we are on main thread
unsafe { self.remove_resource_unchecked() }
}
#[inline]
/// # Safety
/// Only remove `NonSend` resources from the main thread
/// as they cannot be sent across theads
#[allow(unused_unsafe)]
pub unsafe fn remove_resource_unchecked<R: 'static>(&mut self) -> Option<R> {
let component_id = self.components.get_resource_id(TypeId::of::<R>())?;
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 R is dropped
let (ptr, _) = unsafe { column.swap_remove_and_forget_unchecked(0) };
// SAFE: column is of type R
Some(unsafe { ptr.cast::<R>().read() })
}
/// Returns `true` if a resource of type `R` exists. Otherwise returns `false`.
#[inline]
pub fn contains_resource<R: 'static>(&self) -> bool {
let component_id =
if let Some(component_id) = self.components.get_resource_id(TypeId::of::<R>()) {
component_id
} else {
return false;
};
self.get_populated_resource_column(component_id).is_some()
}
pub fn is_resource_added<R: Resource>(&self) -> bool {
let component_id =
if let Some(component_id) = self.components.get_resource_id(TypeId::of::<R>()) {
component_id
} else {
return false;
};
let column = if let Some(column) = self.get_populated_resource_column(component_id) {
column
} else {
return false;
};
// 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<R: Resource>(&self) -> bool {
let component_id =
if let Some(component_id) = self.components.get_resource_id(TypeId::of::<R>()) {
component_id
} else {
return false;
};
let column = if let Some(column) = self.get_populated_resource_column(component_id) {
column
} else {
return false;
};
// 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 reference to the resource of the given type
///
/// # Panics
///
/// Panics if the resource does not exist.
/// Use [`get_resource`](World::get_resource) instead if you want to handle this case.
///
/// If you want to instead insert a value if the resource does not exist,
/// use [`get_resource_or_insert_with`](World::get_resource_or_insert_with).
#[inline]
#[track_caller]
pub fn resource<R: Resource>(&self) -> &R {
match self.get_resource() {
Some(x) => x,
None => panic!(
"Requested resource {} does not exist in the `World`.
Did you forget to add it using `app.add_resource` / `app.init_resource`?
Resources are also implicitly added via `app.add_event`,
and can be added by plugins.",
std::any::type_name::<R>()
),
}
}
/// Gets a mutable reference to the resource of the given type
///
/// # Panics
///
/// Panics if the resource does not exist.
/// Use [`get_resource_mut`](World::get_resource_mut) instead if you want to handle this case.
///
/// If you want to instead insert a value if the resource does not exist,
/// use [`get_resource_or_insert_with`](World::get_resource_or_insert_with).
#[inline]
#[track_caller]
pub fn resource_mut<R: Resource>(&mut self) -> Mut<'_, R> {
match self.get_resource_mut() {
Some(x) => x,
None => panic!(
"Requested resource {} does not exist in the `World`.
Did you forget to add it using `app.add_resource` / `app.init_resource`?
Resources are also implicitly added via `app.add_event`,
and can be added by plugins.",
std::any::type_name::<R>()
),
}
}
/// Gets a reference to the resource of the given type if it exists
#[inline]
pub fn get_resource<R: Resource>(&self) -> Option<&R> {
let component_id = self.components.get_resource_id(TypeId::of::<R>())?;
// SAFE: unique world access
unsafe { self.get_resource_with_id(component_id) }
}
/// Gets a mutable reference to the resource of the given type if it exists
#[inline]
pub fn get_resource_mut<R: Resource>(&mut self) -> Option<Mut<'_, R>> {
// SAFE: unique world access
unsafe { self.get_resource_unchecked_mut() }
}
// PERF: optimize this to avoid redundant lookups
/// Gets a mutable reference to the 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<R: Resource>(
&mut self,
func: impl FnOnce() -> R,
) -> Mut<'_, R> {
if !self.contains_resource::<R>() {
self.insert_resource(func());
}
self.resource_mut()
}
/// Gets a mutable reference to the resource of the given type, if it exists
/// Otherwise returns [None]
///
/// # 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<R: Resource>(&self) -> Option<Mut<'_, R>> {
let component_id = self.components.get_resource_id(TypeId::of::<R>())?;
self.get_resource_unchecked_mut_with_id(component_id)
}
/// Gets an immutable reference to the non-send resource of the given type, if it exists.
///
/// # Panics
///
/// Panics if the resource does not exist.
/// Use [`get_non_send_resource`](World::get_non_send_resource) instead if you want to handle this case.
#[inline]
#[track_caller]
pub fn non_send_resource<R: 'static>(&self) -> &R {
match self.get_non_send_resource() {
Some(x) => x,
None => panic!(
"Requested non-send resource {} does not exist in the `World`.
Did you forget to add it using `app.add_non_send_resource` / `app.init_non_send_resource`?
Non-send resources can also be be added by plugins.",
std::any::type_name::<R>()
),
}
}
/// Gets a mutable reference to the non-send resource of the given type, if it exists.
///
/// # Panics
///
/// Panics if the resource does not exist.
/// Use [`get_non_send_resource_mut`](World::get_non_send_resource_mut) instead if you want to handle this case.
#[inline]
#[track_caller]
pub fn non_send_resource_mut<R: 'static>(&mut self) -> Mut<'_, R> {
match self.get_non_send_resource_mut() {
Some(x) => x,
None => panic!(
"Requested non-send resource {} does not exist in the `World`.
Did you forget to add it using `app.add_non_send_resource` / `app.init_non_send_resource`?
Non-send resources can also be be added by plugins.",
std::any::type_name::<R>()
),
}
}
/// Gets a reference to the non-send resource of the given type, if it exists.
/// Otherwise returns [None]
#[inline]
pub fn get_non_send_resource<R: 'static>(&self) -> Option<&R> {
let component_id = self.components.get_resource_id(TypeId::of::<R>())?;
// 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]
#[inline]
pub fn get_non_send_resource_mut<R: 'static>(&mut self) -> Option<Mut<'_, R>> {
// 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]
///
/// # 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<R: 'static>(&self) -> Option<Mut<'_, R>> {
let component_id = self.components.get_resource_id(TypeId::of::<R>())?;
self.get_non_send_unchecked_mut_with_id(component_id)
}
/// For a given batch of ([Entity], [Bundle]) pairs, either spawns each [Entity] with the given
/// bundle (if the entity does not exist), or inserts the [Bundle] (if the entity already exists).
/// This is faster than doing equivalent operations one-by-one.
/// Returns [Ok] if all entities were successfully inserted into or spawned. Otherwise it returns an [Err]
/// with a list of entities that could not be spawned or inserted into. A "spawn or insert" operation can
/// only fail if an [Entity] is passed in with an "invalid generation" that conflicts with an existing [Entity].
///
/// # Note
/// Spawning a specific `entity` value is rarely the right choice. Most apps should use [`World::spawn_batch`].
/// This method should generally only be used for sharing entities across apps, and only when they have a scheme
/// worked out to share an ID space (which doesn't happen by default).
///
/// ```
/// use bevy_ecs::{entity::Entity, world::World, component::Component};
/// #[derive(Component)]
/// struct A(&'static str);
/// #[derive(Component, PartialEq, Debug)]
/// struct B(f32);
///
/// let mut world = World::new();
/// let e0 = world.spawn().id();
/// let e1 = world.spawn().id();
/// world.insert_or_spawn_batch(vec![
/// (e0, (A("a"), B(0.0))), // the first entity
/// (e1, (A("b"), B(1.0))), // the second entity
/// ]);
///
/// assert_eq!(world.get::<B>(e0), Some(&B(0.0)));
/// ```
pub fn insert_or_spawn_batch<I, B>(&mut self, iter: I) -> Result<(), Vec<Entity>>
where
I: IntoIterator,
I::IntoIter: Iterator<Item = (Entity, B)>,
B: Bundle,
{
self.flush();
let iter = iter.into_iter();
let change_tick = *self.change_tick.get_mut();
let bundle_info = self
.bundles
.init_info::<B>(&mut self.components, &mut self.storages);
enum SpawnOrInsert<'a, 'b> {
Spawn(BundleSpawner<'a, 'b>),
Insert(BundleInserter<'a, 'b>, ArchetypeId),
}
impl<'a, 'b> SpawnOrInsert<'a, 'b> {
fn entities(&mut self) -> &mut Entities {
match self {
SpawnOrInsert::Spawn(spawner) => spawner.entities,
SpawnOrInsert::Insert(inserter, _) => inserter.entities,
}
}
}
let mut spawn_or_insert = SpawnOrInsert::Spawn(bundle_info.get_bundle_spawner(
&mut self.entities,
&mut self.archetypes,
&mut self.components,
&mut self.storages,
change_tick,
));
let mut invalid_entities = Vec::new();
for (entity, bundle) in iter {
match spawn_or_insert
.entities()
.alloc_at_without_replacement(entity)
{
AllocAtWithoutReplacement::Exists(location) => {
match spawn_or_insert {
SpawnOrInsert::Insert(ref mut inserter, archetype)
if location.archetype_id == archetype =>
{
// SAFE: `entity` is valid, `location` matches entity, bundle matches inserter
unsafe { inserter.insert(entity, location.index, bundle) };
}
_ => {
let mut inserter = bundle_info.get_bundle_inserter(
&mut self.entities,
&mut self.archetypes,
&mut self.components,
&mut self.storages,
location.archetype_id,
change_tick,
);
// SAFE: `entity` is valid, `location` matches entity, bundle matches inserter
unsafe { inserter.insert(entity, location.index, bundle) };
spawn_or_insert =
SpawnOrInsert::Insert(inserter, location.archetype_id);
}
};
}
AllocAtWithoutReplacement::DidNotExist => {
if let SpawnOrInsert::Spawn(ref mut spawner) = spawn_or_insert {
// SAFE: `entity` is allocated (but non existent), bundle matches inserter
unsafe { spawner.spawn_non_existent(entity, bundle) };
} else {
let mut spawner = bundle_info.get_bundle_spawner(
&mut self.entities,
&mut self.archetypes,
&mut self.components,
&mut self.storages,
change_tick,
);
// SAFE: `entity` is valid, `location` matches entity, bundle matches inserter
unsafe { spawner.spawn_non_existent(entity, bundle) };
spawn_or_insert = SpawnOrInsert::Spawn(spawner);
}
}
AllocAtWithoutReplacement::ExistsWithWrongGeneration => {
invalid_entities.push(entity);
}
}
}
if invalid_entities.is_empty() {
Ok(())
} else {
Err(invalid_entities)
}
}
/// Temporarily removes the requested resource from this [`World`], then re-adds it before returning.
///
/// This enables safe simultaneous mutable access to both a resource and the rest of the [`World`].
/// For more complex access patterns, consider using [`SystemState`](crate::system::SystemState).
///
/// # Example
/// ```
/// use bevy_ecs::{component::Component, world::{World, Mut}};
/// #[derive(Component)]
/// struct A(u32);
/// #[derive(Component)]
/// 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<R: Resource, U>(&mut self, f: impl FnOnce(&mut World, Mut<R>) -> U) -> U {
let component_id = self
.components
.get_resource_id(TypeId::of::<R>())
.unwrap_or_else(|| panic!("resource does not exist: {}", std::any::type_name::<R>()));
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::<R>())
});
assert!(
!column.is_empty(),
"resource does not exist: {}",
std::any::type_name::<R>()
);
// SAFE: if a resource column exists, row 0 exists as well. caller takes ownership of
// the ptr value / drop is called when R is dropped
unsafe { column.swap_remove_and_forget_unchecked(0) }
};
// SAFE: pointer is of type T and valid to move out of
// Read the value onto the stack to avoid potential mut aliasing.
let mut value = unsafe { std::ptr::read(ptr.cast::<R>()) };
let value_mut = Mut {
value: &mut value,
ticks: Ticks {
component_ticks: &mut ticks,
last_change_tick: self.last_change_tick(),
change_tick: self.change_tick(),
},
};
let result = f(self, value_mut);
assert!(!self.contains_resource::<R>());
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::<R>()));
// Wrap the value in MaybeUninit to prepare for passing the value back into the ECS
let mut nodrop_wrapped_value = std::mem::MaybeUninit::new(value);
unsafe {
// SAFE: pointer is of type T, and valid to move out of
column.push(nodrop_wrapped_value.as_mut_ptr() as *mut _, ticks);
}
result
}
/// # Safety
/// `component_id` must be assigned to a component of type `R`
#[inline]
pub(crate) unsafe fn get_resource_with_id<R: 'static>(
&self,
component_id: ComponentId,
) -> Option<&R> {
let column = self.get_populated_resource_column(component_id)?;
Some(&*column.get_data_ptr().as_ptr().cast::<R>())
}
/// # Safety
/// `component_id` must be assigned to a component of type `R`
/// 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<R>(
&self,
component_id: ComponentId,
) -> Option<Mut<'_, R>> {
let column = self.get_populated_resource_column(component_id)?;
Some(Mut {
value: &mut *column.get_data_ptr().cast::<R>().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 `R`
#[inline]
pub(crate) unsafe fn get_non_send_with_id<R: 'static>(
&self,
component_id: ComponentId,
) -> Option<&R> {
self.validate_non_send_access::<R>();
self.get_resource_with_id(component_id)
}
/// # Safety
/// `component_id` must be assigned to a component of type `R`.
/// 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<R: 'static>(
&self,
component_id: ComponentId,
) -> Option<Mut<'_, R>> {
self.validate_non_send_access::<R>();
self.get_resource_unchecked_mut_with_id(component_id)
}
/// # Safety
/// `component_id` must be valid and correspond to a resource component of type `R`
#[inline]
unsafe fn insert_resource_with_id<R>(&mut self, component_id: ComponentId, value: R) {
let change_tick = self.change_tick();
let column = self.initialize_resource_internal(component_id);
if column.is_empty() {
let mut value = ManuallyDrop::new(value);
// SAFE: column is of type R and has been allocated above
let data = (&mut *value as *mut R).cast::<u8>();
column.push(data, ComponentTicks::new(change_tick));
} else {
// SAFE: column is of type R and has already been allocated
*column.get_data_unchecked(0).cast::<R>() = 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 `R`
#[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<R: Resource>(&mut self) -> ComponentId {
let component_id = self.components.init_resource::<R>();
// SAFE: resource initialized above
unsafe { self.initialize_resource_internal(component_id) };
component_id
}
pub(crate) fn initialize_non_send_resource<R: 'static>(&mut self) -> ComponentId {
let component_id = self.components.init_non_send::<R>();
// 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) {
assert!(
self.main_thread_validator.is_main_thread(),
"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](crate::archetype::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
// SAFE: entity is set to a valid location
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);
}
}
pub fn clear_entities(&mut self) {
self.storages.tables.clear();
self.storages.sparse_sets.clear();
self.archetypes.clear_entities();
self.entities.clear();
}
}
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()
}
}
// TODO: remove allow on lint - https://github.com/bevyengine/bevy/issues/3666
#[allow(clippy::non_send_fields_in_send_ty)]
unsafe impl Send for World {}
unsafe impl Sync for World {}
/// Creates an instance of the type this trait is implemented for
/// using data from the supplied [World].
///
/// This can be helpful for complex initialization or context-aware defaults.
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(),
}
}
}
#[cfg(test)]
mod tests {
use super::World;
use bevy_ecs_macros::Component;
use std::{
panic,
sync::{
atomic::{AtomicBool, Ordering},
Arc, Mutex,
},
};
// For bevy_ecs_macros
use crate as bevy_ecs;
type ID = u8;
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
enum DropLogItem {
Create(ID),
Drop(ID),
}
#[derive(Component)]
struct MayPanicInDrop {
drop_log: Arc<Mutex<Vec<DropLogItem>>>,
expected_panic_flag: Arc<AtomicBool>,
should_panic: bool,
id: u8,
}
impl MayPanicInDrop {
fn new(
drop_log: &Arc<Mutex<Vec<DropLogItem>>>,
expected_panic_flag: &Arc<AtomicBool>,
should_panic: bool,
id: u8,
) -> Self {
println!("creating component with id {}", id);
drop_log.lock().unwrap().push(DropLogItem::Create(id));
Self {
drop_log: Arc::clone(drop_log),
expected_panic_flag: Arc::clone(expected_panic_flag),
should_panic,
id,
}
}
}
impl Drop for MayPanicInDrop {
fn drop(&mut self) {
println!("dropping component with id {}", self.id);
{
let mut drop_log = self.drop_log.lock().unwrap();
drop_log.push(DropLogItem::Drop(self.id));
// Don't keep the mutex while panicking, or we'll poison it.
drop(drop_log);
}
if self.should_panic {
self.expected_panic_flag.store(true, Ordering::SeqCst);
panic!("testing what happens on panic inside drop");
}
}
}
struct DropTestHelper {
drop_log: Arc<Mutex<Vec<DropLogItem>>>,
/// Set to `true` right before we intentionally panic, so that if we get
/// a panic, we know if it was intended or not.
expected_panic_flag: Arc<AtomicBool>,
}
impl DropTestHelper {
pub fn new() -> Self {
Self {
drop_log: Arc::new(Mutex::new(Vec::<DropLogItem>::new())),
expected_panic_flag: Arc::new(AtomicBool::new(false)),
}
}
pub fn make_component(&self, should_panic: bool, id: ID) -> MayPanicInDrop {
MayPanicInDrop::new(&self.drop_log, &self.expected_panic_flag, should_panic, id)
}
pub fn finish(self, panic_res: std::thread::Result<()>) -> Vec<DropLogItem> {
let drop_log = Arc::try_unwrap(self.drop_log)
.unwrap()
.into_inner()
.unwrap();
let expected_panic_flag = self.expected_panic_flag.load(Ordering::SeqCst);
if !expected_panic_flag {
match panic_res {
Ok(()) => panic!("Expected a panic but it didn't happen"),
Err(e) => panic::resume_unwind(e),
}
}
drop_log
}
}
#[test]
fn panic_while_overwriting_component() {
let helper = DropTestHelper::new();
let res = panic::catch_unwind(|| {
let mut world = World::new();
world
.spawn()
.insert(helper.make_component(true, 0))
.insert(helper.make_component(false, 1));
println!("Done inserting! Dropping world...");
});
let drop_log = helper.finish(res);
assert_eq!(
&*drop_log,
[
DropLogItem::Create(0),
DropLogItem::Create(1),
DropLogItem::Drop(0),
DropLogItem::Drop(1)
]
);
}
}