mirror of
https://github.com/tobspr/shapez.io.git
synced 2024-10-27 20:34:29 +00:00
Improve item ejector system
This commit is contained in:
parent
c0c624135b
commit
746f4935ad
@ -40,9 +40,9 @@ export class StaleAreaDetector {
|
|||||||
* Makes this detector recompute the area of an entity whenever
|
* Makes this detector recompute the area of an entity whenever
|
||||||
* it changes in any way
|
* it changes in any way
|
||||||
* @param {Array<typeof Component>} components
|
* @param {Array<typeof Component>} components
|
||||||
* @param {number} tilesAround
|
* @param {number} tilesAround How many tiles arround to expand the area
|
||||||
*/
|
*/
|
||||||
recomputeOnComponentsChanged(components, tilesAround = 1) {
|
recomputeOnComponentsChanged(components, tilesAround) {
|
||||||
const componentIds = components.map(component => component.getId());
|
const componentIds = components.map(component => component.getId());
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -50,6 +50,10 @@ export class StaleAreaDetector {
|
|||||||
* @param {Entity} entity
|
* @param {Entity} entity
|
||||||
*/
|
*/
|
||||||
const checker = entity => {
|
const checker = entity => {
|
||||||
|
if (!this.root.gameInitialized) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// Check for all components
|
// Check for all components
|
||||||
for (let i = 0; i < componentIds.length; ++i) {
|
for (let i = 0; i < componentIds.length; ++i) {
|
||||||
if (entity.components[componentIds[i]]) {
|
if (entity.components[componentIds[i]]) {
|
||||||
|
@ -2,8 +2,11 @@ import { globalConfig } from "../../core/config";
|
|||||||
import { DrawParameters } from "../../core/draw_parameters";
|
import { DrawParameters } from "../../core/draw_parameters";
|
||||||
import { createLogger } from "../../core/logging";
|
import { createLogger } from "../../core/logging";
|
||||||
import { Rectangle } from "../../core/rectangle";
|
import { Rectangle } from "../../core/rectangle";
|
||||||
|
import { StaleAreaDetector } from "../../core/stale_area_detector";
|
||||||
import { enumDirection, enumDirectionToVector } from "../../core/vector";
|
import { enumDirection, enumDirectionToVector } from "../../core/vector";
|
||||||
import { BaseItem } from "../base_item";
|
import { BaseItem } from "../base_item";
|
||||||
|
import { BeltComponent } from "../components/belt";
|
||||||
|
import { ItemAcceptorComponent } from "../components/item_acceptor";
|
||||||
import { ItemEjectorComponent } from "../components/item_ejector";
|
import { ItemEjectorComponent } from "../components/item_ejector";
|
||||||
import { Entity } from "../entity";
|
import { Entity } from "../entity";
|
||||||
import { GameSystemWithFilter } from "../game_system_with_filter";
|
import { GameSystemWithFilter } from "../game_system_with_filter";
|
||||||
@ -15,102 +18,52 @@ export class ItemEjectorSystem extends GameSystemWithFilter {
|
|||||||
constructor(root) {
|
constructor(root) {
|
||||||
super(root, [ItemEjectorComponent]);
|
super(root, [ItemEjectorComponent]);
|
||||||
|
|
||||||
this.root.signals.entityAdded.add(this.checkForCacheInvalidation, this);
|
this.staleAreaDetector = new StaleAreaDetector({
|
||||||
this.root.signals.entityDestroyed.add(this.checkForCacheInvalidation, this);
|
root: this.root,
|
||||||
this.root.signals.postLoadHook.add(this.recomputeCache, this);
|
name: "item-ejector",
|
||||||
|
recomputeMethod: this.recomputeArea.bind(this),
|
||||||
|
});
|
||||||
|
|
||||||
/**
|
this.staleAreaDetector.recomputeOnComponentsChanged(
|
||||||
* @type {Rectangle}
|
[ItemEjectorComponent, ItemAcceptorComponent, BeltComponent],
|
||||||
*/
|
1
|
||||||
this.areaToRecompute = null;
|
);
|
||||||
|
|
||||||
|
this.root.signals.postLoadHook.add(this.recomputeCacheFull, this);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
* Recomputes an area after it changed
|
||||||
* @param {Entity} entity
|
* @param {Rectangle} area
|
||||||
*/
|
*/
|
||||||
checkForCacheInvalidation(entity) {
|
recomputeArea(area) {
|
||||||
if (!this.root.gameInitialized) {
|
/** @type {Set<number>} */
|
||||||
return;
|
const seenUids = new Set();
|
||||||
}
|
for (let x = 0; x < area.w; ++x) {
|
||||||
if (!entity.components.StaticMapEntity) {
|
for (let y = 0; y < area.h; ++y) {
|
||||||
return;
|
const tileX = area.x + x;
|
||||||
}
|
const tileY = area.y + y;
|
||||||
|
// @NOTICE: Item ejector currently only supports regular layer
|
||||||
// Optimize for the common case: adding or removing one building at a time. Clicking
|
const contents = this.root.map.getLayerContentXY(tileX, tileY, "regular");
|
||||||
// and dragging can cause up to 4 add/remove signals.
|
if (contents && contents.components.ItemEjector) {
|
||||||
const staticComp = entity.components.StaticMapEntity;
|
if (!seenUids.has(contents.uid)) {
|
||||||
const bounds = staticComp.getTileSpaceBounds();
|
seenUids.add(contents.uid);
|
||||||
const expandedBounds = bounds.expandedInAllDirections(2);
|
this.recomputeSingleEntityCache(contents);
|
||||||
|
|
||||||
if (this.areaToRecompute) {
|
|
||||||
this.areaToRecompute = this.areaToRecompute.getUnion(expandedBounds);
|
|
||||||
} else {
|
|
||||||
this.areaToRecompute = expandedBounds;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Precomputes the cache, which makes up for a huge performance improvement
|
|
||||||
*/
|
|
||||||
recomputeCache() {
|
|
||||||
if (this.areaToRecompute) {
|
|
||||||
logger.log("Recomputing cache using rectangle");
|
|
||||||
if (G_IS_DEV && globalConfig.debug.renderChanges) {
|
|
||||||
this.root.hud.parts.changesDebugger.renderChange(
|
|
||||||
"ejector-area",
|
|
||||||
this.areaToRecompute,
|
|
||||||
"#fe50a6"
|
|
||||||
);
|
|
||||||
}
|
|
||||||
this.recomputeAreaCache();
|
|
||||||
this.areaToRecompute = null;
|
|
||||||
} else {
|
|
||||||
logger.log("Full cache recompute");
|
|
||||||
if (G_IS_DEV && globalConfig.debug.renderChanges) {
|
|
||||||
this.root.hud.parts.changesDebugger.renderChange(
|
|
||||||
"ejector-full",
|
|
||||||
new Rectangle(-1000, -1000, 2000, 2000),
|
|
||||||
"#fe50a6"
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Try to find acceptors for every ejector
|
|
||||||
for (let i = 0; i < this.allEntities.length; ++i) {
|
|
||||||
const entity = this.allEntities[i];
|
|
||||||
this.recomputeSingleEntityCache(entity);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Recomputes the cache in the given area
|
|
||||||
*/
|
|
||||||
recomputeAreaCache() {
|
|
||||||
const area = this.areaToRecompute;
|
|
||||||
let entryCount = 0;
|
|
||||||
|
|
||||||
logger.log("Recomputing area:", area.x, area.y, "/", area.w, area.h);
|
|
||||||
|
|
||||||
// Store the entities we already recomputed, so we don't do work twice
|
|
||||||
const recomputedEntities = new Set();
|
|
||||||
|
|
||||||
for (let x = area.x; x < area.right(); ++x) {
|
|
||||||
for (let y = area.y; y < area.bottom(); ++y) {
|
|
||||||
const entities = this.root.map.getLayersContentsMultipleXY(x, y);
|
|
||||||
for (let i = 0; i < entities.length; ++i) {
|
|
||||||
const entity = entities[i];
|
|
||||||
|
|
||||||
// Recompute the entity in case its relevant for this system and it
|
|
||||||
// hasn't already been computed
|
|
||||||
if (!recomputedEntities.has(entity.uid) && entity.components.ItemEjector) {
|
|
||||||
recomputedEntities.add(entity.uid);
|
|
||||||
this.recomputeSingleEntityCache(entity);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return entryCount;
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Recomputes the whole cache after the game has loaded
|
||||||
|
*/
|
||||||
|
recomputeCacheFull() {
|
||||||
|
logger.log("Full cache recompute in post load hook");
|
||||||
|
for (let i = 0; i < this.allEntities.length; ++i) {
|
||||||
|
const entity = this.allEntities[i];
|
||||||
|
this.recomputeSingleEntityCache(entity);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -183,9 +136,7 @@ export class ItemEjectorSystem extends GameSystemWithFilter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
update() {
|
update() {
|
||||||
if (this.areaToRecompute) {
|
this.staleAreaDetector.update();
|
||||||
this.recomputeCache();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Precompute effective belt speed
|
// Precompute effective belt speed
|
||||||
let progressGrowth = 2 * this.root.dynamicTickrate.deltaSeconds;
|
let progressGrowth = 2 * this.root.dynamicTickrate.deltaSeconds;
|
||||||
|
Loading…
Reference in New Issue
Block a user