1
0
mirror of https://github.com/tobspr/shapez.io.git synced 2025-06-13 13:04:03 +00:00

Clear duplicated code and add input requirements for acceptor

This commit is contained in:
Sense101 2022-02-08 14:39:43 +00:00
parent 3a99628670
commit 0cacbcd267
6 changed files with 115 additions and 58 deletions

View File

@ -263,16 +263,7 @@ export class BeltPath extends BasicSerializableObject {
const matchingSlotIndex = matchingSlot.index;
return function (item, startProgress = 0.0) {
const storageComp = targetEntity.components.Storage;
if (
storageComp &&
storageComp.tryAcceptItem(item) &&
targetAcceptorComp.tryAcceptItem(matchingSlotIndex, item, startProgress)
) {
// unique duplicated code for storage
return true;
}
if (targetAcceptorComp.tryAcceptItem(matchingSlotIndex, item, startProgress)) {
if (targetAcceptorComp.tryAcceptItem(targetEntity, matchingSlotIndex, item, startProgress)) {
return true;
}
return false;

View File

@ -1,7 +1,7 @@
import { formatItemsPerSecond } from "../../core/utils";
import { enumDirection, Vector } from "../../core/vector";
import { T } from "../../translations";
import { ItemAcceptorComponent } from "../components/item_acceptor";
import { enumInputRequirements, ItemAcceptorComponent } from "../components/item_acceptor";
import { ItemEjectorComponent } from "../components/item_ejector";
import {
enumItemProcessorTypes,
@ -274,6 +274,7 @@ export class MetaPainterBuilding extends MetaBuilding {
filter: "color",
},
]);
entity.components.ItemAcceptor.inputRequirement = enumInputRequirements.quadPainter;
entity.components.ItemEjector.setSlots([
{ pos: new Vector(0, 0), direction: enumDirection.top },

View File

@ -1,7 +1,7 @@
import { formatBigNumber } from "../../core/utils";
import { enumDirection, Vector } from "../../core/vector";
import { T } from "../../translations";
import { ItemAcceptorComponent } from "../components/item_acceptor";
import { enumInputRequirements, ItemAcceptorComponent } from "../components/item_acceptor";
import { ItemEjectorComponent } from "../components/item_ejector";
import { StorageComponent } from "../components/storage";
import { enumPinSlotType, WiredPinsComponent } from "../components/wired_pins";
@ -81,6 +81,7 @@ export class MetaStorageBuilding extends MetaBuilding {
direction: enumDirection.bottom,
},
],
inputRequirement: enumInputRequirements.storage,
})
);

View File

@ -3,6 +3,7 @@ import { types } from "../../savegame/serialization";
import { BaseItem } from "../base_item";
import { Component } from "../component";
import { Entity } from "../entity";
import { isTruthyItem } from "../items/boolean_item";
import { typeItemSingleton } from "../item_resolver";
import { GameRoot } from "../root";
@ -49,6 +50,12 @@ import { GameRoot } from "../root";
* }} InputCompletedArgs
*/
/** @enum {string} */
export const enumInputRequirements = {
quadPainter: "quadPainter",
storage: "storage",
};
export class ItemAcceptorComponent extends Component {
static getId() {
return "ItemAcceptor";
@ -78,18 +85,26 @@ export class ItemAcceptorComponent extends Component {
* @param {object} param0
* @param {Array<ItemAcceptorSlotConfig>} param0.slots The slots from which we accept items
* @param {number=} param0.maxSlotInputs The maximum amount of items one slot can accept before it is full
* @param {string|null=} param0.inputRequirement The requirement to accept items
*/
constructor({ slots = [], maxSlotInputs = 2 }) {
constructor({ slots = [], maxSlotInputs = 2, inputRequirement = null }) {
super();
this.setSlots(slots);
this.inputRequirement = inputRequirement;
// setting this to 1 will cause throughput issues at very high speeds
this.maxSlotInputs = maxSlotInputs;
this.clear();
}
clear() {
/** @type {ItemAcceptorInputs} */
this.inputs = [];
/** @type {ItemAcceptorCompletedInputs} */
this.completedInputs = [];
this.setSlots(slots);
// setting this to 1 will cause throughput issues at very high speeds
this.maxSlotInputs = maxSlotInputs;
}
/**
@ -111,16 +126,74 @@ export class ItemAcceptorComponent extends Component {
}
}
/**
*
* @param {Entity} entity
* @param {BaseItem} item
* @param {number} slotIndex
* @returns
*/
canAcceptItem(entity, item, slotIndex) {
const slot = this.slots[slotIndex];
// make sure there is a slot and we match the filter
if (slot && !(slot.filter && slot.filter != item.getItemType())) {
switch (this.inputRequirement) {
case null: {
return true;
}
case enumInputRequirements.quadPainter: {
const pinsComp = entity.components.WiredPins;
if (slotIndex === 0) {
// Always accept the shape
return true;
}
// Check the network value at the given slot
const network = pinsComp.slots[slotIndex - 1].linkedNetwork;
const slotIsEnabled = network && network.hasValue() && isTruthyItem(network.currentValue);
if (!slotIsEnabled) {
return false;
}
return true;
}
case enumInputRequirements.storage: {
const storageComp = entity.components.Storage;
if (storageComp.storedCount >= storageComp.maximumStorage) {
return false;
}
const itemType = item.getItemType();
if (storageComp.storedItem && itemType !== storageComp.storedItem.getItemType()) {
return false;
}
// set the item straight away - this way different kinds of items can't be inq the acceptor
storageComp.storedItem = item;
storageComp.storedCount++;
return true;
}
default: {
assertAlways(false, "Input requirement is not recognised: " + slot.filter);
break;
}
}
}
return false;
}
/**
* Called when trying to input a new item
* @param {Entity} entity
* @param {number} slotIndex
* @param {BaseItem} item
* @param {number} startProgress World space remaining progress, can be set to set the start position of the item
* @returns {boolean} if the input was succesful
*/
tryAcceptItem(slotIndex, item, startProgress = 0.0) {
const slot = this.slots[slotIndex];
tryAcceptItem(entity, slotIndex, item, startProgress = 0.0) {
// make sure we have space to actually accept
let existingInputs = 0;
for (let i = 0; i < this.inputs.length; i++) {
if (this.inputs[i].slotIndex == slotIndex) {
@ -136,8 +209,7 @@ export class ItemAcceptorComponent extends Component {
if (existingInputs >= this.maxSlotInputs) {
return false;
}
if (slot.filter && slot.filter != item.getItemType()) {
if (!this.canAcceptItem(entity, item, slotIndex)) {
return false;
}

View File

@ -202,17 +202,7 @@ export class ItemEjectorSystem extends GameSystemWithFilter {
const destSlot = sourceSlot.cachedDestSlot;
if (destEntity && destSlot) {
const targetAcceptorComp = destEntity.components.ItemAcceptor;
const storageComp = destEntity.components.Storage;
if (
storageComp &&
storageComp.tryAcceptItem(item) &&
targetAcceptorComp.tryAcceptItem(destSlot.index, item, extraProgress)
) {
// unique duplicated code for storage - hacky :(
sourceSlot.item = null;
return;
}
if (targetAcceptorComp.tryAcceptItem(destSlot.index, item, extraProgress)) {
if (targetAcceptorComp.tryAcceptItem(destEntity, destSlot.index, item, extraProgress)) {
// Handover successful, clear slot
sourceSlot.item = null;
}

View File

@ -146,7 +146,7 @@ export class ItemProcessorSystem extends GameSystemWithFilter {
}
}
// requirements are no longer needed as items will always be accepted, only the next method is.
// input requirements are now handled in the item acceptor, which also fits better with what the acceptor is supposed to do
/**
* Checks whether it's possible to process something
@ -160,21 +160,35 @@ export class ItemProcessorSystem extends GameSystemWithFilter {
// DEFAULT
// By default, we can start processing once all inputs are there
case null: {
return acceptorComp.completedInputs.length >= processorComp.inputsPerCharge;
// Since each slot might have more than one input, don't check each slot more than once
let usedSlots = [];
for (let i = 0; i < acceptorComp.completedInputs.length; i++) {
const index = acceptorComp.completedInputs[i].slotIndex;
if (!usedSlots.includes(index)) {
usedSlots.push(index);
}
}
return usedSlots.length >= processorComp.inputsPerCharge;
}
// QUAD PAINTER
// For the quad painter, it might be possible to start processing earlier
case enumItemProcessorRequirements.painterQuad: {
const pinsComp = entity.components.WiredPins;
const inputs = acceptorComp.completedInputs;
const input = acceptorComp.completedInputs[0];
if (!input) {
return false;
// split inputs efficiently
let items = new Map();
for (let i = 0; i < inputs.length; i++) {
const input = inputs[i];
if (!items.get(input.slotIndex)) {
items.set(input.slotIndex, input.item);
}
}
// First slot is the shape, so if it's not there we can't do anything
const shapeItem = /** @type {ShapeItem} */ (input.item);
const shapeItem = /** @type {ShapeItem} */ (items.get(0));
if (!shapeItem) {
return false;
}
@ -203,10 +217,7 @@ export class ItemProcessorSystem extends GameSystemWithFilter {
// Check if all colors of the enabled slots are there
for (let i = 0; i < slotStatus.length; ++i) {
if (
slotStatus[i] &&
!acceptorComp.completedInputs.find(input => input.slotIndex == i + 1) // @TODO this is slow
) {
if (slotStatus[i] && !items.get(1 + i)) {
// A slot which is enabled wasn't enabled. Make sure if there is anything on the quadrant,
// it is not possible to paint, but if there is nothing we can ignore it
for (let j = 0; j < 4; ++j) {
@ -217,7 +228,6 @@ export class ItemProcessorSystem extends GameSystemWithFilter {
}
}
}
return true;
}
@ -243,8 +253,12 @@ export class ItemProcessorSystem extends GameSystemWithFilter {
for (let i = 0; i < inputs.length; i++) {
const input = inputs[i];
if (!items.get(input.slotIndex)) {
items.set(input.slotIndex, input.item);
extraProgress = Math.max(extraProgress, input.extraProgress);
inputs.splice(i, 1);
i--;
}
}
/** @type {Array<ProducedItem>} */
@ -283,18 +297,6 @@ export class ItemProcessorSystem extends GameSystemWithFilter {
items: outItems,
remainingTime: timeToProcess,
};
// only remove one item from each slot - we don't want to delete extra items!
let usedSlots = [];
for (let i = 0; i < acceptorComp.completedInputs.length; i++) {
const index = acceptorComp.completedInputs[i].slotIndex;
if (!usedSlots.includes(index)) {
usedSlots.push(index);
acceptorComp.completedInputs.splice(i, 1);
i--;
}
}
}
/**