import * as I from 'immutable'; import {compose} from '@avocado/core'; import {StateProperty, Trait} from '@avocado/entity'; const decorate = compose( StateProperty('informSize'), ); class InformedBase extends Trait { static defaultState() { return { informSize: [640, 360], }; } initialize() { this._sentSelf = false; this._socket = undefined; this.lastNearby = I.Set(); } destroy() { if (this._socket) { delete this._socket.entity; delete this._socket; } } createIndexedReducer() { let previous = {}; return (diff, indexed) => { const reducedDiff = {}; const current = {}; for (const index in indexed) { const item = indexed[index]; current[index] = item; // Diff. if (previous[index]) { if (diff[index]) { reducedDiff[index] = diff[index]; } } // Added. else { reducedDiff[index] = item.state.toJS(); } } // Removed. for (const index in previous) { if (!current[index]) { reducedDiff[index] = false; } } previous = current; return reducedDiff; }; } get socket() { return this._socket; } set socket(socket) { socket.entity = this.entity; this._socket = socket; } methods() { const entityReducer = this.createIndexedReducer(); const layerReducer = this.createIndexedReducer(); return { inform: (diff) => { // Remove dead updates. if (0 === Object.keys(diff).length) { return; } if (!this._sentSelf) { diff.selfEntity = this.entity.instanceUuid; this._sentSelf = true; } this._socket.send({ type: 'state-update', payload: diff, }); }, reduceStateDiff: (diff) => { diff.room = diff.room || {}; diff.room.layers = diff.room.layers || {}; // Index layers. const room = this.entity.room; const indexedLayers = {}; for (const index in room.layers.layers) { const layer = room.layers.layers[index]; indexedLayers[index] = layer; } // Reduce layers. diff.room.layers = layerReducer( diff.room.layers, indexedLayers, ); for (const index in diff.room.layers) { // Index entities. const layer = room.layers.layers[index]; const visibleEntities = layer.entityList.visibleEntities( [0, 0, 640, 360] ); const indexedEntities = {}; for (const entity of visibleEntities) { indexedEntities[entity.instanceUuid] = entity; } // Reduce entities. diff.room.layers[index].entityList = entityReducer( diff.room.layers[index].entityList, indexedEntities, ); } return diff; }, }; } } export class Informed extends decorate(InformedBase) {}