Path: blob/main/crates/bevy_ecs/src/system/commands/command.rs
6609 views
//! Contains the definition of the [`Command`] trait,1//! as well as the blanket implementation of the trait for closures.2//!3//! It also contains functions that return closures for use with4//! [`Commands`](crate::system::Commands).56use crate::{7bundle::{Bundle, InsertMode, NoBundleEffect},8change_detection::MaybeLocation,9entity::Entity,10error::Result,11event::{BufferedEvent, Event, Events},12resource::Resource,13schedule::ScheduleLabel,14system::{IntoSystem, SystemId, SystemInput},15world::{FromWorld, SpawnBatchIter, World},16};1718/// A [`World`] mutation.19///20/// Should be used with [`Commands::queue`](crate::system::Commands::queue).21///22/// The `Out` generic parameter is the returned "output" of the command.23///24/// # Usage25///26/// ```27/// # use bevy_ecs::prelude::*;28/// // Our world resource29/// #[derive(Resource, Default)]30/// struct Counter(u64);31///32/// // Our custom command33/// struct AddToCounter(u64);34///35/// impl Command for AddToCounter {36/// fn apply(self, world: &mut World) {37/// let mut counter = world.get_resource_or_insert_with(Counter::default);38/// counter.0 += self.0;39/// }40/// }41///42/// fn some_system(mut commands: Commands) {43/// commands.queue(AddToCounter(42));44/// }45/// ```46pub trait Command<Out = ()>: Send + 'static {47/// Applies this command, causing it to mutate the provided `world`.48///49/// This method is used to define what a command "does" when it is ultimately applied.50/// Because this method takes `self`, you can store data or settings on the type that implements this trait.51/// This data is set by the system or other source of the command, and then ultimately read in this method.52fn apply(self, world: &mut World) -> Out;53}5455impl<F, Out> Command<Out> for F56where57F: FnOnce(&mut World) -> Out + Send + 'static,58{59fn apply(self, world: &mut World) -> Out {60self(world)61}62}6364/// A [`Command`] that consumes an iterator of [`Bundles`](Bundle) to spawn a series of entities.65///66/// This is more efficient than spawning the entities individually.67#[track_caller]68pub fn spawn_batch<I>(bundles_iter: I) -> impl Command69where70I: IntoIterator + Send + Sync + 'static,71I::Item: Bundle<Effect: NoBundleEffect>,72{73let caller = MaybeLocation::caller();74move |world: &mut World| {75SpawnBatchIter::new(world, bundles_iter.into_iter(), caller);76}77}7879/// A [`Command`] that consumes an iterator to add a series of [`Bundles`](Bundle) to a set of entities.80///81/// If any entities do not exist in the world, this command will return a82/// [`TryInsertBatchError`](crate::world::error::TryInsertBatchError).83///84/// This is more efficient than inserting the bundles individually.85#[track_caller]86pub fn insert_batch<I, B>(batch: I, insert_mode: InsertMode) -> impl Command<Result>87where88I: IntoIterator<Item = (Entity, B)> + Send + Sync + 'static,89B: Bundle<Effect: NoBundleEffect>,90{91let caller = MaybeLocation::caller();92move |world: &mut World| -> Result {93world.try_insert_batch_with_caller(batch, insert_mode, caller)?;94Ok(())95}96}9798/// A [`Command`] that inserts a [`Resource`] into the world using a value99/// created with the [`FromWorld`] trait.100#[track_caller]101pub fn init_resource<R: Resource + FromWorld>() -> impl Command {102move |world: &mut World| {103world.init_resource::<R>();104}105}106107/// A [`Command`] that inserts a [`Resource`] into the world.108#[track_caller]109pub fn insert_resource<R: Resource>(resource: R) -> impl Command {110let caller = MaybeLocation::caller();111move |world: &mut World| {112world.insert_resource_with_caller(resource, caller);113}114}115116/// A [`Command`] that removes a [`Resource`] from the world.117pub fn remove_resource<R: Resource>() -> impl Command {118move |world: &mut World| {119world.remove_resource::<R>();120}121}122123/// A [`Command`] that runs the system corresponding to the given [`SystemId`].124pub fn run_system<O: 'static>(id: SystemId<(), O>) -> impl Command<Result> {125move |world: &mut World| -> Result {126world.run_system(id)?;127Ok(())128}129}130131/// A [`Command`] that runs the system corresponding to the given [`SystemId`]132/// and provides the given input value.133pub fn run_system_with<I>(id: SystemId<I>, input: I::Inner<'static>) -> impl Command<Result>134where135I: SystemInput<Inner<'static>: Send> + 'static,136{137move |world: &mut World| -> Result {138world.run_system_with(id, input)?;139Ok(())140}141}142143/// A [`Command`] that runs the given system,144/// caching its [`SystemId`] in a [`CachedSystemId`](crate::system::CachedSystemId) resource.145pub fn run_system_cached<M, S>(system: S) -> impl Command<Result>146where147M: 'static,148S: IntoSystem<(), (), M> + Send + 'static,149{150move |world: &mut World| -> Result {151world.run_system_cached(system)?;152Ok(())153}154}155156/// A [`Command`] that runs the given system with the given input value,157/// caching its [`SystemId`] in a [`CachedSystemId`](crate::system::CachedSystemId) resource.158pub fn run_system_cached_with<I, M, S>(system: S, input: I::Inner<'static>) -> impl Command<Result>159where160I: SystemInput<Inner<'static>: Send> + Send + 'static,161M: 'static,162S: IntoSystem<I, (), M> + Send + 'static,163{164move |world: &mut World| -> Result {165world.run_system_cached_with(system, input)?;166Ok(())167}168}169170/// A [`Command`] that removes a system previously registered with171/// [`Commands::register_system`](crate::system::Commands::register_system) or172/// [`World::register_system`].173pub fn unregister_system<I, O>(system_id: SystemId<I, O>) -> impl Command<Result>174where175I: SystemInput + Send + 'static,176O: Send + 'static,177{178move |world: &mut World| -> Result {179world.unregister_system(system_id)?;180Ok(())181}182}183184/// A [`Command`] that removes a system previously registered with one of the following:185/// - [`Commands::run_system_cached`](crate::system::Commands::run_system_cached)186/// - [`World::run_system_cached`]187/// - [`World::register_system_cached`]188pub fn unregister_system_cached<I, O, M, S>(system: S) -> impl Command<Result>189where190I: SystemInput + Send + 'static,191O: 'static,192M: 'static,193S: IntoSystem<I, O, M> + Send + 'static,194{195move |world: &mut World| -> Result {196world.unregister_system_cached(system)?;197Ok(())198}199}200201/// A [`Command`] that runs the schedule corresponding to the given [`ScheduleLabel`].202pub fn run_schedule(label: impl ScheduleLabel) -> impl Command<Result> {203move |world: &mut World| -> Result {204world.try_run_schedule(label)?;205Ok(())206}207}208209/// Triggers the given [`Event`], which will run any [`Observer`]s watching for it.210///211/// [`Observer`]: crate::observer::Observer212#[track_caller]213pub fn trigger<'a, E: Event<Trigger<'a>: Default>>(mut event: E) -> impl Command {214let caller = MaybeLocation::caller();215move |world: &mut World| {216world.trigger_ref_with_caller(217&mut event,218&mut <E::Trigger<'_> as Default>::default(),219caller,220);221}222}223224/// Triggers the given [`Event`] using the given [`Trigger`], which will run any [`Observer`]s watching for it.225///226/// [`Trigger`]: crate::event::Trigger227/// [`Observer`]: crate::observer::Observer228#[track_caller]229pub fn trigger_with<E: Event<Trigger<'static>: Send + Sync>>(230mut event: E,231mut trigger: E::Trigger<'static>,232) -> impl Command {233let caller = MaybeLocation::caller();234move |world: &mut World| {235world.trigger_ref_with_caller(&mut event, &mut trigger, caller);236}237}238239/// A [`Command`] that writes an arbitrary [`BufferedEvent`].240#[track_caller]241pub fn write_event<E: BufferedEvent>(event: E) -> impl Command {242let caller = MaybeLocation::caller();243move |world: &mut World| {244let mut events = world.resource_mut::<Events<E>>();245events.write_with_caller(event, caller);246}247}248249/// A [`Command`] that writes an arbitrary [`BufferedEvent`].250#[track_caller]251#[deprecated(since = "0.17.0", note = "Use `write_event` instead.")]252pub fn send_event<E: BufferedEvent>(event: E) -> impl Command {253write_event(event)254}255256257