import * as I from 'immutable'; import mapValues from 'lodash.mapvalues'; import {compose} from '@avocado/core'; import {EventEmitter} from '@avocado/mixins'; import {create} from './index'; const decorate = compose( EventEmitter, ); class EntityListBase { constructor() { this.entities_PRIVATE = {}; 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.addEntity(newEntity); this.uuidMap_PRIVATE[uuid] = newEntity.instanceUuid; } } } addEntity(entity) { const uuid = entity.instanceUuid; this.entities_PRIVATE[uuid] = entity; this.state_PRIVATE = this.state_PRIVATE.set(uuid, entity.state()); entity.on('destroyed', () => { this.removeEntity(entity); }); this.emit('entityAdded', entity); } entity(uuid) { return this.entities_PRIVATE[uuid]; } 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); } 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); } } this.recomputeState(); } } export class EntityList extends decorate(EntityListBase) {}