refactor: RIP Listed
This commit is contained in:
parent
f84a607023
commit
211670fd1c
|
@ -64,7 +64,7 @@ export default (latus) => class EntityList extends decorate(JsonResource) {
|
|||
}
|
||||
}
|
||||
|
||||
addEntity(entity) {
|
||||
async addEntity(entity) {
|
||||
const uuid = entity.instanceUuid;
|
||||
// Already exists?
|
||||
if (this.#entities[uuid]) {
|
||||
|
@ -76,7 +76,9 @@ export default (latus) => class EntityList extends decorate(JsonResource) {
|
|||
if ('client' !== process.env.SIDE) {
|
||||
this.#informedEntities.set(entity, []);
|
||||
}
|
||||
entity.attachToList(this);
|
||||
// eslint-disable-next-line no-param-reassign
|
||||
entity.list = this;
|
||||
entity.emit('addedToList');
|
||||
entity.once('destroying', () => this.onEntityDestroying(entity));
|
||||
this.emit('entityAdded', entity);
|
||||
}
|
||||
|
@ -179,7 +181,9 @@ export default (latus) => class EntityList extends decorate(JsonResource) {
|
|||
if ('client' !== process.env.SIDE) {
|
||||
this.#informedEntities.delete(entity);
|
||||
}
|
||||
entity.detachFromList();
|
||||
// eslint-disable-next-line no-param-reassign
|
||||
entity.list = null;
|
||||
entity.emit('removedFromList', this);
|
||||
delete this.#entities[uuid];
|
||||
this.#flatEntities.splice(this.#flatEntities.indexOf(entity), 1);
|
||||
this.#entityTickers.splice(this.#entityTickers.indexOf(entity.tick), 1);
|
||||
|
|
|
@ -1,123 +0,0 @@
|
|||
import {Rectangle} from '@avocado/math';
|
||||
import {Trait} from '@avocado/traits';
|
||||
|
||||
export default () => class Listed extends Trait {
|
||||
|
||||
#quadTreeAabb = [];
|
||||
|
||||
#quadTreeNodes = [];
|
||||
|
||||
addQuadTreeNodes() {
|
||||
const {list} = this.entity;
|
||||
if (!list) {
|
||||
return;
|
||||
}
|
||||
const aabb = this.entity.visibleAabb;
|
||||
if (Rectangle.isNull(aabb)) {
|
||||
return;
|
||||
}
|
||||
// Expand the AABB so we don't have to update it every single tick.
|
||||
const expandedAabb = Rectangle.expand(aabb, [32, 32]);
|
||||
this.#quadTreeAabb = expandedAabb;
|
||||
const points = Rectangle.toPoints(expandedAabb);
|
||||
this.#quadTreeNodes = points.map((point) => [...point, this.entity, aabb]);
|
||||
// Add points to quad tree.
|
||||
const {quadTree} = list;
|
||||
for (let i = 0; i < this.#quadTreeNodes.length; i++) {
|
||||
quadTree.add(this.#quadTreeNodes[i]);
|
||||
}
|
||||
}
|
||||
|
||||
static behaviorTypes() {
|
||||
return {
|
||||
detachFromList: {
|
||||
type: 'void',
|
||||
label: 'Detach from list.',
|
||||
},
|
||||
attachToList: {
|
||||
type: 'void',
|
||||
label: 'Attach to $1.',
|
||||
args: [
|
||||
['list', {
|
||||
type: 'entity-list',
|
||||
}],
|
||||
],
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
destroy() {
|
||||
this.entity.detachFromList();
|
||||
}
|
||||
|
||||
listeners() {
|
||||
return {
|
||||
|
||||
visibleAabbChanged: () => {
|
||||
this.resetQuadTreeNodes();
|
||||
},
|
||||
|
||||
traitAdded: () => {
|
||||
this.resetQuadTreeNodes();
|
||||
},
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
async load(json) {
|
||||
await super.load(json);
|
||||
this.entity.list = null;
|
||||
}
|
||||
|
||||
methods() {
|
||||
return {
|
||||
|
||||
detachFromList: () => {
|
||||
const {list} = this.entity;
|
||||
if (!list) {
|
||||
return;
|
||||
}
|
||||
this.removeQuadTreeNodes();
|
||||
this.entity.list = null;
|
||||
this.entity.emit('removedFromList', list);
|
||||
},
|
||||
|
||||
attachToList: (list) => {
|
||||
this.entity.list = list;
|
||||
this.addQuadTreeNodes();
|
||||
this.entity.emit('addedToList');
|
||||
},
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
removeQuadTreeNodes() {
|
||||
const {list} = this.entity;
|
||||
if (!list) {
|
||||
return;
|
||||
}
|
||||
if (this.#quadTreeNodes.length > 0) {
|
||||
const {quadTree} = list;
|
||||
for (let i = 0; i < this.#quadTreeNodes.length; i++) {
|
||||
quadTree.remove(this.#quadTreeNodes[i]);
|
||||
}
|
||||
this.#quadTreeAabb = [];
|
||||
this.#quadTreeNodes = [];
|
||||
}
|
||||
}
|
||||
|
||||
resetQuadTreeNodes() {
|
||||
if ('client' !== process.env.SIDE) {
|
||||
const aabb = this.entity.visibleAabb;
|
||||
if (
|
||||
this.#quadTreeAabb.length > 0
|
||||
&& Rectangle.isInside(this.#quadTreeAabb, aabb)
|
||||
) {
|
||||
return;
|
||||
}
|
||||
this.removeQuadTreeNodes();
|
||||
this.addQuadTreeNodes();
|
||||
}
|
||||
}
|
||||
|
||||
};
|
|
@ -1,43 +0,0 @@
|
|||
import {Latus} from '@latus/core';
|
||||
import {expect} from 'chai';
|
||||
|
||||
let latus;
|
||||
let Entity;
|
||||
let EntityList;
|
||||
beforeEach(async () => {
|
||||
latus = Latus.mock({
|
||||
'@avocado/entity': require('../src'),
|
||||
'@avocado/resource': require('@avocado/resource'),
|
||||
'@avocado/traits': require('@avocado/traits'),
|
||||
});
|
||||
await Promise.all(latus.invokeFlat('@latus/core/starting'));
|
||||
({Entity, EntityList} = latus.get('%resources'));
|
||||
});
|
||||
describe('Listed', () => {
|
||||
let entity;
|
||||
beforeEach(async () => {
|
||||
entity = await Entity.load({
|
||||
traits: {
|
||||
Listed: {},
|
||||
},
|
||||
});
|
||||
});
|
||||
it('exists', async () => {
|
||||
expect(entity.is('Listed')).to.be.true;
|
||||
});
|
||||
it('can be added to list quadtree', async () => {
|
||||
entity.isVisible = true;
|
||||
entity.visibleAabb = [0, 0, 16, 16];
|
||||
const list = new EntityList();
|
||||
entity.attachToList(list);
|
||||
expect(list.visibleEntities([-16, -16, 32, 32])).to.have.lengthOf(1);
|
||||
});
|
||||
it('will be removed from quadtree on destroy', async () => {
|
||||
entity.isVisible = true;
|
||||
entity.visibleAabb = [0, 0, 16, 16];
|
||||
const list = new EntityList();
|
||||
entity.attachToList(list);
|
||||
entity.emit('destroyed');
|
||||
expect(list.visibleEntities([-16, -16, 32, 32])).to.have.lengthOf(0);
|
||||
});
|
||||
});
|
|
@ -20,14 +20,12 @@ describe('Spawner', () => {
|
|||
beforeEach(async () => {
|
||||
entity = await Entity.load({
|
||||
traits: {
|
||||
Listed: {},
|
||||
Spawner: {
|
||||
params: {
|
||||
spawns: {
|
||||
testy: {
|
||||
traits: {
|
||||
Alive: {},
|
||||
Listed: {},
|
||||
Positioned: {},
|
||||
},
|
||||
},
|
||||
|
@ -61,7 +59,6 @@ describe('Spawner', () => {
|
|||
it('can spawn from arbitrary JSON', async () => {
|
||||
const spawned = await entity.spawnRaw({
|
||||
traits: {
|
||||
Listed: {},
|
||||
Mobile: {},
|
||||
},
|
||||
});
|
||||
|
@ -69,7 +66,6 @@ describe('Spawner', () => {
|
|||
const spawned2 = await entity.spawnRawAt(
|
||||
{
|
||||
traits: {
|
||||
Listed: {},
|
||||
Mobile: {},
|
||||
},
|
||||
},
|
||||
|
@ -82,7 +78,6 @@ describe('Spawner', () => {
|
|||
for (let i = 0; i < COUNT; ++i) {
|
||||
await entity.spawnRaw({
|
||||
traits: {
|
||||
Listed: {},
|
||||
Mobile: {},
|
||||
},
|
||||
});
|
||||
|
|
|
@ -29,6 +29,10 @@ export default () => class Visible extends decorate(Trait) {
|
|||
|
||||
#container;
|
||||
|
||||
#quadTreeAabb = [];
|
||||
|
||||
#quadTreeNodes = [];
|
||||
|
||||
#rawVisibleAabb = [0, 0, 0, 0];
|
||||
|
||||
#scheduledBoundingBoxUpdate = true;
|
||||
|
@ -55,6 +59,27 @@ export default () => class Visible extends decorate(Trait) {
|
|||
}
|
||||
}
|
||||
|
||||
addQuadTreeNodes() {
|
||||
const {list} = this.entity;
|
||||
if (!list) {
|
||||
return;
|
||||
}
|
||||
const aabb = this.entity.visibleAabb;
|
||||
if (Rectangle.isNull(aabb)) {
|
||||
return;
|
||||
}
|
||||
// Expand the AABB so we don't have to update it every single tick.
|
||||
const expandedAabb = Rectangle.expand(aabb, [32, 32]);
|
||||
this.#quadTreeAabb = expandedAabb;
|
||||
const points = Rectangle.toPoints(expandedAabb);
|
||||
this.#quadTreeNodes = points.map((point) => [...point, this.entity, aabb]);
|
||||
// Add points to quad tree.
|
||||
const {quadTree} = list;
|
||||
for (let i = 0; i < this.#quadTreeNodes.length; i++) {
|
||||
quadTree.add(this.#quadTreeNodes[i]);
|
||||
}
|
||||
}
|
||||
|
||||
static behaviorTypes() {
|
||||
return {
|
||||
updateVisibleBoundingBox: {
|
||||
|
@ -125,6 +150,7 @@ export default () => class Visible extends decorate(Trait) {
|
|||
if (this.#container) {
|
||||
this.#container.destroy();
|
||||
}
|
||||
this.removeQuadTreeNodes(this.entity.list);
|
||||
}
|
||||
|
||||
get container() {
|
||||
|
@ -155,6 +181,10 @@ export default () => class Visible extends decorate(Trait) {
|
|||
listeners() {
|
||||
return {
|
||||
|
||||
addedToList: () => {
|
||||
this.addQuadTreeNodes();
|
||||
},
|
||||
|
||||
isVisibleChanged: () => {
|
||||
if (!this.#container) {
|
||||
return;
|
||||
|
@ -173,6 +203,10 @@ export default () => class Visible extends decorate(Trait) {
|
|||
this.translateVisibleAabb();
|
||||
},
|
||||
|
||||
removedFromList: (list) => {
|
||||
this.removeQuadTreeNodes(list);
|
||||
},
|
||||
|
||||
rotationChanged: () => {
|
||||
if (!this.#container) {
|
||||
return;
|
||||
|
@ -181,6 +215,7 @@ export default () => class Visible extends decorate(Trait) {
|
|||
},
|
||||
|
||||
traitAdded: () => {
|
||||
this.resetQuadTreeNodes();
|
||||
this.synchronizePosition();
|
||||
},
|
||||
|
||||
|
@ -188,6 +223,10 @@ export default () => class Visible extends decorate(Trait) {
|
|||
this.#scheduledBoundingBoxUpdate = true;
|
||||
},
|
||||
|
||||
visibleAabbChanged: () => {
|
||||
this.resetQuadTreeNodes();
|
||||
},
|
||||
|
||||
visibleScaleChanged: () => {
|
||||
this.#visibleScale = Vector.copy(this.entity.visibleScale);
|
||||
if (this.#container) {
|
||||
|
@ -258,10 +297,38 @@ export default () => class Visible extends decorate(Trait) {
|
|||
this.entity.visibleScale = scale;
|
||||
}
|
||||
|
||||
removeQuadTreeNodes(list) {
|
||||
if (!list) {
|
||||
return;
|
||||
}
|
||||
if (this.#quadTreeNodes.length > 0) {
|
||||
const {quadTree} = list;
|
||||
for (let i = 0; i < this.#quadTreeNodes.length; i++) {
|
||||
quadTree.remove(this.#quadTreeNodes[i]);
|
||||
}
|
||||
this.#quadTreeAabb = [];
|
||||
this.#quadTreeNodes = [];
|
||||
}
|
||||
}
|
||||
|
||||
renderTick() {
|
||||
this.synchronizePosition();
|
||||
}
|
||||
|
||||
resetQuadTreeNodes() {
|
||||
if ('client' !== process.env.SIDE) {
|
||||
const aabb = this.entity.visibleAabb;
|
||||
if (
|
||||
this.#quadTreeAabb.length > 0
|
||||
&& Rectangle.isInside(this.#quadTreeAabb, aabb)
|
||||
) {
|
||||
return;
|
||||
}
|
||||
this.removeQuadTreeNodes(this.entity.list);
|
||||
this.addQuadTreeNodes();
|
||||
}
|
||||
}
|
||||
|
||||
synchronizePosition() {
|
||||
if (!this.#container) {
|
||||
return;
|
||||
|
|
|
@ -33,7 +33,6 @@
|
|||
"deepmerge": "^4.2.2",
|
||||
"immutable": "^4.0.0-rc.12",
|
||||
"kefir": "^3.8.8",
|
||||
"lodash.get": "^4.4.2",
|
||||
"matter-js": "0.14.2",
|
||||
"poly-decomp": "0.3.0",
|
||||
"proton-engine": "^4.2.1"
|
||||
|
|
|
@ -3,7 +3,6 @@ import {Ticker} from '@avocado/timing';
|
|||
import {Trait} from '@avocado/traits';
|
||||
import {compose} from '@latus/core';
|
||||
import merge from 'deepmerge';
|
||||
import get from 'lodash.get';
|
||||
import K from 'kefir';
|
||||
|
||||
import Proton from '../proton';
|
||||
|
@ -88,7 +87,6 @@ export default (latus) => class Emitter extends decorate(Trait) {
|
|||
|
||||
async emitParticleJson(json) {
|
||||
const {Entity} = latus.get('%resources');
|
||||
const isListed = get(json, 'traits.Emitted.params.listed', true);
|
||||
return this.entity.emitParticleEntity(
|
||||
await Entity.load(
|
||||
merge(
|
||||
|
@ -96,7 +94,6 @@ export default (latus) => class Emitter extends decorate(Trait) {
|
|||
traits: {
|
||||
Positioned: {},
|
||||
Visible: {},
|
||||
...(isListed ? {Listed: {}} : {}),
|
||||
},
|
||||
},
|
||||
json,
|
||||
|
|
|
@ -26,7 +26,6 @@ describe('Layer', () => {
|
|||
entity = await Entity.load({
|
||||
traits: {
|
||||
Layered: {},
|
||||
Listed: {},
|
||||
},
|
||||
});
|
||||
const entityList = new EntityList();
|
||||
|
|
Loading…
Reference in New Issue
Block a user