feat: System priority
This commit is contained in:
parent
4ba38af246
commit
cadabc219d
|
@ -1,3 +1,6 @@
|
|||
import System from '@/ecs/system.js';
|
||||
import gather from '@/util/gather.js';
|
||||
|
||||
export default gather(import.meta.glob('./*.js', {eager: true, import: 'default'}));
|
||||
const gathered = gather(import.meta.glob('./*.js', {eager: true, import: 'default'}));
|
||||
|
||||
export default System.sort(gathered);
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
import Digraph from '@/util/digraph.js';
|
||||
|
||||
import Query from './query.js';
|
||||
|
||||
|
@ -54,6 +55,12 @@ export default class System {
|
|||
this.ecs.insertMany(components);
|
||||
}
|
||||
|
||||
static get priority() {
|
||||
return {
|
||||
phase: 'normal',
|
||||
}
|
||||
}
|
||||
|
||||
static queries() {
|
||||
return {};
|
||||
}
|
||||
|
@ -76,6 +83,38 @@ export default class System {
|
|||
return this.queries[query].select();
|
||||
}
|
||||
|
||||
static sort(Systems) {
|
||||
const phases = {
|
||||
'pre': new Digraph(),
|
||||
'normal': new Digraph(),
|
||||
'post': new Digraph(),
|
||||
};
|
||||
for (const systemName in Systems) {
|
||||
const {priority} = Systems[systemName];
|
||||
const phase = phases[priority.phase || 'normal'];
|
||||
phase.ensureTail(systemName);
|
||||
if (priority.before) {
|
||||
for (const before of Array.isArray(priority.before) ? priority.before : [priority.before]) {
|
||||
phase.addDependency(before, systemName);
|
||||
}
|
||||
}
|
||||
if (priority.after) {
|
||||
for (const after of Array.isArray(priority.after) ? priority.after : [priority.after]) {
|
||||
phase.addDependency(systemName, after);
|
||||
}
|
||||
}
|
||||
}
|
||||
const sorted = [
|
||||
...phases['pre'].sort(),
|
||||
...phases['normal'].sort(),
|
||||
...phases['post'].sort(),
|
||||
];
|
||||
return Object.fromEntries(
|
||||
Object.entries(Systems)
|
||||
.toSorted(([l], [r]) => sorted.indexOf(l) - sorted.indexOf(r)),
|
||||
);
|
||||
}
|
||||
|
||||
tickDestruction() {
|
||||
this.deindex(this.destroying);
|
||||
this.destroying = [];
|
||||
|
|
87
app/util/digraph.js
Normal file
87
app/util/digraph.js
Normal file
|
@ -0,0 +1,87 @@
|
|||
export default class Digraph {
|
||||
|
||||
arcs = new Map();
|
||||
|
||||
addDependency(head, tail) {
|
||||
this.ensureTail(head);
|
||||
this.ensureTail(tail).add(head);
|
||||
}
|
||||
|
||||
detectCycles() {
|
||||
const cycles = [];
|
||||
const visited = new Set();
|
||||
const walking = new Set();
|
||||
const walk = (vertex) => {
|
||||
if (!visited.has(vertex)) {
|
||||
visited.add(vertex);
|
||||
walking.add(vertex);
|
||||
const it = this.neighbors(vertex);
|
||||
for (let current = it.next(); true !== current.done; current = it.next()) {
|
||||
const {value: neighbor} = current;
|
||||
if (!visited.has(neighbor)) {
|
||||
walk(neighbor);
|
||||
}
|
||||
else if (walking.has(neighbor)) {
|
||||
cycles.push([vertex, neighbor]);
|
||||
}
|
||||
}
|
||||
}
|
||||
walking.delete(vertex);
|
||||
};
|
||||
const {tails} = this;
|
||||
for (let current = tails.next(); true !== current.done; current = tails.next()) {
|
||||
walk(current.value);
|
||||
}
|
||||
return cycles;
|
||||
}
|
||||
|
||||
ensureTail(tail) {
|
||||
if (!this.arcs.has(tail)) {
|
||||
this.arcs.set(tail, new Set());
|
||||
}
|
||||
return this.arcs.get(tail);
|
||||
}
|
||||
|
||||
neighbors(vertex) {
|
||||
return this.arcs.get(vertex).values();
|
||||
}
|
||||
|
||||
sort() {
|
||||
const visited = new Set();
|
||||
const scores = new Map();
|
||||
const walk = (vertex, score) => {
|
||||
visited.add(vertex);
|
||||
const neighbors = this.neighbors(vertex);
|
||||
for (let current = neighbors.next(); true !== current.done; current = neighbors.next()) {
|
||||
const {value: neighbor} = current;
|
||||
if (!visited.has(neighbor)) {
|
||||
score = walk(neighbor, score);
|
||||
}
|
||||
}
|
||||
scores.set(vertex, score);
|
||||
return score - 1;
|
||||
};
|
||||
let score = this.arcs.size - 1;
|
||||
const {tails} = this;
|
||||
for (let current = tails.next(); true !== current.done; current = tails.next()) {
|
||||
const {value: vertex} = current;
|
||||
if (!visited.has(vertex)) {
|
||||
score = walk(vertex, score);
|
||||
}
|
||||
}
|
||||
return Array.from(scores.entries())
|
||||
.sort(([, l], [, r]) => l - r)
|
||||
.map(([vertex]) => vertex);
|
||||
}
|
||||
|
||||
removeDependency(head, tail) {
|
||||
if (this.arcs.has(tail)) {
|
||||
this.arcs.get(tail).delete(head);
|
||||
}
|
||||
}
|
||||
|
||||
get tails() {
|
||||
return this.arcs.keys();
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in New Issue
Block a user