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:
parent
3a99628670
commit
0cacbcd267
@ -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;
|
||||
|
@ -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 },
|
||||
|
@ -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,
|
||||
})
|
||||
);
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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--;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
Loading…
Reference in New Issue
Block a user