import * as I from 'immutable'; import mapValues from 'lodash.mapvalues'; import {arrayUnique, compose} from '@avocado/core'; import {QuadTree, Rectangle, Vector} from '@avocado/math'; import {EventEmitter} from '@avocado/mixins'; import {Synchronized} from '@avocado/state'; import {create} from '../index'; const decorate = compose( EventEmitter, ); export class EntityList extends decorate(Synchronized) { constructor() { super(); this._entities = {}; this._quadTree = new QuadTree(); this._uuidMap = {}; } *[Symbol.iterator]() { for (const uuid in this._entities) { const entity = this._entities[uuid]; yield entity; } } addEntity(entity) { const uuid = entity.instanceUuid; this._entities[uuid] = entity; this.state = this.state.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(); } } findEntity(uuid) { if (this._uuidMap[uuid]) { return this._entities[this._uuidMap[uuid]]; } if (this._entities[uuid]) { return this._entities[uuid]; } } patchStateStep(uuid, step) { const localUuid = this._uuidMap[uuid]; const entity = this._entities[localUuid]; if (entity) { if ('remove' === step.op) { // Entity removed. this.removeEntity(entity); } else { // Exists; patch. entity.patchState([step]); } } else { // New entity. Create with patch as traits. const newEntity = create().fromJSON({ traits: step.value, }); this._uuidMap[uuid] = newEntity.instanceUuid; this.addEntity(newEntity); } } get quadTree() { return this._quadTree; } removeEntity(entity) { const uuid = entity.instanceUuid; delete this._entities[uuid]; this.state = this.state.delete(uuid); this.emit('entityRemoved', entity); if (entity.is('listed')) { entity.removeTrait('listed'); } } tick(elapsed) { for (const uuid in this._entities) { const entity = this._entities[uuid]; entity.tick(elapsed); } this.state = this.state.withMutations((state) => { for (const uuid in this._entities) { const entity = this._entities[uuid]; state.set(uuid, entity.state); } }); } visibleEntities(query) { const quadTree = this._quadTree; const entities = quadTree.search(query).map((node) => { return node.data[2]; }); // Hitting multiple points for each entity can return duplicates. return arrayUnique(entities); } } export {EntityListView} from './view';