mirror of
https://github.com/tobspr/shapez.io.git
synced 2024-10-27 20:34:29 +00:00
Refactor item acceptor system for huge performance improvement
This commit is contained in:
parent
e95b055e10
commit
cda24ceb04
@ -1,4 +1,9 @@
|
|||||||
export const CHANGELOG = [
|
export const CHANGELOG = [
|
||||||
|
{
|
||||||
|
version: "1.1.12",
|
||||||
|
date: "unreleased",
|
||||||
|
entries: ["Huge performance improvements! The game should now run up to 80% faster"],
|
||||||
|
},
|
||||||
{
|
{
|
||||||
version: "1.1.11",
|
version: "1.1.11",
|
||||||
date: "13.06.2020",
|
date: "13.06.2020",
|
||||||
|
@ -20,6 +20,14 @@ export const enumItemAcceptorItemFilter = {
|
|||||||
* filter?: enumItemAcceptorItemFilter
|
* filter?: enumItemAcceptorItemFilter
|
||||||
* }} ItemAcceptorSlot */
|
* }} ItemAcceptorSlot */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Contains information about a slot plus its location
|
||||||
|
* @typedef {{
|
||||||
|
* slot: ItemAcceptorSlot,
|
||||||
|
* index: number,
|
||||||
|
* acceptedDirection: enumDirection
|
||||||
|
* }} ItemAcceptorLocatedSlot */
|
||||||
|
|
||||||
export class ItemAcceptorComponent extends Component {
|
export class ItemAcceptorComponent extends Component {
|
||||||
static getId() {
|
static getId() {
|
||||||
return "ItemAcceptor";
|
return "ItemAcceptor";
|
||||||
@ -164,11 +172,7 @@ export class ItemAcceptorComponent extends Component {
|
|||||||
* Tries to find a slot which accepts the current item
|
* Tries to find a slot which accepts the current item
|
||||||
* @param {Vector} targetLocalTile
|
* @param {Vector} targetLocalTile
|
||||||
* @param {enumDirection} fromLocalDirection
|
* @param {enumDirection} fromLocalDirection
|
||||||
* @returns {{
|
* @returns {ItemAcceptorLocatedSlot|null}
|
||||||
* slot: ItemAcceptorSlot,
|
|
||||||
* index: number,
|
|
||||||
* acceptedDirection: enumDirection
|
|
||||||
* }|null}
|
|
||||||
*/
|
*/
|
||||||
findMatchingSlot(targetLocalTile, fromLocalDirection) {
|
findMatchingSlot(targetLocalTile, fromLocalDirection) {
|
||||||
// We need to invert our direction since the acceptor specifies *from* which direction
|
// We need to invert our direction since the acceptor specifies *from* which direction
|
||||||
|
@ -92,6 +92,9 @@ export class GameSystemManager {
|
|||||||
|
|
||||||
add("staticMapEntities", StaticMapEntitySystem);
|
add("staticMapEntities", StaticMapEntitySystem);
|
||||||
|
|
||||||
|
// IMPORTANT: Must be after belt system since belt system can change the
|
||||||
|
// orientation of an entity after it is placed -> the item acceptor cache
|
||||||
|
// then would be invalid
|
||||||
add("itemAcceptor", ItemAcceptorSystem);
|
add("itemAcceptor", ItemAcceptorSystem);
|
||||||
|
|
||||||
logger.log("📦 There are", this.systemUpdateOrder.length, "game systems");
|
logger.log("📦 There are", this.systemUpdateOrder.length, "game systems");
|
||||||
|
@ -6,20 +6,41 @@ 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";
|
||||||
import { Math_min } from "../../core/builtins";
|
import { Math_min } from "../../core/builtins";
|
||||||
|
import { createLogger } from "../../core/logging";
|
||||||
|
|
||||||
|
const logger = createLogger("systems/ejector");
|
||||||
|
|
||||||
export class ItemEjectorSystem extends GameSystemWithFilter {
|
export class ItemEjectorSystem extends GameSystemWithFilter {
|
||||||
constructor(root) {
|
constructor(root) {
|
||||||
super(root, [ItemEjectorComponent]);
|
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);
|
||||||
|
this.root.signals.entityDestroyed.add(this.invalidateCache, this);
|
||||||
}
|
}
|
||||||
|
|
||||||
update() {
|
invalidateCache() {
|
||||||
const effectiveBeltSpeed = this.root.hubGoals.getBeltBaseSpeed() * globalConfig.itemSpacingOnBelts;
|
this.cacheNeedsUpdate = true;
|
||||||
let progressGrowth = (effectiveBeltSpeed / 0.5) * this.root.dynamicTickrate.deltaSeconds;
|
|
||||||
|
|
||||||
if (G_IS_DEV && globalConfig.debug.instantBelts) {
|
|
||||||
progressGrowth = 1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Precomputes the cache, which makes up for a huge performance improvement
|
||||||
|
*/
|
||||||
|
recomputeCache() {
|
||||||
|
logger.log("Recomputing cache");
|
||||||
|
|
||||||
|
const cache = [];
|
||||||
|
|
||||||
// Try to find acceptors for every ejector
|
// 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];
|
||||||
@ -29,17 +50,6 @@ export class ItemEjectorSystem extends GameSystemWithFilter {
|
|||||||
// For every ejector slot, try to find an acceptor
|
// For every ejector slot, try to find an acceptor
|
||||||
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];
|
||||||
const ejectingItem = ejectorSlot.item;
|
|
||||||
if (!ejectingItem) {
|
|
||||||
// No item ejected
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
ejectorSlot.progress = Math_min(1, ejectorSlot.progress + progressGrowth);
|
|
||||||
if (ejectorSlot.progress < 1.0) {
|
|
||||||
// Still ejecting
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Figure out where and into which direction we eject items
|
// Figure out where and into which direction we eject items
|
||||||
const ejectSlotWsTile = staticComp.localTileToWorld(ejectorSlot.pos);
|
const ejectSlotWsTile = staticComp.localTileToWorld(ejectorSlot.pos);
|
||||||
@ -71,20 +81,63 @@ export class ItemEjectorSystem extends GameSystemWithFilter {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!targetAcceptorComp.canAcceptItem(matchingSlot.index, ejectingItem)) {
|
// Ok we found a connection
|
||||||
// Can not accept item
|
cache.push({
|
||||||
|
targetEntity,
|
||||||
|
sourceSlot: ejectorSlot,
|
||||||
|
destSlot: matchingSlot,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this.cache = cache;
|
||||||
|
logger.log("Found", cache.length, "entries to update");
|
||||||
|
}
|
||||||
|
|
||||||
|
update() {
|
||||||
|
if (this.cacheNeedsUpdate) {
|
||||||
|
this.cacheNeedsUpdate = false;
|
||||||
|
this.recomputeCache();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Precompute effective belt speed
|
||||||
|
const effectiveBeltSpeed = this.root.hubGoals.getBeltBaseSpeed() * globalConfig.itemSpacingOnBelts;
|
||||||
|
let progressGrowth = (effectiveBeltSpeed / 0.5) * this.root.dynamicTickrate.deltaSeconds;
|
||||||
|
|
||||||
|
if (G_IS_DEV && globalConfig.debug.instantBelts) {
|
||||||
|
progressGrowth = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.tryPassOverItem(ejectingItem, targetEntity, matchingSlot.index)) {
|
// Advance items on the slot
|
||||||
targetAcceptorComp.onItemAccepted(
|
sourceSlot.progress = Math_min(1, sourceSlot.progress + progressGrowth);
|
||||||
matchingSlot.index,
|
|
||||||
matchingSlot.acceptedDirection,
|
// Check if we are still in the process of ejecting, can't proceed then
|
||||||
ejectingItem
|
if (sourceSlot.progress < 1.0) {
|
||||||
);
|
|
||||||
ejectorSlot.item = null;
|
|
||||||
continue;
|
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