import * as I from 'immutable'; import {compose} from '@avocado/core'; import {simpleState, Trait} from '@avocado/entity'; const decorate = compose( simpleState('informSize'), ); class InformedBase extends Trait { static defaultState() { return { informSize: [1280, 720], }; } destroy() { delete this._socket.entity; delete this._socket; } initialize() { this._socket = undefined; this.lastNearby = I.Set(); } reduceStateDiffForEntityList(diff) { // Reduce the entity list. const nearbyEntities = this.entity.entitiesToInform(); const reducedEntityList = {}; let nearby = I.Set(); for (const entity of nearbyEntities) { nearby = nearby.add(entity); const uuid = entity.instanceUuid; if (this.lastNearby.has(entity)) { // Keep diff. if (diff.entityList[uuid]) { reducedEntityList[uuid] = diff.entityList[uuid]; } } else { // Added. reducedEntityList[uuid] = entity.state().toJS(); } } for (const entity of this.lastNearby.values()) { const uuid = entity.instanceUuid; if (!nearby.has(entity)) { // Removed. reducedEntityList[uuid] = false; } } // Track who's nearby. this.lastNearby = nearby; // Merge the reduction. diff = { ...diff, entityList: reducedEntityList, }; // Remove dead update. if (0 === Object.keys(diff.entityList).length) { delete diff.entityList; } return diff; } get socket() { return this._socket; } set socket(socket) { this._socket = socket; } methods() { return { entitiesToInform: () => { const informSize = this.entity.informSize.toJS(); return this.entity.nearbyEntities(informSize); }, inform: (diff) => { // Remove dead updates. if (0 === Object.keys(diff).length) { return; } this._socket.send({ type: 'state-update', payload: diff, }); }, reduceStateDiff: (diff) => { return this.reduceStateDiffForEntityList(diff); }, }; } } export class Informed extends decorate(InformedBase) {}