///|
priv enum SystemEntry {
DirectSystem(System)
DeferredSystem(CommandSystem)
}
///|
priv struct ScheduledSystem {
stage : Stage
label : SystemLabel
before : Array[SystemLabel]
after : Array[SystemLabel]
run_if : (World) -> Bool
entry : SystemEntry
}
///|
fn always_run(_world : World) -> Bool {
true
}
///|
fn labels_contain(labels : Array[SystemLabel], label : SystemLabel) -> Bool {
for candidate in labels {
if candidate == label {
return true
}
}
false
}
///|
fn indices_contain(indices : Array[Int], index : Int) -> Bool {
for candidate in indices {
if candidate == index {
return true
}
}
false
}
///|
fn World::stage_contains_label(
self : Self,
indices : Array[Int],
label : SystemLabel,
) -> Bool {
for index in indices {
if self.systems[index].label == label {
return true
}
}
false
}
///|
fn World::ordered_contains_label(
self : Self,
indices : Array[Int],
label : SystemLabel,
) -> Bool {
for index in indices {
if self.systems[index].label == label {
return true
}
}
false
}
///|
fn World::system_ready(
self : Self,
system_index : Int,
candidates : Array[Int],
ordered : Array[Int],
) -> Bool {
let scheduled = self.systems[system_index]
for label in scheduled.after {
if self.stage_contains_label(candidates, label) &&
!self.ordered_contains_label(ordered, label) {
return false
}
}
for other_index in candidates {
if other_index != system_index && !indices_contain(ordered, other_index) {
let other = self.systems[other_index]
if labels_contain(other.before, scheduled.label) {
return false
}
}
}
true
}
///|
fn World::ordered_system_indices(self : Self, stage : Stage) -> Array[Int] {
let candidates : Array[Int] = []
for index in 0.. Bool,
) -> Unit {
self.systems.push({ stage, label, before, after, run_if, entry })
}
///|
fn World::run_system_entry(
self : Self,
entry : SystemEntry,
) -> Unit raise NotSpawned {
match entry {
DirectSystem(system) => (system.func)(self)
DeferredSystem(system) => {
let commands = self.commands()
(system.func)(self, commands)
self.apply_commands(commands)
}
}
}
///|
pub fn World::add_system_to_stage(
self : Self,
stage : Stage,
system : System,
before? : Array[SystemLabel] = [],
after? : Array[SystemLabel] = [],
run_if? : (World) -> Bool = always_run,
) -> Unit {
self.add_scheduled_system(
stage,
system.label(),
DirectSystem(system),
before,
after,
run_if,
)
}
///|
pub fn World::add_system_fn_to_stage(
self : Self,
stage : Stage,
func : (World) -> Unit,
name? : String = "system",
before? : Array[SystemLabel] = [],
after? : Array[SystemLabel] = [],
run_if? : (World) -> Bool = always_run,
) -> Unit {
self.add_system_to_stage(stage, System(func, name~), before~, after~, run_if~)
}
///|
pub fn World::add_command_system_to_stage(
self : Self,
stage : Stage,
system : CommandSystem,
before? : Array[SystemLabel] = [],
after? : Array[SystemLabel] = [],
run_if? : (World) -> Bool = always_run,
) -> Unit {
self.add_scheduled_system(
stage,
system.label(),
DeferredSystem(system),
before,
after,
run_if,
)
}
///|
pub fn World::add_command_system_fn_to_stage(
self : Self,
stage : Stage,
func : (World, Commands) -> Unit,
name? : String = "system",
before? : Array[SystemLabel] = [],
after? : Array[SystemLabel] = [],
run_if? : (World) -> Bool = always_run,
) -> Unit {
self.add_command_system_to_stage(
stage,
CommandSystem(func, name~),
before~,
after~,
run_if~,
)
}
///|
pub fn World::run_stage(self : Self, stage : Stage) -> Unit raise NotSpawned {
for index in self.ordered_system_indices(stage) {
let system = self.systems[index]
if (system.run_if)(self) {
self.run_system_entry(system.entry)
}
}
}
///|
pub fn World::fixed_step(self : Self) -> Unit raise NotSpawned {
self.run_stage(FixedUpdate)
}
///|
pub fn World::system_order(
self : Self,
stage? : Stage = Update,
) -> Array[SystemLabel] {
let labels : Array[SystemLabel] = []
for index in self.ordered_system_indices(stage) {
labels.push(self.systems[index].label)
}
labels
}