bevy/crates/bevy_ecs/src/system/commands/mod.rs
Carter Anderson 3c8fae2390
Improved Entity Mapping and Cloning (#17687)
Fixes #17535

Bevy's approach to handling "entity mapping" during spawning and cloning
needs some work. The addition of
[Relations](https://github.com/bevyengine/bevy/pull/17398) both
[introduced a new "duplicate entities" bug when spawning scenes in the
scene system](#17535) and made the weaknesses of the current mapping
system exceedingly clear:

1. Entity mapping requires _a ton_ of boilerplate (implement or derive
VisitEntities and VisitEntitesMut, then register / reflect MapEntities).
Knowing the incantation is challenging and if you forget to do it in
part or in whole, spawning subtly breaks.
2. Entity mapping a spawned component in scenes incurs unnecessary
overhead: look up ReflectMapEntities, create a _brand new temporary
instance_ of the component using FromReflect, map the entities in that
instance, and then apply that on top of the actual component using
reflection. We can do much better.

Additionally, while our new [Entity cloning
system](https://github.com/bevyengine/bevy/pull/16132) is already pretty
great, it has some areas we can make better:

* It doesn't expose semantic info about the clone (ex: ignore or "clone
empty"), meaning we can't key off of that in places where it would be
useful, such as scene spawning. Rather than duplicating this info across
contexts, I think it makes more sense to add that info to the clone
system, especially given that we'd like to use cloning code in some of
our spawning scenarios.
* EntityCloner is currently built in a way that prioritizes a single
entity clone
* EntityCloner's recursive cloning is built to be done "inside out" in a
parallel context (queue commands that each have a clone of
EntityCloner). By making EntityCloner the orchestrator of the clone we
can remove internal arcs, improve the clarity of the code, make
EntityCloner mutable again, and simplify the builder code.
* EntityCloner does not currently take into account entity mapping. This
is necessary to do true "bullet proof" cloning, would allow us to unify
the per-component scene spawning and cloning UX, and ultimately would
allow us to use EntityCloner in place of raw reflection for scenes like
`Scene(World)` (which would give us a nice performance boost: fewer
archetype moves, less reflection overhead).

## Solution

### Improved Entity Mapping

First, components now have first-class "entity visiting and mapping"
behavior:

```rust
#[derive(Component, Reflect)]
#[reflect(Component)]
struct Inventory {
    size: usize,
    #[entities]
    items: Vec<Entity>,
}
```

Any field with the `#[entities]` annotation will be viewable and
mappable when cloning and spawning scenes.

Compare that to what was required before!

```rust
#[derive(Component, Reflect, VisitEntities, VisitEntitiesMut)]
#[reflect(Component, MapEntities)]
struct Inventory {
    #[visit_entities(ignore)]
    size: usize,
    items: Vec<Entity>,
}
```

Additionally, for relationships `#[entities]` is implied, meaning this
"just works" in scenes and cloning:

```rust
#[derive(Component, Reflect)]
#[relationship(relationship_target = Children)]
#[reflect(Component)]
struct ChildOf(pub Entity);
```

Note that Component _does not_ implement `VisitEntities` directly.
Instead, it has `Component::visit_entities` and
`Component::visit_entities_mut` methods. This is for a few reasons:

1. We cannot implement `VisitEntities for C: Component` because that
would conflict with our impl of VisitEntities for anything that
implements `IntoIterator<Item=Entity>`. Preserving that impl is more
important from a UX perspective.
2. We should not implement `Component: VisitEntities` VisitEntities in
the Component derive, as that would increase the burden of manual
Component trait implementors.
3. Making VisitEntitiesMut directly callable for components would make
it easy to invalidate invariants defined by a component author. By
putting it in the `Component` impl, we can make it harder to call
naturally / unavailable to autocomplete using `fn
visit_entities_mut(this: &mut Self, ...)`.

`ReflectComponent::apply_or_insert` is now
`ReflectComponent::apply_or_insert_mapped`. By moving mapping inside
this impl, we remove the need to go through the reflection system to do
entity mapping, meaning we no longer need to create a clone of the
target component, map the entities in that component, and patch those
values on top. This will make spawning mapped entities _much_ faster
(The default `Component::visit_entities_mut` impl is an inlined empty
function, so it will incur no overhead for unmapped entities).

### The Bug Fix

To solve #17535, spawning code now skips entities with the new
`ComponentCloneBehavior::Ignore` and
`ComponentCloneBehavior::RelationshipTarget` variants (note
RelationshipTarget is a temporary "workaround" variant that allows
scenes to skip these components. This is a temporary workaround that can
be removed as these cases should _really_ be using EntityCloner logic,
which should be done in a followup PR. When that is done,
`ComponentCloneBehavior::RelationshipTarget` can be merged into the
normal `ComponentCloneBehavior::Custom`).

### Improved Cloning

* `Option<ComponentCloneHandler>` has been replaced by
`ComponentCloneBehavior`, which encodes additional intent and context
(ex: `Default`, `Ignore`, `Custom`, `RelationshipTarget` (this last one
is temporary)).
* Global per-world entity cloning configuration has been removed. This
felt overly complicated, increased our API surface, and felt too
generic. Each clone context can have different requirements (ex: what a
user wants in a specific system, what a scene spawner wants, etc). I'd
prefer to see how far context-specific EntityCloners get us first.
* EntityCloner's internals have been reworked to remove Arcs and make it
mutable.
* EntityCloner is now directly stored on EntityClonerBuilder,
simplifying the code somewhat
* EntityCloner's "bundle scratch" pattern has been moved into the new
BundleScratch type, improving its usability and making it usable in
other contexts (such as future cross-world cloning code). Currently this
is still private, but with some higher level safe APIs it could be used
externally for making dynamic bundles
* EntityCloner's recursive cloning behavior has been "externalized". It
is now responsible for orchestrating recursive clones, meaning it no
longer needs to be sharable/clone-able across threads / read-only.
* EntityCloner now does entity mapping during clones, like scenes do.
This gives behavior parity and also makes it more generically useful.
* `RelatonshipTarget::RECURSIVE_SPAWN` is now
`RelationshipTarget::LINKED_SPAWN`, and this field is used when cloning
relationship targets to determine if cloning should happen recursively.
The new `LINKED_SPAWN` term was picked to make it more generically
applicable across spawning and cloning scenarios.

## Next Steps

* I think we should adapt EntityCloner to support cross world cloning. I
think this PR helps set the stage for that by making the internals
slightly more generalized. We could have a CrossWorldEntityCloner that
reuses a lot of this infrastructure.
* Once we support cross world cloning, we should use EntityCloner to
spawn `Scene(World)` scenes. This would yield significant performance
benefits (no archetype moves, less reflection overhead).

---------

Co-authored-by: eugineerd <70062110+eugineerd@users.noreply.github.com>
Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
2025-02-06 22:13:41 +00:00

2592 lines
90 KiB
Rust

pub mod command;
pub mod entity_command;
pub mod error_handler;
#[cfg(feature = "std")]
mod parallel_scope;
pub use command::Command;
pub use entity_command::EntityCommand;
#[cfg(feature = "std")]
pub use parallel_scope::*;
use alloc::boxed::Box;
use core::marker::PhantomData;
use core::panic::Location;
use log::error;
use crate::{
self as bevy_ecs,
bundle::{Bundle, InsertMode},
change_detection::Mut,
component::{Component, ComponentId, Mutable},
entity::{Entities, Entity, EntityClonerBuilder},
event::Event,
observer::{Observer, TriggerTargets},
resource::Resource,
result::Error,
schedule::ScheduleLabel,
system::{
command::HandleError, entity_command::CommandWithEntity, input::SystemInput, Deferred,
IntoObserverSystem, IntoSystem, RegisteredSystem, SystemId,
},
world::{
command_queue::RawCommandQueue, unsafe_world_cell::UnsafeWorldCell, CommandQueue,
EntityWorldMut, FromWorld, World,
},
};
/// A [`Command`] queue to perform structural changes to the [`World`].
///
/// Since each command requires exclusive access to the `World`,
/// all queued commands are automatically applied in sequence
/// when the `ApplyDeferred` system runs (see [`ApplyDeferred`] documentation for more details).
///
/// Each command can be used to modify the [`World`] in arbitrary ways:
/// * spawning or despawning entities
/// * inserting components on new or existing entities
/// * inserting resources
/// * etc.
///
/// For a version of [`Commands`] that works in parallel contexts (such as
/// within [`Query::par_iter`](crate::system::Query::par_iter)) see
/// [`ParallelCommands`]
///
/// # Usage
///
/// Add `mut commands: Commands` as a function argument to your system to get a
/// copy of this struct that will be applied the next time a copy of [`ApplyDeferred`] runs.
/// Commands are almost always used as a [`SystemParam`](crate::system::SystemParam).
///
/// ```
/// # use bevy_ecs::prelude::*;
/// #
/// fn my_system(mut commands: Commands) {
/// // ...
/// }
/// # bevy_ecs::system::assert_is_system(my_system);
/// ```
///
/// # Implementing
///
/// Each built-in command is implemented as a separate method, e.g. [`Commands::spawn`].
/// In addition to the pre-defined command methods, you can add commands with any arbitrary
/// behavior using [`Commands::queue`], which accepts any type implementing [`Command`].
///
/// Since closures and other functions implement this trait automatically, this allows one-shot,
/// anonymous custom commands.
///
/// ```
/// # use bevy_ecs::prelude::*;
/// # fn foo(mut commands: Commands) {
/// // NOTE: type inference fails here, so annotations are required on the closure.
/// commands.queue(|w: &mut World| {
/// // Mutate the world however you want...
/// # todo!();
/// });
/// # }
/// ```
///
/// # Error handling
///
/// Commands can return a [`Result`](crate::result::Result), which can be passed to
/// an error handler. Error handlers are functions/closures of the form
/// `fn(&mut World, CommandError)`.
///
/// The default error handler panics. It can be configured by enabling the `configurable_error_handler`
/// cargo feature, then setting the `GLOBAL_ERROR_HANDLER`.
///
/// Alternatively, you can customize the error handler for a specific command by calling [`Commands::queue_handled`].
///
/// The [`error_handler`] module provides some simple error handlers for convenience.
///
/// [`ApplyDeferred`]: crate::schedule::ApplyDeferred
pub struct Commands<'w, 's> {
queue: InternalQueue<'s>,
entities: &'w Entities,
}
// SAFETY: All commands [`Command`] implement [`Send`]
unsafe impl Send for Commands<'_, '_> {}
// SAFETY: `Commands` never gives access to the inner commands.
unsafe impl Sync for Commands<'_, '_> {}
const _: () = {
type __StructFieldsAlias<'w, 's> = (Deferred<'s, CommandQueue>, &'w Entities);
#[doc(hidden)]
pub struct FetchState {
state: <__StructFieldsAlias<'static, 'static> as bevy_ecs::system::SystemParam>::State,
}
// SAFETY: Only reads Entities
unsafe impl bevy_ecs::system::SystemParam for Commands<'_, '_> {
type State = FetchState;
type Item<'w, 's> = Commands<'w, 's>;
fn init_state(
world: &mut World,
system_meta: &mut bevy_ecs::system::SystemMeta,
) -> Self::State {
FetchState {
state: <__StructFieldsAlias<'_, '_> as bevy_ecs::system::SystemParam>::init_state(
world,
system_meta,
),
}
}
unsafe fn new_archetype(
state: &mut Self::State,
archetype: &bevy_ecs::archetype::Archetype,
system_meta: &mut bevy_ecs::system::SystemMeta,
) {
// SAFETY: Caller guarantees the archetype is from the world used in `init_state`
unsafe {
<__StructFieldsAlias<'_, '_> as bevy_ecs::system::SystemParam>::new_archetype(
&mut state.state,
archetype,
system_meta,
);
};
}
fn apply(
state: &mut Self::State,
system_meta: &bevy_ecs::system::SystemMeta,
world: &mut World,
) {
<__StructFieldsAlias<'_, '_> as bevy_ecs::system::SystemParam>::apply(
&mut state.state,
system_meta,
world,
);
}
fn queue(
state: &mut Self::State,
system_meta: &bevy_ecs::system::SystemMeta,
world: bevy_ecs::world::DeferredWorld,
) {
<__StructFieldsAlias<'_, '_> as bevy_ecs::system::SystemParam>::queue(
&mut state.state,
system_meta,
world,
);
}
#[inline]
unsafe fn validate_param(
state: &Self::State,
system_meta: &bevy_ecs::system::SystemMeta,
world: UnsafeWorldCell,
) -> bool {
<(Deferred<CommandQueue>, &Entities) as bevy_ecs::system::SystemParam>::validate_param(
&state.state,
system_meta,
world,
)
}
#[inline]
unsafe fn get_param<'w, 's>(
state: &'s mut Self::State,
system_meta: &bevy_ecs::system::SystemMeta,
world: UnsafeWorldCell<'w>,
change_tick: bevy_ecs::component::Tick,
) -> Self::Item<'w, 's> {
let(f0, f1) = <(Deferred<'s, CommandQueue>, &'w Entities) as bevy_ecs::system::SystemParam>::get_param(&mut state.state, system_meta, world, change_tick);
Commands {
queue: InternalQueue::CommandQueue(f0),
entities: f1,
}
}
}
// SAFETY: Only reads Entities
unsafe impl<'w, 's> bevy_ecs::system::ReadOnlySystemParam for Commands<'w, 's>
where
Deferred<'s, CommandQueue>: bevy_ecs::system::ReadOnlySystemParam,
&'w Entities: bevy_ecs::system::ReadOnlySystemParam,
{
}
};
enum InternalQueue<'s> {
CommandQueue(Deferred<'s, CommandQueue>),
RawCommandQueue(RawCommandQueue),
}
impl<'w, 's> Commands<'w, 's> {
/// Returns a new `Commands` instance from a [`CommandQueue`] and a [`World`].
///
/// It is not required to call this constructor when using `Commands` as a [system parameter].
///
/// [system parameter]: crate::system::SystemParam
pub fn new(queue: &'s mut CommandQueue, world: &'w World) -> Self {
Self::new_from_entities(queue, &world.entities)
}
/// Returns a new `Commands` instance from a [`CommandQueue`] and an [`Entities`] reference.
///
/// It is not required to call this constructor when using `Commands` as a [system parameter].
///
/// [system parameter]: crate::system::SystemParam
pub fn new_from_entities(queue: &'s mut CommandQueue, entities: &'w Entities) -> Self {
Self {
queue: InternalQueue::CommandQueue(Deferred(queue)),
entities,
}
}
/// Returns a new `Commands` instance from a [`RawCommandQueue`] and an [`Entities`] reference.
///
/// This is used when constructing [`Commands`] from a [`DeferredWorld`](crate::world::DeferredWorld).
///
/// # Safety
///
/// * Caller ensures that `queue` must outlive 'w
pub(crate) unsafe fn new_raw_from_entities(
queue: RawCommandQueue,
entities: &'w Entities,
) -> Self {
Self {
queue: InternalQueue::RawCommandQueue(queue),
entities,
}
}
/// Returns a [`Commands`] with a smaller lifetime.
/// This is useful if you have `&mut Commands` but need `Commands`.
///
/// # Examples
///
/// ```
/// # use bevy_ecs::prelude::*;
/// fn my_system(mut commands: Commands) {
/// // We do our initialization in a separate function,
/// // which expects an owned `Commands`.
/// do_initialization(commands.reborrow());
///
/// // Since we only reborrowed the commands instead of moving them, we can still use them.
/// commands.spawn_empty();
/// }
/// #
/// # fn do_initialization(_: Commands) {}
/// ```
pub fn reborrow(&mut self) -> Commands<'w, '_> {
Commands {
queue: match &mut self.queue {
InternalQueue::CommandQueue(queue) => InternalQueue::CommandQueue(queue.reborrow()),
InternalQueue::RawCommandQueue(queue) => {
InternalQueue::RawCommandQueue(queue.clone())
}
},
entities: self.entities,
}
}
/// Take all commands from `other` and append them to `self`, leaving `other` empty
pub fn append(&mut self, other: &mut CommandQueue) {
match &mut self.queue {
InternalQueue::CommandQueue(queue) => queue.bytes.append(&mut other.bytes),
InternalQueue::RawCommandQueue(queue) => {
// SAFETY: Pointers in `RawCommandQueue` are never null
unsafe { queue.bytes.as_mut() }.append(&mut other.bytes);
}
}
}
/// Reserves a new empty [`Entity`] to be spawned, and returns its corresponding [`EntityCommands`].
///
/// See [`World::spawn_empty`] for more details.
///
/// # Example
///
/// ```
/// # use bevy_ecs::prelude::*;
///
/// #[derive(Component)]
/// struct Label(&'static str);
/// #[derive(Component)]
/// struct Strength(u32);
/// #[derive(Component)]
/// struct Agility(u32);
///
/// fn example_system(mut commands: Commands) {
/// // Create a new empty entity and retrieve its id.
/// let empty_entity = commands.spawn_empty().id();
///
/// // Create another empty entity, then add some component to it
/// commands.spawn_empty()
/// // adds a new component bundle to the entity
/// .insert((Strength(1), Agility(2)))
/// // adds a single component to the entity
/// .insert(Label("hello world"));
/// }
/// # bevy_ecs::system::assert_is_system(example_system);
/// ```
///
/// # See also
///
/// - [`spawn`](Self::spawn) to spawn an entity with a bundle.
/// - [`spawn_batch`](Self::spawn_batch) to spawn entities with a bundle each.
pub fn spawn_empty(&mut self) -> EntityCommands {
let entity = self.entities.reserve_entity();
EntityCommands {
entity,
commands: self.reborrow(),
}
}
/// Pushes a [`Command`] to the queue for creating a new entity with the given [`Bundle`]'s components,
/// and returns its corresponding [`EntityCommands`].
///
/// In case multiple bundles of the same [`Bundle`] type need to be spawned,
/// [`spawn_batch`](Self::spawn_batch) should be used for better performance.
///
/// # Example
///
/// ```
/// use bevy_ecs::prelude::*;
///
/// #[derive(Component)]
/// struct Component1;
/// #[derive(Component)]
/// struct Component2;
/// #[derive(Component)]
/// struct Label(&'static str);
/// #[derive(Component)]
/// struct Strength(u32);
/// #[derive(Component)]
/// struct Agility(u32);
///
/// #[derive(Bundle)]
/// struct ExampleBundle {
/// a: Component1,
/// b: Component2,
/// }
///
/// fn example_system(mut commands: Commands) {
/// // Create a new entity with a single component.
/// commands.spawn(Component1);
///
/// // Create a new entity with a component bundle.
/// commands.spawn(ExampleBundle {
/// a: Component1,
/// b: Component2,
/// });
///
/// commands
/// // Create a new entity with two components using a "tuple bundle".
/// .spawn((Component1, Component2))
/// // `spawn returns a builder, so you can insert more bundles like this:
/// .insert((Strength(1), Agility(2)))
/// // or insert single components like this:
/// .insert(Label("hello world"));
/// }
/// # bevy_ecs::system::assert_is_system(example_system);
/// ```
///
/// # See also
///
/// - [`spawn_empty`](Self::spawn_empty) to spawn an entity without any components.
/// - [`spawn_batch`](Self::spawn_batch) to spawn entities with a bundle each.
#[track_caller]
pub fn spawn<T: Bundle>(&mut self, bundle: T) -> EntityCommands {
let mut entity = self.spawn_empty();
entity.insert(bundle);
entity
}
/// Returns the [`EntityCommands`] for the requested [`Entity`].
///
/// This method does not guarantee that commands queued by the `EntityCommands`
/// will be successful, since the entity could be despawned before they are executed.
///
/// # Panics
///
/// This method panics if the requested entity does not exist.
///
/// # Example
///
/// ```
/// use bevy_ecs::prelude::*;
///
/// #[derive(Component)]
/// struct Label(&'static str);
/// #[derive(Component)]
/// struct Strength(u32);
/// #[derive(Component)]
/// struct Agility(u32);
///
/// fn example_system(mut commands: Commands) {
/// // Create a new, empty entity
/// let entity = commands.spawn_empty().id();
///
/// commands.entity(entity)
/// // adds a new component bundle to the entity
/// .insert((Strength(1), Agility(2)))
/// // adds a single component to the entity
/// .insert(Label("hello world"));
/// }
/// # bevy_ecs::system::assert_is_system(example_system);
/// ```
///
/// # See also
///
/// - [`get_entity`](Self::get_entity) for the fallible version.
#[inline]
#[track_caller]
pub fn entity(&mut self, entity: Entity) -> EntityCommands {
#[inline(never)]
#[cold]
#[track_caller]
fn panic_no_entity(entities: &Entities, entity: Entity) -> ! {
panic!(
"Attempting to create an EntityCommands for entity {entity}, which {}",
entities.entity_does_not_exist_error_details(entity)
);
}
if self.get_entity(entity).is_some() {
EntityCommands {
entity,
commands: self.reborrow(),
}
} else {
panic_no_entity(self.entities, entity)
}
}
/// Returns the [`EntityCommands`] for the requested [`Entity`], if it exists.
///
/// Returns `None` if the entity does not exist.
///
/// This method does not guarantee that commands queued by the `EntityCommands`
/// will be successful, since the entity could be despawned before they are executed.
///
/// # Example
///
/// ```
/// use bevy_ecs::prelude::*;
///
/// #[derive(Component)]
/// struct Label(&'static str);
/// fn example_system(mut commands: Commands) {
/// // Create a new, empty entity
/// let entity = commands.spawn_empty().id();
///
/// // Get the entity if it still exists, which it will in this case
/// if let Some(mut entity_commands) = commands.get_entity(entity) {
/// // adds a single component to the entity
/// entity_commands.insert(Label("hello world"));
/// }
/// }
/// # bevy_ecs::system::assert_is_system(example_system);
/// ```
///
/// # See also
///
/// - [`entity`](Self::entity) for the panicking version.
#[inline]
#[track_caller]
pub fn get_entity(&mut self, entity: Entity) -> Option<EntityCommands> {
self.entities.contains(entity).then_some(EntityCommands {
entity,
commands: self.reborrow(),
})
}
/// Pushes a [`Command`] to the queue for creating entities with a particular [`Bundle`] type.
///
/// `bundles_iter` is a type that can be converted into a [`Bundle`] iterator
/// (it can also be a collection).
///
/// This method is equivalent to iterating `bundles_iter`
/// and calling [`spawn`](Self::spawn) on each bundle,
/// but it is faster due to memory pre-allocation.
///
/// # Example
///
/// ```
/// # use bevy_ecs::prelude::*;
/// #
/// # #[derive(Component)]
/// # struct Name(String);
/// # #[derive(Component)]
/// # struct Score(u32);
/// #
/// # fn system(mut commands: Commands) {
/// commands.spawn_batch(vec![
/// (
/// Name("Alice".to_string()),
/// Score(0),
/// ),
/// (
/// Name("Bob".to_string()),
/// Score(0),
/// ),
/// ]);
/// # }
/// # bevy_ecs::system::assert_is_system(system);
/// ```
///
/// # See also
///
/// - [`spawn`](Self::spawn) to spawn an entity with a bundle.
/// - [`spawn_empty`](Self::spawn_empty) to spawn an entity without any components.
#[track_caller]
pub fn spawn_batch<I>(&mut self, bundles_iter: I)
where
I: IntoIterator + Send + Sync + 'static,
I::Item: Bundle,
{
self.queue(command::spawn_batch(bundles_iter));
}
/// Pushes a generic [`Command`] to the command queue.
///
/// If the [`Command`] returns a [`Result`], it will be handled using the [default error handler](error_handler::default).
///
/// To use a custom error handler, see [`Commands::queue_handled`].
///
/// The command can be:
/// - A custom struct that implements [`Command`].
/// - A closure or function that matches one of the following signatures:
/// - [`(&mut World)`](World)
/// - A built-in command from the [`command`] module.
///
/// # Example
///
/// ```
/// # use bevy_ecs::prelude::*;
/// #[derive(Resource, Default)]
/// struct Counter(u64);
///
/// struct AddToCounter(String);
///
/// impl Command<Result> for AddToCounter {
/// fn apply(self, world: &mut World) -> Result {
/// let mut counter = world.get_resource_or_insert_with(Counter::default);
/// let amount: u64 = self.0.parse()?;
/// counter.0 += amount;
/// Ok(())
/// }
/// }
///
/// fn add_three_to_counter_system(mut commands: Commands) {
/// commands.queue(AddToCounter("3".to_string()));
/// }
/// fn add_twenty_five_to_counter_system(mut commands: Commands) {
/// commands.queue(|world: &mut World| {
/// let mut counter = world.get_resource_or_insert_with(Counter::default);
/// counter.0 += 25;
/// });
/// }
/// # bevy_ecs::system::assert_is_system(add_three_to_counter_system);
/// # bevy_ecs::system::assert_is_system(add_twenty_five_to_counter_system);
/// ```
pub fn queue<C: Command<T> + HandleError<T>, T>(&mut self, command: C) {
self.queue_internal(command.handle_error());
}
/// Pushes a generic [`Command`] to the command queue. If the command returns a [`Result`] the given
/// `error_handler` will be used to handle error cases.
///
/// To implicitly use the default error handler, see [`Commands::queue`].
///
/// The command can be:
/// - A custom struct that implements [`Command`].
/// - A closure or function that matches one of the following signatures:
/// - [`(&mut World)`](World)
/// - [`(&mut World)`](World) `->` [`Result`]
/// - A built-in command from the [`command`] module.
///
/// # Example
///
/// ```
/// # use bevy_ecs::prelude::*;
/// # use bevy_ecs::system::error_handler;
/// #[derive(Resource, Default)]
/// struct Counter(u64);
///
/// struct AddToCounter(String);
///
/// impl Command<Result> for AddToCounter {
/// fn apply(self, world: &mut World) -> Result {
/// let mut counter = world.get_resource_or_insert_with(Counter::default);
/// let amount: u64 = self.0.parse()?;
/// counter.0 += amount;
/// Ok(())
/// }
/// }
///
/// fn add_three_to_counter_system(mut commands: Commands) {
/// commands.queue_handled(AddToCounter("3".to_string()), error_handler::warn());
/// }
/// fn add_twenty_five_to_counter_system(mut commands: Commands) {
/// commands.queue(|world: &mut World| {
/// let mut counter = world.get_resource_or_insert_with(Counter::default);
/// counter.0 += 25;
/// });
/// }
/// # bevy_ecs::system::assert_is_system(add_three_to_counter_system);
/// # bevy_ecs::system::assert_is_system(add_twenty_five_to_counter_system);
/// ```
pub fn queue_handled<C: Command<T> + HandleError<T>, T>(
&mut self,
command: C,
error_handler: fn(&mut World, Error),
) {
self.queue_internal(command.handle_error_with(error_handler));
}
fn queue_internal(&mut self, command: impl Command) {
match &mut self.queue {
InternalQueue::CommandQueue(queue) => {
queue.push(command);
}
InternalQueue::RawCommandQueue(queue) => {
// SAFETY: `RawCommandQueue` is only every constructed in `Commands::new_raw_from_entities`
// where the caller of that has ensured that `queue` outlives `self`
unsafe {
queue.push(command);
}
}
}
}
/// Pushes a [`Command`] to the queue for creating entities, if needed,
/// and for adding a bundle to each entity.
///
/// `bundles_iter` is a type that can be converted into an ([`Entity`], [`Bundle`]) iterator
/// (it can also be a collection).
///
/// When the command is applied,
/// for each (`Entity`, `Bundle`) pair in the given `bundles_iter`,
/// the `Entity` is spawned, if it does not exist already.
/// Then, the `Bundle` is added to the entity.
///
/// This method is equivalent to iterating `bundles_iter`,
/// calling [`spawn`](Self::spawn) for each bundle,
/// and passing it to [`insert`](EntityCommands::insert),
/// but it is faster due to memory pre-allocation.
///
/// # Note
///
/// Spawning a specific `entity` value is rarely the right choice. Most apps should use [`Commands::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).
#[track_caller]
pub fn insert_or_spawn_batch<I, B>(&mut self, bundles_iter: I)
where
I: IntoIterator<Item = (Entity, B)> + Send + Sync + 'static,
B: Bundle,
{
let caller = Location::caller();
self.queue(move |world: &mut World| {
if let Err(invalid_entities) = world.insert_or_spawn_batch_with_caller(
bundles_iter,
#[cfg(feature = "track_location")]
caller,
) {
error!(
"{caller}: Failed to 'insert or spawn' bundle of type {} into the following invalid entities: {:?}",
core::any::type_name::<B>(),
invalid_entities
);
}
});
}
/// Pushes a [`Command`] to the queue for adding a [`Bundle`] type to a batch of [`Entities`](Entity).
///
/// A batch can be any type that implements [`IntoIterator`] containing `(Entity, Bundle)` tuples,
/// such as a [`Vec<(Entity, Bundle)>`](alloc::vec::Vec) or an array `[(Entity, Bundle); N]`.
///
/// When the command is applied, for each `(Entity, Bundle)` pair in the given batch,
/// the `Bundle` is added to the `Entity`, overwriting any existing components shared by the `Bundle`.
///
/// This method is equivalent to iterating the batch,
/// calling [`entity`](Self::entity) for each pair,
/// and passing the bundle to [`insert`](EntityCommands::insert),
/// but it is faster due to memory pre-allocation.
///
/// # Panics
///
/// This command panics if any of the given entities do not exist.
///
/// For the non-panicking version, see [`try_insert_batch`](Self::try_insert_batch).
#[track_caller]
pub fn insert_batch<I, B>(&mut self, batch: I)
where
I: IntoIterator<Item = (Entity, B)> + Send + Sync + 'static,
B: Bundle,
{
self.queue(command::insert_batch(batch, InsertMode::Replace));
}
/// Pushes a [`Command`] to the queue for adding a [`Bundle`] type to a batch of [`Entities`](Entity).
///
/// A batch can be any type that implements [`IntoIterator`] containing `(Entity, Bundle)` tuples,
/// such as a [`Vec<(Entity, Bundle)>`](alloc::vec::Vec) or an array `[(Entity, Bundle); N]`.
///
/// When the command is applied, for each `(Entity, Bundle)` pair in the given batch,
/// the `Bundle` is added to the `Entity`, except for any components already present on the `Entity`.
///
/// This method is equivalent to iterating the batch,
/// calling [`entity`](Self::entity) for each pair,
/// and passing the bundle to [`insert_if_new`](EntityCommands::insert_if_new),
/// but it is faster due to memory pre-allocation.
///
/// # Panics
///
/// This command panics if any of the given entities do not exist.
///
/// For the non-panicking version, see [`try_insert_batch_if_new`](Self::try_insert_batch_if_new).
#[track_caller]
pub fn insert_batch_if_new<I, B>(&mut self, batch: I)
where
I: IntoIterator<Item = (Entity, B)> + Send + Sync + 'static,
B: Bundle,
{
self.queue(command::insert_batch(batch, InsertMode::Keep));
}
/// Pushes a [`Command`] to the queue for adding a [`Bundle`] type to a batch of [`Entities`](Entity).
///
/// A batch can be any type that implements [`IntoIterator`] containing `(Entity, Bundle)` tuples,
/// such as a [`Vec<(Entity, Bundle)>`](alloc::vec::Vec) or an array `[(Entity, Bundle); N]`.
///
/// When the command is applied, for each `(Entity, Bundle)` pair in the given batch,
/// the `Bundle` is added to the `Entity`, overwriting any existing components shared by the `Bundle`.
///
/// This method is equivalent to iterating the batch,
/// calling [`get_entity`](Self::get_entity) for each pair,
/// and passing the bundle to [`insert`](EntityCommands::insert),
/// but it is faster due to memory pre-allocation.
///
/// This command will send a warning if any of the given entities do not exist.
///
/// For the panicking version, see [`insert_batch`](Self::insert_batch).
#[track_caller]
pub fn try_insert_batch<I, B>(&mut self, batch: I)
where
I: IntoIterator<Item = (Entity, B)> + Send + Sync + 'static,
B: Bundle,
{
self.queue(
command::insert_batch(batch, InsertMode::Replace)
.handle_error_with(error_handler::warn()),
);
}
/// Pushes a [`Command`] to the queue for adding a [`Bundle`] type to a batch of [`Entities`](Entity).
///
/// A batch can be any type that implements [`IntoIterator`] containing `(Entity, Bundle)` tuples,
/// such as a [`Vec<(Entity, Bundle)>`](alloc::vec::Vec) or an array `[(Entity, Bundle); N]`.
///
/// When the command is applied, for each `(Entity, Bundle)` pair in the given batch,
/// the `Bundle` is added to the `Entity`, except for any components already present on the `Entity`.
///
/// This method is equivalent to iterating the batch,
/// calling [`get_entity`](Self::get_entity) for each pair,
/// and passing the bundle to [`insert_if_new`](EntityCommands::insert_if_new),
/// but it is faster due to memory pre-allocation.
///
/// This command will send a warning if any of the given entities do not exist.
///
/// For the panicking version, see [`insert_batch_if_new`](Self::insert_batch_if_new).
#[track_caller]
pub fn try_insert_batch_if_new<I, B>(&mut self, batch: I)
where
I: IntoIterator<Item = (Entity, B)> + Send + Sync + 'static,
B: Bundle,
{
self.queue(
command::insert_batch(batch, InsertMode::Keep).handle_error_with(error_handler::warn()),
);
}
/// Pushes a [`Command`] to the queue for inserting a [`Resource`] in the [`World`] with an inferred value.
///
/// The inferred value is determined by the [`FromWorld`] trait of the resource.
/// When the command is applied,
/// if the resource already exists, nothing happens.
///
/// See [`World::init_resource`] for more details.
///
/// # Example
///
/// ```
/// # use bevy_ecs::prelude::*;
/// #
/// # #[derive(Resource, Default)]
/// # struct Scoreboard {
/// # current_score: u32,
/// # high_score: u32,
/// # }
/// #
/// # fn initialize_scoreboard(mut commands: Commands) {
/// commands.init_resource::<Scoreboard>();
/// # }
/// # bevy_ecs::system::assert_is_system(initialize_scoreboard);
/// ```
#[track_caller]
pub fn init_resource<R: Resource + FromWorld>(&mut self) {
self.queue(command::init_resource::<R>());
}
/// Pushes a [`Command`] to the queue for inserting a [`Resource`] in the [`World`] with a specific value.
///
/// This will overwrite any previous value of the same resource type.
///
/// See [`World::insert_resource`] for more details.
///
/// # Example
///
/// ```
/// # use bevy_ecs::prelude::*;
/// #
/// # #[derive(Resource)]
/// # struct Scoreboard {
/// # current_score: u32,
/// # high_score: u32,
/// # }
/// #
/// # fn system(mut commands: Commands) {
/// commands.insert_resource(Scoreboard {
/// current_score: 0,
/// high_score: 0,
/// });
/// # }
/// # bevy_ecs::system::assert_is_system(system);
/// ```
#[track_caller]
pub fn insert_resource<R: Resource>(&mut self, resource: R) {
self.queue(command::insert_resource(resource));
}
/// Pushes a [`Command`] to the queue for removing a [`Resource`] from the [`World`].
///
/// See [`World::remove_resource`] for more details.
///
/// # Example
///
/// ```
/// # use bevy_ecs::prelude::*;
/// #
/// # #[derive(Resource)]
/// # struct Scoreboard {
/// # current_score: u32,
/// # high_score: u32,
/// # }
/// #
/// # fn system(mut commands: Commands) {
/// commands.remove_resource::<Scoreboard>();
/// # }
/// # bevy_ecs::system::assert_is_system(system);
/// ```
pub fn remove_resource<R: Resource>(&mut self) {
self.queue(command::remove_resource::<R>());
}
/// Runs the system corresponding to the given [`SystemId`].
/// Systems are ran in an exclusive and single threaded way.
/// Running slow systems can become a bottleneck.
///
/// Calls [`World::run_system`](World::run_system).
///
/// There is no way to get the output of a system when run as a command, because the
/// execution of the system happens later. To get the output of a system, use
/// [`World::run_system`] or [`World::run_system_with`] instead of running the system as a command.
pub fn run_system(&mut self, id: SystemId) {
self.queue(command::run_system(id).handle_error_with(error_handler::warn()));
}
/// Runs the system corresponding to the given [`SystemId`].
/// Systems are ran in an exclusive and single threaded way.
/// Running slow systems can become a bottleneck.
///
/// Calls [`World::run_system_with`](World::run_system_with).
///
/// There is no way to get the output of a system when run as a command, because the
/// execution of the system happens later. To get the output of a system, use
/// [`World::run_system`] or [`World::run_system_with`] instead of running the system as a command.
pub fn run_system_with<I>(&mut self, id: SystemId<I>, input: I::Inner<'static>)
where
I: SystemInput<Inner<'static>: Send> + 'static,
{
self.queue(command::run_system_with(id, input).handle_error_with(error_handler::warn()));
}
/// Registers a system and returns a [`SystemId`] so it can later be called by [`World::run_system`].
///
/// It's possible to register the same systems more than once, they'll be stored separately.
///
/// This is different from adding systems to a [`Schedule`](crate::schedule::Schedule),
/// because the [`SystemId`] that is returned can be used anywhere in the [`World`] to run the associated system.
/// This allows for running systems in a push-based fashion.
/// Using a [`Schedule`](crate::schedule::Schedule) is still preferred for most cases
/// due to its better performance and ability to run non-conflicting systems simultaneously.
///
/// If you want to prevent Commands from registering the same system multiple times, consider using [`Local`](crate::system::Local)
///
/// # Example
///
/// ```
/// # use bevy_ecs::{prelude::*, world::CommandQueue, system::SystemId};
///
/// #[derive(Resource)]
/// struct Counter(i32);
///
/// fn register_system(mut local_system: Local<Option<SystemId>>, mut commands: Commands) {
/// if let Some(system) = *local_system {
/// commands.run_system(system);
/// } else {
/// *local_system = Some(commands.register_system(increment_counter));
/// }
/// }
///
/// fn increment_counter(mut value: ResMut<Counter>) {
/// value.0 += 1;
/// }
///
/// # let mut world = World::default();
/// # world.insert_resource(Counter(0));
/// # let mut queue_1 = CommandQueue::default();
/// # let systemid = {
/// # let mut commands = Commands::new(&mut queue_1, &world);
/// # commands.register_system(increment_counter)
/// # };
/// # let mut queue_2 = CommandQueue::default();
/// # {
/// # let mut commands = Commands::new(&mut queue_2, &world);
/// # commands.run_system(systemid);
/// # }
/// # queue_1.append(&mut queue_2);
/// # queue_1.apply(&mut world);
/// # assert_eq!(1, world.resource::<Counter>().0);
/// # bevy_ecs::system::assert_is_system(register_system);
/// ```
pub fn register_system<I, O, M>(
&mut self,
system: impl IntoSystem<I, O, M> + 'static,
) -> SystemId<I, O>
where
I: SystemInput + Send + 'static,
O: Send + 'static,
{
let entity = self.spawn_empty().id();
let system = RegisteredSystem::<I, O>::new(Box::new(IntoSystem::into_system(system)));
self.entity(entity).insert(system);
SystemId::from_entity(entity)
}
/// Removes a system previously registered with [`Commands::register_system`] or [`World::register_system`].
///
/// See [`World::unregister_system`] for more information.
pub fn unregister_system<I, O>(&mut self, system_id: SystemId<I, O>)
where
I: SystemInput + Send + 'static,
O: Send + 'static,
{
self.queue(command::unregister_system(system_id).handle_error_with(error_handler::warn()));
}
/// Removes a system previously registered with [`World::register_system_cached`].
///
/// See [`World::unregister_system_cached`] for more information.
pub fn unregister_system_cached<
I: SystemInput + Send + 'static,
O: 'static,
M: 'static,
S: IntoSystem<I, O, M> + Send + 'static,
>(
&mut self,
system: S,
) {
self.queue(
command::unregister_system_cached(system).handle_error_with(error_handler::warn()),
);
}
/// Similar to [`Self::run_system`], but caching the [`SystemId`] in a
/// [`CachedSystemId`](crate::system::CachedSystemId) resource.
///
/// See [`World::register_system_cached`] for more information.
pub fn run_system_cached<M: 'static, S: IntoSystem<(), (), M> + Send + 'static>(
&mut self,
system: S,
) {
self.queue(command::run_system_cached(system).handle_error_with(error_handler::warn()));
}
/// Similar to [`Self::run_system_with`], but caching the [`SystemId`] in a
/// [`CachedSystemId`](crate::system::CachedSystemId) resource.
///
/// See [`World::register_system_cached`] for more information.
pub fn run_system_cached_with<I, M, S>(&mut self, system: S, input: I::Inner<'static>)
where
I: SystemInput<Inner<'static>: Send> + Send + 'static,
M: 'static,
S: IntoSystem<I, (), M> + Send + 'static,
{
self.queue(
command::run_system_cached_with(system, input).handle_error_with(error_handler::warn()),
);
}
/// Sends a "global" [`Trigger`] without any targets. This will run any [`Observer`] of the `event` that
/// isn't scoped to specific targets.
///
/// [`Trigger`]: crate::observer::Trigger
#[track_caller]
pub fn trigger(&mut self, event: impl Event) {
self.queue(command::trigger(event));
}
/// Sends a [`Trigger`] for the given targets. This will run any [`Observer`] of the `event` that
/// watches those targets.
///
/// [`Trigger`]: crate::observer::Trigger
#[track_caller]
pub fn trigger_targets(
&mut self,
event: impl Event,
targets: impl TriggerTargets + Send + Sync + 'static,
) {
self.queue(command::trigger_targets(event, targets));
}
/// Spawns an [`Observer`] and returns the [`EntityCommands`] associated
/// with the entity that stores the observer.
///
/// **Calling [`observe`](EntityCommands::observe) on the returned
/// [`EntityCommands`] will observe the observer itself, which you very
/// likely do not want.**
pub fn add_observer<E: Event, B: Bundle, M>(
&mut self,
observer: impl IntoObserverSystem<E, B, M>,
) -> EntityCommands {
self.spawn(Observer::new(observer))
}
/// Sends an arbitrary [`Event`].
///
/// This is a convenience method for sending events without requiring an [`EventWriter`].
/// ## Performance
/// Since this is a command, exclusive world access is used, which means that it will not profit from
/// system-level parallelism on supported platforms.
/// If these events are performance-critical or very frequently
/// sent, consider using a typed [`EventWriter`] instead.
///
/// [`EventWriter`]: crate::event::EventWriter
#[track_caller]
pub fn send_event<E: Event>(&mut self, event: E) -> &mut Self {
self.queue(command::send_event(event));
self
}
/// Runs the schedule corresponding to the given [`ScheduleLabel`].
///
/// Calls [`World::try_run_schedule`](World::try_run_schedule).
///
/// This will log an error if the schedule is not available to be run.
///
/// # Examples
///
/// ```
/// # use bevy_ecs::prelude::*;
/// # use bevy_ecs::schedule::ScheduleLabel;
/// #
/// # #[derive(Default, Resource)]
/// # struct Counter(u32);
/// #
/// #[derive(ScheduleLabel, Hash, Debug, PartialEq, Eq, Clone, Copy)]
/// struct FooSchedule;
///
/// # fn foo_system(mut counter: ResMut<Counter>) {
/// # counter.0 += 1;
/// # }
/// #
/// # let mut schedule = Schedule::new(FooSchedule);
/// # schedule.add_systems(foo_system);
/// #
/// # let mut world = World::default();
/// #
/// # world.init_resource::<Counter>();
/// # world.add_schedule(schedule);
/// #
/// # assert_eq!(world.resource::<Counter>().0, 0);
/// #
/// # let mut commands = world.commands();
/// commands.run_schedule(FooSchedule);
/// #
/// # world.flush();
/// #
/// # assert_eq!(world.resource::<Counter>().0, 1);
/// ```
pub fn run_schedule(&mut self, label: impl ScheduleLabel) {
self.queue(command::run_schedule(label).handle_error_with(error_handler::warn()));
}
}
/// A list of commands that will be run to modify an [`Entity`].
///
/// # Note
///
/// Most [`Commands`] (and thereby [`EntityCommands`]) are deferred: when you call the command,
/// if it requires mutable access to the [`World`] (that is, if it removes, adds, or changes something),
/// it's not executed immediately. Instead, the command is added to a "command queue."
/// The command queue is applied between [`Schedules`](bevy_ecs::schedule::Schedule), one by one,
/// so that each command can have exclusive access to the World.
///
/// # Fallible
///
/// Due to their deferred nature, an entity you're trying to change with an [`EntityCommand`] can be
/// despawned by the time the command is executed. All deferred entity commands will check if the
/// entity exists at the time of execution and will return an error if it doesn't.
///
/// # Error handling
///
/// [`EntityCommands`] can return a [`Result`](crate::result::Result), which can be passed to
/// an error handler. Error handlers are functions/closures of the form
/// `fn(&mut World, CommandError)`.
///
/// The default error handler panics. It can be configured by enabling the `configurable_error_handler`
/// cargo feature, then setting the `GLOBAL_ERROR_HANDLER`.
///
/// Alternatively, you can customize the error handler for a specific command by calling [`EntityCommands::queue_handled`].
///
/// The [`error_handler`] module provides some simple error handlers for convenience.
pub struct EntityCommands<'a> {
pub(crate) entity: Entity,
pub(crate) commands: Commands<'a, 'a>,
}
impl<'a> EntityCommands<'a> {
/// Returns the [`Entity`] id of the entity.
///
/// # Example
///
/// ```
/// # use bevy_ecs::prelude::*;
/// #
/// fn my_system(mut commands: Commands) {
/// let entity_id = commands.spawn_empty().id();
/// }
/// # bevy_ecs::system::assert_is_system(my_system);
/// ```
#[inline]
#[must_use = "Omit the .id() call if you do not need to store the `Entity` identifier."]
pub fn id(&self) -> Entity {
self.entity
}
/// Returns an [`EntityCommands`] with a smaller lifetime.
/// This is useful if you have `&mut EntityCommands` but you need `EntityCommands`.
pub fn reborrow(&mut self) -> EntityCommands {
EntityCommands {
entity: self.entity,
commands: self.commands.reborrow(),
}
}
/// Get an [`EntityEntryCommands`] for the [`Component`] `T`,
/// allowing you to modify it or insert it if it isn't already present.
///
/// See also [`insert_if_new`](Self::insert_if_new), which lets you insert a [`Bundle`] without overwriting it.
///
/// # Example
///
/// ```
/// # use bevy_ecs::prelude::*;
/// # #[derive(Resource)]
/// # struct PlayerEntity { entity: Entity }
/// #[derive(Component)]
/// struct Level(u32);
///
/// fn level_up_system(mut commands: Commands, player: Res<PlayerEntity>) {
/// commands
/// .entity(player.entity)
/// .entry::<Level>()
/// // Modify the component if it exists
/// .and_modify(|mut lvl| lvl.0 += 1)
/// // Otherwise insert a default value
/// .or_insert(Level(0));
/// }
/// # bevy_ecs::system::assert_is_system(level_up_system);
/// ```
pub fn entry<T: Component>(&mut self) -> EntityEntryCommands<T> {
EntityEntryCommands {
entity_commands: self.reborrow(),
marker: PhantomData,
}
}
/// Adds a [`Bundle`] of components to the entity.
///
/// This will overwrite any previous value(s) of the same component type.
/// See [`EntityCommands::insert_if_new`] to keep the old value instead.
///
/// # Panics
///
/// The command will panic when applied if the associated entity does not exist.
///
/// To avoid a panic in this case, use the command [`Self::try_insert`] instead.
///
/// # Example
///
/// ```
/// # use bevy_ecs::prelude::*;
/// # #[derive(Resource)]
/// # struct PlayerEntity { entity: Entity }
/// #[derive(Component)]
/// struct Health(u32);
/// #[derive(Component)]
/// struct Strength(u32);
/// #[derive(Component)]
/// struct Defense(u32);
///
/// #[derive(Bundle)]
/// struct CombatBundle {
/// health: Health,
/// strength: Strength,
/// }
///
/// fn add_combat_stats_system(mut commands: Commands, player: Res<PlayerEntity>) {
/// commands
/// .entity(player.entity)
/// // You can insert individual components:
/// .insert(Defense(10))
/// // You can also insert pre-defined bundles of components:
/// .insert(CombatBundle {
/// health: Health(100),
/// strength: Strength(40),
/// })
/// // You can also insert tuples of components and bundles.
/// // This is equivalent to the calls above:
/// .insert((
/// Defense(10),
/// CombatBundle {
/// health: Health(100),
/// strength: Strength(40),
/// },
/// ));
/// }
/// # bevy_ecs::system::assert_is_system(add_combat_stats_system);
/// ```
#[track_caller]
pub fn insert(&mut self, bundle: impl Bundle) -> &mut Self {
self.queue(entity_command::insert(bundle))
}
/// Similar to [`Self::insert`] but will only insert if the predicate returns true.
/// This is useful for chaining method calls.
///
/// # Panics
///
/// The command will panic when applied if the associated entity does not exist.
///
/// To avoid a panic in this case, use the command [`Self::try_insert_if`] instead.
///
/// # Example
///
/// ```
/// # use bevy_ecs::prelude::*;
/// # #[derive(Resource)]
/// # struct PlayerEntity { entity: Entity }
/// # impl PlayerEntity { fn is_spectator(&self) -> bool { true } }
/// #[derive(Component)]
/// struct StillLoadingStats;
/// #[derive(Component)]
/// struct Health(u32);
///
/// fn add_health_system(mut commands: Commands, player: Res<PlayerEntity>) {
/// commands
/// .entity(player.entity)
/// .insert_if(Health(10), || !player.is_spectator())
/// .remove::<StillLoadingStats>();
/// }
/// # bevy_ecs::system::assert_is_system(add_health_system);
/// ```
#[track_caller]
pub fn insert_if<F>(&mut self, bundle: impl Bundle, condition: F) -> &mut Self
where
F: FnOnce() -> bool,
{
if condition() {
self.insert(bundle)
} else {
self
}
}
/// Adds a [`Bundle`] of components to the entity without overwriting.
///
/// This is the same as [`EntityCommands::insert`], but in case of duplicate
/// components will leave the old values instead of replacing them with new
/// ones.
///
/// See also [`entry`](Self::entry), which lets you modify a [`Component`] if it's present,
/// as well as initialize it with a default value.
///
/// # Panics
///
/// The command will panic when applied if the associated entity does not exist.
///
/// To avoid a panic in this case, use the command [`Self::try_insert_if_new`] instead.
#[track_caller]
pub fn insert_if_new(&mut self, bundle: impl Bundle) -> &mut Self {
self.queue(entity_command::insert_if_new(bundle))
}
/// Adds a [`Bundle`] of components to the entity without overwriting if the
/// predicate returns true.
///
/// This is the same as [`EntityCommands::insert_if`], but in case of duplicate
/// components will leave the old values instead of replacing them with new
/// ones.
///
/// # Panics
///
/// The command will panic when applied if the associated entity does not
/// exist.
///
/// To avoid a panic in this case, use the command [`Self::try_insert_if_new`]
/// instead.
#[track_caller]
pub fn insert_if_new_and<F>(&mut self, bundle: impl Bundle, condition: F) -> &mut Self
where
F: FnOnce() -> bool,
{
if condition() {
self.insert_if_new(bundle)
} else {
self
}
}
/// Adds a dynamic component to an entity.
///
/// See [`EntityWorldMut::insert_by_id`] for more information.
///
/// # Panics
///
/// The command will panic when applied if the associated entity does not exist.
///
/// To avoid a panic in this case, use the command [`Self::try_insert_by_id`] instead.
///
/// # Safety
///
/// - [`ComponentId`] must be from the same world as `self`.
/// - `T` must have the same layout as the one passed during `component_id` creation.
#[track_caller]
pub unsafe fn insert_by_id<T: Send + 'static>(
&mut self,
component_id: ComponentId,
value: T,
) -> &mut Self {
self.queue(entity_command::insert_by_id(component_id, value))
}
/// Attempts to add a dynamic component to an entity.
///
/// See [`EntityWorldMut::insert_by_id`] for more information.
///
/// # Safety
///
/// - [`ComponentId`] must be from the same world as `self`.
/// - `T` must have the same layout as the one passed during `component_id` creation.
#[track_caller]
pub unsafe fn try_insert_by_id<T: Send + 'static>(
&mut self,
component_id: ComponentId,
value: T,
) -> &mut Self {
self.queue_handled(
entity_command::insert_by_id(component_id, value),
error_handler::silent(),
)
}
/// Tries to add a [`Bundle`] of components to the entity.
///
/// This will overwrite any previous value(s) of the same component type.
///
/// # Note
///
/// Unlike [`Self::insert`], this will not panic if the associated entity does not exist.
///
/// # Example
///
/// ```
/// # use bevy_ecs::prelude::*;
/// # #[derive(Resource)]
/// # struct PlayerEntity { entity: Entity }
/// #[derive(Component)]
/// struct Health(u32);
/// #[derive(Component)]
/// struct Strength(u32);
/// #[derive(Component)]
/// struct Defense(u32);
///
/// #[derive(Bundle)]
/// struct CombatBundle {
/// health: Health,
/// strength: Strength,
/// }
///
/// fn add_combat_stats_system(mut commands: Commands, player: Res<PlayerEntity>) {
/// commands.entity(player.entity)
/// // You can try_insert individual components:
/// .try_insert(Defense(10))
///
/// // You can also insert tuples of components:
/// .try_insert(CombatBundle {
/// health: Health(100),
/// strength: Strength(40),
/// });
///
/// // Suppose this occurs in a parallel adjacent system or process
/// commands.entity(player.entity)
/// .despawn();
///
/// commands.entity(player.entity)
/// // This will not panic nor will it add the component
/// .try_insert(Defense(5));
/// }
/// # bevy_ecs::system::assert_is_system(add_combat_stats_system);
/// ```
#[track_caller]
pub fn try_insert(&mut self, bundle: impl Bundle) -> &mut Self {
self.queue_handled(entity_command::insert(bundle), error_handler::silent())
}
/// Similar to [`Self::try_insert`] but will only try to insert if the predicate returns true.
/// This is useful for chaining method calls.
///
/// # Example
///
/// ```
/// # use bevy_ecs::prelude::*;
/// # #[derive(Resource)]
/// # struct PlayerEntity { entity: Entity }
/// # impl PlayerEntity { fn is_spectator(&self) -> bool { true } }
/// #[derive(Component)]
/// struct StillLoadingStats;
/// #[derive(Component)]
/// struct Health(u32);
///
/// fn add_health_system(mut commands: Commands, player: Res<PlayerEntity>) {
/// commands.entity(player.entity)
/// .try_insert_if(Health(10), || !player.is_spectator())
/// .remove::<StillLoadingStats>();
///
/// commands.entity(player.entity)
/// // This will not panic nor will it add the component
/// .try_insert_if(Health(5), || !player.is_spectator());
/// }
/// # bevy_ecs::system::assert_is_system(add_health_system);
/// ```
#[track_caller]
pub fn try_insert_if<F>(&mut self, bundle: impl Bundle, condition: F) -> &mut Self
where
F: FnOnce() -> bool,
{
if condition() {
self.try_insert(bundle)
} else {
self
}
}
/// Tries to add a [`Bundle`] of components to the entity without overwriting if the
/// predicate returns true.
///
/// This is the same as [`EntityCommands::try_insert_if`], but in case of duplicate
/// components will leave the old values instead of replacing them with new
/// ones.
///
/// # Note
///
/// Unlike [`Self::insert_if_new_and`], this will not panic if the associated entity does
/// not exist.
///
/// # Example
///
/// ```
/// # use bevy_ecs::prelude::*;
/// # #[derive(Resource)]
/// # struct PlayerEntity { entity: Entity }
/// # impl PlayerEntity { fn is_spectator(&self) -> bool { true } }
/// #[derive(Component)]
/// struct StillLoadingStats;
/// #[derive(Component)]
/// struct Health(u32);
///
/// fn add_health_system(mut commands: Commands, player: Res<PlayerEntity>) {
/// commands.entity(player.entity)
/// .try_insert_if(Health(10), || player.is_spectator())
/// .remove::<StillLoadingStats>();
///
/// commands.entity(player.entity)
/// // This will not panic nor will it overwrite the component
/// .try_insert_if_new_and(Health(5), || player.is_spectator());
/// }
/// # bevy_ecs::system::assert_is_system(add_health_system);
/// ```
#[track_caller]
pub fn try_insert_if_new_and<F>(&mut self, bundle: impl Bundle, condition: F) -> &mut Self
where
F: FnOnce() -> bool,
{
if condition() {
self.try_insert_if_new(bundle)
} else {
self
}
}
/// Tries to add a [`Bundle`] of components to the entity without overwriting.
///
/// This is the same as [`EntityCommands::try_insert`], but in case of duplicate
/// components will leave the old values instead of replacing them with new
/// ones.
///
/// # Note
///
/// Unlike [`Self::insert_if_new`], this will not panic if the associated entity does not exist.
#[track_caller]
pub fn try_insert_if_new(&mut self, bundle: impl Bundle) -> &mut Self {
self.queue_handled(
entity_command::insert_if_new(bundle),
error_handler::silent(),
)
}
/// Removes a [`Bundle`] of components from the entity.
///
/// # Example
///
/// ```
/// # use bevy_ecs::prelude::*;
/// #
/// # #[derive(Resource)]
/// # struct PlayerEntity { entity: Entity }
/// #[derive(Component)]
/// struct Health(u32);
/// #[derive(Component)]
/// struct Strength(u32);
/// #[derive(Component)]
/// struct Defense(u32);
///
/// #[derive(Bundle)]
/// struct CombatBundle {
/// health: Health,
/// strength: Strength,
/// }
///
/// fn remove_combat_stats_system(mut commands: Commands, player: Res<PlayerEntity>) {
/// commands
/// .entity(player.entity)
/// // You can remove individual components:
/// .remove::<Defense>()
/// // You can also remove pre-defined Bundles of components:
/// .remove::<CombatBundle>()
/// // You can also remove tuples of components and bundles.
/// // This is equivalent to the calls above:
/// .remove::<(Defense, CombatBundle)>();
/// }
/// # bevy_ecs::system::assert_is_system(remove_combat_stats_system);
/// ```
#[track_caller]
pub fn remove<T>(&mut self) -> &mut Self
where
T: Bundle,
{
self.queue_handled(entity_command::remove::<T>(), error_handler::warn())
}
/// Removes a [`Bundle`] of components from the entity.
///
/// # Note
///
/// Unlike [`Self::remove`], this will not panic if the associated entity does not exist.
///
/// # Example
///
/// ```
/// # use bevy_ecs::prelude::*;
/// #
/// # #[derive(Resource)]
/// # struct PlayerEntity { entity: Entity }
/// #[derive(Component)]
/// struct Health(u32);
/// #[derive(Component)]
/// struct Strength(u32);
/// #[derive(Component)]
/// struct Defense(u32);
///
/// #[derive(Bundle)]
/// struct CombatBundle {
/// health: Health,
/// strength: Strength,
/// }
///
/// fn remove_combat_stats_system(mut commands: Commands, player: Res<PlayerEntity>) {
/// commands
/// .entity(player.entity)
/// // You can remove individual components:
/// .try_remove::<Defense>()
/// // You can also remove pre-defined Bundles of components:
/// .try_remove::<CombatBundle>()
/// // You can also remove tuples of components and bundles.
/// // This is equivalent to the calls above:
/// .try_remove::<(Defense, CombatBundle)>();
/// }
/// # bevy_ecs::system::assert_is_system(remove_combat_stats_system);
/// ```
pub fn try_remove<T>(&mut self) -> &mut Self
where
T: Bundle,
{
self.queue_handled(entity_command::remove::<T>(), error_handler::silent())
}
/// Removes all components in the [`Bundle`] components and remove all required components for each component in the [`Bundle`] from entity.
///
/// # Example
///
/// ```
/// use bevy_ecs::prelude::*;
///
/// #[derive(Component)]
/// #[require(B)]
/// struct A;
/// #[derive(Component, Default)]
/// struct B;
///
/// #[derive(Resource)]
/// struct PlayerEntity { entity: Entity }
///
/// fn remove_with_requires_system(mut commands: Commands, player: Res<PlayerEntity>) {
/// commands
/// .entity(player.entity)
/// // Remove both A and B components from the entity, because B is required by A
/// .remove_with_requires::<A>();
/// }
/// # bevy_ecs::system::assert_is_system(remove_with_requires_system);
/// ```
#[track_caller]
pub fn remove_with_requires<T: Bundle>(&mut self) -> &mut Self {
self.queue(entity_command::remove_with_requires::<T>())
}
/// Removes a dynamic [`Component`] from the entity if it exists.
///
/// # Panics
///
/// Panics if the provided [`ComponentId`] does not exist in the [`World`].
#[track_caller]
pub fn remove_by_id(&mut self, component_id: ComponentId) -> &mut Self {
self.queue(entity_command::remove_by_id(component_id))
}
/// Removes all components associated with the entity.
#[track_caller]
pub fn clear(&mut self) -> &mut Self {
self.queue(entity_command::clear())
}
/// Despawns the entity.
///
/// This will emit a warning if the entity does not exist.
///
/// See [`World::despawn`] for more details.
///
/// # Note
///
/// This will also despawn the entities in any [`RelationshipTarget`](crate::relationship::RelationshipTarget) that is configured
/// to despawn descendants. For example, this will recursively despawn [`Children`](crate::hierarchy::Children).
///
/// # Example
///
/// ```
/// # use bevy_ecs::prelude::*;
/// #
/// # #[derive(Resource)]
/// # struct CharacterToRemove { entity: Entity }
/// #
/// fn remove_character_system(
/// mut commands: Commands,
/// character_to_remove: Res<CharacterToRemove>
/// )
/// {
/// commands.entity(character_to_remove.entity).despawn();
/// }
/// # bevy_ecs::system::assert_is_system(remove_character_system);
/// ```
#[track_caller]
pub fn despawn(&mut self) {
self.queue_handled(entity_command::despawn(), error_handler::warn());
}
/// Despawns the provided entity and its descendants.
#[deprecated(
since = "0.16.0",
note = "Use entity.despawn(), which now automatically despawns recursively."
)]
pub fn despawn_recursive(&mut self) {
self.despawn();
}
/// Despawns the entity.
///
/// This will not emit a warning if the entity does not exist, essentially performing
/// the same function as [`Self::despawn`] without emitting warnings.
///
/// # Note
///
/// This will also despawn the entities in any [`RelationshipTarget`](crate::relationship::RelationshipTarget) that are configured
/// to despawn descendants. For example, this will recursively despawn [`Children`](crate::hierarchy::Children).
pub fn try_despawn(&mut self) {
self.queue_handled(entity_command::despawn(), error_handler::silent());
}
/// Pushes an [`EntityCommand`] to the queue, which will get executed for the current [`Entity`].
///
/// If the [`EntityCommand`] returns a [`Result`], it will be handled using the [default error handler](error_handler::default).
///
/// To use a custom error handler, see [`EntityCommands::queue_handled`].
///
/// The command can be:
/// - A custom struct that implements [`EntityCommand`].
/// - A closure or function that matches the following signature:
/// - [`(EntityWorldMut)`](EntityWorldMut)
/// - [`(EntityWorldMut)`](EntityWorldMut) `->` [`Result`]
/// - A built-in command from the [`entity_command`] module.
///
/// # Examples
///
/// ```
/// # use bevy_ecs::prelude::*;
/// # fn my_system(mut commands: Commands) {
/// commands
/// .spawn_empty()
/// // Closures with this signature implement `EntityCommand`.
/// .queue(|entity: EntityWorldMut| {
/// println!("Executed an EntityCommand for {}", entity.id());
/// });
/// # }
/// # bevy_ecs::system::assert_is_system(my_system);
/// ```
pub fn queue<C: EntityCommand<T> + CommandWithEntity<M>, T, M>(
&mut self,
command: C,
) -> &mut Self {
self.commands.queue(command.with_entity(self.entity));
self
}
/// Pushes an [`EntityCommand`] to the queue, which will get executed for the current [`Entity`].
/// If the command returns a [`Result`] the given `error_handler` will be used to handle error cases.
///
/// To implicitly use the default error handler, see [`EntityCommands::queue`].
///
/// The command can be:
/// - A custom struct that implements [`EntityCommand`].
/// - A closure or function that matches the following signature:
/// - [`(EntityWorldMut)`](EntityWorldMut)
/// - [`(EntityWorldMut)`](EntityWorldMut) `->` [`Result`]
/// - A built-in command from the [`entity_command`] module.
///
/// # Examples
///
/// ```
/// # use bevy_ecs::prelude::*;
/// # use bevy_ecs::system::error_handler;
/// # fn my_system(mut commands: Commands) {
/// commands
/// .spawn_empty()
/// // Closures with this signature implement `EntityCommand`.
/// .queue_handled(
/// |entity: EntityWorldMut| -> Result {
/// let value: usize = "100".parse()?;
/// println!("Successfully parsed the value {} for entity {}", value, entity.id());
/// Ok(())
/// },
/// error_handler::warn()
/// );
/// # }
/// # bevy_ecs::system::assert_is_system(my_system);
/// ```
pub fn queue_handled<C: EntityCommand<T> + CommandWithEntity<M>, T, M>(
&mut self,
command: C,
error_handler: fn(&mut World, Error),
) -> &mut Self {
self.commands
.queue_handled(command.with_entity(self.entity), error_handler);
self
}
/// Removes all components except the given [`Bundle`] from the entity.
///
/// This can also be used to remove all the components from the entity by passing it an empty Bundle.
///
/// # Example
///
/// ```
/// # use bevy_ecs::prelude::*;
/// #
/// # #[derive(Resource)]
/// # struct PlayerEntity { entity: Entity }
/// #[derive(Component)]
/// struct Health(u32);
/// #[derive(Component)]
/// struct Strength(u32);
/// #[derive(Component)]
/// struct Defense(u32);
///
/// #[derive(Bundle)]
/// struct CombatBundle {
/// health: Health,
/// strength: Strength,
/// }
///
/// fn remove_combat_stats_system(mut commands: Commands, player: Res<PlayerEntity>) {
/// commands
/// .entity(player.entity)
/// // You can retain a pre-defined Bundle of components,
/// // with this removing only the Defense component
/// .retain::<CombatBundle>()
/// // You can also retain only a single component
/// .retain::<Health>()
/// // And you can remove all the components by passing in an empty Bundle
/// .retain::<()>();
/// }
/// # bevy_ecs::system::assert_is_system(remove_combat_stats_system);
/// ```
#[track_caller]
pub fn retain<T>(&mut self) -> &mut Self
where
T: Bundle,
{
self.queue(entity_command::retain::<T>())
}
/// Logs the components of the entity at the info level.
///
/// # Panics
///
/// The command will panic when applied if the associated entity does not exist.
pub fn log_components(&mut self) -> &mut Self {
self.queue(entity_command::log_components())
}
/// Returns the underlying [`Commands`].
pub fn commands(&mut self) -> Commands {
self.commands.reborrow()
}
/// Returns a mutable reference to the underlying [`Commands`].
pub fn commands_mut(&mut self) -> &mut Commands<'a, 'a> {
&mut self.commands
}
/// Sends a [`Trigger`] targeting this entity. This will run any [`Observer`] of the `event` that
/// watches this entity.
///
/// [`Trigger`]: crate::observer::Trigger
pub fn trigger(&mut self, event: impl Event) -> &mut Self {
self.commands.trigger_targets(event, self.entity);
self
}
/// Creates an [`Observer`] listening for events of type `E` targeting this entity.
pub fn observe<E: Event, B: Bundle, M>(
&mut self,
observer: impl IntoObserverSystem<E, B, M>,
) -> &mut Self {
self.queue(entity_command::observe(observer))
}
/// Clones parts of an entity (components, observers, etc.) onto another entity,
/// configured through [`EntityClonerBuilder`].
///
/// By default, the other entity will receive all the components of the original that implement
/// [`Clone`] or [`Reflect`](bevy_reflect::Reflect).
///
/// # Panics
///
/// The command will panic when applied if the target entity does not exist.
///
/// # Example
///
/// Configure through [`EntityClonerBuilder`] as follows:
/// ```
/// # use bevy_ecs::prelude::*;
///
/// #[derive(Component, Clone)]
/// struct ComponentA(u32);
/// #[derive(Component, Clone)]
/// struct ComponentB(u32);
///
/// fn example_system(mut commands: Commands) {
/// // Create an empty entity
/// let target = commands.spawn_empty().id();
///
/// // Create a new entity and keep its EntityCommands
/// let mut entity = commands.spawn((ComponentA(10), ComponentB(20)));
///
/// // Clone only ComponentA onto the target
/// entity.clone_with(target, |builder| {
/// builder.deny::<ComponentB>();
/// });
/// }
/// # bevy_ecs::system::assert_is_system(example_system);
/// ```
///
/// See [`EntityClonerBuilder`] for more options.
pub fn clone_with(
&mut self,
target: Entity,
config: impl FnOnce(&mut EntityClonerBuilder) + Send + Sync + 'static,
) -> &mut Self {
self.queue(entity_command::clone_with(target, config))
}
/// Spawns a clone of this entity and returns the [`EntityCommands`] of the clone.
///
/// The clone will receive all the components of the original that implement
/// [`Clone`] or [`Reflect`](bevy_reflect::Reflect).
///
/// To configure cloning behavior (such as only cloning certain components),
/// use [`EntityCommands::clone_and_spawn_with`].
///
/// # Note
///
/// If the original entity does not exist when this command is applied,
/// the returned entity will have no components.
///
/// # Example
///
/// ```
/// # use bevy_ecs::prelude::*;
///
/// #[derive(Component, Clone)]
/// struct ComponentA(u32);
/// #[derive(Component, Clone)]
/// struct ComponentB(u32);
///
/// fn example_system(mut commands: Commands) {
/// // Create a new entity and keep its EntityCommands
/// let mut entity = commands.spawn((ComponentA(10), ComponentB(20)));
///
/// // Create a clone of the first entity
/// let mut entity_clone = entity.clone_and_spawn();
/// }
/// # bevy_ecs::system::assert_is_system(example_system);
pub fn clone_and_spawn(&mut self) -> EntityCommands<'_> {
self.clone_and_spawn_with(|_| {})
}
/// Spawns a clone of this entity and allows configuring cloning behavior
/// using [`EntityClonerBuilder`], returning the [`EntityCommands`] of the clone.
///
/// By default, the clone will receive all the components of the original that implement
/// [`Clone`] or [`Reflect`](bevy_reflect::Reflect).
///
/// To exclude specific components, use [`EntityClonerBuilder::deny`].
/// To only include specific components, use [`EntityClonerBuilder::deny_all`]
/// followed by [`EntityClonerBuilder::allow`].
///
/// See the methods on [`EntityClonerBuilder`] for more options.
///
/// # Note
///
/// If the original entity does not exist when this command is applied,
/// the returned entity will have no components.
///
/// # Example
///
/// ```
/// # use bevy_ecs::prelude::*;
///
/// #[derive(Component, Clone)]
/// struct ComponentA(u32);
/// #[derive(Component, Clone)]
/// struct ComponentB(u32);
///
/// fn example_system(mut commands: Commands) {
/// // Create a new entity and keep its EntityCommands
/// let mut entity = commands.spawn((ComponentA(10), ComponentB(20)));
///
/// // Create a clone of the first entity, but without ComponentB
/// let mut entity_clone = entity.clone_and_spawn_with(|builder| {
/// builder.deny::<ComponentB>();
/// });
/// }
/// # bevy_ecs::system::assert_is_system(example_system);
pub fn clone_and_spawn_with(
&mut self,
config: impl FnOnce(&mut EntityClonerBuilder) + Send + Sync + 'static,
) -> EntityCommands<'_> {
let entity_clone = self.commands().spawn_empty().id();
self.clone_with(entity_clone, config);
EntityCommands {
commands: self.commands_mut().reborrow(),
entity: entity_clone,
}
}
/// Clones the specified components of this entity and inserts them into another entity.
///
/// Components can only be cloned if they implement
/// [`Clone`] or [`Reflect`](bevy_reflect::Reflect).
///
/// # Panics
///
/// The command will panic when applied if the target entity does not exist.
pub fn clone_components<B: Bundle>(&mut self, target: Entity) -> &mut Self {
self.queue(entity_command::clone_components::<B>(target))
}
/// Clones the specified components of this entity and inserts them into another entity,
/// then removes the components from this entity.
///
/// Components can only be cloned if they implement
/// [`Clone`] or [`Reflect`](bevy_reflect::Reflect).
///
/// # Panics
///
/// The command will panic when applied if the target entity does not exist.
pub fn move_components<B: Bundle>(&mut self, target: Entity) -> &mut Self {
self.queue(entity_command::move_components::<B>(target))
}
}
/// A wrapper around [`EntityCommands`] with convenience methods for working with a specified component type.
pub struct EntityEntryCommands<'a, T> {
entity_commands: EntityCommands<'a>,
marker: PhantomData<T>,
}
impl<'a, T: Component<Mutability = Mutable>> EntityEntryCommands<'a, T> {
/// Modify the component `T` if it exists, using the function `modify`.
pub fn and_modify(&mut self, modify: impl FnOnce(Mut<T>) + Send + Sync + 'static) -> &mut Self {
self.entity_commands
.queue(move |mut entity: EntityWorldMut| {
if let Some(value) = entity.get_mut() {
modify(value);
}
});
self
}
}
impl<'a, T: Component> EntityEntryCommands<'a, T> {
/// [Insert](EntityCommands::insert) `default` into this entity, if `T` is not already present.
///
/// See also [`or_insert_with`](Self::or_insert_with).
///
/// # Panics
///
/// Panics if the entity does not exist.
/// See [`or_try_insert`](Self::or_try_insert) for a non-panicking version.
#[track_caller]
pub fn or_insert(&mut self, default: T) -> &mut Self {
self.entity_commands.insert_if_new(default);
self
}
/// [Insert](EntityCommands::insert) `default` into this entity, if `T` is not already present.
///
/// Unlike [`or_insert`](Self::or_insert), this will not panic if the entity does not exist.
///
/// See also [`or_insert_with`](Self::or_insert_with).
#[track_caller]
pub fn or_try_insert(&mut self, default: T) -> &mut Self {
self.entity_commands.try_insert_if_new(default);
self
}
/// [Insert](EntityCommands::insert) the value returned from `default` into this entity, if `T` is not already present.
///
/// See also [`or_insert`](Self::or_insert) and [`or_try_insert`](Self::or_try_insert).
///
/// # Panics
///
/// Panics if the entity does not exist.
/// See [`or_try_insert_with`](Self::or_try_insert_with) for a non-panicking version.
#[track_caller]
pub fn or_insert_with(&mut self, default: impl Fn() -> T) -> &mut Self {
self.or_insert(default())
}
/// [Insert](EntityCommands::insert) the value returned from `default` into this entity, if `T` is not already present.
///
/// Unlike [`or_insert_with`](Self::or_insert_with), this will not panic if the entity does not exist.
///
/// See also [`or_insert`](Self::or_insert) and [`or_try_insert`](Self::or_try_insert).
#[track_caller]
pub fn or_try_insert_with(&mut self, default: impl Fn() -> T) -> &mut Self {
self.or_try_insert(default())
}
/// [Insert](EntityCommands::insert) `T::default` into this entity, if `T` is not already present.
///
/// See also [`or_insert`](Self::or_insert) and [`or_from_world`](Self::or_from_world).
///
/// # Panics
///
/// Panics if the entity does not exist.
#[track_caller]
pub fn or_default(&mut self) -> &mut Self
where
T: Default,
{
self.or_insert(T::default())
}
/// [Insert](EntityCommands::insert) `T::from_world` into this entity, if `T` is not already present.
///
/// See also [`or_insert`](Self::or_insert) and [`or_default`](Self::or_default).
///
/// # Panics
///
/// Panics if the entity does not exist.
#[track_caller]
pub fn or_from_world(&mut self) -> &mut Self
where
T: FromWorld,
{
self.entity_commands
.queue(entity_command::insert_from_world::<T>(InsertMode::Keep));
self
}
/// Get the [`EntityCommands`] from which the [`EntityEntryCommands`] was initiated.
///
/// This allows you to continue chaining method calls after calling [`EntityCommands::entry`].
///
/// # Example
///
/// ```
/// # use bevy_ecs::prelude::*;
/// # #[derive(Resource)]
/// # struct PlayerEntity { entity: Entity }
/// #[derive(Component)]
/// struct Level(u32);
///
/// fn level_up_system(mut commands: Commands, player: Res<PlayerEntity>) {
/// commands
/// .entity(player.entity)
/// .entry::<Level>()
/// // Modify the component if it exists
/// .and_modify(|mut lvl| lvl.0 += 1)
/// // Otherwise insert a default value
/// .or_insert(Level(0))
/// // Return the EntityCommands for the entity
/// .entity()
/// // And continue chaining method calls
/// .insert(Name::new("Player"));
/// }
/// # bevy_ecs::system::assert_is_system(level_up_system);
/// ```
pub fn entity(&mut self) -> EntityCommands {
self.entity_commands.reborrow()
}
}
#[cfg(test)]
mod tests {
use crate::{
self as bevy_ecs,
component::{require, Component},
resource::Resource,
system::Commands,
world::{CommandQueue, FromWorld, World},
};
use alloc::{string::String, sync::Arc, vec, vec::Vec};
use core::{
any::TypeId,
sync::atomic::{AtomicUsize, Ordering},
};
#[expect(
dead_code,
reason = "This struct is used to test how `Drop` behavior works in regards to SparseSet storage, and as such is solely a wrapper around `DropCk` to make it use the SparseSet storage. Because of this, the inner field is intentionally never read."
)]
#[derive(Component)]
#[component(storage = "SparseSet")]
struct SparseDropCk(DropCk);
#[derive(Component)]
struct DropCk(Arc<AtomicUsize>);
impl DropCk {
fn new_pair() -> (Self, Arc<AtomicUsize>) {
let atomic = Arc::new(AtomicUsize::new(0));
(DropCk(atomic.clone()), atomic)
}
}
impl Drop for DropCk {
fn drop(&mut self) {
self.0.as_ref().fetch_add(1, Ordering::Relaxed);
}
}
#[derive(Component, Resource)]
struct W<T>(T);
fn simple_command(world: &mut World) {
world.spawn((W(0u32), W(42u64)));
}
impl FromWorld for W<String> {
fn from_world(world: &mut World) -> Self {
let v = world.resource::<W<usize>>();
Self("*".repeat(v.0))
}
}
#[test]
fn entity_commands_entry() {
let mut world = World::default();
let mut queue = CommandQueue::default();
let mut commands = Commands::new(&mut queue, &world);
let entity = commands.spawn_empty().id();
commands
.entity(entity)
.entry::<W<u32>>()
.and_modify(|_| unreachable!());
queue.apply(&mut world);
assert!(!world.entity(entity).contains::<W<u32>>());
let mut commands = Commands::new(&mut queue, &world);
commands
.entity(entity)
.entry::<W<u32>>()
.or_insert(W(0))
.and_modify(|mut val| {
val.0 = 21;
});
queue.apply(&mut world);
assert_eq!(21, world.get::<W<u32>>(entity).unwrap().0);
let mut commands = Commands::new(&mut queue, &world);
commands
.entity(entity)
.entry::<W<u64>>()
.and_modify(|_| unreachable!())
.or_insert(W(42));
queue.apply(&mut world);
assert_eq!(42, world.get::<W<u64>>(entity).unwrap().0);
world.insert_resource(W(5_usize));
let mut commands = Commands::new(&mut queue, &world);
commands.entity(entity).entry::<W<String>>().or_from_world();
queue.apply(&mut world);
assert_eq!("*****", &world.get::<W<String>>(entity).unwrap().0);
let mut commands = Commands::new(&mut queue, &world);
let id = commands.entity(entity).entry::<W<u64>>().entity().id();
queue.apply(&mut world);
assert_eq!(id, entity);
}
#[test]
fn commands() {
let mut world = World::default();
let mut command_queue = CommandQueue::default();
let entity = Commands::new(&mut command_queue, &world)
.spawn((W(1u32), W(2u64)))
.id();
command_queue.apply(&mut world);
assert_eq!(world.entities().len(), 1);
let results = world
.query::<(&W<u32>, &W<u64>)>()
.iter(&world)
.map(|(a, b)| (a.0, b.0))
.collect::<Vec<_>>();
assert_eq!(results, vec![(1u32, 2u64)]);
// test entity despawn
{
let mut commands = Commands::new(&mut command_queue, &world);
commands.entity(entity).despawn();
commands.entity(entity).despawn(); // double despawn shouldn't panic
}
command_queue.apply(&mut world);
let results2 = world
.query::<(&W<u32>, &W<u64>)>()
.iter(&world)
.map(|(a, b)| (a.0, b.0))
.collect::<Vec<_>>();
assert_eq!(results2, vec![]);
// test adding simple (FnOnce) commands
{
let mut commands = Commands::new(&mut command_queue, &world);
// set up a simple command using a closure that adds one additional entity
commands.queue(|world: &mut World| {
world.spawn((W(42u32), W(0u64)));
});
// set up a simple command using a function that adds one additional entity
commands.queue(simple_command);
}
command_queue.apply(&mut world);
let results3 = world
.query::<(&W<u32>, &W<u64>)>()
.iter(&world)
.map(|(a, b)| (a.0, b.0))
.collect::<Vec<_>>();
assert_eq!(results3, vec![(42u32, 0u64), (0u32, 42u64)]);
}
#[test]
fn insert_components() {
let mut world = World::default();
let mut command_queue1 = CommandQueue::default();
// insert components
let entity = Commands::new(&mut command_queue1, &world)
.spawn(())
.insert_if(W(1u8), || true)
.insert_if(W(2u8), || false)
.insert_if_new(W(1u16))
.insert_if_new(W(2u16))
.insert_if_new_and(W(1u32), || false)
.insert_if_new_and(W(2u32), || true)
.insert_if_new_and(W(3u32), || true)
.id();
command_queue1.apply(&mut world);
let results = world
.query::<(&W<u8>, &W<u16>, &W<u32>)>()
.iter(&world)
.map(|(a, b, c)| (a.0, b.0, c.0))
.collect::<Vec<_>>();
assert_eq!(results, vec![(1u8, 1u16, 2u32)]);
// try to insert components after despawning entity
// in another command queue
Commands::new(&mut command_queue1, &world)
.entity(entity)
.try_insert_if_new_and(W(1u64), || true);
let mut command_queue2 = CommandQueue::default();
Commands::new(&mut command_queue2, &world)
.entity(entity)
.despawn();
command_queue2.apply(&mut world);
command_queue1.apply(&mut world);
}
#[test]
fn remove_components() {
let mut world = World::default();
let mut command_queue = CommandQueue::default();
let (dense_dropck, dense_is_dropped) = DropCk::new_pair();
let (sparse_dropck, sparse_is_dropped) = DropCk::new_pair();
let sparse_dropck = SparseDropCk(sparse_dropck);
let entity = Commands::new(&mut command_queue, &world)
.spawn((W(1u32), W(2u64), dense_dropck, sparse_dropck))
.id();
command_queue.apply(&mut world);
let results_before = world
.query::<(&W<u32>, &W<u64>)>()
.iter(&world)
.map(|(a, b)| (a.0, b.0))
.collect::<Vec<_>>();
assert_eq!(results_before, vec![(1u32, 2u64)]);
// test component removal
Commands::new(&mut command_queue, &world)
.entity(entity)
.remove::<W<u32>>()
.remove::<(W<u32>, W<u64>, SparseDropCk, DropCk)>();
assert_eq!(dense_is_dropped.load(Ordering::Relaxed), 0);
assert_eq!(sparse_is_dropped.load(Ordering::Relaxed), 0);
command_queue.apply(&mut world);
assert_eq!(dense_is_dropped.load(Ordering::Relaxed), 1);
assert_eq!(sparse_is_dropped.load(Ordering::Relaxed), 1);
let results_after = world
.query::<(&W<u32>, &W<u64>)>()
.iter(&world)
.map(|(a, b)| (a.0, b.0))
.collect::<Vec<_>>();
assert_eq!(results_after, vec![]);
let results_after_u64 = world
.query::<&W<u64>>()
.iter(&world)
.map(|v| v.0)
.collect::<Vec<_>>();
assert_eq!(results_after_u64, vec![]);
}
#[test]
fn remove_components_by_id() {
let mut world = World::default();
let mut command_queue = CommandQueue::default();
let (dense_dropck, dense_is_dropped) = DropCk::new_pair();
let (sparse_dropck, sparse_is_dropped) = DropCk::new_pair();
let sparse_dropck = SparseDropCk(sparse_dropck);
let entity = Commands::new(&mut command_queue, &world)
.spawn((W(1u32), W(2u64), dense_dropck, sparse_dropck))
.id();
command_queue.apply(&mut world);
let results_before = world
.query::<(&W<u32>, &W<u64>)>()
.iter(&world)
.map(|(a, b)| (a.0, b.0))
.collect::<Vec<_>>();
assert_eq!(results_before, vec![(1u32, 2u64)]);
// test component removal
Commands::new(&mut command_queue, &world)
.entity(entity)
.remove_by_id(world.components().get_id(TypeId::of::<W<u32>>()).unwrap())
.remove_by_id(world.components().get_id(TypeId::of::<W<u64>>()).unwrap())
.remove_by_id(world.components().get_id(TypeId::of::<DropCk>()).unwrap())
.remove_by_id(
world
.components()
.get_id(TypeId::of::<SparseDropCk>())
.unwrap(),
);
assert_eq!(dense_is_dropped.load(Ordering::Relaxed), 0);
assert_eq!(sparse_is_dropped.load(Ordering::Relaxed), 0);
command_queue.apply(&mut world);
assert_eq!(dense_is_dropped.load(Ordering::Relaxed), 1);
assert_eq!(sparse_is_dropped.load(Ordering::Relaxed), 1);
let results_after = world
.query::<(&W<u32>, &W<u64>)>()
.iter(&world)
.map(|(a, b)| (a.0, b.0))
.collect::<Vec<_>>();
assert_eq!(results_after, vec![]);
let results_after_u64 = world
.query::<&W<u64>>()
.iter(&world)
.map(|v| v.0)
.collect::<Vec<_>>();
assert_eq!(results_after_u64, vec![]);
}
#[test]
fn remove_resources() {
let mut world = World::default();
let mut queue = CommandQueue::default();
{
let mut commands = Commands::new(&mut queue, &world);
commands.insert_resource(W(123i32));
commands.insert_resource(W(456.0f64));
}
queue.apply(&mut world);
assert!(world.contains_resource::<W<i32>>());
assert!(world.contains_resource::<W<f64>>());
{
let mut commands = Commands::new(&mut queue, &world);
// test resource removal
commands.remove_resource::<W<i32>>();
}
queue.apply(&mut world);
assert!(!world.contains_resource::<W<i32>>());
assert!(world.contains_resource::<W<f64>>());
}
#[test]
fn remove_component_with_required_components() {
#[derive(Component)]
#[require(Y)]
struct X;
#[derive(Component, Default)]
struct Y;
#[derive(Component)]
struct Z;
let mut world = World::default();
let mut queue = CommandQueue::default();
let e = {
let mut commands = Commands::new(&mut queue, &world);
commands.spawn((X, Z)).id()
};
queue.apply(&mut world);
assert!(world.get::<Y>(e).is_some());
assert!(world.get::<X>(e).is_some());
assert!(world.get::<Z>(e).is_some());
{
let mut commands = Commands::new(&mut queue, &world);
commands.entity(e).remove_with_requires::<X>();
}
queue.apply(&mut world);
assert!(world.get::<Y>(e).is_none());
assert!(world.get::<X>(e).is_none());
assert!(world.get::<Z>(e).is_some());
}
#[test]
fn unregister_system_cached_commands() {
let mut world = World::default();
let mut queue = CommandQueue::default();
fn nothing() {}
let resources = world.iter_resources().count();
let id = world.register_system_cached(nothing);
assert_eq!(world.iter_resources().count(), resources + 1);
assert!(world.get_entity(id.entity).is_ok());
let mut commands = Commands::new(&mut queue, &world);
commands.unregister_system_cached(nothing);
queue.apply(&mut world);
assert_eq!(world.iter_resources().count(), resources);
assert!(world.get_entity(id.entity).is_err());
}
fn is_send<T: Send>() {}
fn is_sync<T: Sync>() {}
#[test]
fn test_commands_are_send_and_sync() {
is_send::<Commands>();
is_sync::<Commands>();
}
#[test]
fn append() {
let mut world = World::default();
let mut queue_1 = CommandQueue::default();
{
let mut commands = Commands::new(&mut queue_1, &world);
commands.insert_resource(W(123i32));
}
let mut queue_2 = CommandQueue::default();
{
let mut commands = Commands::new(&mut queue_2, &world);
commands.insert_resource(W(456.0f64));
}
queue_1.append(&mut queue_2);
queue_1.apply(&mut world);
assert!(world.contains_resource::<W<i32>>());
assert!(world.contains_resource::<W<f64>>());
}
}