silphius/app/ecs/system.js
2024-07-04 09:10:37 -05:00

130 lines
2.6 KiB
JavaScript

import Digraph from '@/util/digraph.js';
import Query from './query.js';
export default class System {
active = false;
destroying = [];
ecs;
elapsed = 0;
frequency;
queries = {};
constructor(ecs) {
this.ecs = ecs;
const queries = this.constructor.queries();
for (const i in queries) {
this.queries[i] = new Query(queries[i], ecs);
}
this.reindex(ecs.entities);
}
createEntity(components) {
return this.ecs.create(components);
}
createManyEntities(componentsList) {
return this.ecs.createMany(componentsList);
}
deindex(entityIds) {
for (const i in this.queries) {
this.queries[i].deindex(entityIds);
}
}
destroyEntity(entityId) {
this.destroyManyEntities([entityId]);
}
destroyManyEntities(entityIds) {
for (let i = 0; i < entityIds.length; i++) {
this.destroying.push(entityIds[i]);
}
}
async insertComponents(entityId, components) {
return this.ecs.insert(entityId, components);
}
async insertManyComponents(components) {
return this.ecs.insertMany(components);
}
static get priority() {
return {
phase: 'normal',
}
}
static queries() {
return {};
}
reindex(entityIds) {
for (const i in this.queries) {
this.queries[i].reindex(entityIds);
}
}
removeComponents(entityId, components) {
this.ecs.remove(entityId, components);
}
removeManyComponents(entityIds) {
this.ecs.removeMany(entityIds);
}
select(query) {
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() {
if (this.destroying.length > 0) {
this.deindex(this.destroying);
}
this.destroying = [];
}
tick() {}
}