perf: list ticking/dirty optimization

This commit is contained in:
cha0s 2019-05-03 13:26:51 -05:00
parent 9317c69c57
commit 9909b12c41
3 changed files with 53 additions and 30 deletions

View File

@ -278,6 +278,9 @@ export class Entity extends decorate(Resource) {
}
instance.isDirty = false;
this.isDirty = true;
if (this.is('listed')) {
this.list.markEntityDirty(this);
}
this._setInstanceState(state, type, instance);
}
});

View File

@ -17,7 +17,9 @@ export class EntityList extends decorate(class {}) {
constructor() {
super();
this._afterDestructionTickers = [];
this._dirtyEntities = [];
this._entities = {};
this._flatEntities = [];
this._quadTree = new QuadTree();
}
@ -31,15 +33,19 @@ export class EntityList extends decorate(class {}) {
addEntity(entity) {
const uuid = entity.instanceUuid;
this._entities[uuid] = entity;
this._flatEntities.push(entity);
this.state = this.state.set(uuid, entity.state);
entity.addTrait('listed');
entity.list = this;
entity.setIntoList(this);
entity.once('destroy', () => {
this.removeEntity(entity);
// In the process of destroying, allow entities to specify tickers that
// must live on past destruction.
const tickers = entity.invokeHookFlat('afterDestructionTickers');
this._afterDestructionTickers.push(...tickers);
for (let i = 0; i < tickers.length; i++) {
const ticker = tickers[i];
this._afterDestructionTickers.push(ticker);
}
});
this.emit('entityAdded', entity);
}
@ -51,11 +57,17 @@ export class EntityList extends decorate(class {}) {
}
findEntity(uuid) {
if (this._entities[uuid]) {
if (uuid in this._entities) {
return this._entities[uuid];
}
}
markEntityDirty(entity) {
if (-1 === this._dirtyEntities.indexOf(entity)) {
this._dirtyEntities.push(entity);
}
}
patchStateStep(uuid, step) {
const entity = this._entities[uuid];
if ('/' === step.path) {
@ -90,6 +102,8 @@ export class EntityList extends decorate(class {}) {
removeEntity(entity) {
const uuid = entity.instanceUuid;
delete this._entities[uuid];
const index = this._flatEntities.indexOf(entity);
this._flatEntities.splice(index, 1);
this.state = this.state.delete(uuid);
this.emit('entityRemoved', entity);
if (entity.is('listed')) {
@ -99,24 +113,17 @@ export class EntityList extends decorate(class {}) {
tick(elapsed) {
// Run after destruction tickers.
if (this._afterDestructionTickers.length > 0) {
this.tickAfterDestructionTickers(elapsed);
}
// Run normal tickers.
for (const uuid in this._entities) {
const entity = this._entities[uuid];
for (let i = 0; i < this._flatEntities.length; i++) {
const entity = this._flatEntities[i];
entity.tick(elapsed);
}
// Update state.
if (AVOCADO_SERVER) {
this.state = this.state.withMutations((state) => {
for (const uuid in this._entities) {
const entity = this._entities[uuid];
if (!entity.isDirty) {
continue;
}
entity.isDirty = false;
state.set(uuid, entity.state);
}
});
this.tickMutateState();
}
}
@ -135,6 +142,17 @@ export class EntityList extends decorate(class {}) {
}
}
tickMutateState(state) {
this.state = this.state.withMutations((state) => {
for (let i = 0; i < this._dirtyEntities.length; i++) {
const entity = this._dirtyEntities[i];
entity.isDirty = false;
state.set(entity.$$avocado_property_instanceUuid, entity.state);
}
});
this._dirtyEntities = [];
}
visibleEntities(query) {
const entities = [];
const entitiesTrack = [];

View File

@ -5,29 +5,19 @@ import {Trait} from '../trait';
export class Listed extends Trait {
initialize() {
this._list = undefined;
this.entity.list = undefined;
this.quadTreeAabb = [];
this.quadTreeNodes = [];
}
destroy() {
this.removeQuadTreeNodes();
delete this._list;
delete this.entity.list;
this.entity.emit('removedFromList');
}
get list() {
return this._list;
}
set list(list) {
this._list = list;
this.addQuadTreeNodes();
this.entity.emit('addedToList');
}
addQuadTreeNodes() {
const list = this._list;
const list = this.entity.list;
if (!list) {
return;
}
@ -54,7 +44,7 @@ export class Listed extends Trait {
}
removeQuadTreeNodes() {
const list = this._list;
const list = this.entity.list;
if (!list) {
return;
}
@ -97,5 +87,17 @@ export class Listed extends Trait {
}
}
methods() {
return {
setIntoList: (list) => {
this.entity.list = list;
this.addQuadTreeNodes();
this.entity.emit('addedToList');
},
};
}
}