From 0c5f6db70c1ff184c36d1d30d9e926991a7f3ced Mon Sep 17 00:00:00 2001 From: Bart Remmers Date: Tue, 7 Mar 2023 22:49:36 +0100 Subject: [PATCH] Migrated array of entities in entity_manager.js to map using uid as key --- src/js/game/core.js | 2 +- src/js/game/entity_manager.js | 54 ++++++++----------- .../game/hud/parts/puzzle_editor_settings.js | 2 +- src/js/game/hud/parts/wires_overlay.js | 2 +- src/js/game/logic.js | 2 +- src/js/savegame/savegame_serializer.js | 4 +- src/js/savegame/serializer_internal.js | 7 ++- 7 files changed, 32 insertions(+), 41 deletions(-) diff --git a/src/js/game/core.js b/src/js/game/core.js index 7283710e..f7583418 100644 --- a/src/js/game/core.js +++ b/src/js/game/core.js @@ -440,7 +440,7 @@ export class GameCore { this.overlayAlpha = lerp(this.overlayAlpha, desiredOverlayAlpha, 0.25); // On low performance, skip the fade - if (this.root.entityMgr.entities.length > 5000 || this.root.dynamicTickrate.averageFps < 50) { + if (this.root.entityMgr.entities.size > 5000 || this.root.dynamicTickrate.averageFps < 50) { this.overlayAlpha = desiredOverlayAlpha; } diff --git a/src/js/game/entity_manager.js b/src/js/game/entity_manager.js index b4101fc8..ffd2ea97 100644 --- a/src/js/game/entity_manager.js +++ b/src/js/game/entity_manager.js @@ -20,8 +20,8 @@ export class EntityManager extends BasicSerializableObject { /** @type {GameRoot} */ this.root = root; - /** @type {Array} */ - this.entities = []; + /** @type {Map} */ + this.entities = new Map(); // We store a separate list with entities to destroy, since we don't destroy // them instantly @@ -48,7 +48,7 @@ export class EntityManager extends BasicSerializableObject { } getStatsText() { - return this.entities.length + " entities [" + this.destroyList.length + " to kill]"; + return this.entities.size + " entities [" + this.destroyList.length + " to kill]"; } // Main update @@ -63,7 +63,7 @@ export class EntityManager extends BasicSerializableObject { */ registerEntity(entity, uid = null) { if (G_IS_DEV && !globalConfig.debug.disableSlowAsserts) { - assert(this.entities.indexOf(entity) < 0, `RegisterEntity() called twice for entity ${entity}`); + assert(this.entities.get(entity.uid) !== entity, `RegisterEntity() called twice for entity ${entity}`); } assert(!entity.destroyed, `Attempting to register destroyed entity ${entity}`); @@ -72,7 +72,11 @@ export class EntityManager extends BasicSerializableObject { assert(uid >= 0 && uid < Number.MAX_SAFE_INTEGER, "Invalid uid passed: " + uid); } - this.entities.push(entity); + // Give each entity a unique id + entity.uid = uid ? uid : this.generateUid(); + entity.registered = true; + + this.entities.set(entity.uid, entity); // Register into the componentToEntity map for (const componentId in entity.components) { @@ -85,10 +89,6 @@ export class EntityManager extends BasicSerializableObject { } } - // Give each entity a unique id - entity.uid = uid ? uid : this.generateUid(); - entity.registered = true; - this.root.signals.entityAdded.dispatch(entity); } @@ -136,23 +136,17 @@ export class EntityManager extends BasicSerializableObject { * @returns {Entity} */ findByUid(uid, errorWhenNotFound = true) { - const arr = this.entities; - for (let i = 0, len = arr.length; i < len; ++i) { - const entity = arr[i]; - if (entity.uid === uid) { - if (entity.queuedForDestroy || entity.destroyed) { - if (errorWhenNotFound) { - logger.warn("Entity with UID", uid, "not found (destroyed)"); - } - return null; - } - return entity; + const entity = this.entities.get(uid); + + if (entity === undefined || entity.queuedForDestroy || entity.destroyed) { + if (errorWhenNotFound) { + logger.warn("Entity with UID", uid, "not found (destroyed)"); } + + return null } - if (errorWhenNotFound) { - logger.warn("Entity with UID", uid, "not found"); - } - return null; + + return entity } /** @@ -163,14 +157,12 @@ export class EntityManager extends BasicSerializableObject { */ getFrozenUidSearchMap() { const result = new Map(); - const array = this.entities; - for (let i = 0, len = array.length; i < len; ++i) { - const entity = array[i]; + for (const [uid, entity] of this.entities.entries()){ if (!entity.queuedForDestroy && !entity.destroyed) { - result.set(entity.uid, entity); + result.set(uid, entity); } } - return result; + return result } /** @@ -200,8 +192,8 @@ export class EntityManager extends BasicSerializableObject { for (let i = 0; i < this.destroyList.length; ++i) { const entity = this.destroyList[i]; - // Remove from entities list - arrayDeleteValue(this.entities, entity); + // Remove from entities map + this.entities.delete(entity.uid) // Remove from componentToEntity list this.unregisterEntityComponents(entity); diff --git a/src/js/game/hud/parts/puzzle_editor_settings.js b/src/js/game/hud/parts/puzzle_editor_settings.js index bd738198..4935898c 100644 --- a/src/js/game/hud/parts/puzzle_editor_settings.js +++ b/src/js/game/hud/parts/puzzle_editor_settings.js @@ -93,7 +93,7 @@ export class HUDPuzzleEditorSettings extends BaseHUDPart { trim() { // Now, find the center - const buildings = this.root.entityMgr.entities.slice(); + const buildings = Array.from(this.root.entityMgr.entities.values()); if (buildings.length === 0) { // nothing to do diff --git a/src/js/game/hud/parts/wires_overlay.js b/src/js/game/hud/parts/wires_overlay.js index 328d6689..a8357e53 100644 --- a/src/js/game/hud/parts/wires_overlay.js +++ b/src/js/game/hud/parts/wires_overlay.js @@ -64,7 +64,7 @@ export class HUDWiresOverlay extends BaseHUDPart { const desiredAlpha = this.root.currentLayer === "wires" ? 1.0 : 0.0; // On low performance, skip the fade - if (this.root.entityMgr.entities.length > 5000 || this.root.dynamicTickrate.averageFps < 50) { + if (this.root.entityMgr.entities.size > 5000 || this.root.dynamicTickrate.averageFps < 50) { this.currentAlpha = desiredAlpha; } else { this.currentAlpha = lerp(this.currentAlpha, desiredAlpha, 0.12); diff --git a/src/js/game/logic.js b/src/js/game/logic.js index 3fdc871e..9f3e9ef5 100644 --- a/src/js/game/logic.js +++ b/src/js/game/logic.js @@ -473,7 +473,7 @@ export class GameLogic { * Clears all belts and items */ clearAllBeltsAndItems() { - for (const entity of this.root.entityMgr.entities) { + for (const entity of this.root.entityMgr.entities.values()) { for (const component of Object.values(entity.components)) { /** @type {Component} */ (component).clear(); } diff --git a/src/js/savegame/savegame_serializer.js b/src/js/savegame/savegame_serializer.js index f95c9896..ac3fe8ca 100644 --- a/src/js/savegame/savegame_serializer.js +++ b/src/js/savegame/savegame_serializer.js @@ -37,7 +37,7 @@ export class SavegameSerializer { gameMode: root.gameMode.serialize(), entityMgr: root.entityMgr.serialize(), hubGoals: root.hubGoals.serialize(), - entities: this.internal.serializeEntityArray(root.entityMgr.entities), + entities: this.internal.serializeEntityMap(root.entityMgr.entities), beltPaths: root.systemMgr.systems.belt.serializePaths(), pinnedShapes: root.hud.parts.pinnedShapes ? root.hud.parts.pinnedShapes.serialize() : null, waypoints: root.hud.parts.waypoints ? root.hud.parts.waypoints.serialize() : null, @@ -86,7 +86,7 @@ export class SavegameSerializer { } seenUids.add(uid); - // Verify components + // Verify components/ if (!entity.components) { return ExplainedResult.bad("Entity is missing key 'components': " + JSON.stringify(entity)); } diff --git a/src/js/savegame/serializer_internal.js b/src/js/savegame/serializer_internal.js index c75cebad..e09e1f75 100644 --- a/src/js/savegame/serializer_internal.js +++ b/src/js/savegame/serializer_internal.js @@ -11,12 +11,11 @@ const logger = createLogger("serializer_internal"); export class SerializerInternal { /** * Serializes an array of entities - * @param {Array} array + * @param {Map} map */ - serializeEntityArray(array) { + serializeEntityMap(map) { const serialized = []; - for (let i = 0; i < array.length; ++i) { - const entity = array[i]; + for (const entity of map.values()) { if (!entity.queuedForDestroy && !entity.destroyed) { serialized.push(entity.serialize()); }