import * as I from 'immutable'; import mapValues from 'lodash.mapvalues'; import {compose} from '@avocado/core'; import {QuadTree} from '@avocado/math'; import {EventEmitter} from '@avocado/mixins'; import {create} from './index'; const decorate = compose( EventEmitter, ); class EntityListBase { constructor() { this.entities_PRIVATE = {}; this.quadTree_PRIVATE = new QuadTree(); this.world_PRIVATE = undefined; this.state_PRIVATE = I.Map(); this.uuidMap_PRIVATE = {}; } *[Symbol.iterator]() { for (const uuid in this.entities_PRIVATE) { const entity = this.entities_PRIVATE[uuid]; yield entity; } } acceptStateChange(change) { for (const uuid in change) { const localUuid = this.uuidMap_PRIVATE[uuid]; const entity = this.entities_PRIVATE[localUuid]; if (entity) { if (false === change[uuid]) { // Entity removed. this.removeEntity(entity); } else { entity.acceptStateChange(change[uuid]); this.state_PRIVATE = this.state_PRIVATE.set(localUuid, entity.state); } } else { // New entity. Create with change as traits. const newEntity = create().fromJSON({ traits: change[uuid], }); this.uuidMap_PRIVATE[uuid] = newEntity.instanceUuid; this.addEntity(newEntity); } } } addEntity(entity) { const uuid = entity.instanceUuid; this.entities_PRIVATE[uuid] = entity; this.state_PRIVATE = this.state_PRIVATE.set(uuid, entity.state); entity.addTrait('listed'); entity.list = this; entity.once('destroyed', () => { this.removeEntity(entity); }); this.emit('entityAdded', entity); } destroy() { for (const entity of this) { entity.destroy(); } } entity(uuid) { return this.entities_PRIVATE[uuid]; } mappedUuid(uuid) { return this.uuidMap_PRIVATE[uuid]; } get world() { return this.world_PRIVATE; } set world(world) { this.world_PRIVATE = world; } quadTree() { return this.quadTree_PRIVATE; } recomputeState() { for (const uuid in this.entities_PRIVATE) { const entity = this.entities_PRIVATE[uuid]; this.state_PRIVATE = this.state_PRIVATE.set(uuid, entity.state); } } removeEntity(entity) { const uuid = entity.instanceUuid; delete this.entities_PRIVATE[uuid]; this.state_PRIVATE = this.state_PRIVATE.delete(uuid); this.emit('entityRemoved', entity); if (entity.is('listed')) { entity.removeTrait('listed'); } } get state() { return this.state_PRIVATE; } tick(elapsed) { for (const uuid in this.entities_PRIVATE) { const entity = this.entities_PRIVATE[uuid]; if ('tick' in entity) { entity.tick(elapsed); } } if (this.world_PRIVATE) { this.world_PRIVATE.tick(elapsed); } this.recomputeState(); } } export class EntityList extends decorate(EntityListBase) {}