humus-old/traits/informed.js

140 lines
3.2 KiB
JavaScript
Raw Normal View History

2019-03-20 18:35:59 -05:00
import * as I from 'immutable';
2019-03-28 03:39:57 -05:00
import isPlainObject from 'is-plain-object';
2019-03-20 18:35:59 -05:00
2019-03-20 18:58:19 -05:00
import {compose} from '@avocado/core';
2019-03-23 23:24:31 -05:00
import {StateProperty, Trait} from '@avocado/entity';
2019-03-20 18:35:59 -05:00
2019-03-20 18:58:19 -05:00
const decorate = compose(
2019-03-23 23:24:31 -05:00
StateProperty('informSize'),
2019-03-20 18:58:19 -05:00
);
class InformedBase extends Trait {
static defaultState() {
return {
2019-03-25 18:57:28 -05:00
informSize: [640, 360],
2019-03-20 18:58:19 -05:00
};
}
2019-03-20 18:35:59 -05:00
initialize() {
this.entityReducer = this.createIndexedReducer();
this._informState = I.Map();
this._sentSelf = false;
this._socket = undefined;
2019-03-20 18:35:59 -05:00
this.lastNearby = I.Set();
}
2019-03-20 23:22:54 -05:00
destroy() {
2019-03-21 01:32:59 -05:00
if (this._socket) {
delete this._socket.entity;
delete this._socket;
}
2019-03-20 23:22:54 -05:00
}
2019-03-28 03:39:57 -05:00
collapseStateDiff(diff) {
for (const index in diff) {
const value = diff[index];
if (isPlainObject(value)) {
if (!this.collapseStateDiff(value)) {
delete diff[index];
}
}
}
if (0 === Object.keys(diff).length) {
return null;
}
return diff;
}
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];
}
2019-03-20 18:58:19 -05:00
}
// Added.
else {
reducedDiff[index] = item.state.toJS();
}
2019-03-20 18:58:19 -05:00
}
// Removed.
for (const index in previous) {
if (!current[index]) {
reducedDiff[index] = false;
}
2019-03-20 18:58:19 -05:00
}
previous = current;
return reducedDiff;
2019-03-20 18:58:19 -05:00
};
}
reduceStateDiff(diff) {
if (!diff || !diff.room || !diff.room.layers) {
return diff
}
const room = this.entity.room;
for (const index in diff.room.layers) {
// Index entities.
const layer = room.layer(index);
const visibleEntities = layer.visibleEntities(
2019-03-28 03:39:40 -05:00
[0, 0, 320, 180]
);
const indexedEntities = {};
for (const entity of visibleEntities) {
indexedEntities[entity.instanceUuid] = entity;
}
// Reduce entities.
diff.room.layers[index].entityList = this.entityReducer(
diff.room.layers[index].entityList || {},
indexedEntities,
);
}
2019-03-28 03:39:57 -05:00
return this.collapseStateDiff(diff);
}
get socket() {
return this._socket;
}
set socket(socket) {
socket.entity = this.entity;
this._socket = socket;
}
2019-03-20 18:35:59 -05:00
methods() {
return {
inform: (stateSynchronizer) => {
// Take diff.
let diff = stateSynchronizer.diff(this._informState);
diff = this.reduceStateDiff(diff);
2019-03-28 03:39:57 -05:00
diff = diff ? diff : {};
this._informState = stateSynchronizer.state;
// Let the client know who they are.
if (!this._sentSelf) {
2019-03-21 18:33:29 -05:00
diff.selfEntity = this.entity.instanceUuid;
this._sentSelf = true;
}
// Remove dead updates.
if (0 === Object.keys(diff).length) {
return;
}
// Emit!
this._socket.send({type: 'state-update', payload: diff});
2019-03-20 18:35:59 -05:00
},
};
}
}
2019-03-20 18:58:19 -05:00
export class Informed extends decorate(InformedBase) {}