diff --git a/crates/bevy_ecs/src/system/commands/mod.rs b/crates/bevy_ecs/src/system/commands/mod.rs index 80de73f9f1..cd62763fa6 100644 --- a/crates/bevy_ecs/src/system/commands/mod.rs +++ b/crates/bevy_ecs/src/system/commands/mod.rs @@ -409,7 +409,7 @@ impl<'w, 's> Commands<'w, 's> { I: IntoIterator + Send + Sync + 'static, I::Item: Bundle, { - self.queue.push(SpawnBatch { bundles_iter }); + self.queue.push(spawn_batch(bundles_iter)); } /// Pushes a [`Command`] to the queue for creating entities, if needed, @@ -433,13 +433,12 @@ impl<'w, 's> Commands<'w, 's> { /// 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). - pub fn insert_or_spawn_batch(&mut self, bundles_iter: I) + pub fn insert_or_spawn_batch(&mut self, bundles: I) where - I: IntoIterator + Send + Sync + 'static, - I::IntoIter: Iterator, + I: IntoIterator + Send + Sync + 'static, B: Bundle, { - self.queue.push(InsertOrSpawnBatch { bundles_iter }); + self.queue.push(insert_or_spawn_batch(bundles)); } /// Pushes a [`Command`] to the queue for inserting a [`Resource`] in the [`World`] with an inferred value. @@ -467,7 +466,7 @@ impl<'w, 's> Commands<'w, 's> { /// # bevy_ecs::system::assert_is_system(initialise_scoreboard); /// ``` pub fn init_resource(&mut self) { - self.queue.push(InitResource::::new()); + self.queue.push(init_resource::); } /// Pushes a [`Command`] to the queue for inserting a [`Resource`] in the [`World`] with a specific value. @@ -496,7 +495,7 @@ impl<'w, 's> Commands<'w, 's> { /// # bevy_ecs::system::assert_is_system(system); /// ``` pub fn insert_resource(&mut self, resource: R) { - self.queue.push(InsertResource { resource }); + self.queue.push(insert_resource(resource)); } /// Pushes a [`Command`] to the queue for removing a [`Resource`] from the [`World`]. @@ -520,7 +519,7 @@ impl<'w, 's> Commands<'w, 's> { /// # bevy_ecs::system::assert_is_system(system); /// ``` pub fn remove_resource(&mut self) { - self.queue.push(RemoveResource::::new()); + self.queue.push(remove_resource::); } /// Runs the system corresponding to the given [`SystemId`]. @@ -608,18 +607,14 @@ impl<'w, 's> Commands<'w, 's> { /// struct Counter(i64); /// /// /// A `Command` which names an entity based on a global counter. -/// struct CountName; +/// fn count_name(entity: Entity, world: &mut World) { +/// // Get the current value of the counter, and increment it for next time. +/// let mut counter = world.resource_mut::(); +/// let i = counter.0; +/// counter.0 += 1; /// -/// impl EntityCommand for CountName { -/// fn apply(self, id: Entity, world: &mut World) { -/// // Get the current value of the counter, and increment it for next time. -/// let mut counter = world.resource_mut::(); -/// let i = counter.0; -/// counter.0 += 1; -/// -/// // Name the entity after the value of the counter. -/// world.entity_mut(id).insert(Name::new(format!("Entity #{i}"))); -/// } +/// // Name the entity after the value of the counter. +/// world.entity_mut(entity).insert(Name::new(format!("Entity #{i}"))); /// } /// /// // App creation boilerplate omitted... @@ -635,8 +630,8 @@ impl<'w, 's> Commands<'w, 's> { /// # assert_schedule.run(&mut world); /// /// fn setup(mut commands: Commands) { -/// commands.spawn_empty().add(CountName); -/// commands.spawn_empty().add(CountName); +/// commands.spawn_empty().add(count_name); +/// commands.spawn_empty().add(count_name); /// } /// /// fn assert_names(named: Query<&Name>) { @@ -645,25 +640,33 @@ impl<'w, 's> Commands<'w, 's> { /// assert_eq!(names, HashSet::from_iter(["Entity #0", "Entity #1"])); /// } /// ``` -pub trait EntityCommand: Send + 'static { +pub trait EntityCommand: Send + 'static { /// Executes this command for the given [`Entity`]. fn apply(self, id: Entity, world: &mut World); /// Returns a [`Command`] which executes this [`EntityCommand`] for the given [`Entity`]. - fn with_entity(self, id: Entity) -> WithEntity + fn with_entity(self, id: Entity) -> WithEntity where Self: Sized, { - WithEntity { cmd: self, id } + WithEntity { + cmd: self, + id, + marker: PhantomData, + } } } /// Turns an [`EntityCommand`] type into a [`Command`] type. -pub struct WithEntity { +pub struct WithEntity> { cmd: C, id: Entity, + marker: PhantomData Marker>, } -impl Command for WithEntity { +impl> Command for WithEntity +where + M: 'static, +{ #[inline] fn apply(self, world: &mut World) { self.cmd.apply(self.id, world); @@ -747,11 +750,7 @@ impl<'w, 's, 'a> EntityCommands<'w, 's, 'a> { /// # bevy_ecs::system::assert_is_system(add_combat_stats_system); /// ``` pub fn insert(&mut self, bundle: impl Bundle) -> &mut Self { - self.commands.add(Insert { - entity: self.entity, - bundle, - }); - self + self.add(insert(bundle)) } /// Tries to add a [`Bundle`] of components to the entity. @@ -803,11 +802,7 @@ impl<'w, 's, 'a> EntityCommands<'w, 's, 'a> { /// # bevy_ecs::system::assert_is_system(add_combat_stats_system); /// ``` pub fn try_insert(&mut self, bundle: impl Bundle) -> &mut Self { - self.commands.add(TryInsert { - entity: self.entity, - bundle, - }); - self + self.add(try_insert(bundle)) } /// Removes a [`Bundle`] of components from the entity. @@ -849,8 +844,7 @@ impl<'w, 's, 'a> EntityCommands<'w, 's, 'a> { where T: Bundle, { - self.commands.add(Remove::::new(self.entity)); - self + self.add(remove::) } /// Despawns the entity. @@ -884,9 +878,7 @@ impl<'w, 's, 'a> EntityCommands<'w, 's, 'a> { /// # bevy_ecs::system::assert_is_system(remove_character_system); /// ``` pub fn despawn(&mut self) { - self.commands.add(Despawn { - entity: self.entity, - }); + self.add(despawn); } /// Pushes an [`EntityCommand`] to the queue, which will get executed for the current [`Entity`]. @@ -905,7 +897,7 @@ impl<'w, 's, 'a> EntityCommands<'w, 's, 'a> { /// # } /// # bevy_ecs::system::assert_is_system(my_system); /// ``` - pub fn add(&mut self, command: C) -> &mut Self { + pub fn add(&mut self, command: impl EntityCommand) -> &mut Self { self.commands.add(command.with_entity(self.entity)); self } @@ -951,8 +943,7 @@ impl<'w, 's, 'a> EntityCommands<'w, 's, 'a> { where T: Bundle, { - self.commands.add(Retain::::new(self.entity)); - self + self.add(retain::) } /// Logs the components of the entity at the info level. @@ -961,9 +952,7 @@ impl<'w, 's, 'a> EntityCommands<'w, 's, 'a> { /// /// The command will panic when applied if the associated entity does not exist. pub fn log_components(&mut self) { - self.commands.add(LogComponents { - entity: self.entity, - }); + self.add(log_components); } /// Returns the underlying [`Commands`]. @@ -981,7 +970,7 @@ where } } -impl EntityCommand for F +impl EntityCommand for F where F: FnOnce(EntityWorldMut) + Send + 'static, { @@ -990,41 +979,25 @@ where } } -/// A [`Command`] that spawns a new entity and adds the components in a [`Bundle`] to it. -#[derive(Debug)] -pub struct Spawn { - /// The [`Bundle`] of components that will be added to the newly-spawned entity. - pub bundle: T, -} - -impl Command for Spawn +impl EntityCommand for F where - T: Bundle, + F: FnOnce(Entity, &mut World) + Send + 'static, { - fn apply(self, world: &mut World) { - world.spawn(self.bundle); + fn apply(self, id: Entity, world: &mut World) { + self(id, world); } } /// A [`Command`] that consumes an iterator of [`Bundle`]s to spawn a series of entities. /// /// This is more efficient than spawning the entities individually. -pub struct SpawnBatch +fn spawn_batch(bundles: I) -> impl Command where - I: IntoIterator, - I::Item: Bundle, + I: IntoIterator + Send + Sync + 'static, + B: Bundle, { - /// The iterator that returns the [`Bundle`]s which will be added to each newly-spawned entity. - pub bundles_iter: I, -} - -impl Command for SpawnBatch -where - I: IntoIterator + Send + Sync + 'static, - I::Item: Bundle, -{ - fn apply(self, world: &mut World) { - world.spawn_batch(self.bundles_iter); + move |world: &mut World| { + world.spawn_batch(bundles); } } @@ -1032,24 +1005,13 @@ where /// If any entities do not already exist in the world, they will be spawned. /// /// This is more efficient than inserting the bundles individually. -pub struct InsertOrSpawnBatch +fn insert_or_spawn_batch(bundles: I) -> impl Command where - I: IntoIterator + Send + Sync + 'static, + I: IntoIterator + Send + Sync + 'static, B: Bundle, - I::IntoIter: Iterator, { - /// The iterator that returns each [entity ID](Entity) and corresponding [`Bundle`]. - pub bundles_iter: I, -} - -impl Command for InsertOrSpawnBatch -where - I: IntoIterator + Send + Sync + 'static, - B: Bundle, - I::IntoIter: Iterator, -{ - fn apply(self, world: &mut World) { - if let Err(invalid_entities) = world.insert_or_spawn_batch(self.bundles_iter) { + move |world: &mut World| { + if let Err(invalid_entities) = world.insert_or_spawn_batch(bundles) { error!( "Failed to 'insert or spawn' bundle of type {} into the following invalid entities: {:?}", std::any::type_name::(), @@ -1066,54 +1028,26 @@ where /// /// This won't clean up external references to the entity (such as parent-child relationships /// if you're using `bevy_hierarchy`), which may leave the world in an invalid state. -#[derive(Debug)] -pub struct Despawn { - /// The entity that will be despawned. - pub entity: Entity, +fn despawn(entity: Entity, world: &mut World) { + world.despawn(entity); } -impl Command for Despawn { - fn apply(self, world: &mut World) { - world.despawn(self.entity); - } -} - -/// A [`Command`] that adds the components in a [`Bundle`] to an entity. -pub struct Insert { - /// The entity to which the components will be added. - pub entity: Entity, - /// The [`Bundle`] containing the components that will be added to the entity. - pub bundle: T, -} - -impl Command for Insert -where - T: Bundle + 'static, -{ - fn apply(self, world: &mut World) { - if let Some(mut entity) = world.get_entity_mut(self.entity) { - entity.insert(self.bundle); +/// An [`EntityCommand`] that adds the components in a [`Bundle`] to an entity. +fn insert(bundle: T) -> impl EntityCommand { + move |entity: Entity, world: &mut World| { + if let Some(mut entity) = world.get_entity_mut(entity) { + entity.insert(bundle); } else { - panic!("error[B0003]: Could not insert a bundle (of type `{}`) for entity {:?} because it doesn't exist in this World.", std::any::type_name::(), self.entity); + panic!("error[B0003]: Could not insert a bundle (of type `{}`) for entity {:?} because it doesn't exist in this World.", std::any::type_name::(), entity); } } } -/// A [`Command`] that attempts to add the components in a [`Bundle`] to an entity. -pub struct TryInsert { - /// The entity to which the components will be added. - pub entity: Entity, - /// The [`Bundle`] containing the components that will be added to the entity. - pub bundle: T, -} - -impl Command for TryInsert -where - T: Bundle + 'static, -{ - fn apply(self, world: &mut World) { - if let Some(mut entity) = world.get_entity_mut(self.entity) { - entity.insert(self.bundle); +/// An [`EntityCommand`] that attempts to add the components in a [`Bundle`] to an entity. +fn try_insert(bundle: impl Bundle) -> impl EntityCommand { + move |entity, world: &mut World| { + if let Some(mut entity) = world.get_entity_mut(entity) { + entity.insert(bundle); } } } @@ -1121,132 +1055,47 @@ where /// A [`Command`] that removes components from an entity. /// For a [`Bundle`] type `T`, this will remove any components in the bundle. /// Any components in the bundle that aren't found on the entity will be ignored. -#[derive(Debug)] -pub struct Remove { - /// The entity from which the components will be removed. - pub entity: Entity, - _marker: PhantomData, -} - -impl Command for Remove -where - T: Bundle, -{ - fn apply(self, world: &mut World) { - if let Some(mut entity_mut) = world.get_entity_mut(self.entity) { - entity_mut.remove::(); - } - } -} - -impl Remove { - /// Creates a [`Command`] which will remove the specified [`Entity`] when applied. - pub const fn new(entity: Entity) -> Self { - Self { - entity, - _marker: PhantomData, - } +fn remove(entity: Entity, world: &mut World) { + if let Some(mut entity_mut) = world.get_entity_mut(entity) { + entity_mut.remove::(); } } /// A [`Command`] that removes components from an entity. /// For a [`Bundle`] type `T`, this will remove all components except those in the bundle. /// Any components in the bundle that aren't found on the entity will be ignored. -#[derive(Debug)] -pub struct Retain { - /// The entity from which the components will be removed. - pub entity: Entity, - _marker: PhantomData, -} - -impl Command for Retain -where - T: Bundle, -{ - fn apply(self, world: &mut World) { - if let Some(mut entity_mut) = world.get_entity_mut(self.entity) { - entity_mut.retain::(); - } - } -} - -impl Retain { - /// Creates a [`Command`] which will remove all but the specified components when applied. - pub const fn new(entity: Entity) -> Self { - Self { - entity, - _marker: PhantomData, - } +fn retain(entity: Entity, world: &mut World) { + if let Some(mut entity_mut) = world.get_entity_mut(entity) { + entity_mut.retain::(); } } /// A [`Command`] that inserts a [`Resource`] into the world using a value /// created with the [`FromWorld`] trait. -pub struct InitResource { - _marker: PhantomData, -} - -impl Command for InitResource { - fn apply(self, world: &mut World) { - world.init_resource::(); - } -} - -impl InitResource { - /// Creates a [`Command`] which will insert a default created [`Resource`] into the [`World`] - pub const fn new() -> Self { - Self { - _marker: PhantomData, - } - } -} - -/// A [`Command`] that inserts a [`Resource`] into the world. -pub struct InsertResource { - /// The resource that will be added to the world. - pub resource: R, -} - -impl Command for InsertResource { - fn apply(self, world: &mut World) { - world.insert_resource(self.resource); - } +fn init_resource(world: &mut World) { + world.init_resource::(); } /// A [`Command`] that removes the [resource](Resource) `R` from the world. -pub struct RemoveResource { - _marker: PhantomData, +fn remove_resource(world: &mut World) { + world.remove_resource::(); } -impl Command for RemoveResource { - fn apply(self, world: &mut World) { - world.remove_resource::(); +/// A [`Command`] that inserts a [`Resource`] into the world. +fn insert_resource(resource: R) -> impl Command { + move |world: &mut World| { + world.insert_resource(resource); } } -impl RemoveResource { - /// Creates a [`Command`] which will remove a [`Resource`] from the [`World`] - pub const fn new() -> Self { - Self { - _marker: PhantomData, - } - } -} - -/// [`Command`] to log the components of a given entity. See [`EntityCommands::log_components`]. -pub struct LogComponents { - entity: Entity, -} - -impl Command for LogComponents { - fn apply(self, world: &mut World) { - let debug_infos: Vec<_> = world - .inspect_entity(self.entity) - .into_iter() - .map(|component_info| component_info.name()) - .collect(); - info!("Entity {:?}: {:?}", self.entity, debug_infos); - } +/// [`EntityCommand`] to log the components of a given entity. See [`EntityCommands::log_components`]. +fn log_components(entity: Entity, world: &mut World) { + let debug_infos: Vec<_> = world + .inspect_entity(entity) + .into_iter() + .map(|component_info| component_info.name()) + .collect(); + info!("Entity {:?}: {:?}", entity, debug_infos); } #[cfg(test)]