perf: faster dirty entities

This commit is contained in:
cha0s 2019-05-08 17:51:29 -05:00
parent f2860eed06
commit eb7fdf4f78
3 changed files with 19 additions and 53 deletions

View File

@ -85,8 +85,8 @@ export class Entity extends decorate(Resource) {
constructor(json) {
super();
this._hooks = {};
this.isDirty = true;
this._traits = {};
this._traitsTypesDirty = [];
this._traitsFlat = [];
this._traitTickers = [];
this._traitRenderTickers = [];
@ -156,7 +156,10 @@ export class Entity extends decorate(Resource) {
});
}
// Add state.
this.state = this._setInstanceState(this.state, type, instance);
this.state = this.state.set(type, I.Map({
params: instance.params,
state: instance.state,
}))
// Track trait.
this._traits[type] = instance;
this._traitsFlat.push(instance);
@ -238,12 +241,13 @@ export class Entity extends decorate(Resource) {
}
this.addTrait(type, step.value);
instance = this._traits[type];
this.state = this.state.setIn([type, 'params'], instance.params);
}
else {
// Accept state.
instance.patchState([step]);
}
this.state = this._setInstanceState(this.state, type, instance);
this.state = this.state.setIn([type, 'state'], instance.state);
}
renderTick(elapsed) {
@ -318,12 +322,11 @@ export class Entity extends decorate(Resource) {
types.forEach((type) => this.removeTrait(type));
}
_setInstanceState(state, type, instance) {
return state.setIn(
[type, 'state'], instance.state
).setIn(
[type, 'params'], instance.params
);
setTraitDirty(type) {
this._traitsTypesDirty.push(type);
if (this.is('listed')) {
this.list && this.list.markEntityDirty(this);
}
}
tick(elapsed) {
@ -337,18 +340,13 @@ export class Entity extends decorate(Resource) {
tickMutateState() {
this.state = this.state.withMutations((state) => {
for (let i = 0; i < this._traitsFlat.length; i++) {
const instance = this._traitsFlat[i];
if (!instance.isDirty) {
continue;
}
instance.isDirty = false;
if (this.is('listed')) {
this.list && this.list.markEntityDirty(this);
}
this._setInstanceState(state, instance.constructor.type(), instance);
for (let i = 0; i < this._traitsTypesDirty.length; i++) {
const type = this._traitsTypesDirty[i];
const instance = this._traits[type];
state.setIn([type, 'state'], instance.state);
}
});
this._traitsTypesDirty = [];
}
toJSON() {

View File

@ -16,7 +16,6 @@ export class Trait extends decorate(class {}) {
super();
this.entity = entity;
const ctor = this.constructor;
this.isDirty = true;
this._memoizedListeners = undefined;
this.params = Object.assign({}, ctor.defaultParams(), params);
this.state = I.fromJS(ctor.defaultState()).merge(I.fromJS(state));
@ -120,41 +119,10 @@ export function StateProperty(key, meta = {}) {
return this.${transformedProperty};
`);
meta.set = meta.set || new Function('value', `
this.isDirty = true;
this.entity.setTraitDirty(this.constructor.type());
this.${transformedProperty} = value;
this.state = this.state.set('${key}', value);
`);
return Property(key, meta)(Superclass);
}
}
StateProperty.Vector = (vector, x, y, meta = {}) => {
return (Superclass) => {
meta.default = undefined;
meta.emit = meta.emit || function(...args) {
this.entity.emit(...args);
};
meta.get = meta.get || function() {
return [
this.state.get(x),
this.state.get(y),
];
};
meta.set = meta.set || function(vector) {
if (meta.track && meta.emit) {
if (this.state.get(x) !== vector[0]) {
meta.emit.call(this, `${x}Changed`, this.state.get(x), vector[0]);
}
if (this.state.get(y) !== vector[1]) {
meta.emit.call(this, `${y}Changed`, this.state.get(y), vector[1]);
}
}
this.isDirty = true;
this.state = this.state.merge({
[x]: vector[0],
[y]: vector[1],
});
};
return Vector.Mixin(vector, x, y, meta)(Superclass);
};
}

View File

@ -57,7 +57,7 @@ export class Positioned extends decorate(Trait) {
this.state = this.state.withMutations((state) => {
state.set('x', x).set('y', y);
});
this.isDirty = true;
this.entity.setTraitDirty('positioned');
}
this.entity.emit('positionChanged', oldPosition, newPosition);
}