diff --git a/packages/entity/index.js b/packages/entity/index.js index 28e5bfc..0b2db5a 100644 --- a/packages/entity/index.js +++ b/packages/entity/index.js @@ -68,6 +68,7 @@ export class Entity extends decorate(Resource) { this.once('destroyed', () => { this.removeAllTraits(); }); + this.initializeSynchronizedChildren(); } acceptPacket(packet) { diff --git a/packages/entity/list/index.js b/packages/entity/list/index.js index edf28ab..ec5606b 100644 --- a/packages/entity/list/index.js +++ b/packages/entity/list/index.js @@ -21,6 +21,7 @@ export class EntityList extends decorate(class {}) { this._entities = {}; this._flatEntities = []; this._quadTree = new QuadTree(); + this.initializeSynchronizedChildren(); } *[Symbol.iterator]() { @@ -117,10 +118,7 @@ export class EntityList extends decorate(class {}) { this.tickAfterDestructionTickers(elapsed); } // Run normal tickers. - for (let i = 0; i < this._flatEntities.length; i++) { - const entity = this._flatEntities[i]; - entity.tick(elapsed); - } + this.tickEntities(elapsed) // Update state. if (AVOCADO_SERVER) { this.tickMutateState(); @@ -142,6 +140,13 @@ export class EntityList extends decorate(class {}) { } } + tickEntities(elapsed) { + for (let i = 0; i < this._flatEntities.length; i++) { + const entity = this._flatEntities[i]; + entity.tick(elapsed); + } + } + tickMutateState(state) { this.state = this.state.withMutations((state) => { for (let i = 0; i < this._dirtyEntities.length; i++) { diff --git a/packages/entity/trait/index.js b/packages/entity/trait/index.js index 8109818..470625d 100644 --- a/packages/entity/trait/index.js +++ b/packages/entity/trait/index.js @@ -19,6 +19,7 @@ export class Trait extends decorate(class {}) { this._memoizedListeners = undefined; this.params = I.fromJS(ctor.defaultParams()).merge(I.fromJS(params)); this.state = I.fromJS(ctor.defaultState()).merge(I.fromJS(state)); + this.initializeSynchronizedChildren(); } destroy() {} diff --git a/packages/state/synchronized.js b/packages/state/synchronized.js index 17f3f08..047a258 100644 --- a/packages/state/synchronized.js +++ b/packages/state/synchronized.js @@ -14,6 +14,31 @@ export function Synchronized(Superclass) { constructor(...args) { super(...args); this.state = I.Map(); + this._childrenWithState = [] + this._childrenWithoutState = []; + this._childrenWithTickers = []; + } + + initializeSynchronizedChildren() { + const synchronizedChildren = this.synchronizedChildren(); + for (let i = 0; i < synchronizedChildren.length; ++i) { + const key = synchronizedChildren[i]; + if ( + 'undefined' !== typeof this[key] + && 'undefined' !== typeof this[key].tick + ) { + this._childrenWithTickers.push(key); + } + if ( + 'undefined' !== typeof this[key] + && 'undefined' !== typeof this[key].state + ) { + this._childrenWithState.push(key); + } + else { + this._childrenWithoutState.push(key); + } + } } synchronizedChildren() { @@ -59,33 +84,39 @@ export function Synchronized(Superclass) { } tick(elapsed) { - const children = this.synchronizedChildren(); - for (let i = 0; i < children.length; ++i) { - const key = children[i]; - if ( - 'undefined' !== typeof this[key] - && 'undefined' !== typeof this[key].tick - ) { - this[key].tick(elapsed); - } + for (let i = 0; i < this._childrenWithTickers.length; i++) { + const key = this._childrenWithTickers[i]; + this[key].tick(elapsed); } if (AVOCADO_SERVER) { - this.state = this.state.withMutations((state) => { - for (let i = 0; i < children.length; ++i) { - const key = children[i]; - if ( - 'undefined' !== typeof this[key] - && 'undefined' !== typeof this[key].state - ) { - state.set(key, this[key].state); - } - else { - state.set(key, this[key]); - } - } - }); + this.tickMutateState(); } } + prepareStateMutation() { + const mutation = {}; + for (let i = 0; i < this._childrenWithState.length; i++) { + const key = this._childrenWithState[i]; + mutation[key] = this[key].state; + } + for (let i = 0; i < this._childrenWithoutState.length; i++) { + const key = this._childrenWithoutState[i]; + mutation[key] = this[key]; + } + } + + tickMutateState() { + this.state = this.state.withMutations((state) => { + for (let i = 0; i < this._childrenWithState.length; i++) { + const key = this._childrenWithState[i]; + state.set(key, this[key].state); + } + for (let i = 0; i < this._childrenWithoutState.length; i++) { + const key = this._childrenWithoutState[i]; + state.set(key, this[key]); + } + }); + } + } } diff --git a/packages/topdown/layer.js b/packages/topdown/layer.js index 71c9f9b..a8ce0d8 100644 --- a/packages/topdown/layer.js +++ b/packages/topdown/layer.js @@ -38,6 +38,7 @@ export class Layer extends decorate(class {}) { this.on('tilesetUriChanged', this.onTilesetUriChanged, this); this.onTilesetUriChanged(); this.on('worldChanged', this.onWorldChanged, this); + this.initializeSynchronizedChildren(); } addEntity(entity) { diff --git a/packages/topdown/layers.js b/packages/topdown/layers.js index 9c6724e..a340946 100644 --- a/packages/topdown/layers.js +++ b/packages/topdown/layers.js @@ -15,6 +15,7 @@ export class Layers extends decorate(class {}) { constructor() { super(); this.layers = {}; + this.initializeSynchronizedChildren(); } *[Symbol.iterator]() { diff --git a/packages/topdown/room.js b/packages/topdown/room.js index dca7c23..1620f5c 100644 --- a/packages/topdown/room.js +++ b/packages/topdown/room.js @@ -34,6 +34,7 @@ export class Room extends decorate(class {}) { this.layers.on('layerAdded', this.onLayerAdded, this); this.on('sizeChanged', this.onSizeChanged, this); this.on('worldChanged', this.onWorldChanged, this); + this.initializeSynchronizedChildren(); } addEntityToLayer(entity, layerIndex = 0) { diff --git a/packages/topdown/tiles.js b/packages/topdown/tiles.js index 34d3428..7843977 100644 --- a/packages/topdown/tiles.js +++ b/packages/topdown/tiles.js @@ -17,6 +17,7 @@ export class Tiles extends decorate(class {}) { constructor() { super(); this.data = I.List(); + this.initializeSynchronizedChildren(); } forEachTile(fn) {