mirror of
https://github.com/tobspr/shapez.io.git
synced 2024-10-27 20:34:29 +00:00
Remove ejector cache; use slot caches instead
This is a small refactoring that removes the main ejector cache. The cache is now tracked by slots and ejector components. It avoids a large array allocation and many small object allocations, but adds many small array allocations. It's net neutral for performance.
This commit is contained in:
parent
b753187cde
commit
36cf28029e
@ -3,13 +3,16 @@ import { BaseItem } from "../base_item";
|
||||
import { Component } from "../component";
|
||||
import { types } from "../../savegame/serialization";
|
||||
import { gItemRegistry } from "../../core/global_registries";
|
||||
import { Entity } from "../entity";
|
||||
|
||||
/**
|
||||
* @typedef {{
|
||||
* pos: Vector,
|
||||
* direction: enumDirection,
|
||||
* item: BaseItem,
|
||||
* progress: number?
|
||||
* progress: number?,
|
||||
* cachedDestSlot?: import("./item_acceptor").ItemAcceptorLocatedSlot,
|
||||
* cachedTargetEntity?: Entity
|
||||
* }} ItemEjectorSlot
|
||||
*/
|
||||
|
||||
@ -19,6 +22,8 @@ export class ItemEjectorComponent extends Component {
|
||||
}
|
||||
|
||||
static getSchema() {
|
||||
// The cachedDestSlot, cachedTargetEntity, and cachedConnectedSlots fields
|
||||
// are not serialized.
|
||||
return {
|
||||
instantEject: types.bool,
|
||||
slots: types.array(
|
||||
@ -61,6 +66,9 @@ export class ItemEjectorComponent extends Component {
|
||||
this.instantEject = instantEject;
|
||||
|
||||
this.setSlots(slots);
|
||||
|
||||
/** @type {ItemEjectorSlot[]} */
|
||||
this.cachedConnectedSlots = null;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -76,6 +84,8 @@ export class ItemEjectorComponent extends Component {
|
||||
direction: slot.direction,
|
||||
item: null,
|
||||
progress: 0,
|
||||
cachedDestSlot: null,
|
||||
cachedTargetEntity: null,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -14,15 +14,6 @@ export class ItemEjectorSystem extends GameSystemWithFilter {
|
||||
constructor(root) {
|
||||
super(root, [ItemEjectorComponent]);
|
||||
|
||||
/**
|
||||
* @type {Array<{
|
||||
* targetEntity: Entity,
|
||||
* sourceSlot: import("../components/item_ejector").ItemEjectorSlot,
|
||||
* destSlot: import("../components/item_acceptor").ItemAcceptorLocatedSlot
|
||||
* }>}
|
||||
*/
|
||||
this.cache = [];
|
||||
|
||||
this.cacheNeedsUpdate = true;
|
||||
|
||||
this.root.signals.entityAdded.add(this.invalidateCache, this);
|
||||
@ -39,18 +30,24 @@ export class ItemEjectorSystem extends GameSystemWithFilter {
|
||||
recomputeCache() {
|
||||
logger.log("Recomputing cache");
|
||||
|
||||
const cache = [];
|
||||
|
||||
// Try to find acceptors for every ejector
|
||||
let entryCount = 0;
|
||||
for (let i = 0; i < this.allEntities.length; ++i) {
|
||||
const entity = this.allEntities[i];
|
||||
const ejectorComp = entity.components.ItemEjector;
|
||||
const staticComp = entity.components.StaticMapEntity;
|
||||
|
||||
// Clear the old cache.
|
||||
ejectorComp.cachedConnectedSlots = null;
|
||||
|
||||
// For every ejector slot, try to find an acceptor
|
||||
for (let ejectorSlotIndex = 0; ejectorSlotIndex < ejectorComp.slots.length; ++ejectorSlotIndex) {
|
||||
const ejectorSlot = ejectorComp.slots[ejectorSlotIndex];
|
||||
|
||||
// Clear the old cache.
|
||||
ejectorSlot.cachedDestSlot = null;
|
||||
ejectorSlot.cachedTargetEntity = null;
|
||||
|
||||
// Figure out where and into which direction we eject items
|
||||
const ejectSlotWsTile = staticComp.localTileToWorld(ejectorSlot.pos);
|
||||
const ejectSlotWsDirection = staticComp.localDirectionToWorld(ejectorSlot.direction);
|
||||
@ -82,16 +79,18 @@ export class ItemEjectorSystem extends GameSystemWithFilter {
|
||||
}
|
||||
|
||||
// Ok we found a connection
|
||||
cache.push({
|
||||
targetEntity,
|
||||
sourceSlot: ejectorSlot,
|
||||
destSlot: matchingSlot,
|
||||
});
|
||||
if (ejectorComp.cachedConnectedSlots) {
|
||||
ejectorComp.cachedConnectedSlots.push(ejectorSlot);
|
||||
} else {
|
||||
ejectorComp.cachedConnectedSlots = [ejectorSlot];
|
||||
}
|
||||
ejectorSlot.cachedTargetEntity = targetEntity;
|
||||
ejectorSlot.cachedDestSlot = matchingSlot;
|
||||
entryCount += 1;
|
||||
}
|
||||
}
|
||||
|
||||
this.cache = cache;
|
||||
logger.log("Found", cache.length, "entries to update");
|
||||
logger.log("Found", entryCount, "entries to update");
|
||||
}
|
||||
|
||||
update() {
|
||||
@ -109,35 +108,45 @@ export class ItemEjectorSystem extends GameSystemWithFilter {
|
||||
}
|
||||
|
||||
// Go over all cache entries
|
||||
for (let i = 0; i < this.cache.length; ++i) {
|
||||
const { sourceSlot, destSlot, targetEntity } = this.cache[i];
|
||||
const item = sourceSlot.item;
|
||||
|
||||
if (!item) {
|
||||
// No item available to be ejected
|
||||
for (let i = 0; i < this.allEntities.length; ++i) {
|
||||
const sourceEntity = this.allEntities[i];
|
||||
const sourceEjectorComp = sourceEntity.components.ItemEjector;
|
||||
if (!sourceEjectorComp.cachedConnectedSlots) {
|
||||
continue;
|
||||
}
|
||||
for (let j = 0; j < sourceEjectorComp.cachedConnectedSlots.length; j++) {
|
||||
const sourceSlot = sourceEjectorComp.cachedConnectedSlots[j];
|
||||
const destSlot = sourceSlot.cachedDestSlot;
|
||||
const targetEntity = sourceSlot.cachedTargetEntity;
|
||||
|
||||
// Advance items on the slot
|
||||
sourceSlot.progress = Math_min(1, sourceSlot.progress + progressGrowth);
|
||||
const item = sourceSlot.item;
|
||||
|
||||
// Check if we are still in the process of ejecting, can't proceed then
|
||||
if (sourceSlot.progress < 1.0) {
|
||||
continue;
|
||||
}
|
||||
if (!item) {
|
||||
// No item available to be ejected
|
||||
continue;
|
||||
}
|
||||
|
||||
// Check if the target acceptor can actually accept this item
|
||||
const targetAcceptorComp = targetEntity.components.ItemAcceptor;
|
||||
if (!targetAcceptorComp.canAcceptItem(destSlot.index, item)) {
|
||||
continue;
|
||||
}
|
||||
// Advance items on the slot
|
||||
sourceSlot.progress = Math_min(1, sourceSlot.progress + progressGrowth);
|
||||
|
||||
// Try to hand over the item
|
||||
if (this.tryPassOverItem(item, targetEntity, destSlot.index)) {
|
||||
// Handover successful, clear slot
|
||||
targetAcceptorComp.onItemAccepted(destSlot.index, destSlot.acceptedDirection, item);
|
||||
sourceSlot.item = null;
|
||||
continue;
|
||||
// Check if we are still in the process of ejecting, can't proceed then
|
||||
if (sourceSlot.progress < 1.0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Check if the target acceptor can actually accept this item
|
||||
const targetAcceptorComp = targetEntity.components.ItemAcceptor;
|
||||
if (!targetAcceptorComp.canAcceptItem(destSlot.index, item)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Try to hand over the item
|
||||
if (this.tryPassOverItem(item, targetEntity, destSlot.index)) {
|
||||
// Handover successful, clear slot
|
||||
targetAcceptorComp.onItemAccepted(destSlot.index, destSlot.acceptedDirection, item);
|
||||
sourceSlot.item = null;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user