mirror of
https://github.com/tobspr/shapez.io.git
synced 2024-10-27 20:34:29 +00:00
Optimize ejector cache for common case
This commit optimizes the ejector cache for clicking and dragging belts, or adding/removing a building. It's a big performance improvement for large maps; on average, it only has to visit 60 slots per update, compared to 20,000+ slots.
This commit is contained in:
parent
36cf28029e
commit
aef96cff6e
@ -7,6 +7,7 @@ import { Entity } from "../entity";
|
|||||||
import { GameSystemWithFilter } from "../game_system_with_filter";
|
import { GameSystemWithFilter } from "../game_system_with_filter";
|
||||||
import { Math_min } from "../../core/builtins";
|
import { Math_min } from "../../core/builtins";
|
||||||
import { createLogger } from "../../core/logging";
|
import { createLogger } from "../../core/logging";
|
||||||
|
import { Rectangle } from "../../core/rectangle";
|
||||||
|
|
||||||
const logger = createLogger("systems/ejector");
|
const logger = createLogger("systems/ejector");
|
||||||
|
|
||||||
@ -18,10 +19,30 @@ export class ItemEjectorSystem extends GameSystemWithFilter {
|
|||||||
|
|
||||||
this.root.signals.entityAdded.add(this.invalidateCache, this);
|
this.root.signals.entityAdded.add(this.invalidateCache, this);
|
||||||
this.root.signals.entityDestroyed.add(this.invalidateCache, this);
|
this.root.signals.entityDestroyed.add(this.invalidateCache, this);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @type {Rectangle[]}
|
||||||
|
*/
|
||||||
|
this.smallCacheAreas = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param {Entity} entity
|
||||||
|
*/
|
||||||
|
invalidateCache(entity) {
|
||||||
|
if (!entity.components.StaticMapEntity) {
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
invalidateCache() {
|
|
||||||
this.cacheNeedsUpdate = true;
|
this.cacheNeedsUpdate = true;
|
||||||
|
|
||||||
|
// Optimize for the common case: adding or removing one building at a time. Clicking
|
||||||
|
// and dragging can cause up to 4 add/remove signals.
|
||||||
|
const staticComp = entity.components.StaticMapEntity;
|
||||||
|
const bounds = staticComp.getTileSpaceBounds();
|
||||||
|
const expandedBounds = bounds.expandedInAllDirections(2);
|
||||||
|
this.smallCacheAreas.push(expandedBounds);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -30,10 +51,47 @@ export class ItemEjectorSystem extends GameSystemWithFilter {
|
|||||||
recomputeCache() {
|
recomputeCache() {
|
||||||
logger.log("Recomputing cache");
|
logger.log("Recomputing cache");
|
||||||
|
|
||||||
// Try to find acceptors for every ejector
|
|
||||||
let entryCount = 0;
|
let entryCount = 0;
|
||||||
|
if (this.smallCacheAreas.length <= 4) {
|
||||||
|
// Only recompute caches of entities inside the rectangles.
|
||||||
|
for (let i = 0; i < this.smallCacheAreas.length; i++) {
|
||||||
|
entryCount += this.recomputeAreaCaches(this.smallCacheAreas[i]);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Try to find acceptors for every ejector
|
||||||
for (let i = 0; i < this.allEntities.length; ++i) {
|
for (let i = 0; i < this.allEntities.length; ++i) {
|
||||||
const entity = this.allEntities[i];
|
const entity = this.allEntities[i];
|
||||||
|
entryCount += this.recomputeSingleEntityCache(entity);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
logger.log("Found", entryCount, "entries to update");
|
||||||
|
|
||||||
|
this.smallCacheAreas = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param {Rectangle} area
|
||||||
|
*/
|
||||||
|
recomputeAreaCaches(area) {
|
||||||
|
let entryCount = 0;
|
||||||
|
for (let x = area.x; x < area.right(); ++x) {
|
||||||
|
for (let y = area.y; y < area.bottom(); ++y) {
|
||||||
|
const entity = this.root.map.getTileContentXY(x, y);
|
||||||
|
if (entity && entity.components.ItemEjector) {
|
||||||
|
entryCount += this.recomputeSingleEntityCache(entity);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return entryCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param {Entity} entity
|
||||||
|
*/
|
||||||
|
recomputeSingleEntityCache(entity) {
|
||||||
const ejectorComp = entity.components.ItemEjector;
|
const ejectorComp = entity.components.ItemEjector;
|
||||||
const staticComp = entity.components.StaticMapEntity;
|
const staticComp = entity.components.StaticMapEntity;
|
||||||
|
|
||||||
@ -41,6 +99,7 @@ export class ItemEjectorSystem extends GameSystemWithFilter {
|
|||||||
ejectorComp.cachedConnectedSlots = null;
|
ejectorComp.cachedConnectedSlots = null;
|
||||||
|
|
||||||
// For every ejector slot, try to find an acceptor
|
// For every ejector slot, try to find an acceptor
|
||||||
|
let entryCount = 0;
|
||||||
for (let ejectorSlotIndex = 0; ejectorSlotIndex < ejectorComp.slots.length; ++ejectorSlotIndex) {
|
for (let ejectorSlotIndex = 0; ejectorSlotIndex < ejectorComp.slots.length; ++ejectorSlotIndex) {
|
||||||
const ejectorSlot = ejectorComp.slots[ejectorSlotIndex];
|
const ejectorSlot = ejectorComp.slots[ejectorSlotIndex];
|
||||||
|
|
||||||
@ -88,9 +147,7 @@ export class ItemEjectorSystem extends GameSystemWithFilter {
|
|||||||
ejectorSlot.cachedDestSlot = matchingSlot;
|
ejectorSlot.cachedDestSlot = matchingSlot;
|
||||||
entryCount += 1;
|
entryCount += 1;
|
||||||
}
|
}
|
||||||
}
|
return entryCount;
|
||||||
|
|
||||||
logger.log("Found", entryCount, "entries to update");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
update() {
|
update() {
|
||||||
|
Loading…
Reference in New Issue
Block a user