bevy_ecs/system/commands/
parallel_scope.rs

1use bevy_utils::Parallel;
2
3use crate::{
4    self as bevy_ecs,
5    entity::Entities,
6    prelude::World,
7    system::{Deferred, SystemBuffer, SystemMeta, SystemParam},
8};
9
10use super::{CommandQueue, Commands};
11
12#[derive(Default)]
13struct ParallelCommandQueue {
14    thread_queues: Parallel<CommandQueue>,
15}
16
17/// An alternative to [`Commands`] that can be used in parallel contexts, such as those in [`Query::par_iter`](crate::system::Query::par_iter)
18///
19/// Note: Because command application order will depend on how many threads are ran, non-commutative commands may result in non-deterministic results.
20///
21/// Example:
22/// ```
23/// # use bevy_ecs::prelude::*;
24/// # use bevy_tasks::ComputeTaskPool;
25/// #
26/// # #[derive(Component)]
27/// # struct Velocity;
28/// # impl Velocity { fn magnitude(&self) -> f32 { 42.0 } }
29/// fn parallel_command_system(
30///     mut query: Query<(Entity, &Velocity)>,
31///     par_commands: ParallelCommands
32/// ) {
33///     query.par_iter().for_each(|(entity, velocity)| {
34///         if velocity.magnitude() > 10.0 {
35///             par_commands.command_scope(|mut commands| {
36///                 commands.entity(entity).despawn();
37///             });
38///         }
39///     });
40/// }
41/// # bevy_ecs::system::assert_is_system(parallel_command_system);
42///```
43#[derive(SystemParam)]
44pub struct ParallelCommands<'w, 's> {
45    state: Deferred<'s, ParallelCommandQueue>,
46    entities: &'w Entities,
47}
48
49impl SystemBuffer for ParallelCommandQueue {
50    #[inline]
51    fn apply(&mut self, _system_meta: &SystemMeta, world: &mut World) {
52        #[cfg(feature = "trace")]
53        let _system_span = _system_meta.commands_span.enter();
54        for cq in self.thread_queues.iter_mut() {
55            cq.apply(world);
56        }
57    }
58}
59
60impl<'w, 's> ParallelCommands<'w, 's> {
61    /// Temporarily provides access to the [`Commands`] for the current thread.
62    ///
63    /// For an example, see the type-level documentation for [`ParallelCommands`].
64    pub fn command_scope<R>(&self, f: impl FnOnce(Commands) -> R) -> R {
65        self.state.thread_queues.scope(|queue| {
66            let commands = Commands::new_from_entities(queue, self.entities);
67            f(commands)
68        })
69    }
70}