Path: blob/main/crates/bevy_ecs/src/system/commands/command.rs
6849 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::Event,12message::{Message, Messages},13resource::Resource,14schedule::ScheduleLabel,15system::{IntoSystem, SystemId, SystemInput},16world::{FromWorld, SpawnBatchIter, World},17};1819/// A [`World`] mutation.20///21/// Should be used with [`Commands::queue`](crate::system::Commands::queue).22///23/// The `Out` generic parameter is the returned "output" of the command.24///25/// # Usage26///27/// ```28/// # use bevy_ecs::prelude::*;29/// // Our world resource30/// #[derive(Resource, Default)]31/// struct Counter(u64);32///33/// // Our custom command34/// struct AddToCounter(u64);35///36/// impl Command for AddToCounter {37/// fn apply(self, world: &mut World) {38/// let mut counter = world.get_resource_or_insert_with(Counter::default);39/// counter.0 += self.0;40/// }41/// }42///43/// fn some_system(mut commands: Commands) {44/// commands.queue(AddToCounter(42));45/// }46/// ```47pub trait Command<Out = ()>: Send + 'static {48/// Applies this command, causing it to mutate the provided `world`.49///50/// This method is used to define what a command "does" when it is ultimately applied.51/// Because this method takes `self`, you can store data or settings on the type that implements this trait.52/// This data is set by the system or other source of the command, and then ultimately read in this method.53fn apply(self, world: &mut World) -> Out;54}5556impl<F, Out> Command<Out> for F57where58F: FnOnce(&mut World) -> Out + Send + 'static,59{60fn apply(self, world: &mut World) -> Out {61self(world)62}63}6465/// A [`Command`] that consumes an iterator of [`Bundles`](Bundle) to spawn a series of entities.66///67/// This is more efficient than spawning the entities individually.68#[track_caller]69pub fn spawn_batch<I>(bundles_iter: I) -> impl Command70where71I: IntoIterator + Send + Sync + 'static,72I::Item: Bundle<Effect: NoBundleEffect>,73{74let caller = MaybeLocation::caller();75move |world: &mut World| {76SpawnBatchIter::new(world, bundles_iter.into_iter(), caller);77}78}7980/// A [`Command`] that consumes an iterator to add a series of [`Bundles`](Bundle) to a set of entities.81///82/// If any entities do not exist in the world, this command will return a83/// [`TryInsertBatchError`](crate::world::error::TryInsertBatchError).84///85/// This is more efficient than inserting the bundles individually.86#[track_caller]87pub fn insert_batch<I, B>(batch: I, insert_mode: InsertMode) -> impl Command<Result>88where89I: IntoIterator<Item = (Entity, B)> + Send + Sync + 'static,90B: Bundle<Effect: NoBundleEffect>,91{92let caller = MaybeLocation::caller();93move |world: &mut World| -> Result {94world.try_insert_batch_with_caller(batch, insert_mode, caller)?;95Ok(())96}97}9899/// A [`Command`] that inserts a [`Resource`] into the world using a value100/// created with the [`FromWorld`] trait.101#[track_caller]102pub fn init_resource<R: Resource + FromWorld>() -> impl Command {103move |world: &mut World| {104world.init_resource::<R>();105}106}107108/// A [`Command`] that inserts a [`Resource`] into the world.109#[track_caller]110pub fn insert_resource<R: Resource>(resource: R) -> impl Command {111let caller = MaybeLocation::caller();112move |world: &mut World| {113world.insert_resource_with_caller(resource, caller);114}115}116117/// A [`Command`] that removes a [`Resource`] from the world.118pub fn remove_resource<R: Resource>() -> impl Command {119move |world: &mut World| {120world.remove_resource::<R>();121}122}123124/// A [`Command`] that runs the system corresponding to the given [`SystemId`].125pub fn run_system<O: 'static>(id: SystemId<(), O>) -> impl Command<Result> {126move |world: &mut World| -> Result {127world.run_system(id)?;128Ok(())129}130}131132/// A [`Command`] that runs the system corresponding to the given [`SystemId`]133/// and provides the given input value.134pub fn run_system_with<I>(id: SystemId<I>, input: I::Inner<'static>) -> impl Command<Result>135where136I: SystemInput<Inner<'static>: Send> + 'static,137{138move |world: &mut World| -> Result {139world.run_system_with(id, input)?;140Ok(())141}142}143144/// A [`Command`] that runs the given system,145/// caching its [`SystemId`] in a [`CachedSystemId`](crate::system::CachedSystemId) resource.146pub fn run_system_cached<M, S>(system: S) -> impl Command<Result>147where148M: 'static,149S: IntoSystem<(), (), M> + Send + 'static,150{151move |world: &mut World| -> Result {152world.run_system_cached(system)?;153Ok(())154}155}156157/// A [`Command`] that runs the given system with the given input value,158/// caching its [`SystemId`] in a [`CachedSystemId`](crate::system::CachedSystemId) resource.159pub fn run_system_cached_with<I, M, S>(system: S, input: I::Inner<'static>) -> impl Command<Result>160where161I: SystemInput<Inner<'static>: Send> + Send + 'static,162M: 'static,163S: IntoSystem<I, (), M> + Send + 'static,164{165move |world: &mut World| -> Result {166world.run_system_cached_with(system, input)?;167Ok(())168}169}170171/// A [`Command`] that removes a system previously registered with172/// [`Commands::register_system`](crate::system::Commands::register_system) or173/// [`World::register_system`].174pub fn unregister_system<I, O>(system_id: SystemId<I, O>) -> impl Command<Result>175where176I: SystemInput + Send + 'static,177O: Send + 'static,178{179move |world: &mut World| -> Result {180world.unregister_system(system_id)?;181Ok(())182}183}184185/// A [`Command`] that removes a system previously registered with one of the following:186/// - [`Commands::run_system_cached`](crate::system::Commands::run_system_cached)187/// - [`World::run_system_cached`]188/// - [`World::register_system_cached`]189pub fn unregister_system_cached<I, O, M, S>(system: S) -> impl Command<Result>190where191I: SystemInput + Send + 'static,192O: 'static,193M: 'static,194S: IntoSystem<I, O, M> + Send + 'static,195{196move |world: &mut World| -> Result {197world.unregister_system_cached(system)?;198Ok(())199}200}201202/// A [`Command`] that runs the schedule corresponding to the given [`ScheduleLabel`].203pub fn run_schedule(label: impl ScheduleLabel) -> impl Command<Result> {204move |world: &mut World| -> Result {205world.try_run_schedule(label)?;206Ok(())207}208}209210/// Triggers the given [`Event`], which will run any [`Observer`]s watching for it.211///212/// [`Observer`]: crate::observer::Observer213#[track_caller]214pub fn trigger<'a, E: Event<Trigger<'a>: Default>>(mut event: E) -> impl Command {215let caller = MaybeLocation::caller();216move |world: &mut World| {217world.trigger_ref_with_caller(218&mut event,219&mut <E::Trigger<'_> as Default>::default(),220caller,221);222}223}224225/// Triggers the given [`Event`] using the given [`Trigger`], which will run any [`Observer`]s watching for it.226///227/// [`Trigger`]: crate::event::Trigger228/// [`Observer`]: crate::observer::Observer229#[track_caller]230pub fn trigger_with<E: Event<Trigger<'static>: Send + Sync>>(231mut event: E,232mut trigger: E::Trigger<'static>,233) -> impl Command {234let caller = MaybeLocation::caller();235move |world: &mut World| {236world.trigger_ref_with_caller(&mut event, &mut trigger, caller);237}238}239240/// A [`Command`] that writes an arbitrary [`Message`].241#[track_caller]242pub fn write_message<M: Message>(message: M) -> impl Command {243let caller = MaybeLocation::caller();244move |world: &mut World| {245let mut messages = world.resource_mut::<Messages<M>>();246messages.write_with_caller(message, caller);247}248}249250/// A [`Command`] that writes an arbitrary [`Message`].251#[track_caller]252#[deprecated(since = "0.17.0", note = "Use `write_message` instead.")]253pub fn send_event<E: Message>(event: E) -> impl Command {254write_message(event)255}256257258