refactor: indexing

This commit is contained in:
cha0s 2024-08-04 20:54:56 -05:00
parent eaec1d0022
commit 16a094806e
2 changed files with 42 additions and 48 deletions

View File

@ -23,18 +23,22 @@ export default class Ecs {
deferredChanges = {} deferredChanges = {}
$$deindexing = new Set();
$$destructionDependencies = new Map(); $$destructionDependencies = new Map();
$$detached = new Set(); $$detached = new Set();
diff = {}; diff = {};
Systems = {};
$$entities = {}; $$entities = {};
$$entityFactory = new EntityFactory(); $$entityFactory = new EntityFactory();
$$reindexing = new Set();
Systems = {};
constructor({Systems, Components} = {}) { constructor({Systems, Components} = {}) {
for (const componentName in Components) { for (const componentName in Components) {
this.Components[componentName] = new Components[componentName](this); this.Components[componentName] = new Components[componentName](this);
@ -129,8 +133,8 @@ export default class Ecs {
attach(entityIds) { attach(entityIds) {
for (const entityId of entityIds) { for (const entityId of entityIds) {
this.$$detached.delete(entityId); this.$$detached.delete(entityId);
this.$$reindexing.add(entityId);
} }
this.reindex(entityIds);
} }
changed(criteria) { changed(criteria) {
@ -209,6 +213,7 @@ export default class Ecs {
} }
} }
entityIds.add(entityId); entityIds.add(entityId);
this.$$reindexing.add(entityId);
this.rebuild(entityId, () => componentNames); this.rebuild(entityId, () => componentNames);
for (const componentName of componentNames) { for (const componentName of componentNames) {
if (!creating[componentName]) { if (!creating[componentName]) {
@ -234,7 +239,6 @@ export default class Ecs {
this.markChange(entityId, components); this.markChange(entityId, components);
} }
} }
this.reindex(entityIds);
return entityIds; return entityIds;
} }
@ -301,8 +305,9 @@ export default class Ecs {
destroyMany(entityIds) { destroyMany(entityIds) {
const destroying = {}; const destroying = {};
this.deindex(entityIds); // this.deindex(entityIds);
for (const entityId of entityIds) { for (const entityId of entityIds) {
this.$$deindexing.add(entityId);
if (!this.$$entities[entityId]) { if (!this.$$entities[entityId]) {
throw new Error(`can't destroy non-existent entity ${entityId}`); throw new Error(`can't destroy non-existent entity ${entityId}`);
} }
@ -323,8 +328,8 @@ export default class Ecs {
} }
detach(entityIds) { detach(entityIds) {
this.deindex(entityIds);
for (const entityId of entityIds) { for (const entityId of entityIds) {
this.$$deindexing.add(entityId);
this.$$detached.add(entityId); this.$$detached.add(entityId);
} }
} }
@ -358,6 +363,7 @@ export default class Ecs {
diff[componentName] = {}; diff[componentName] = {};
inserting[componentName].push([entityId, components[componentName]]); inserting[componentName].push([entityId, components[componentName]]);
} }
this.$$reindexing.add(entityId);
unique.add(entityId); unique.add(entityId);
this.markChange(entityId, diff); this.markChange(entityId, diff);
} }
@ -366,7 +372,6 @@ export default class Ecs {
promises.push(this.Components[componentName].insertMany(inserting[componentName])); promises.push(this.Components[componentName].insertMany(inserting[componentName]));
} }
await Promise.all(promises); await Promise.all(promises);
this.reindex(unique);
} }
markChange(entityId, components) { markChange(entityId, components) {
@ -383,13 +388,7 @@ export default class Ecs {
} }
// Created? // Created?
else if (!this.diff[entityId]) { else if (!this.diff[entityId]) {
const filtered = {}; this.diff[entityId] = components;
for (const componentName in components) {
filtered[componentName] = false === components[componentName]
? false
: components[componentName];
}
this.diff[entityId] = filtered;
} }
// Otherwise, merge. // Otherwise, merge.
else { else {
@ -487,6 +486,7 @@ export default class Ecs {
const removing = {}; const removing = {};
const unique = new Set(); const unique = new Set();
for (const [entityId, components] of entities) { for (const [entityId, components] of entities) {
this.$$reindexing.add(entityId);
unique.add(entityId); unique.add(entityId);
const diff = {}; const diff = {};
for (const componentName of components) { for (const componentName of components) {
@ -502,7 +502,6 @@ export default class Ecs {
for (const componentName in removing) { for (const componentName in removing) {
this.Components[componentName].destroyMany(removing[componentName]); this.Components[componentName].destroyMany(removing[componentName]);
} }
this.reindex(unique);
} }
static serialize(ecs, view) { static serialize(ecs, view) {
@ -523,6 +522,26 @@ export default class Ecs {
} }
tick(elapsed) { tick(elapsed) {
// destroy entities
const destroying = new Set();
for (const [entityId, {promises}] of this.$$destructionDependencies) {
if (0 === promises.size) {
destroying.add(entityId);
}
}
if (destroying.size > 0) {
this.destroyMany(destroying);
for (const entityId of destroying) {
this.$$destructionDependencies.get(entityId).resolvers.resolve();
this.$$destructionDependencies.delete(entityId);
}
}
// update indices
this.deindex(this.$$deindexing);
this.$$deindexing.clear();
this.reindex(this.$$reindexing);
this.$$reindexing.clear();
// tick systems
for (const systemName in this.Systems) { for (const systemName in this.Systems) {
const System = this.Systems[systemName]; const System = this.Systems[systemName];
if (!System.active) { if (!System.active) {
@ -538,19 +557,6 @@ export default class Ecs {
System.elapsed -= System.frequency; System.elapsed -= System.frequency;
} }
} }
const destroying = new Set();
for (const [entityId, {promises}] of this.$$destructionDependencies) {
if (0 === promises.size) {
destroying.add(entityId);
}
}
if (destroying.size > 0) {
this.destroyMany(destroying);
for (const entityId of destroying) {
this.$$destructionDependencies.get(entityId).resolvers.resolve();
this.$$destructionDependencies.delete(entityId);
}
}
} }
toJSON() { toJSON() {
@ -583,6 +589,7 @@ export default class Ecs {
} }
updating[componentName].push([entityId, components[componentName]]); updating[componentName].push([entityId, components[componentName]]);
} }
this.$$reindexing.add(entityId);
unique.add(entityId); unique.add(entityId);
} }
const promises = []; const promises = [];
@ -590,7 +597,6 @@ export default class Ecs {
promises.push(this.Components[componentName].updateMany(updating[componentName])); promises.push(this.Components[componentName].updateMany(updating[componentName]));
} }
await Promise.all(promises); await Promise.all(promises);
this.reindex(unique);
} }
} }

View File

@ -2,7 +2,7 @@ export default class Query {
$$criteria = {with: [], without: []}; $$criteria = {with: [], without: []};
$$ecs; $$ecs;
$$index = new Set(); $$map = new Map();
constructor(parameters, ecs) { constructor(parameters, ecs) {
this.$$ecs = ecs; this.$$ecs = ecs;
@ -20,19 +20,19 @@ export default class Query {
} }
get count() { get count() {
return this.$$index.size; return this.$$map.size;
} }
deindex(entityIds) { deindex(entityIds) {
for (const entityId of entityIds) { for (const entityId of entityIds) {
this.$$index.delete(entityId); this.$$map.delete(entityId);
} }
} }
reindex(entityIds) { reindex(entityIds) {
if (0 === this.$$criteria.with.length && 0 === this.$$criteria.without.length) { if (0 === this.$$criteria.with.length && 0 === this.$$criteria.without.length) {
for (const entityId of entityIds) { for (const entityId of entityIds) {
this.$$index.add(entityId); this.$$map.set(entityId, this.$$ecs.get(entityId));
} }
return; return;
} }
@ -53,28 +53,16 @@ export default class Query {
} }
} }
if (should) { if (should) {
this.$$index.add(entityId); this.$$map.set(entityId, this.$$ecs.get(entityId));
} }
else if (!should) { else if (!should) {
this.$$index.delete(entityId); this.$$map.delete(entityId);
} }
} }
} }
select() { select() {
const it = this.$$index.values(); return this.$$map.values();
return {
[Symbol.iterator]() {
return this;
},
next: () => {
const result = it.next();
if (result.done) {
return {done: true, value: undefined};
}
return {done: false, value: this.$$ecs.get(result.value)};
},
};
} }
} }