diff --git a/app/ecs/ecs.js b/app/ecs/ecs.js index 3915f1f..6fa4fe3 100644 --- a/app/ecs/ecs.js +++ b/app/ecs/ecs.js @@ -22,6 +22,8 @@ export default class Ecs { deferredChanges = {} + destroying = new Set(); + diff = {}; Systems = {}; @@ -206,6 +208,10 @@ export default class Ecs { } destroy(entityId) { + this.destroying.add(entityId); + } + + destroyImmediately(entityId) { this.destroyMany([entityId]); } @@ -427,31 +433,24 @@ export default class Ecs { } tick(elapsed) { - const destroying = new Set(); for (const systemName in this.Systems) { const System = this.Systems[systemName]; - if (System.active) { - if (System.frequency) { - System.elapsed += elapsed; - if (System.elapsed < System.frequency) { - continue; - } - } - while (!System.frequency || System.elapsed >= System.frequency) { - System.tick(System.frequency ? System.elapsed : elapsed); - for (let j = 0; j < System.destroying.length; j++) { - destroying.add(System.destroying[j]); - } - System.tickDestruction(); - if (!System.frequency) { - break; - } - System.elapsed -= System.frequency; - } + if (!System.active) { + continue; + } + if (!System.frequency) { + System.tick(elapsed); + continue; + } + System.elapsed += elapsed; + while (System.elapsed >= System.frequency) { + System.tick(System.frequency); + System.elapsed -= System.frequency; } } - if (destroying.size > 0) { - this.destroyMany(destroying.values()); + if (this.destroying.size > 0) { + this.destroyMany(this.destroying); + this.destroying.clear(); } } diff --git a/app/ecs/ecs.test.js b/app/ecs/ecs.test.js index f72dcc0..808b031 100644 --- a/app/ecs/ecs.test.js +++ b/app/ecs/ecs.test.js @@ -114,7 +114,7 @@ test('destroys entities', async () => { expect(ecs.get(entity)) .to.be.undefined; expect(() => { - ecs.destroy(entity); + ecs.destroyImmediately(entity); }) .to.throw(); }); @@ -170,50 +170,14 @@ test('ticks systems', async () => { .to.deep.equal(JSON.stringify({y: 128 + 30})); }); -test('creates many entities when ticking systems', () => { - const ecs = new Ecs({ - Systems: { - Spawn: class extends System { - tick() { - this.createManyEntities(Array.from({length: 5}).map(() => [])); - } - }, - }, - }); - ecs.system('Spawn').active = true; - ecs.create(); - expect(ecs.get(5)) - .to.be.undefined; - ecs.tick(1); - expect(ecs.get(5)) - .to.not.be.undefined; -}); - -test('creates entities when ticking systems', () => { - const ecs = new Ecs({ - Systems: { - Spawn: class extends System { - tick() { - this.createEntity(); - } - }, - }, - }); - ecs.system('Spawn').active = true; - ecs.create(); - expect(ecs.get(2)) - .to.be.undefined; - ecs.tick(1); - expect(ecs.get(2)) - .to.not.be.undefined; -}); - test('schedules entities to be deleted when ticking systems', () => { const ecs = new Ecs({ Systems: { Despawn: class extends System { tick() { - this.destroyEntity(1); + this.ecs.destroy(1); + expect(ecs.get(1)) + .to.not.be.undefined; } }, }, @@ -225,50 +189,6 @@ test('schedules entities to be deleted when ticking systems', () => { .to.be.undefined; }); -test('adds components to and remove components from entities when ticking systems', async () => { - let promise; - const ecs = new Ecs({ - Components: {Foo: wrapProperties('Foo', {bar: {type: 'uint8'}})}, - Systems: { - AddComponent: class extends System { - static queries() { - return { - default: ['Foo'], - }; - } - tick() { - promise = this.insertComponents(1, {Foo: {}}); - } - }, - RemoveComponent: class extends System { - static queries() { - return { - default: ['Foo'], - }; - } - tick() { - this.removeComponents(1, ['Foo']); - } - }, - }, - }); - ecs.system('AddComponent').active = true; - ecs.create(); - ecs.tick(1); - await promise; - expect(Array.from(ecs.system('AddComponent').select('default')).length) - .to.equal(1); - expect(ecs.get(1).Foo) - .to.not.be.undefined; - ecs.system('AddComponent').active = false; - ecs.system('RemoveComponent').active = true; - ecs.tick(1); - expect(Array.from(ecs.system('RemoveComponent').select('default')).length) - .to.equal(0); - expect(ecs.get(1).Foo) - .to.be.undefined; -}); - test('generates diffs for entity creation', async () => { const ecs = new Ecs(); let entity; @@ -347,7 +267,7 @@ test('generates diffs for deletions', async () => { let entity; entity = await ecs.create(); ecs.setClean(); - ecs.destroy(entity); + ecs.destroyImmediately(entity); expect(ecs.diff) .to.deep.equal({[entity]: false}); }); diff --git a/app/ecs/system.js b/app/ecs/system.js index 9b6d381..1bded49 100644 --- a/app/ecs/system.js +++ b/app/ecs/system.js @@ -6,8 +6,6 @@ export default class System { active = false; - destroying = []; - ecs; elapsed = 0; @@ -25,38 +23,12 @@ export default class System { 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', @@ -73,14 +45,6 @@ export default class System { } } - removeComponents(entityId, components) { - this.ecs.remove(entityId, components); - } - - removeManyComponents(entityIds) { - this.ecs.removeMany(entityIds); - } - select(query) { return this.queries[query].select(); } @@ -117,13 +81,6 @@ export default class System { ); } - tickDestruction() { - if (this.destroying.length > 0) { - this.deindex(this.destroying); - } - this.destroying = []; - } - tick() {} } diff --git a/app/server/engine.js b/app/server/engine.js index 56ed3ac..613e779 100644 --- a/app/server/engine.js +++ b/app/server/engine.js @@ -322,6 +322,7 @@ export default class Engine { stop() { clearTimeout(this.handle); this.handle = undefined; + this.tick(0); } tick(elapsed) { diff --git a/app/server/worker.js b/app/server/worker.js index b04354a..7cf74a7 100644 --- a/app/server/worker.js +++ b/app/server/worker.js @@ -45,8 +45,8 @@ const engine = new Engine(WorkerServer); onmessage = async (event) => { if (0 === event.data) { - engine.stop(); await engine.disconnectPlayer(0); + engine.stop(); await engine.saveEcses(); postMessage(0); return;