mirror of
https://github.com/bevyengine/bevy
synced 2024-12-23 19:43:07 +00:00
c720e7fb5e
# Objective - remove code deprecated in 0.11 ## Changelog - remove code that was deprecated
2294 lines
86 KiB
Rust
2294 lines
86 KiB
Rust
//! Defines the [`World`] and APIs for accessing it directly.
|
|
|
|
mod entity_ref;
|
|
pub mod error;
|
|
mod spawn_batch;
|
|
pub mod unsafe_world_cell;
|
|
mod world_cell;
|
|
|
|
pub use crate::change_detection::{Mut, Ref, CHECK_TICK_THRESHOLD};
|
|
pub use entity_ref::{EntityMut, EntityRef};
|
|
pub use spawn_batch::*;
|
|
pub use world_cell::*;
|
|
|
|
use crate::{
|
|
archetype::{ArchetypeComponentId, ArchetypeId, ArchetypeRow, Archetypes},
|
|
bundle::{Bundle, BundleInserter, BundleSpawner, Bundles},
|
|
change_detection::{MutUntyped, TicksMut},
|
|
component::{Component, ComponentDescriptor, ComponentId, ComponentInfo, Components, Tick},
|
|
entity::{AllocAtWithoutReplacement, Entities, Entity, EntityLocation},
|
|
event::{Event, Events},
|
|
query::{DebugCheckedUnwrap, QueryState, ReadOnlyWorldQuery, WorldQuery},
|
|
removal_detection::RemovedComponentEvents,
|
|
schedule::{Schedule, ScheduleLabel, Schedules},
|
|
storage::{ResourceData, Storages},
|
|
system::Resource,
|
|
world::error::TryRunScheduleError,
|
|
};
|
|
use bevy_ptr::{OwningPtr, Ptr};
|
|
use bevy_utils::tracing::warn;
|
|
use std::{
|
|
any::TypeId,
|
|
fmt,
|
|
sync::atomic::{AtomicU32, Ordering},
|
|
};
|
|
mod identifier;
|
|
|
|
pub use identifier::WorldId;
|
|
|
|
use self::unsafe_world_cell::UnsafeWorldCell;
|
|
|
|
/// 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 [`Resource`]s,
|
|
/// 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.
|
|
/// See [`Resource`] for usage.
|
|
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: RemovedComponentEvents,
|
|
/// Access cache used by [`WorldCell`]. Is only accessed in the `Drop` impl of `WorldCell`.
|
|
pub(crate) archetype_component_access: ArchetypeComponentAccess,
|
|
pub(crate) change_tick: AtomicU32,
|
|
pub(crate) last_change_tick: Tick,
|
|
pub(crate) last_check_tick: Tick,
|
|
}
|
|
|
|
impl Default for World {
|
|
fn default() -> Self {
|
|
Self {
|
|
id: WorldId::new().expect("More `bevy` `World`s have been created than is supported"),
|
|
entities: Entities::new(),
|
|
components: Default::default(),
|
|
archetypes: Archetypes::new(),
|
|
storages: Default::default(),
|
|
bundles: Default::default(),
|
|
removed_components: Default::default(),
|
|
archetype_component_access: 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: Tick::new(0),
|
|
last_check_tick: Tick::new(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
|
|
}
|
|
|
|
/// Creates a new [`UnsafeWorldCell`] view with complete read+write access.
|
|
#[inline]
|
|
pub fn as_unsafe_world_cell(&mut self) -> UnsafeWorldCell<'_> {
|
|
UnsafeWorldCell::new_mutable(self)
|
|
}
|
|
|
|
/// Creates a new [`UnsafeWorldCell`] view with only read access to everything.
|
|
#[inline]
|
|
pub fn as_unsafe_world_cell_readonly(&self) -> UnsafeWorldCell<'_> {
|
|
UnsafeWorldCell::new_readonly(self)
|
|
}
|
|
|
|
/// 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 this world's [`RemovedComponentEvents`] collection
|
|
#[inline]
|
|
pub fn removed_components(&self) -> &RemovedComponentEvents {
|
|
&self.removed_components
|
|
}
|
|
|
|
/// 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)
|
|
}
|
|
|
|
/// Initializes a new [`Component`] type and returns the [`ComponentId`] created for it.
|
|
pub fn init_component<T: Component>(&mut self) -> ComponentId {
|
|
self.components.init_component::<T>(&mut self.storages)
|
|
}
|
|
|
|
/// Initializes a new [`Component`] type and returns the [`ComponentId`] created for it.
|
|
///
|
|
/// This method differs from [`World::init_component`] in that it uses a [`ComponentDescriptor`]
|
|
/// to initialize the new component type instead of statically available type information. This
|
|
/// enables the dynamic initialization of new component definitions at runtime for advanced use cases.
|
|
///
|
|
/// While the option to initialize a component from a descriptor is useful in type-erased
|
|
/// contexts, the standard `World::init_component` function should always be used instead
|
|
/// when type information is available at compile time.
|
|
pub fn init_component_with_descriptor(
|
|
&mut self,
|
|
descriptor: ComponentDescriptor,
|
|
) -> ComponentId {
|
|
self.components
|
|
.init_component_with_descriptor(&mut self.storages, descriptor)
|
|
}
|
|
|
|
/// Returns the [`ComponentId`] of the given [`Component`] type `T`.
|
|
///
|
|
/// The returned `ComponentId` is specific to the `World` instance
|
|
/// it was retrieved from and should not be used with another `World` instance.
|
|
///
|
|
/// Returns [`None`] if the `Component` type has not yet been initialized within
|
|
/// the `World` using [`World::init_component`].
|
|
///
|
|
/// ```rust
|
|
/// use bevy_ecs::prelude::*;
|
|
///
|
|
/// let mut world = World::new();
|
|
///
|
|
/// #[derive(Component)]
|
|
/// struct ComponentA;
|
|
///
|
|
/// let component_a_id = world.init_component::<ComponentA>();
|
|
///
|
|
/// assert_eq!(component_a_id, world.component_id::<ComponentA>().unwrap())
|
|
/// ```
|
|
#[inline]
|
|
pub fn component_id<T: Component>(&self) -> Option<ComponentId> {
|
|
self.components.component_id::<T>()
|
|
}
|
|
|
|
/// 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(Position { x: 0.0, y: 0.0 }).id();
|
|
/// let position = world.entity(entity).get::<Position>().unwrap();
|
|
/// assert_eq!(position.x, 0.0);
|
|
/// ```
|
|
#[inline]
|
|
#[track_caller]
|
|
pub fn entity(&self, entity: Entity) -> EntityRef {
|
|
#[inline(never)]
|
|
#[cold]
|
|
#[track_caller]
|
|
fn panic_no_entity(entity: Entity) -> ! {
|
|
panic!("Entity {entity:?} does not exist");
|
|
}
|
|
|
|
match self.get_entity(entity) {
|
|
Some(entity) => entity,
|
|
None => panic_no_entity(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(Position { x: 0.0, y: 0.0 }).id();
|
|
/// let mut entity_mut = world.entity_mut(entity);
|
|
/// let mut position = entity_mut.get_mut::<Position>().unwrap();
|
|
/// position.x = 1.0;
|
|
/// ```
|
|
#[inline]
|
|
#[track_caller]
|
|
pub fn entity_mut(&mut self, entity: Entity) -> EntityMut {
|
|
#[inline(never)]
|
|
#[cold]
|
|
#[track_caller]
|
|
fn panic_no_entity(entity: Entity) -> ! {
|
|
panic!("Entity {entity:?} does not exist");
|
|
}
|
|
|
|
match self.get_entity_mut(entity) {
|
|
Some(entity) => entity,
|
|
None => panic_no_entity(entity),
|
|
}
|
|
}
|
|
|
|
/// Returns the components of an [`Entity`](crate::entity::Entity) through [`ComponentInfo`](crate::component::ComponentInfo).
|
|
#[inline]
|
|
pub fn inspect_entity(&self, entity: Entity) -> Vec<&ComponentInfo> {
|
|
let entity_location = self
|
|
.entities()
|
|
.get(entity)
|
|
.unwrap_or_else(|| panic!("Entity {entity:?} does not exist"));
|
|
|
|
let archetype = self
|
|
.archetypes()
|
|
.get(entity_location.archetype_id)
|
|
.unwrap_or_else(|| {
|
|
panic!(
|
|
"Archetype {:?} does not exist",
|
|
entity_location.archetype_id
|
|
)
|
|
});
|
|
|
|
archetype
|
|
.components()
|
|
.filter_map(|id| self.components().get_info(id))
|
|
.collect()
|
|
}
|
|
|
|
/// 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) => {
|
|
// SAFETY: `entity` exists and `location` is that entity's location
|
|
Some(unsafe { EntityMut::new(self, entity, location) })
|
|
}
|
|
AllocAtWithoutReplacement::DidNotExist => {
|
|
// SAFETY: entity was just allocated
|
|
Some(unsafe { self.spawn_at_empty_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(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)?;
|
|
// SAFETY: if the Entity is invalid, the function returns early.
|
|
// Additionally, Entities::get(entity) returns the correct EntityLocation if the entity exists.
|
|
let entity_ref = unsafe { EntityRef::new(self, entity, location) };
|
|
Some(entity_ref)
|
|
}
|
|
|
|
/// Returns an [`Entity`] iterator of current entities.
|
|
///
|
|
/// This is useful in contexts where you only have read-only access to the [`World`].
|
|
#[inline]
|
|
pub fn iter_entities(&self) -> impl Iterator<Item = EntityRef<'_>> + '_ {
|
|
self.archetypes.iter().flat_map(|archetype| {
|
|
archetype
|
|
.entities()
|
|
.iter()
|
|
.enumerate()
|
|
.map(|(archetype_row, archetype_entity)| {
|
|
let entity = archetype_entity.entity();
|
|
let location = EntityLocation {
|
|
archetype_id: archetype.id(),
|
|
archetype_row: ArchetypeRow::new(archetype_row),
|
|
table_id: archetype.table_id(),
|
|
table_row: archetype_entity.table_row(),
|
|
};
|
|
|
|
// SAFETY: entity exists and location accurately specifies the archetype where the entity is stored
|
|
unsafe { 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(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)?;
|
|
// SAFETY: `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_empty()
|
|
/// .insert(Position { x: 0.0, y: 0.0 }) // add a single component
|
|
/// .insert((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_empty(&mut self) -> EntityMut {
|
|
self.flush();
|
|
let entity = self.entities.alloc();
|
|
// SAFETY: entity was just allocated
|
|
unsafe { self.spawn_at_empty_internal(entity) }
|
|
}
|
|
|
|
/// Spawns a new [`Entity`] with a given [`Bundle`] of [components](`Component`) and returns
|
|
/// a corresponding [`EntityMut`], which can be used to add components to the entity or
|
|
/// retrieve its id.
|
|
///
|
|
/// ```
|
|
/// use bevy_ecs::{bundle::Bundle, component::Component, world::World};
|
|
///
|
|
/// #[derive(Component)]
|
|
/// struct Position {
|
|
/// x: f32,
|
|
/// y: f32,
|
|
/// }
|
|
///
|
|
/// #[derive(Component)]
|
|
/// struct Velocity {
|
|
/// x: f32,
|
|
/// y: f32,
|
|
/// };
|
|
///
|
|
/// #[derive(Component)]
|
|
/// struct Name(&'static str);
|
|
///
|
|
/// #[derive(Bundle)]
|
|
/// struct PhysicsBundle {
|
|
/// position: Position,
|
|
/// velocity: Velocity,
|
|
/// }
|
|
///
|
|
/// let mut world = World::new();
|
|
///
|
|
/// // `spawn` can accept a single component:
|
|
/// world.spawn(Position { x: 0.0, y: 0.0 });
|
|
|
|
/// // It can also accept a tuple of components:
|
|
/// world.spawn((
|
|
/// Position { x: 0.0, y: 0.0 },
|
|
/// Velocity { x: 1.0, y: 1.0 },
|
|
/// ));
|
|
|
|
/// // Or it can accept a pre-defined Bundle of components:
|
|
/// world.spawn(PhysicsBundle {
|
|
/// position: Position { x: 2.0, y: 2.0 },
|
|
/// velocity: Velocity { x: 0.0, y: 4.0 },
|
|
/// });
|
|
///
|
|
/// let entity = world
|
|
/// // Tuples can also mix Bundles and Components
|
|
/// .spawn((
|
|
/// PhysicsBundle {
|
|
/// position: Position { x: 2.0, y: 2.0 },
|
|
/// velocity: Velocity { x: 0.0, y: 4.0 },
|
|
/// },
|
|
/// Name("Elaina Proctor"),
|
|
/// ))
|
|
/// // Calling id() will return the unique identifier for the spawned entity
|
|
/// .id();
|
|
/// let position = world.entity(entity).get::<Position>().unwrap();
|
|
/// assert_eq!(position.x, 2.0);
|
|
/// ```
|
|
pub fn spawn<B: Bundle>(&mut self, bundle: B) -> EntityMut {
|
|
self.flush();
|
|
let change_tick = self.change_tick();
|
|
let entity = self.entities.alloc();
|
|
let entity_location = {
|
|
let bundle_info = self
|
|
.bundles
|
|
.init_info::<B>(&mut self.components, &mut self.storages);
|
|
let mut spawner = bundle_info.get_bundle_spawner(
|
|
&mut self.entities,
|
|
&mut self.archetypes,
|
|
&mut self.components,
|
|
&mut self.storages,
|
|
change_tick,
|
|
);
|
|
|
|
// SAFETY: bundle's type matches `bundle_info`, entity is allocated but non-existent
|
|
unsafe { spawner.spawn_non_existent(entity, bundle) }
|
|
};
|
|
|
|
// SAFETY: entity and location are valid, as they were just created above
|
|
unsafe { EntityMut::new(self, entity, entity_location) }
|
|
}
|
|
|
|
/// # Safety
|
|
/// must be called on an entity that was just allocated
|
|
unsafe fn spawn_at_empty_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);
|
|
// SAFETY: no components are allocated by archetype.allocate() because the archetype is
|
|
// empty
|
|
let location = archetype.allocate(entity, table_row);
|
|
// SAFETY: entity index was just allocated
|
|
self.entities.set(entity.index(), 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(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(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>> {
|
|
// SAFETY:
|
|
// - `as_unsafe_world_cell` is the only thing that is borrowing world
|
|
// - `as_unsafe_world_cell` provides mutable permission to everything
|
|
// - `&mut self` ensures no other borrows on world data
|
|
unsafe { self.as_unsafe_world_cell().get_entity(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(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 {
|
|
if let Some(entity) = self.get_entity_mut(entity) {
|
|
entity.despawn();
|
|
true
|
|
} else {
|
|
warn!("error[B0003]: Could not despawn entity {:?} because it doesn't exist in this World.", entity);
|
|
false
|
|
}
|
|
}
|
|
|
|
/// Clears the internal component tracker state.
|
|
///
|
|
/// The world maintains some internal state about changed and removed components. This state
|
|
/// is used by [`RemovedComponents`] to provide access to the entities that had a specific type
|
|
/// of component removed since last tick.
|
|
///
|
|
/// The state is also used for change detection when accessing components and resources outside
|
|
/// of a system, for example via [`World::get_mut()`] or [`World::get_resource_mut()`].
|
|
///
|
|
/// By clearing this internal state, the world "forgets" about those changes, allowing a new round
|
|
/// of detection to be recorded.
|
|
///
|
|
/// When using `bevy_ecs` as part of the full Bevy engine, this method is added as a system to the
|
|
/// main app, to run during `CoreSet::Last`, so you don't need to call it manually. When using
|
|
/// `bevy_ecs` as a separate standalone crate however, you need to call this manually.
|
|
///
|
|
/// ```
|
|
/// # use bevy_ecs::prelude::*;
|
|
/// # #[derive(Component, Default)]
|
|
/// # struct Transform;
|
|
/// // a whole new world
|
|
/// let mut world = World::new();
|
|
///
|
|
/// // you changed it
|
|
/// let entity = world.spawn(Transform::default()).id();
|
|
///
|
|
/// // change is detected
|
|
/// let transform = world.get_mut::<Transform>(entity).unwrap();
|
|
/// assert!(transform.is_changed());
|
|
///
|
|
/// // update the last change tick
|
|
/// world.clear_trackers();
|
|
///
|
|
/// // change is no longer detected
|
|
/// let transform = world.get_mut::<Transform>(entity).unwrap();
|
|
/// assert!(!transform.is_changed());
|
|
/// ```
|
|
///
|
|
/// [`RemovedComponents`]: crate::removal_detection::RemovedComponents
|
|
pub fn clear_trackers(&mut self) {
|
|
self.removed_components.update();
|
|
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((Order(2), Label("second"))).id();
|
|
/// let b = world.spawn((Order(3), Label("third"))).id();
|
|
/// let c = world.spawn((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, ()> {
|
|
self.query_filtered::<Q, ()>()
|
|
}
|
|
|
|
/// 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(A).id();
|
|
/// let e2 = world.spawn((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: ReadOnlyWorldQuery>(&mut self) -> QueryState<Q, F> {
|
|
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) -> impl Iterator<Item = Entity> + '_ {
|
|
self.components
|
|
.get_id(TypeId::of::<T>())
|
|
.map(|component_id| self.removed_with_id(component_id))
|
|
.into_iter()
|
|
.flatten()
|
|
}
|
|
|
|
/// 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) -> impl Iterator<Item = Entity> + '_ {
|
|
self.removed_components
|
|
.get(component_id)
|
|
.map(|removed| removed.iter_current_update_events().cloned())
|
|
.into_iter()
|
|
.flatten()
|
|
.map(|e| e.into())
|
|
}
|
|
|
|
/// Initializes a new resource and returns the [`ComponentId`] created for it.
|
|
///
|
|
/// 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) -> ComponentId {
|
|
let component_id = self.components.init_resource::<R>();
|
|
if self
|
|
.storages
|
|
.resources
|
|
.get(component_id)
|
|
.map_or(true, |data| !data.is_present())
|
|
{
|
|
let value = R::from_world(self);
|
|
OwningPtr::make(value, |ptr| {
|
|
// SAFETY: component_id was just initialized and corresponds to resource of type R.
|
|
unsafe {
|
|
self.insert_resource_by_id(component_id, ptr);
|
|
}
|
|
});
|
|
}
|
|
component_id
|
|
}
|
|
|
|
/// 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>();
|
|
OwningPtr::make(value, |ptr| {
|
|
// SAFETY: component_id was just initialized and corresponds to resource of type R.
|
|
unsafe {
|
|
self.insert_resource_by_id(component_id, ptr);
|
|
}
|
|
});
|
|
}
|
|
|
|
/// Initializes a new non-send resource and returns the [`ComponentId`] created for it.
|
|
///
|
|
/// 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.
|
|
///
|
|
/// # Panics
|
|
///
|
|
/// Panics if called from a thread other than the main thread.
|
|
#[inline]
|
|
pub fn init_non_send_resource<R: 'static + FromWorld>(&mut self) -> ComponentId {
|
|
let component_id = self.components.init_non_send::<R>();
|
|
if self
|
|
.storages
|
|
.non_send_resources
|
|
.get(component_id)
|
|
.map_or(true, |data| !data.is_present())
|
|
{
|
|
let value = R::from_world(self);
|
|
OwningPtr::make(value, |ptr| {
|
|
// SAFETY: component_id was just initialized and corresponds to resource of type R.
|
|
unsafe {
|
|
self.insert_non_send_by_id(component_id, ptr);
|
|
}
|
|
});
|
|
}
|
|
component_id
|
|
}
|
|
|
|
/// 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.
|
|
///
|
|
/// # Panics
|
|
/// If a value is already present, this function will panic if called
|
|
/// from a different thread than where the original value was inserted from.
|
|
#[inline]
|
|
pub fn insert_non_send_resource<R: 'static>(&mut self, value: R) {
|
|
let component_id = self.components.init_non_send::<R>();
|
|
OwningPtr::make(value, |ptr| {
|
|
// SAFETY: component_id was just initialized and corresponds to resource of type R.
|
|
unsafe {
|
|
self.insert_non_send_by_id(component_id, ptr);
|
|
}
|
|
});
|
|
}
|
|
|
|
/// 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> {
|
|
let component_id = self.components.get_resource_id(TypeId::of::<R>())?;
|
|
let (ptr, _) = self.storages.resources.get_mut(component_id)?.remove()?;
|
|
// SAFETY: `component_id` was gotten via looking up the `R` type
|
|
unsafe { Some(ptr.read::<R>()) }
|
|
}
|
|
|
|
/// Removes a `!Send` resource from the world and returns it, if present.
|
|
///
|
|
/// `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.
|
|
///
|
|
/// Returns `None` if a value was not previously present.
|
|
///
|
|
/// # Panics
|
|
/// If a value is present, this function will panic if called from a different
|
|
/// thread than where the value was inserted from.
|
|
#[inline]
|
|
pub fn remove_non_send_resource<R: 'static>(&mut self) -> Option<R> {
|
|
let component_id = self.components.get_resource_id(TypeId::of::<R>())?;
|
|
let (ptr, _) = self
|
|
.storages
|
|
.non_send_resources
|
|
.get_mut(component_id)?
|
|
.remove()?;
|
|
// SAFETY: `component_id` was gotten via looking up the `R` type
|
|
unsafe { Some(ptr.read::<R>()) }
|
|
}
|
|
|
|
/// Returns `true` if a resource of type `R` exists. Otherwise returns `false`.
|
|
#[inline]
|
|
pub fn contains_resource<R: Resource>(&self) -> bool {
|
|
self.components
|
|
.get_resource_id(TypeId::of::<R>())
|
|
.and_then(|component_id| self.storages.resources.get(component_id))
|
|
.map(|info| info.is_present())
|
|
.unwrap_or(false)
|
|
}
|
|
|
|
/// Returns `true` if a resource of type `R` exists. Otherwise returns `false`.
|
|
#[inline]
|
|
pub fn contains_non_send<R: 'static>(&self) -> bool {
|
|
self.components
|
|
.get_resource_id(TypeId::of::<R>())
|
|
.and_then(|component_id| self.storages.non_send_resources.get(component_id))
|
|
.map(|info| info.is_present())
|
|
.unwrap_or(false)
|
|
}
|
|
|
|
/// Return's `true` if a resource of type `R` exists and was added since the world's
|
|
/// [`last_change_tick`](World::last_change_tick()). Otherwise, this return's `false`.
|
|
///
|
|
/// This means that:
|
|
/// - When called from an exclusive system, this will check for additions since the system last ran.
|
|
/// - When called elsewhere, this will check for additions since the last time that [`World::clear_trackers`]
|
|
/// was called.
|
|
pub fn is_resource_added<R: Resource>(&self) -> bool {
|
|
self.components
|
|
.get_resource_id(TypeId::of::<R>())
|
|
.and_then(|component_id| self.storages.resources.get(component_id)?.get_ticks())
|
|
.map(|ticks| ticks.is_added(self.last_change_tick(), self.read_change_tick()))
|
|
.unwrap_or(false)
|
|
}
|
|
|
|
/// Return's `true` if a resource of type `R` exists and was modified since the world's
|
|
/// [`last_change_tick`](World::last_change_tick()). Otherwise, this return's `false`.
|
|
///
|
|
/// This means that:
|
|
/// - When called from an exclusive system, this will check for changes since the system last ran.
|
|
/// - When called elsewhere, this will check for changes since the last time that [`World::clear_trackers`]
|
|
/// was called.
|
|
pub fn is_resource_changed<R: Resource>(&self) -> bool {
|
|
self.components
|
|
.get_resource_id(TypeId::of::<R>())
|
|
.and_then(|component_id| self.storages.resources.get(component_id)?.get_ticks())
|
|
.map(|ticks| ticks.is_changed(self.last_change_tick(), self.read_change_tick()))
|
|
.unwrap_or(false)
|
|
}
|
|
|
|
/// 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.insert_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.insert_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> {
|
|
// SAFETY:
|
|
// - `as_unsafe_world_cell_readonly` gives permission to access everything immutably
|
|
// - `&self` ensures nothing in world is borrowed immutably
|
|
unsafe { self.as_unsafe_world_cell_readonly().get_resource() }
|
|
}
|
|
|
|
/// 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>> {
|
|
// SAFETY:
|
|
// - `as_unsafe_world_cell` gives permission to access everything mutably
|
|
// - `&mut self` ensures nothing in world is borrowed
|
|
unsafe { self.as_unsafe_world_cell().get_resource_mut() }
|
|
}
|
|
|
|
/// 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> {
|
|
let change_tick = self.change_tick();
|
|
let last_change_tick = self.last_change_tick();
|
|
|
|
let component_id = self.components.init_resource::<R>();
|
|
let data = self.initialize_resource_internal(component_id);
|
|
if !data.is_present() {
|
|
OwningPtr::make(func(), |ptr| {
|
|
// SAFETY: component_id was just initialized and corresponds to resource of type R.
|
|
unsafe {
|
|
data.insert(ptr, change_tick);
|
|
}
|
|
});
|
|
}
|
|
|
|
// SAFETY: The resource must be present, as we would have inserted it if it was empty.
|
|
let data = unsafe {
|
|
data.get_mut(last_change_tick, change_tick)
|
|
.debug_checked_unwrap()
|
|
};
|
|
// SAFETY: The underlying type of the resource is `R`.
|
|
unsafe { data.with_type::<R>() }
|
|
}
|
|
|
|
/// 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.
|
|
///
|
|
/// This function will panic if it isn't called from the same thread that the resource was inserted from.
|
|
#[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.insert_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.
|
|
///
|
|
/// This function will panic if it isn't called from the same thread that the resource was inserted from.
|
|
#[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.insert_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].
|
|
///
|
|
/// # Panics
|
|
/// This function will panic if it isn't called from the same thread that the resource was inserted from.
|
|
#[inline]
|
|
pub fn get_non_send_resource<R: 'static>(&self) -> Option<&R> {
|
|
// SAFETY:
|
|
// - `as_unsafe_world_cell_readonly` gives permission to access the entire world immutably
|
|
// - `&self` ensures that there are no mutable borrows of world data
|
|
unsafe { self.as_unsafe_world_cell_readonly().get_non_send_resource() }
|
|
}
|
|
|
|
/// Gets a mutable reference to the non-send resource of the given type, if it exists.
|
|
/// Otherwise returns [None]
|
|
///
|
|
/// # Panics
|
|
/// This function will panic if it isn't called from the same thread that the resource was inserted from.
|
|
#[inline]
|
|
pub fn get_non_send_resource_mut<R: 'static>(&mut self) -> Option<Mut<'_, R>> {
|
|
// SAFETY:
|
|
// - `as_unsafe_world_cell` gives permission to access the entire world mutably
|
|
// - `&mut self` ensures that there are no borrows of world data
|
|
unsafe { self.as_unsafe_world_cell().get_non_send_resource_mut() }
|
|
}
|
|
|
|
// Shorthand helper function for getting the [`ArchetypeComponentId`] for a resource.
|
|
#[inline]
|
|
pub(crate) fn get_resource_archetype_component_id(
|
|
&self,
|
|
component_id: ComponentId,
|
|
) -> Option<ArchetypeComponentId> {
|
|
let resource = self.storages.resources.get(component_id)?;
|
|
Some(resource.id())
|
|
}
|
|
|
|
// Shorthand helper function for getting the [`ArchetypeComponentId`] for a resource.
|
|
#[inline]
|
|
pub(crate) fn get_non_send_archetype_component_id(
|
|
&self,
|
|
component_id: ComponentId,
|
|
) -> Option<ArchetypeComponentId> {
|
|
let resource = self.storages.non_send_resources.get(component_id)?;
|
|
Some(resource.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_empty().id();
|
|
/// let e1 = world.spawn_empty().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 change_tick = self.change_tick();
|
|
|
|
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 =>
|
|
{
|
|
// SAFETY: `entity` is valid, `location` matches entity, bundle matches inserter
|
|
unsafe { inserter.insert(entity, location, 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,
|
|
);
|
|
// SAFETY: `entity` is valid, `location` matches entity, bundle matches inserter
|
|
unsafe { inserter.insert(entity, location, bundle) };
|
|
spawn_or_insert =
|
|
SpawnOrInsert::Insert(inserter, location.archetype_id);
|
|
}
|
|
};
|
|
}
|
|
AllocAtWithoutReplacement::DidNotExist => {
|
|
if let SpawnOrInsert::Spawn(ref mut spawner) = spawn_or_insert {
|
|
// SAFETY: `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,
|
|
);
|
|
// SAFETY: `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`], runs custom user code,
|
|
/// then re-adds the resource 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::prelude::*;
|
|
/// #[derive(Resource)]
|
|
/// struct A(u32);
|
|
/// #[derive(Component)]
|
|
/// struct B(u32);
|
|
/// let mut world = World::new();
|
|
/// world.insert_resource(A(1));
|
|
/// let entity = world.spawn(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 last_change_tick = self.last_change_tick();
|
|
let change_tick = self.change_tick();
|
|
|
|
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) = self
|
|
.storages
|
|
.resources
|
|
.get_mut(component_id)
|
|
.and_then(|info| info.remove())
|
|
.unwrap_or_else(|| panic!("resource does not exist: {}", std::any::type_name::<R>()));
|
|
// Read the value onto the stack to avoid potential mut aliasing.
|
|
// SAFETY: `ptr` was obtained from the TypeId of `R`.
|
|
let mut value = unsafe { ptr.read::<R>() };
|
|
let value_mut = Mut {
|
|
value: &mut value,
|
|
ticks: TicksMut {
|
|
added: &mut ticks.added,
|
|
changed: &mut ticks.changed,
|
|
last_run: last_change_tick,
|
|
this_run: change_tick,
|
|
},
|
|
};
|
|
let result = f(self, value_mut);
|
|
assert!(!self.contains_resource::<R>(),
|
|
"Resource `{}` was inserted during a call to World::resource_scope.\n\
|
|
This is not allowed as the original resource is reinserted to the world after the closure is invoked.",
|
|
std::any::type_name::<R>());
|
|
|
|
OwningPtr::make(value, |ptr| {
|
|
// SAFETY: pointer is of type R
|
|
unsafe {
|
|
self.storages
|
|
.resources
|
|
.get_mut(component_id)
|
|
.map(|info| info.insert_with_ticks(ptr, ticks))
|
|
.unwrap_or_else(|| {
|
|
panic!(
|
|
"No resource of type {} exists in the World.",
|
|
std::any::type_name::<R>()
|
|
)
|
|
});
|
|
}
|
|
});
|
|
|
|
result
|
|
}
|
|
|
|
/// Sends an [`Event`].
|
|
#[inline]
|
|
pub fn send_event<E: Event>(&mut self, event: E) {
|
|
self.send_event_batch(std::iter::once(event));
|
|
}
|
|
|
|
/// Sends the default value of the [`Event`] of type `E`.
|
|
#[inline]
|
|
pub fn send_event_default<E: Event + Default>(&mut self) {
|
|
self.send_event_batch(std::iter::once(E::default()));
|
|
}
|
|
|
|
/// Sends a batch of [`Event`]s from an iterator.
|
|
#[inline]
|
|
pub fn send_event_batch<E: Event>(&mut self, events: impl IntoIterator<Item = E>) {
|
|
match self.get_resource_mut::<Events<E>>() {
|
|
Some(mut events_resource) => events_resource.extend(events),
|
|
None => bevy_utils::tracing::error!(
|
|
"Unable to send event `{}`\n\tEvent must be added to the app with `add_event()`\n\thttps://docs.rs/bevy/*/bevy/app/struct.App.html#method.add_event ",
|
|
std::any::type_name::<E>()
|
|
),
|
|
}
|
|
}
|
|
|
|
/// Inserts a new resource with the given `value`. Will replace the value if it already existed.
|
|
///
|
|
/// **You should prefer to use the typed API [`World::insert_resource`] where possible and only
|
|
/// use this in cases where the actual types are not known at compile time.**
|
|
///
|
|
/// # Safety
|
|
/// The value referenced by `value` must be valid for the given [`ComponentId`] of this world.
|
|
#[inline]
|
|
pub unsafe fn insert_resource_by_id(
|
|
&mut self,
|
|
component_id: ComponentId,
|
|
value: OwningPtr<'_>,
|
|
) {
|
|
let change_tick = self.change_tick();
|
|
|
|
// SAFETY: value is valid for component_id, ensured by caller
|
|
self.initialize_resource_internal(component_id)
|
|
.insert(value, change_tick);
|
|
}
|
|
|
|
/// Inserts a new `!Send` resource with the given `value`. Will replace the value if it already
|
|
/// existed.
|
|
///
|
|
/// **You should prefer to use the typed API [`World::insert_non_send_resource`] where possible and only
|
|
/// use this in cases where the actual types are not known at compile time.**
|
|
///
|
|
/// # Panics
|
|
/// If a value is already present, this function will panic if not called from the same
|
|
/// thread that the original value was inserted from.
|
|
///
|
|
/// # Safety
|
|
/// The value referenced by `value` must be valid for the given [`ComponentId`] of this world.
|
|
#[inline]
|
|
pub unsafe fn insert_non_send_by_id(
|
|
&mut self,
|
|
component_id: ComponentId,
|
|
value: OwningPtr<'_>,
|
|
) {
|
|
let change_tick = self.change_tick();
|
|
|
|
// SAFETY: value is valid for component_id, ensured by caller
|
|
self.initialize_non_send_internal(component_id)
|
|
.insert(value, change_tick);
|
|
}
|
|
|
|
/// # Panics
|
|
/// Panics if `component_id` is not registered as a `Send` component type in this `World`
|
|
#[inline]
|
|
fn initialize_resource_internal(
|
|
&mut self,
|
|
component_id: ComponentId,
|
|
) -> &mut ResourceData<true> {
|
|
let archetype_component_count = &mut self.archetypes.archetype_component_count;
|
|
self.storages
|
|
.resources
|
|
.initialize_with(component_id, &self.components, || {
|
|
let id = ArchetypeComponentId::new(*archetype_component_count);
|
|
*archetype_component_count += 1;
|
|
id
|
|
})
|
|
}
|
|
|
|
/// # Panics
|
|
/// panics if `component_id` is not registered in this world
|
|
#[inline]
|
|
fn initialize_non_send_internal(
|
|
&mut self,
|
|
component_id: ComponentId,
|
|
) -> &mut ResourceData<false> {
|
|
let archetype_component_count = &mut self.archetypes.archetype_component_count;
|
|
self.storages
|
|
.non_send_resources
|
|
.initialize_with(component_id, &self.components, || {
|
|
let id = ArchetypeComponentId::new(*archetype_component_count);
|
|
*archetype_component_count += 1;
|
|
id
|
|
})
|
|
}
|
|
|
|
pub(crate) fn initialize_resource<R: Resource>(&mut self) -> ComponentId {
|
|
let component_id = self.components.init_resource::<R>();
|
|
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>();
|
|
self.initialize_non_send_internal(component_id);
|
|
component_id
|
|
}
|
|
|
|
/// 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();
|
|
let table = &mut self.storages.tables[empty_archetype.table_id()];
|
|
// PERF: consider pre-allocating space for flushed entities
|
|
// SAFETY: entity is set to a valid location
|
|
unsafe {
|
|
self.entities.flush(|entity, location| {
|
|
// SAFETY: no components are allocated by archetype.allocate() because the archetype
|
|
// is empty
|
|
*location = empty_archetype.allocate(entity, table.allocate(entity));
|
|
});
|
|
}
|
|
}
|
|
|
|
/// Increments the world's current change tick and returns the old value.
|
|
#[inline]
|
|
pub fn increment_change_tick(&self) -> Tick {
|
|
let prev_tick = self.change_tick.fetch_add(1, Ordering::AcqRel);
|
|
Tick::new(prev_tick)
|
|
}
|
|
|
|
/// Reads the current change tick of this world.
|
|
///
|
|
/// If you have exclusive (`&mut`) access to the world, consider using [`change_tick()`](Self::change_tick),
|
|
/// which is more efficient since it does not require atomic synchronization.
|
|
#[inline]
|
|
pub fn read_change_tick(&self) -> Tick {
|
|
let tick = self.change_tick.load(Ordering::Acquire);
|
|
Tick::new(tick)
|
|
}
|
|
|
|
/// Reads the current change tick of this world.
|
|
///
|
|
/// This does the same thing as [`read_change_tick()`](Self::read_change_tick), only this method
|
|
/// is more efficient since it does not require atomic synchronization.
|
|
#[inline]
|
|
pub fn change_tick(&mut self) -> Tick {
|
|
let tick = *self.change_tick.get_mut();
|
|
Tick::new(tick)
|
|
}
|
|
|
|
/// When called from within an exclusive system (a [`System`] that takes `&mut World` as its first
|
|
/// parameter), this method returns the [`Tick`] indicating the last time the exclusive system was run.
|
|
///
|
|
/// Otherwise, this returns the `Tick` indicating the last time that [`World::clear_trackers`] was called.
|
|
///
|
|
/// [`System`]: crate::system::System
|
|
#[inline]
|
|
pub fn last_change_tick(&self) -> Tick {
|
|
self.last_change_tick
|
|
}
|
|
|
|
/// Iterates all component change ticks and clamps any older than [`MAX_CHANGE_AGE`](crate::change_detection::MAX_CHANGE_AGE).
|
|
/// This prevents overflow and thus prevents false positives.
|
|
///
|
|
/// **Note:** Does nothing if the [`World`] counter has not been incremented at least [`CHECK_TICK_THRESHOLD`](crate::change_detection::CHECK_TICK_THRESHOLD)
|
|
/// times since the previous pass.
|
|
// TODO: benchmark and optimize
|
|
pub fn check_change_ticks(&mut self) {
|
|
let change_tick = self.change_tick();
|
|
if change_tick.relative_to(self.last_check_tick).get() < CHECK_TICK_THRESHOLD {
|
|
return;
|
|
}
|
|
|
|
let Storages {
|
|
ref mut tables,
|
|
ref mut sparse_sets,
|
|
ref mut resources,
|
|
ref mut non_send_resources,
|
|
} = self.storages;
|
|
|
|
#[cfg(feature = "trace")]
|
|
let _span = bevy_utils::tracing::info_span!("check component ticks").entered();
|
|
tables.check_change_ticks(change_tick);
|
|
sparse_sets.check_change_ticks(change_tick);
|
|
resources.check_change_ticks(change_tick);
|
|
non_send_resources.check_change_ticks(change_tick);
|
|
|
|
if let Some(mut schedules) = self.get_resource_mut::<crate::schedule::Schedules>() {
|
|
schedules.check_change_ticks(change_tick);
|
|
}
|
|
|
|
self.last_check_tick = change_tick;
|
|
}
|
|
|
|
/// Runs both [`clear_entities`](Self::clear_entities) and [`clear_resources`](Self::clear_resources),
|
|
/// invalidating all [`Entity`] and resource fetches such as [`Res`](crate::system::Res), [`ResMut`](crate::system::ResMut)
|
|
pub fn clear_all(&mut self) {
|
|
self.clear_entities();
|
|
self.clear_resources();
|
|
}
|
|
|
|
/// Despawns all entities in this [`World`].
|
|
pub fn clear_entities(&mut self) {
|
|
self.storages.tables.clear();
|
|
self.storages.sparse_sets.clear_entities();
|
|
self.archetypes.clear_entities();
|
|
self.entities.clear();
|
|
}
|
|
|
|
/// Clears all resources in this [`World`].
|
|
///
|
|
/// **Note:** Any resource fetch to this [World] will fail unless they are re-initialized,
|
|
/// including engine-internal resources that are only initialized on app/world construction.
|
|
///
|
|
/// This can easily cause systems expecting certain resources to immediately start panicking.
|
|
/// Use with caution.
|
|
pub fn clear_resources(&mut self) {
|
|
self.storages.resources.clear();
|
|
self.storages.non_send_resources.clear();
|
|
}
|
|
}
|
|
|
|
impl World {
|
|
/// Gets a pointer to the resource with the id [`ComponentId`] if it exists.
|
|
/// The returned pointer must not be used to modify the resource, and must not be
|
|
/// dereferenced after the immutable borrow of the [`World`] ends.
|
|
///
|
|
/// **You should prefer to use the typed API [`World::get_resource`] where possible and only
|
|
/// use this in cases where the actual types are not known at compile time.**
|
|
#[inline]
|
|
pub fn get_resource_by_id(&self, component_id: ComponentId) -> Option<Ptr<'_>> {
|
|
// SAFETY:
|
|
// - `as_unsafe_world_cell_readonly` gives permission to access the whole world immutably
|
|
// - `&self` ensures there are no mutable borrows on world data
|
|
unsafe {
|
|
self.as_unsafe_world_cell_readonly()
|
|
.get_resource_by_id(component_id)
|
|
}
|
|
}
|
|
|
|
/// Gets a pointer to the resource with the id [`ComponentId`] if it exists.
|
|
/// The returned pointer may be used to modify the resource, as long as the mutable borrow
|
|
/// of the [`World`] is still valid.
|
|
///
|
|
/// **You should prefer to use the typed API [`World::get_resource_mut`] where possible and only
|
|
/// use this in cases where the actual types are not known at compile time.**
|
|
#[inline]
|
|
pub fn get_resource_mut_by_id(&mut self, component_id: ComponentId) -> Option<MutUntyped<'_>> {
|
|
// SAFETY:
|
|
// - `&mut self` ensures that all accessed data is unaliased
|
|
// - `as_unsafe_world_cell` provides mutable permission to the whole world
|
|
unsafe {
|
|
self.as_unsafe_world_cell()
|
|
.get_resource_mut_by_id(component_id)
|
|
}
|
|
}
|
|
|
|
/// Gets a `!Send` resource to the resource with the id [`ComponentId`] if it exists.
|
|
/// The returned pointer must not be used to modify the resource, and must not be
|
|
/// dereferenced after the immutable borrow of the [`World`] ends.
|
|
///
|
|
/// **You should prefer to use the typed API [`World::get_resource`] where possible and only
|
|
/// use this in cases where the actual types are not known at compile time.**
|
|
///
|
|
/// # Panics
|
|
/// This function will panic if it isn't called from the same thread that the resource was inserted from.
|
|
#[inline]
|
|
pub fn get_non_send_by_id(&self, component_id: ComponentId) -> Option<Ptr<'_>> {
|
|
// SAFETY:
|
|
// - `as_unsafe_world_cell_readonly` gives permission to access the whole world immutably
|
|
// - `&self` ensures there are no mutable borrows on world data
|
|
unsafe {
|
|
self.as_unsafe_world_cell_readonly()
|
|
.get_non_send_resource_by_id(component_id)
|
|
}
|
|
}
|
|
|
|
/// Gets a `!Send` resource to the resource with the id [`ComponentId`] if it exists.
|
|
/// The returned pointer may be used to modify the resource, as long as the mutable borrow
|
|
/// of the [`World`] is still valid.
|
|
///
|
|
/// **You should prefer to use the typed API [`World::get_resource_mut`] where possible and only
|
|
/// use this in cases where the actual types are not known at compile time.**
|
|
///
|
|
/// # Panics
|
|
/// This function will panic if it isn't called from the same thread that the resource was inserted from.
|
|
#[inline]
|
|
pub fn get_non_send_mut_by_id(&mut self, component_id: ComponentId) -> Option<MutUntyped<'_>> {
|
|
// SAFETY:
|
|
// - `&mut self` ensures that all accessed data is unaliased
|
|
// - `as_unsafe_world_cell` provides mutable permission to the whole world
|
|
unsafe {
|
|
self.as_unsafe_world_cell()
|
|
.get_non_send_resource_mut_by_id(component_id)
|
|
}
|
|
}
|
|
|
|
/// Removes the resource of a given type, if it exists. Otherwise returns [None].
|
|
///
|
|
/// **You should prefer to use the typed API [`World::remove_resource`] where possible and only
|
|
/// use this in cases where the actual types are not known at compile time.**
|
|
pub fn remove_resource_by_id(&mut self, component_id: ComponentId) -> Option<()> {
|
|
self.storages
|
|
.resources
|
|
.get_mut(component_id)?
|
|
.remove_and_drop();
|
|
Some(())
|
|
}
|
|
|
|
/// Removes the resource of a given type, if it exists. Otherwise returns [None].
|
|
///
|
|
/// **You should prefer to use the typed API [`World::remove_resource`] where possible and only
|
|
/// use this in cases where the actual types are not known at compile time.**
|
|
///
|
|
/// # Panics
|
|
/// This function will panic if it isn't called from the same thread that the resource was inserted from.
|
|
pub fn remove_non_send_by_id(&mut self, component_id: ComponentId) -> Option<()> {
|
|
self.storages
|
|
.non_send_resources
|
|
.get_mut(component_id)?
|
|
.remove_and_drop();
|
|
Some(())
|
|
}
|
|
|
|
/// Retrieves an immutable untyped reference to the given `entity`'s [Component] of the given [`ComponentId`].
|
|
/// Returns [None] if the `entity` does not have a [Component] of the given type.
|
|
///
|
|
/// **You should prefer to use the typed API [`World::get_mut`] where possible and only
|
|
/// use this in cases where the actual types are not known at compile time.**
|
|
///
|
|
/// # Panics
|
|
/// This function will panic if it isn't called from the same thread that the resource was inserted from.
|
|
#[inline]
|
|
pub fn get_by_id(&self, entity: Entity, component_id: ComponentId) -> Option<Ptr<'_>> {
|
|
// SAFETY:
|
|
// - `&self` ensures that all accessed data is not mutably aliased
|
|
// - `as_unsafe_world_cell_readonly` provides shared/readonly permission to the whole world
|
|
unsafe {
|
|
self.as_unsafe_world_cell_readonly()
|
|
.get_entity(entity)?
|
|
.get_by_id(component_id)
|
|
}
|
|
}
|
|
|
|
/// Retrieves a mutable untyped reference to the given `entity`'s [Component] of the given [`ComponentId`].
|
|
/// Returns [None] if the `entity` does not have a [Component] of the given type.
|
|
///
|
|
/// **You should prefer to use the typed API [`World::get_mut`] where possible and only
|
|
/// use this in cases where the actual types are not known at compile time.**
|
|
#[inline]
|
|
pub fn get_mut_by_id(
|
|
&mut self,
|
|
entity: Entity,
|
|
component_id: ComponentId,
|
|
) -> Option<MutUntyped<'_>> {
|
|
// SAFETY:
|
|
// - `&mut self` ensures that all accessed data is unaliased
|
|
// - `as_unsafe_world_cell` provides mutable permission to the whole world
|
|
unsafe {
|
|
self.as_unsafe_world_cell()
|
|
.get_entity(entity)?
|
|
.get_mut_by_id(component_id)
|
|
}
|
|
}
|
|
}
|
|
|
|
// Schedule-related methods
|
|
impl World {
|
|
/// Adds the specified [`Schedule`] to the world. The schedule can later be run
|
|
/// by calling [`.run_schedule(label)`](Self::run_schedule) or by directly
|
|
/// accessing the [`Schedules`] resource.
|
|
///
|
|
/// The `Schedules` resource will be initialized if it does not already exist.
|
|
pub fn add_schedule(&mut self, schedule: Schedule, label: impl ScheduleLabel) {
|
|
let mut schedules = self.get_resource_or_insert_with(Schedules::default);
|
|
schedules.insert(label, schedule);
|
|
}
|
|
|
|
/// Temporarily removes the schedule associated with `label` from the world,
|
|
/// runs user code, and finally re-adds the schedule.
|
|
/// This returns a [`TryRunScheduleError`] if there is no schedule
|
|
/// associated with `label`.
|
|
///
|
|
/// The [`Schedule`] is fetched from the [`Schedules`] resource of the world by its label,
|
|
/// and system state is cached.
|
|
///
|
|
/// For simple cases where you just need to call the schedule once,
|
|
/// consider using [`World::try_run_schedule`] instead.
|
|
/// For other use cases, see the example on [`World::schedule_scope`].
|
|
pub fn try_schedule_scope<R>(
|
|
&mut self,
|
|
label: impl AsRef<dyn ScheduleLabel>,
|
|
f: impl FnOnce(&mut World, &mut Schedule) -> R,
|
|
) -> Result<R, TryRunScheduleError> {
|
|
let label = label.as_ref();
|
|
let Some((extracted_label, mut schedule))
|
|
= self.get_resource_mut::<Schedules>().and_then(|mut s| s.remove_entry(label))
|
|
else {
|
|
return Err(TryRunScheduleError(label.dyn_clone()));
|
|
};
|
|
|
|
// TODO: move this span to Schedule::run
|
|
#[cfg(feature = "trace")]
|
|
let _span = bevy_utils::tracing::info_span!("schedule", name = ?extracted_label).entered();
|
|
let value = f(self, &mut schedule);
|
|
|
|
let old = self
|
|
.resource_mut::<Schedules>()
|
|
.insert(extracted_label, schedule);
|
|
if old.is_some() {
|
|
warn!("Schedule `{label:?}` was inserted during a call to `World::schedule_scope`: its value has been overwritten");
|
|
}
|
|
|
|
Ok(value)
|
|
}
|
|
|
|
/// Temporarily removes the schedule associated with `label` from the world,
|
|
/// runs user code, and finally re-adds the schedule.
|
|
///
|
|
/// The [`Schedule`] is fetched from the [`Schedules`] resource of the world by its label,
|
|
/// and system state is cached.
|
|
///
|
|
/// # Examples
|
|
///
|
|
/// ```
|
|
/// # use bevy_ecs::{prelude::*, schedule::ScheduleLabel};
|
|
/// # #[derive(ScheduleLabel, Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
|
/// # pub struct MySchedule;
|
|
/// # #[derive(Resource)]
|
|
/// # struct Counter(usize);
|
|
/// #
|
|
/// # let mut world = World::new();
|
|
/// # world.insert_resource(Counter(0));
|
|
/// # let mut schedule = Schedule::new();
|
|
/// # schedule.add_systems(tick_counter);
|
|
/// # world.init_resource::<Schedules>();
|
|
/// # world.add_schedule(schedule, MySchedule);
|
|
/// # fn tick_counter(mut counter: ResMut<Counter>) { counter.0 += 1; }
|
|
/// // Run the schedule five times.
|
|
/// world.schedule_scope(MySchedule, |world, schedule| {
|
|
/// for _ in 0..5 {
|
|
/// schedule.run(world);
|
|
/// }
|
|
/// });
|
|
/// # assert_eq!(world.resource::<Counter>().0, 5);
|
|
/// ```
|
|
///
|
|
/// For simple cases where you just need to call the schedule once,
|
|
/// consider using [`World::run_schedule`] instead.
|
|
///
|
|
/// # Panics
|
|
///
|
|
/// If the requested schedule does not exist.
|
|
pub fn schedule_scope<R>(
|
|
&mut self,
|
|
label: impl AsRef<dyn ScheduleLabel>,
|
|
f: impl FnOnce(&mut World, &mut Schedule) -> R,
|
|
) -> R {
|
|
self.try_schedule_scope(label, f)
|
|
.unwrap_or_else(|e| panic!("{e}"))
|
|
}
|
|
|
|
/// Attempts to run the [`Schedule`] associated with the `label` a single time,
|
|
/// and returns a [`TryRunScheduleError`] if the schedule does not exist.
|
|
///
|
|
/// The [`Schedule`] is fetched from the [`Schedules`] resource of the world by its label,
|
|
/// and system state is cached.
|
|
///
|
|
/// For simple testing use cases, call [`Schedule::run(&mut world)`](Schedule::run) instead.
|
|
pub fn try_run_schedule(
|
|
&mut self,
|
|
label: impl AsRef<dyn ScheduleLabel>,
|
|
) -> Result<(), TryRunScheduleError> {
|
|
self.try_schedule_scope(label, |world, sched| sched.run(world))
|
|
}
|
|
|
|
/// Runs the [`Schedule`] associated with the `label` a single time.
|
|
///
|
|
/// The [`Schedule`] is fetched from the [`Schedules`] resource of the world by its label,
|
|
/// and system state is cached.
|
|
///
|
|
/// For simple testing use cases, call [`Schedule::run(&mut world)`](Schedule::run) instead.
|
|
///
|
|
/// # Panics
|
|
///
|
|
/// If the requested schedule does not exist.
|
|
pub fn run_schedule(&mut self, label: impl AsRef<dyn ScheduleLabel>) {
|
|
self.schedule_scope(label, |world, sched| sched.run(world));
|
|
}
|
|
}
|
|
|
|
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.storages.resources.len())
|
|
.finish()
|
|
}
|
|
}
|
|
|
|
// SAFETY: all methods on the world ensure that non-send resources are only accessible on the main thread
|
|
unsafe impl Send for World {}
|
|
// SAFETY: all methods on the world ensure that non-send resources are only accessible on the main thread
|
|
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()
|
|
}
|
|
}
|
|
|
|
#[cfg(test)]
|
|
mod tests {
|
|
use super::{FromWorld, World};
|
|
use crate::{
|
|
change_detection::DetectChangesMut,
|
|
component::{ComponentDescriptor, ComponentInfo, StorageType},
|
|
ptr::OwningPtr,
|
|
system::Resource,
|
|
};
|
|
use bevy_ecs_macros::Component;
|
|
use bevy_utils::{HashMap, HashSet};
|
|
use std::{
|
|
any::TypeId,
|
|
panic,
|
|
sync::{
|
|
atomic::{AtomicBool, AtomicU32, 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(Resource, 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 = self.drop_log.lock().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.to_owned()
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
fn panic_while_overwriting_component() {
|
|
let helper = DropTestHelper::new();
|
|
|
|
let res = panic::catch_unwind(|| {
|
|
let mut world = World::new();
|
|
world
|
|
.spawn_empty()
|
|
.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),
|
|
]
|
|
);
|
|
}
|
|
|
|
#[derive(Resource)]
|
|
struct TestResource(u32);
|
|
|
|
#[test]
|
|
fn get_resource_by_id() {
|
|
let mut world = World::new();
|
|
world.insert_resource(TestResource(42));
|
|
let component_id = world
|
|
.components()
|
|
.get_resource_id(std::any::TypeId::of::<TestResource>())
|
|
.unwrap();
|
|
|
|
let resource = world.get_resource_by_id(component_id).unwrap();
|
|
// SAFETY: `TestResource` is the correct resource type
|
|
let resource = unsafe { resource.deref::<TestResource>() };
|
|
|
|
assert_eq!(resource.0, 42);
|
|
}
|
|
|
|
#[test]
|
|
fn get_resource_mut_by_id() {
|
|
let mut world = World::new();
|
|
world.insert_resource(TestResource(42));
|
|
let component_id = world
|
|
.components()
|
|
.get_resource_id(std::any::TypeId::of::<TestResource>())
|
|
.unwrap();
|
|
|
|
{
|
|
let mut resource = world.get_resource_mut_by_id(component_id).unwrap();
|
|
resource.set_changed();
|
|
// SAFETY: `TestResource` is the correct resource type
|
|
let resource = unsafe { resource.into_inner().deref_mut::<TestResource>() };
|
|
resource.0 = 43;
|
|
}
|
|
|
|
let resource = world.get_resource_by_id(component_id).unwrap();
|
|
// SAFETY: `TestResource` is the correct resource type
|
|
let resource = unsafe { resource.deref::<TestResource>() };
|
|
|
|
assert_eq!(resource.0, 43);
|
|
}
|
|
|
|
#[test]
|
|
fn custom_resource_with_layout() {
|
|
static DROP_COUNT: AtomicU32 = AtomicU32::new(0);
|
|
|
|
let mut world = World::new();
|
|
|
|
// SAFETY: the drop function is valid for the layout and the data will be safe to access from any thread
|
|
let descriptor = unsafe {
|
|
ComponentDescriptor::new_with_layout(
|
|
"Custom Test Component".to_string(),
|
|
StorageType::Table,
|
|
std::alloc::Layout::new::<[u8; 8]>(),
|
|
Some(|ptr| {
|
|
let data = ptr.read::<[u8; 8]>();
|
|
assert_eq!(data, [0, 1, 2, 3, 4, 5, 6, 7]);
|
|
DROP_COUNT.fetch_add(1, std::sync::atomic::Ordering::SeqCst);
|
|
}),
|
|
)
|
|
};
|
|
|
|
let component_id = world.init_component_with_descriptor(descriptor);
|
|
|
|
let value: [u8; 8] = [0, 1, 2, 3, 4, 5, 6, 7];
|
|
OwningPtr::make(value, |ptr| {
|
|
// SAFETY: value is valid for the component layout
|
|
unsafe {
|
|
world.insert_resource_by_id(component_id, ptr);
|
|
}
|
|
});
|
|
|
|
// SAFETY: [u8; 8] is the correct type for the resource
|
|
let data = unsafe {
|
|
world
|
|
.get_resource_by_id(component_id)
|
|
.unwrap()
|
|
.deref::<[u8; 8]>()
|
|
};
|
|
assert_eq!(*data, [0, 1, 2, 3, 4, 5, 6, 7]);
|
|
|
|
assert!(world.remove_resource_by_id(component_id).is_some());
|
|
|
|
assert_eq!(DROP_COUNT.load(std::sync::atomic::Ordering::SeqCst), 1);
|
|
}
|
|
|
|
#[derive(Resource)]
|
|
struct TestFromWorld(u32);
|
|
impl FromWorld for TestFromWorld {
|
|
fn from_world(world: &mut World) -> Self {
|
|
let b = world.resource::<TestResource>();
|
|
Self(b.0)
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
fn init_resource_does_not_overwrite() {
|
|
let mut world = World::new();
|
|
world.insert_resource(TestResource(0));
|
|
world.init_resource::<TestFromWorld>();
|
|
world.insert_resource(TestResource(1));
|
|
world.init_resource::<TestFromWorld>();
|
|
|
|
let resource = world.resource::<TestFromWorld>();
|
|
|
|
assert_eq!(resource.0, 0);
|
|
}
|
|
|
|
#[test]
|
|
fn init_non_send_resource_does_not_overwrite() {
|
|
let mut world = World::new();
|
|
world.insert_resource(TestResource(0));
|
|
world.init_non_send_resource::<TestFromWorld>();
|
|
world.insert_resource(TestResource(1));
|
|
world.init_non_send_resource::<TestFromWorld>();
|
|
|
|
let resource = world.non_send_resource::<TestFromWorld>();
|
|
|
|
assert_eq!(resource.0, 0);
|
|
}
|
|
|
|
#[derive(Component)]
|
|
struct Foo;
|
|
|
|
#[derive(Component)]
|
|
struct Bar;
|
|
|
|
#[derive(Component)]
|
|
struct Baz;
|
|
|
|
#[test]
|
|
fn inspect_entity_components() {
|
|
let mut world = World::new();
|
|
let ent0 = world.spawn((Foo, Bar, Baz)).id();
|
|
let ent1 = world.spawn((Foo, Bar)).id();
|
|
let ent2 = world.spawn((Bar, Baz)).id();
|
|
let ent3 = world.spawn((Foo, Baz)).id();
|
|
let ent4 = world.spawn(Foo).id();
|
|
let ent5 = world.spawn(Bar).id();
|
|
let ent6 = world.spawn(Baz).id();
|
|
|
|
fn to_type_ids(component_infos: Vec<&ComponentInfo>) -> HashSet<Option<TypeId>> {
|
|
component_infos
|
|
.into_iter()
|
|
.map(|component_info| component_info.type_id())
|
|
.collect()
|
|
}
|
|
|
|
let foo_id = TypeId::of::<Foo>();
|
|
let bar_id = TypeId::of::<Bar>();
|
|
let baz_id = TypeId::of::<Baz>();
|
|
assert_eq!(
|
|
to_type_ids(world.inspect_entity(ent0)),
|
|
[Some(foo_id), Some(bar_id), Some(baz_id)].into()
|
|
);
|
|
assert_eq!(
|
|
to_type_ids(world.inspect_entity(ent1)),
|
|
[Some(foo_id), Some(bar_id)].into()
|
|
);
|
|
assert_eq!(
|
|
to_type_ids(world.inspect_entity(ent2)),
|
|
[Some(bar_id), Some(baz_id)].into()
|
|
);
|
|
assert_eq!(
|
|
to_type_ids(world.inspect_entity(ent3)),
|
|
[Some(foo_id), Some(baz_id)].into()
|
|
);
|
|
assert_eq!(
|
|
to_type_ids(world.inspect_entity(ent4)),
|
|
[Some(foo_id)].into()
|
|
);
|
|
assert_eq!(
|
|
to_type_ids(world.inspect_entity(ent5)),
|
|
[Some(bar_id)].into()
|
|
);
|
|
assert_eq!(
|
|
to_type_ids(world.inspect_entity(ent6)),
|
|
[Some(baz_id)].into()
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn iterate_entities() {
|
|
let mut world = World::new();
|
|
let mut entity_counters = HashMap::new();
|
|
|
|
let iterate_and_count_entities = |world: &World, entity_counters: &mut HashMap<_, _>| {
|
|
entity_counters.clear();
|
|
for entity in world.iter_entities() {
|
|
let counter = entity_counters.entry(entity.id()).or_insert(0);
|
|
*counter += 1;
|
|
}
|
|
};
|
|
|
|
// Adding one entity and validating iteration
|
|
let ent0 = world.spawn((Foo, Bar, Baz)).id();
|
|
|
|
iterate_and_count_entities(&world, &mut entity_counters);
|
|
assert_eq!(entity_counters[&ent0], 1);
|
|
assert_eq!(entity_counters.len(), 1);
|
|
|
|
// Spawning three more entities and then validating iteration
|
|
let ent1 = world.spawn((Foo, Bar)).id();
|
|
let ent2 = world.spawn((Bar, Baz)).id();
|
|
let ent3 = world.spawn((Foo, Baz)).id();
|
|
|
|
iterate_and_count_entities(&world, &mut entity_counters);
|
|
|
|
assert_eq!(entity_counters[&ent0], 1);
|
|
assert_eq!(entity_counters[&ent1], 1);
|
|
assert_eq!(entity_counters[&ent2], 1);
|
|
assert_eq!(entity_counters[&ent3], 1);
|
|
assert_eq!(entity_counters.len(), 4);
|
|
|
|
// Despawning first entity and then validating the iteration
|
|
assert!(world.despawn(ent0));
|
|
|
|
iterate_and_count_entities(&world, &mut entity_counters);
|
|
|
|
assert_eq!(entity_counters[&ent1], 1);
|
|
assert_eq!(entity_counters[&ent2], 1);
|
|
assert_eq!(entity_counters[&ent3], 1);
|
|
assert_eq!(entity_counters.len(), 3);
|
|
|
|
// Spawning three more entities, despawning three and then validating the iteration
|
|
let ent4 = world.spawn(Foo).id();
|
|
let ent5 = world.spawn(Bar).id();
|
|
let ent6 = world.spawn(Baz).id();
|
|
|
|
assert!(world.despawn(ent2));
|
|
assert!(world.despawn(ent3));
|
|
assert!(world.despawn(ent4));
|
|
|
|
iterate_and_count_entities(&world, &mut entity_counters);
|
|
|
|
assert_eq!(entity_counters[&ent1], 1);
|
|
assert_eq!(entity_counters[&ent5], 1);
|
|
assert_eq!(entity_counters[&ent6], 1);
|
|
assert_eq!(entity_counters.len(), 3);
|
|
|
|
// Despawning remaining entities and then validating the iteration
|
|
assert!(world.despawn(ent1));
|
|
assert!(world.despawn(ent5));
|
|
assert!(world.despawn(ent6));
|
|
|
|
iterate_and_count_entities(&world, &mut entity_counters);
|
|
|
|
assert_eq!(entity_counters.len(), 0);
|
|
}
|
|
|
|
#[test]
|
|
fn spawn_empty_bundle() {
|
|
let mut world = World::new();
|
|
world.spawn(());
|
|
}
|
|
}
|