hecs_schedule/
commandbuffer.rs

1use hecs::{
2    Bundle, CommandBuffer as CommandBufferInternal, Component, DynamicBundle, Entity, World,
3};
4
5#[derive(Default)]
6/// Extends the built in [hecs::CommandBuffer].
7///
8/// Allows for deferred modifications to the world, spawn, insert, remove,
9/// despawn, or custom closures.
10///
11/// It is possible to insert a commandbuffer into another commandbuffer.
12pub struct CommandBuffer {
13    /// Use the already existing hecs::CommmandBuffer
14    components: CommandBufferInternal,
15    despawns: Vec<Entity>,
16    writes: Vec<Box<dyn FnOnce(&mut World) + Send + Sync>>,
17}
18
19impl CommandBuffer {
20    /// Creates a new empty commandbuffer
21    pub fn new() -> Self {
22        Self::default()
23    }
24
25    /// Inserts components into an already existing or reserved entity
26    pub fn insert(&mut self, entity: Entity, components: impl DynamicBundle) {
27        self.components.insert(entity, components)
28    }
29
30    /// Inserts a single component into an already existing or reserved entity
31    pub fn insert_one(&mut self, entity: Entity, component: impl Component) {
32        self.components.insert(entity, (component,))
33    }
34
35    /// Spawns a new entity with components.
36    /// If the entity ID is desired, consider reserving an entity and then inserting
37    pub fn spawn(&mut self, components: impl DynamicBundle) {
38        self.components.spawn(components)
39    }
40
41    /// Despawn an entity from the world
42    pub fn despawn(&mut self, entity: Entity) {
43        self.despawns.push(entity)
44    }
45
46    /// Remove components from entity
47    pub fn remove<C: Component + Bundle>(&mut self, entity: Entity) {
48        self.writes.push(Box::new(move |w| {
49            let _ = w.remove::<C>(entity);
50        }))
51    }
52
53    /// Remove a single component from the world
54    pub fn remove_one<C: Component>(&mut self, entity: Entity) {
55        self.writes.push(Box::new(move |w| {
56            let _ = w.remove_one::<C>(entity);
57        }))
58    }
59
60    /// Applies the recorded commands on the world
61    pub fn execute(&mut self, world: &mut World) {
62        self.components.run_on(world);
63
64        self.writes.drain(..).for_each(|cmd| (cmd)(world));
65
66        self.despawns
67            .drain(..)
68            .for_each(|e| world.despawn(e).expect("Failed to despawn entity"));
69    }
70
71    /// Nest a commandbuffer
72    pub fn append(&mut self, mut other: Self) {
73        self.write(move |w| other.execute(w))
74    }
75
76    /// Record a custom command modifying the world
77    pub fn write(&mut self, cmd: impl FnOnce(&mut World) + Component) {
78        self.writes.push(Box::new(cmd))
79    }
80
81    /// Drop all recorded commands
82    pub fn clear(&mut self) {
83        self.despawns.clear();
84        self.writes.clear();
85        self.components.clear();
86    }
87}
88