diff --git a/src/js/game/game_system_with_filter.js b/src/js/game/game_system_with_filter.js index 7b1ffbf0..eb1807d2 100644 --- a/src/js/game/game_system_with_filter.js +++ b/src/js/game/game_system_with_filter.js @@ -21,9 +21,11 @@ export class GameSystemWithFilter extends GameSystem { /** * All entities which match the current components - * @type {Array} + * @type {Set} */ - this.allEntities = []; + this.allEntitiesSet = new Set(); + this.allEntitiesArray = []; + this.allEntitiesArrayIsOutdated = true; this.root.signals.entityAdded.add(this.internalPushEntityIfMatching, this); this.root.signals.entityGotNewComponent.add(this.internalReconsiderEntityToAdd, this); @@ -34,6 +36,17 @@ export class GameSystemWithFilter extends GameSystem { this.root.signals.bulkOperationFinished.add(this.refreshCaches, this); } + getUpdateEntitiesArray() { + if (!this.allEntitiesArrayIsOutdated) { + return this.allEntitiesArray; + } + + this.allEntitiesArray = [...this.allEntitiesSet.values()]; + + this.allEntitiesArrayIsOutdated = true; + return this.allEntitiesArray; + } + /** * @param {Entity} entity */ @@ -44,7 +57,7 @@ export class GameSystemWithFilter extends GameSystem { } } - assert(this.allEntities.indexOf(entity) < 0, "entity already in list: " + entity); + assert(!this.allEntitiesSet.has(entity), "entity already in list: " + entity); this.internalRegisterEntity(entity); } @@ -53,7 +66,7 @@ export class GameSystemWithFilter extends GameSystem { * @param {Entity} entity */ internalCheckEntityAfterComponentRemoval(entity) { - if (this.allEntities.indexOf(entity) < 0) { + if (!this.allEntitiesSet.has(entity)) { // Entity wasn't interesting anyways return; } @@ -61,7 +74,8 @@ export class GameSystemWithFilter extends GameSystem { for (let i = 0; i < this.requiredComponentIds.length; ++i) { if (!entity.components[this.requiredComponentIds[i]]) { // Entity is not interesting anymore - arrayDeleteValue(this.allEntities, entity); + //arrayDeleteValue(this.allEntities, entity); + this.allEntitiesArrayIsOutdated = this.allEntitiesSet.delete(entity); } } } @@ -76,20 +90,30 @@ export class GameSystemWithFilter extends GameSystem { return; } } - if (this.allEntities.indexOf(entity) >= 0) { + if (this.allEntitiesSet.has(entity)) { return; } this.internalRegisterEntity(entity); } refreshCaches() { - this.allEntities.sort((a, b) => a.uid - b.uid); + //this.allEntities.sort((a, b) => a.uid - b.uid); // Remove all entities which are queued for destroy - for (let i = 0; i < this.allEntities.length; ++i) { - const entity = this.allEntities[i]; + // for (let i = 0; i < this.allEntities.length; ++i) { + // const entity = this.allEntities[i]; + // if (entity.queuedForDestroy || entity.destroyed) { + // this.allEntities.splice(i, 1); + // } + // } + + for ( + let arr = [...this.allEntitiesSet.values()], i = arr.length - 1, entity; + (entity = arr[i]) && i >= 0; + --i + ) { if (entity.queuedForDestroy || entity.destroyed) { - this.allEntities.splice(i, 1); + this.allEntitiesArrayIsOutdated = this.allEntitiesSet.delete(entity); } } } @@ -106,12 +130,12 @@ export class GameSystemWithFilter extends GameSystem { * @param {Entity} entity */ internalRegisterEntity(entity) { - this.allEntities.push(entity); + this.allEntitiesSet.add(entity); - if (this.root.gameInitialized && !this.root.bulkOperationRunning) { - // Sort entities by uid so behaviour is predictable - this.allEntities.sort((a, b) => a.uid - b.uid); - } + // if (this.root.gameInitialized && !this.root.bulkOperationRunning) { + // // Sort entities by uid so behaviour is predictable + // this.allEntities.sort((a, b) => a.uid - b.uid); + // } } /** @@ -123,9 +147,6 @@ export class GameSystemWithFilter extends GameSystem { // We do this in refreshCaches afterwards return; } - const index = this.allEntities.indexOf(entity); - if (index >= 0) { - arrayDelete(this.allEntities, index); - } + this.allEntitiesSet.delete(entity); } } diff --git a/src/js/game/systems/belt_reader.js b/src/js/game/systems/belt_reader.js index abddd999..df780bcb 100644 --- a/src/js/game/systems/belt_reader.js +++ b/src/js/game/systems/belt_reader.js @@ -12,9 +12,12 @@ export class BeltReaderSystem extends GameSystemWithFilter { const now = this.root.time.now(); const minimumTime = now - globalConfig.readerAnalyzeIntervalSeconds; const minimumTimeForThroughput = now - 1; - for (let i = 0; i < this.allEntities.length; ++i) { - const entity = this.allEntities[i]; + for ( + let arr = this.getUpdateEntitiesArray(), i = arr.length - 1, entity; + (entity = arr[i]) && i >= 0; + --i + ) { const readerComp = entity.components.BeltReader; const pinsComp = entity.components.WiredPins; diff --git a/src/js/game/systems/constant_signal.js b/src/js/game/systems/constant_signal.js index 93417ef5..135501ce 100644 --- a/src/js/game/systems/constant_signal.js +++ b/src/js/game/systems/constant_signal.js @@ -19,8 +19,11 @@ export class ConstantSignalSystem extends GameSystemWithFilter { update() { // Set signals - for (let i = 0; i < this.allEntities.length; ++i) { - const entity = this.allEntities[i]; + for ( + let arr = this.getUpdateEntitiesArray(), i = arr.length - 1, entity; + (entity = arr[i]) && i >= 0; + --i + ) { const pinsComp = entity.components.WiredPins; const signalComp = entity.components.ConstantSignal; pinsComp.slots[0].value = signalComp.signal; diff --git a/src/js/game/systems/hub.js b/src/js/game/systems/hub.js index 2270f941..917ca240 100644 --- a/src/js/game/systems/hub.js +++ b/src/js/game/systems/hub.js @@ -25,15 +25,21 @@ export class HubSystem extends GameSystemWithFilter { * @param {DrawParameters} parameters */ draw(parameters) { - for (let i = 0; i < this.allEntities.length; ++i) { - this.drawEntity(parameters, this.allEntities[i]); + for ( + let arr = this.getUpdateEntitiesArray(), i = arr.length - 1, entity; + (entity = arr[i]) && i >= 0; + --i + ) { + this.drawEntity(parameters, entity); } } update() { - for (let i = 0; i < this.allEntities.length; ++i) { - // Set hub goal - const entity = this.allEntities[i]; + for ( + let arr = this.getUpdateEntitiesArray(), i = arr.length - 1, entity; + (entity = arr[i]) && i >= 0; + --i + ) { const pinsComp = entity.components.WiredPins; pinsComp.slots[0].value = this.root.shapeDefinitionMgr.getShapeItemFromDefinition( this.root.hubGoals.currentGoal.definition diff --git a/src/js/game/systems/item_acceptor.js b/src/js/game/systems/item_acceptor.js index 6d6fec77..1d43f3cf 100644 --- a/src/js/game/systems/item_acceptor.js +++ b/src/js/game/systems/item_acceptor.js @@ -18,8 +18,11 @@ export class ItemAcceptorSystem extends GameSystemWithFilter { this.root.hubGoals.getBeltBaseSpeed() * globalConfig.itemSpacingOnBelts; // * 2 because its only a half tile - for (let i = 0; i < this.allEntities.length; ++i) { - const entity = this.allEntities[i]; + for ( + let arr = this.getUpdateEntitiesArray(), i = arr.length - 1, entity; + (entity = arr[i]) && i >= 0; + --i + ) { const aceptorComp = entity.components.ItemAcceptor; const animations = aceptorComp.itemConsumptionAnimations; diff --git a/src/js/game/systems/item_ejector.js b/src/js/game/systems/item_ejector.js index 925dcc2e..386d3157 100644 --- a/src/js/game/systems/item_ejector.js +++ b/src/js/game/systems/item_ejector.js @@ -76,8 +76,11 @@ export class ItemEjectorSystem extends GameSystemWithFilter { } // Try to find acceptors for every ejector - for (let i = 0; i < this.allEntities.length; ++i) { - const entity = this.allEntities[i]; + for ( + let arr = this.getUpdateEntitiesArray(), i = arr.length - 1, entity; + (entity = arr[i]) && i >= 0; + --i + ) { this.recomputeSingleEntityCache(entity); } } @@ -195,8 +198,11 @@ export class ItemEjectorSystem extends GameSystemWithFilter { } // Go over all cache entries - for (let i = 0; i < this.allEntities.length; ++i) { - const sourceEntity = this.allEntities[i]; + for ( + let arr = this.getUpdateEntitiesArray(), i = arr.length - 1, sourceEntity; + (sourceEntity = arr[i]) && i >= 0; + --i + ) { const sourceEjectorComp = sourceEntity.components.ItemEjector; if (!sourceEjectorComp.enabled) { continue; diff --git a/src/js/game/systems/item_processor.js b/src/js/game/systems/item_processor.js index d58aa697..7c112d04 100644 --- a/src/js/game/systems/item_processor.js +++ b/src/js/game/systems/item_processor.js @@ -22,9 +22,11 @@ export class ItemProcessorSystem extends GameSystemWithFilter { } update() { - for (let i = 0; i < this.allEntities.length; ++i) { - const entity = this.allEntities[i]; - + for ( + let arr = this.getUpdateEntitiesArray(), i = arr.length - 1, entity; + (entity = arr[i]) && i >= 0; + --i + ) { const processorComp = entity.components.ItemProcessor; const ejectorComp = entity.components.ItemEjector; diff --git a/src/js/game/systems/lever.js b/src/js/game/systems/lever.js index 75b6cf28..4710ed09 100644 --- a/src/js/game/systems/lever.js +++ b/src/js/game/systems/lever.js @@ -14,9 +14,11 @@ export class LeverSystem extends GameSystemWithFilter { } update() { - for (let i = 0; i < this.allEntities.length; ++i) { - const entity = this.allEntities[i]; - + for ( + let arr = this.getUpdateEntitiesArray(), i = arr.length - 1, entity; + (entity = arr[i]) && i >= 0; + --i + ) { const leverComp = entity.components.Lever; const pinsComp = entity.components.WiredPins; diff --git a/src/js/game/systems/logic_gate.js b/src/js/game/systems/logic_gate.js index 3bfc20cd..ea873a41 100644 --- a/src/js/game/systems/logic_gate.js +++ b/src/js/game/systems/logic_gate.js @@ -28,8 +28,11 @@ export class LogicGateSystem extends GameSystemWithFilter { } update() { - for (let i = 0; i < this.allEntities.length; ++i) { - const entity = this.allEntities[i]; + for ( + let arr = this.getUpdateEntitiesArray(), i = arr.length - 1, entity; + (entity = arr[i]) && i >= 0; + --i + ) { const logicComp = entity.components.LogicGate; const slotComp = entity.components.WiredPins; diff --git a/src/js/game/systems/miner.js b/src/js/game/systems/miner.js index 94f2791e..9036d185 100644 --- a/src/js/game/systems/miner.js +++ b/src/js/game/systems/miner.js @@ -36,8 +36,11 @@ export class MinerSystem extends GameSystemWithFilter { miningSpeed *= 100; } - for (let i = 0; i < this.allEntities.length; ++i) { - const entity = this.allEntities[i]; + for ( + let arr = this.getUpdateEntitiesArray(), i = arr.length - 1, entity; + (entity = arr[i]) && i >= 0; + --i + ) { const minerComp = entity.components.Miner; // Reset everything on recompute diff --git a/src/js/game/systems/storage.js b/src/js/game/systems/storage.js index 5a2b57bb..6eda7b1f 100644 --- a/src/js/game/systems/storage.js +++ b/src/js/game/systems/storage.js @@ -26,8 +26,11 @@ export class StorageSystem extends GameSystemWithFilter { } update() { - for (let i = 0; i < this.allEntities.length; ++i) { - const entity = this.allEntities[i]; + for ( + let arr = this.getUpdateEntitiesArray(), i = arr.length - 1, entity; + (entity = arr[i]) && i >= 0; + --i + ) { const storageComp = entity.components.Storage; const pinsComp = entity.components.WiredPins; diff --git a/src/js/game/systems/underground_belt.js b/src/js/game/systems/underground_belt.js index 90d29e50..68a47d61 100644 --- a/src/js/game/systems/underground_belt.js +++ b/src/js/game/systems/underground_belt.js @@ -255,8 +255,11 @@ export class UndergroundBeltSystem extends GameSystemWithFilter { const delta = this.root.dynamicTickrate.deltaSeconds; - for (let i = 0; i < this.allEntities.length; ++i) { - const entity = this.allEntities[i]; + for ( + let arr = this.getUpdateEntitiesArray(), i = arr.length - 1, entity; + (entity = arr[i]) && i >= 0; + --i + ) { const undergroundComp = entity.components.UndergroundBelt; const pendingItems = undergroundComp.pendingItems;