Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
bevyengine
GitHub Repository: bevyengine/bevy
Path: blob/main/crates/bevy_ecs/src/system/commands/parallel_scope.rs
9371 views
1
use bevy_utils::Parallel;
2
3
use crate::{
4
entity::{Entities, EntityAllocator},
5
prelude::World,
6
system::{Deferred, SystemBuffer, SystemMeta, SystemParam},
7
world::DeferredWorld,
8
};
9
10
use super::{CommandQueue, Commands};
11
12
#[derive(Default)]
13
struct ParallelCommandQueue {
14
thread_queues: Parallel<CommandQueue>,
15
}
16
17
/// An alternative to [`Commands`] that can be used in parallel contexts, such as those
18
/// in [`Query::par_iter`](crate::system::Query::par_iter).
19
///
20
/// For cases where multiple non-computation-heavy (lightweight) bundles of the same
21
/// [`Bundle`](crate::prelude::Bundle) type need to be spawned, consider using
22
/// [`Commands::spawn_batch`] for better performance.
23
///
24
/// # Note
25
///
26
/// Because command application order will depend on how many threads are ran,
27
/// non-commutative commands may result in non-deterministic results.
28
///
29
/// # Example
30
///
31
/// ```
32
/// # use bevy_ecs::prelude::*;
33
/// # use bevy_tasks::ComputeTaskPool;
34
/// #
35
/// # #[derive(Component)]
36
/// # struct Velocity;
37
/// # impl Velocity { fn magnitude(&self) -> f32 { 42.0 } }
38
/// fn parallel_command_system(
39
/// mut query: Query<(Entity, &Velocity)>,
40
/// par_commands: ParallelCommands
41
/// ) {
42
/// query.par_iter().for_each(|(entity, velocity)| {
43
/// if velocity.magnitude() > 10.0 {
44
/// par_commands.command_scope(|mut commands| {
45
/// commands.entity(entity).despawn();
46
/// });
47
/// }
48
/// });
49
/// }
50
/// # bevy_ecs::system::assert_is_system(parallel_command_system);
51
/// ```
52
#[derive(SystemParam)]
53
pub struct ParallelCommands<'w, 's> {
54
state: Deferred<'s, ParallelCommandQueue>,
55
allocator: &'w EntityAllocator,
56
entities: &'w Entities,
57
}
58
59
impl SystemBuffer for ParallelCommandQueue {
60
#[inline]
61
fn apply(&mut self, _system_meta: &SystemMeta, world: &mut World) {
62
#[cfg(feature = "trace")]
63
let _system_span = _system_meta.commands_span.enter();
64
for cq in self.thread_queues.iter_mut() {
65
cq.apply(world);
66
}
67
}
68
69
#[inline]
70
fn queue(&mut self, _system_meta: &SystemMeta, mut world: DeferredWorld) {
71
#[cfg(feature = "trace")]
72
let _system_span = _system_meta.commands_span.enter();
73
for cq in self.thread_queues.iter_mut() {
74
world.commands().append(cq);
75
}
76
}
77
}
78
79
impl<'w, 's> ParallelCommands<'w, 's> {
80
/// Temporarily provides access to the [`Commands`] for the current thread.
81
///
82
/// For an example, see the type-level documentation for [`ParallelCommands`].
83
pub fn command_scope<R>(&self, f: impl FnOnce(Commands) -> R) -> R {
84
self.state.thread_queues.scope(|queue| {
85
let commands = Commands::new_from_entities(queue, self.allocator, self.entities);
86
f(commands)
87
})
88
}
89
}
90
91