use specs::{prelude::*, world::LazyBuilder};
use std::sync::atomic::{AtomicBool, Ordering};
pub trait TaskComponent<'a>: Component {
type Data: SystemData<'a>;
fn run(&mut self, data: &mut Self::Data) -> bool;
}
#[doc(hidden)]
#[derive(Default)]
pub struct TaskProgress {
pub(crate) is_complete: AtomicBool,
pub(crate) is_unblocked: bool,
}
impl Component for TaskProgress {
type Storage = VecStorage<Self>;
}
impl TaskProgress {
pub(crate) fn is_complete(&self) -> bool {
self.is_complete.load(Ordering::Relaxed)
}
pub(crate) fn complete(&self) {
self.is_complete.store(true, Ordering::Relaxed);
}
pub(crate) fn unblock(&mut self) {
self.is_unblocked = true;
}
}
#[doc(hidden)]
#[derive(Clone)]
pub struct SingleEdge {
pub(crate) child: Entity,
}
impl Component for SingleEdge {
type Storage = VecStorage<Self>;
}
#[doc(hidden)]
#[derive(Clone, Default)]
pub struct MultiEdge {
pub(crate) children: Vec<Entity>,
}
impl MultiEdge {
fn add_child(&mut self, entity: Entity) {
self.children.push(entity);
}
}
impl Component for MultiEdge {
type Storage = VecStorage<Self>;
}
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
pub enum OnCompletion {
None,
Delete,
DeleteDescendents,
}
impl Default for OnCompletion {
fn default() -> Self {
OnCompletion::None
}
}
#[doc(hidden)]
#[derive(Clone, Copy, Default)]
pub struct FinalTag {
pub(crate) on_completion: OnCompletion,
}
impl Component for FinalTag {
type Storage = VecStorage<Self>;
}
#[derive(SystemData)]
pub struct TaskMaker<'a> {
lazy: Read<'a, LazyUpdate>,
entities: Entities<'a>,
}
impl<'a> TaskMaker<'a> {
pub fn make_task_with_entity<'b, T: TaskComponent<'b>>(&self, entity: Entity, task: T) {
LazyBuilder {
entity,
lazy: &self.lazy,
}
.with(task)
.with(TaskProgress::default())
.build();
log::debug!("Created task {:?}", entity);
}
pub fn make_task<'b, T: TaskComponent<'b>>(&self, task: T) -> Entity {
let entity = self
.lazy
.create_entity(&self.entities)
.with(task)
.with(TaskProgress::default())
.build();
log::debug!("Created task {:?}", entity);
entity
}
pub fn make_final_task_with_entity<'b, T: TaskComponent<'b>>(
&self,
entity: Entity,
task: T,
on_completion: OnCompletion,
) -> Entity {
self.make_task_with_entity(entity, task);
self.finalize(entity, on_completion);
entity
}
pub fn make_final_task<'b, T: TaskComponent<'b>>(
&self,
task: T,
on_completion: OnCompletion,
) -> Entity {
let task_entity = self.make_task(task);
self.finalize(task_entity, on_completion);
task_entity
}
pub fn make_fork(&self) -> Entity {
let entity = self
.lazy
.create_entity(&self.entities)
.with(MultiEdge::default())
.build();
log::debug!("Created fork {:?}", entity);
entity
}
pub fn add_prong(&self, fork_entity: Entity, prong: Entity) {
self.lazy.exec_mut(move |world| {
let mut multi_edges = world.write_component::<MultiEdge>();
let multi_edge = multi_edges.get_mut(fork_entity).unwrap_or_else(|| {
panic!(
"Tried to add prong {:?} to non-fork entity {:?}",
prong, fork_entity
)
});
multi_edge.add_child(prong);
});
}
pub fn join(&self, parent: Entity, child: Entity) {
self.lazy.exec_mut(move |world| {
let mut single_edges = world.write_component::<SingleEdge>();
if let Some(edge) = single_edges.get_mut(parent) {
panic!(
"Attempted to make task {:?} child of {:?}, but task {:?} already has child {:?}",
child, parent, parent, edge.child
);
} else {
single_edges.insert(parent, SingleEdge { child }).unwrap();
}
});
}
pub fn finalize(&self, entity: Entity, on_completion: OnCompletion) {
self.lazy.exec_mut(move |world| {
let mut finalized = world.write_component::<FinalTag>();
finalized
.insert(entity, FinalTag { on_completion })
.unwrap();
});
}
}