refactor: indexing
This commit is contained in:
parent
eaec1d0022
commit
16a094806e
|
@ -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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -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)};
|
|
||||||
},
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user