Fork-join multitasking for Legion ECS

Instead of hand-rolling state machines to sequence the effects of various ECS systems, spawn tasks as entities and declare explicit temporal dependencies between them.

Code Example: making task graphs and dispatching task runners

```rust use legion::prelude::; use legion_task::;

[derive(Clone)]

struct SaySomething(&'static str); impl<'a> TaskComponent<'a> for SaySomething { type Data = (); fn run(&mut self, data: &mut Self::Data) -> bool { println!("{}", self.0); true } }

[derive(Clone, Debug)]

struct PushValue { value: usize, }

impl<'a> TaskComponent<'a> for PushValue { type Data = Vec; fn run(&mut self, data: &mut Self::Data) -> bool { data.push(self.value); true } }

fn makestatictaskgraph(cmd: &mut CommandBuffer) { // Any component that implements TaskComponent can be spawned. let taskgraph: TaskGraph = seq!( @SaySomething("hello"), fork!( @PushValue { value: 1 }, @PushValue { value: 2 }, @PushValue { value: 3 } ), @SaySomething("goodbye") ); task_graph.assemble(OnCompletion::Delete, cmd); }

fn makedynamictaskgraph(cmd: &mut CommandBuffer) { let first: TaskGraph = task!(@SaySomething("hello")); let mut middle: TaskGraph = emptygraph!(); for i in 0..10 { middle = fork!(middle, @PushValue { value: i }); } let last: TaskGraph = task!(@SaySomething("goodbye")); let taskgraph: TaskGraph = seq!(first, middle, last); taskgraph.assemble(OnCompletion::Delete, cmd); }

fn buildsaysomethingtaskrunnersystem() -> Box { SystemBuilder::new("saysomethingtaskrunner") .withquery(taskrunnerquery::()) .build(|, mut world, , taskquery| { runtasks(&mut world, &mut (), taskquery) }) }

fn buildpushvaluetaskrunnersystem() -> Box { SystemBuilder::new("pushvaluetaskrunner") .writeresource::>() .withquery(taskrunnerquery::()) .build(|, mut world, value, taskquery| { runtasks(&mut world, &mut **value, taskquery) }) }

fn makeschedule() -> Schedule { Schedule::builder() .addsystem(buildsaysomethingtaskrunnersystem()) .addsystem(buildpushvaluetaskrunnersystem()) .addsystem(buildtaskmanagersystem("taskmanager")) .build() } ```