specs_task/
user.rs

1use crate::{components::*, writer::TaskWriter, TaskData};
2
3use specs::{prelude::*, storage::GenericReadStorage, world::LazyBuilder};
4
5/// `SystemData` for all read-only task-related operations. Can create and modify tasks lazily.
6pub type TaskUser<'a> = TaskData<'a,
7    ReadStorage<'a, TaskProgress>,
8    ReadStorage<'a, SingleEdge>,
9    ReadStorage<'a, MultiEdge>,
10    (),
11>;
12
13impl<'a, P, S, M, F> TaskData<'a, P, S, M, F>
14where
15    P: GenericReadStorage<Component=TaskProgress>,
16    S: GenericReadStorage<Component=SingleEdge>,
17    M: GenericReadStorage<Component=MultiEdge>,
18    &'a P: 'a + Join,
19{
20    /// Like `make_task`, but use `entity` for tracking the task components. This can make it easier
21    /// to manage tasks coupled with a specific entity (rather than storing a separate task entity
22    /// in a component).
23    pub fn make_task_with_entity_lazy<'b, T: TaskComponent<'b> + Send + Sync>(
24        &self, entity: Entity, task: T
25    ) {
26        self.lazy.exec(move |world| {
27            world.exec(move |(mut builder, mut task_storage): (TaskWriter, WriteStorage<T>)| {
28                builder.make_task_with_entity(entity, task, &mut task_storage);
29            })
30        })
31    }
32
33    /// Create a new task entity with the given `TaskComponent`. The task will not make progress
34    /// until it is either finalized or the descendent of a finalized entity.
35    pub fn make_task_lazy<'b, T: TaskComponent<'b> + Send + Sync>(&self, task: T) -> Entity {
36        let entity = self.entities.create();
37        self.make_task_with_entity_lazy(entity, task);
38
39        entity
40    }
41
42    pub fn make_final_task_lazy<'b, T: TaskComponent<'b> + Send + Sync>(
43        &self, task: T, on_completion: OnCompletion,
44    ) -> Entity {
45        let entity = self.make_task_lazy(task);
46        self.finalize_lazy(entity, on_completion);
47
48        entity
49    }
50
51    /// Create a new fork entity with no children.
52    pub fn make_fork_lazy(&self) -> Entity {
53        let entity = self
54            .lazy
55            .create_entity(&self.entities)
56            .with(MultiEdge::default())
57            .build();
58        log::debug!("Created fork {:?}", entity);
59
60        entity
61    }
62
63    /// Add `prong` as a child on the `MultiEdge` of `fork_entity`.
64    pub fn add_prong_lazy(&self, fork_entity: Entity, prong: Entity) {
65        self.lazy.exec(move |world| {
66            world.exec(move |mut builder: TaskWriter| {
67                builder.add_prong(fork_entity, prong);
68            })
69        });
70    }
71
72    /// Creates a `SingleEdge` from `parent` to `child`. Creates a fork-join if `parent` is a fork.
73    pub fn join_lazy(&self, parent: Entity, child: Entity) {
74        self.lazy.exec(move |world| {
75            world.exec(move |mut builder: TaskWriter| {
76                builder.join(parent, child);
77            })
78        });
79    }
80
81    /// Mark `entity` as final. This will make all of `entity`'s descendents visible to the
82    /// `TaskManagerSystem`, allowing them to make progress. If `OnCompletion::Delete`, then
83    /// `entity` and all of its descendents will be deleted when `entity` is complete (and hence the
84    /// entire graph is complete). Otherwise, you need to clean up the entities your self by calling
85    /// `delete_entity_and_descendents`. God help you if you leak an orphaned entity.
86    pub fn finalize_lazy(&self, entity: Entity, on_completion: OnCompletion) {
87        LazyBuilder {
88            entity,
89            lazy: &self.lazy,
90        }
91        .with(FinalTag { on_completion })
92        .build();
93    }
94
95    /// Returns true iff the task was seen as complete on the last run of the `TaskManagerSystem`.
96    pub fn task_is_complete(&self, task: Entity) -> bool {
97        if let Some(progress) = self.progress.get(task) {
98            progress.is_complete()
99        } else {
100            // Task entity may not have a TaskProgress component yet if it's constructed lazily.
101            false
102        }
103    }
104
105    /// Returns true iff all of `entity`'s children are complete.
106    fn fork_is_complete(&self, multi_children: &[Entity]) -> bool {
107        // We know that a fork's SingleEdge child is complete if any of the MultiEdge children are
108        // complete.
109        for child in multi_children.iter() {
110            if !self.entity_is_complete(*child) {
111                return false;
112            }
113        }
114
115        true
116    }
117
118    /// Tells you whether a fork or a task entity is complete.
119    pub fn entity_is_complete(&self, entity: Entity) -> bool {
120        // Only fork entities can have `MultiEdge`s. If the entity is being created lazily, we won't
121        // know if it's a fork or task, but we won't consider it complete regardless.
122        if let Some(MultiEdge { children }) = self.multi_edges.get(entity) {
123            self.fork_is_complete(&children)
124        } else {
125            self.task_is_complete(entity)
126        }
127    }
128
129    /// Returns the number of tasks that haven't yet completed.
130    pub fn count_tasks_in_progress(&'a self) -> usize {
131        (&self.progress).join().count()
132    }
133
134    /// Deletes only the descendent entities of `entity`, but leaves `entity` alive.
135    fn delete_descendents(&self, entity: Entity) {
136        if let Some(MultiEdge { children }) = self.multi_edges.get(entity) {
137            for child in children.iter() {
138                self.delete_entity_and_descendents(*child);
139            }
140        }
141        if let Some(SingleEdge { child }) = self.single_edges.get(entity) {
142            self.delete_entity_and_descendents(*child);
143        }
144    }
145
146    /// Deletes `entity` and all of its descendents.
147    pub fn delete_entity_and_descendents(&self, entity: Entity) {
148        // Support async deletion. If a child is deleted, we assume all of its descendants were also
149        // deleted.
150        if !self.entities.is_alive(entity) {
151            return;
152        }
153
154        self.delete_descendents(entity);
155        log::debug!("Deleting {:?}", entity);
156        self.entities.delete(entity).unwrap();
157    }
158
159    /// Deletes the entity and descendents if they are all complete. Returns true iff the entity and
160    /// all descendents are complete.
161    pub fn delete_if_complete(&self, entity: Entity) -> bool {
162        if self.entity_is_complete(entity) {
163            self.delete_entity_and_descendents(entity);
164
165            true
166        } else {
167            false
168        }
169    }
170
171    /// Returns `true` iff `entity` is complete.
172    fn maintain_task_and_descendents(&self, entity: Entity) -> bool {
173        let (is_unblocked, is_complete) = if let Some(progress) = self.progress.get(entity) {
174            (progress.is_unblocked(), progress.is_complete())
175        } else {
176            // Missing progress means the task is complete and progress was already removed.
177            return true;
178        };
179
180        if is_complete {
181            log::debug!(
182                "Noticed task {:?} is complete, removing TaskProgress",
183                entity
184            );
185            return true;
186        }
187
188        // If `is_unblocked`, the children don't need maintenance, because we already verified they
189        // are all complete.
190        if is_unblocked {
191            return false;
192        }
193
194        // Unblock the task if its child is complete.
195        let mut child_complete = true;
196        if let Some(SingleEdge { child }) = self.single_edges.get(entity).cloned() {
197            child_complete = self.maintain_entity_and_descendents(child);
198        }
199        if child_complete {
200            log::debug!("Unblocking task {:?}", entity);
201            let progress = self
202                .progress
203                .get(entity)
204                .expect("Blocked task must have progress");
205            progress.unblock();
206        }
207
208        false
209    }
210
211    /// Returns `true` iff `entity` is complete.
212    fn maintain_fork_and_descendents(
213        &self,
214        entity: Entity,
215        multi_edge_children: &[Entity],
216    ) -> bool {
217        // We make sure that the SingleEdge child completes before any of the MultiEdge descendents
218        // can start.
219        let mut single_child_complete = true;
220        if let Some(SingleEdge { child }) = self.single_edges.get(entity).cloned() {
221            single_child_complete = self.maintain_entity_and_descendents(child);
222        }
223        let mut multi_children_complete = true;
224        if single_child_complete {
225            for child in multi_edge_children.iter() {
226                multi_children_complete &= self.maintain_entity_and_descendents(*child);
227            }
228        }
229
230        single_child_complete && multi_children_complete
231    }
232
233    /// Returns `true` iff `entity` is complete.
234    pub(crate) fn maintain_entity_and_descendents(&self, entity: Entity) -> bool {
235        // Only fork entities can have `MultiEdge`s, and they always do.
236        if let Some(MultiEdge { children }) = self.multi_edges.get(entity).cloned() {
237            self.maintain_fork_and_descendents(entity, &children)
238        } else {
239            self.maintain_task_and_descendents(entity)
240        }
241    }
242}