1
0
mirror of https://github.com/tobspr/shapez.io.git synced 2024-10-27 20:34:29 +00:00

Simplify item processor slot logic. (#1257)

Track input slot assignment by array index rather than including extra
data in a new object. This greatly reduces the amount of garbage
generated by tryTakeItem and other item process operations.
This commit is contained in:
PFedak 2021-08-04 04:34:15 -06:00 committed by GitHub
parent 0a15958af9
commit e4f02abeb3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 44 additions and 51 deletions

View File

@ -84,10 +84,16 @@ export class ItemProcessorComponent extends Component {
/** /**
* Our current inputs * Our current inputs
* @type {Array<{ item: BaseItem, sourceSlot: number }>} * @type {Array<BaseItem?>}
*/ */
this.inputSlots = []; this.inputSlots = [];
/**
* Current input count
* @type {number}
*/
this.inputCount = 0;
/** /**
* What we are currently processing, empty if we don't produce anything rn * What we are currently processing, empty if we don't produce anything rn
* requiredSlot: Item *must* be ejected on this slot * requiredSlot: Item *must* be ejected on this slot
@ -115,19 +121,16 @@ export class ItemProcessorComponent extends Component {
this.type === enumItemProcessorTypes.goal this.type === enumItemProcessorTypes.goal
) { ) {
// Hub has special logic .. not really nice but efficient. // Hub has special logic .. not really nice but efficient.
this.inputSlots.push({ item, sourceSlot }); this.inputSlots.push(item);
this.inputCount++;
return true; return true;
} }
// Check that we only take one item per slot // Check that we only take one item per slot
for (let i = 0; i < this.inputSlots.length; ++i) { if (this.inputSlots[sourceSlot]) return false;
const slot = this.inputSlots[i];
if (slot.sourceSlot === sourceSlot) {
return false;
}
}
this.inputSlots.push({ item, sourceSlot }); this.inputSlots[sourceSlot] = item;
this.inputCount++;
return true; return true;
} }
} }

View File

@ -32,8 +32,7 @@ const MAX_QUEUED_CHARGES = 2;
* Type of a processor implementation * Type of a processor implementation
* @typedef {{ * @typedef {{
* entity: Entity, * entity: Entity,
* items: Array<{ item: BaseItem, sourceSlot: number }>, * items: Array<BaseItem?>,
* itemsBySlot: Object<number, BaseItem>,
* outItems: Array<ProducedItem> * outItems: Array<ProducedItem>
* }} ProcessorImplementationPayload * }} ProcessorImplementationPayload
*/ */
@ -189,7 +188,7 @@ export class ItemProcessorSystem extends GameSystemWithFilter {
// DEFAULT // DEFAULT
// By default, we can start processing once all inputs are there // By default, we can start processing once all inputs are there
case null: { case null: {
return processorComp.inputSlots.length >= processorComp.inputsPerCharge; return processorComp.inputCount >= processorComp.inputsPerCharge;
} }
// QUAD PAINTER // QUAD PAINTER
@ -197,18 +196,12 @@ export class ItemProcessorSystem extends GameSystemWithFilter {
case enumItemProcessorRequirements.painterQuad: { case enumItemProcessorRequirements.painterQuad: {
const pinsComp = entity.components.WiredPins; const pinsComp = entity.components.WiredPins;
/** @type {Object.<number, { item: BaseItem, sourceSlot: number }>} */
const itemsBySlot = {};
for (let i = 0; i < processorComp.inputSlots.length; ++i) {
itemsBySlot[processorComp.inputSlots[i].sourceSlot] = processorComp.inputSlots[i];
}
// First slot is the shape, so if it's not there we can't do anything // First slot is the shape, so if it's not there we can't do anything
if (!itemsBySlot[0]) { if (!processorComp.inputSlots[0]) {
return false; return false;
} }
const shapeItem = /** @type {ShapeItem} */ (itemsBySlot[0].item); const shapeItem = /** @type {ShapeItem} */ (processorComp.inputSlots[0]);
const slotStatus = []; const slotStatus = [];
// Check which slots are enabled // Check which slots are enabled
@ -233,7 +226,7 @@ export class ItemProcessorSystem extends GameSystemWithFilter {
// Check if all colors of the enabled slots are there // Check if all colors of the enabled slots are there
for (let i = 0; i < slotStatus.length; ++i) { for (let i = 0; i < slotStatus.length; ++i) {
if (slotStatus[i] && !itemsBySlot[1 + i]) { if (slotStatus[i] && !processorComp.inputSlots[1 + i]) {
// A slot which is enabled wasn't enabled. Make sure if there is anything on the quadrant, // 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 // it is not possible to paint, but if there is nothing we can ignore it
for (let j = 0; j < 4; ++j) { for (let j = 0; j < 4; ++j) {
@ -262,13 +255,6 @@ export class ItemProcessorSystem extends GameSystemWithFilter {
// First, take items // First, take items
const items = processorComp.inputSlots; const items = processorComp.inputSlots;
processorComp.inputSlots = [];
/** @type {Object<string, BaseItem>} */
const itemsBySlot = {};
for (let i = 0; i < items.length; ++i) {
itemsBySlot[items[i].sourceSlot] = items[i].item;
}
/** @type {Array<ProducedItem>} */ /** @type {Array<ProducedItem>} */
const outItems = []; const outItems = [];
@ -281,7 +267,6 @@ export class ItemProcessorSystem extends GameSystemWithFilter {
handler({ handler({
entity, entity,
items, items,
itemsBySlot,
outItems, outItems,
}); });
@ -304,6 +289,9 @@ export class ItemProcessorSystem extends GameSystemWithFilter {
items: outItems, items: outItems,
remainingTime: timeToProcess, remainingTime: timeToProcess,
}); });
processorComp.inputSlots.length = 0;
processorComp.inputCount = 0;
} }
/** /**
@ -320,8 +308,9 @@ export class ItemProcessorSystem extends GameSystemWithFilter {
const nextSlot = processorComp.nextOutputSlot++ % availableSlots; const nextSlot = processorComp.nextOutputSlot++ % availableSlots;
for (let i = 0; i < payload.items.length; ++i) { for (let i = 0; i < payload.items.length; ++i) {
if (!payload.items[i]) continue;
payload.outItems.push({ payload.outItems.push({
item: payload.items[i].item, item: payload.items[i],
preferredSlot: (nextSlot + i) % availableSlots, preferredSlot: (nextSlot + i) % availableSlots,
doNotTrack: true, doNotTrack: true,
}); });
@ -333,7 +322,7 @@ export class ItemProcessorSystem extends GameSystemWithFilter {
* @param {ProcessorImplementationPayload} payload * @param {ProcessorImplementationPayload} payload
*/ */
process_CUTTER(payload) { process_CUTTER(payload) {
const inputItem = /** @type {ShapeItem} */ (payload.items[0].item); const inputItem = /** @type {ShapeItem} */ (payload.items[0]);
assert(inputItem instanceof ShapeItem, "Input for cut is not a shape"); assert(inputItem instanceof ShapeItem, "Input for cut is not a shape");
const inputDefinition = inputItem.definition; const inputDefinition = inputItem.definition;
@ -354,7 +343,7 @@ export class ItemProcessorSystem extends GameSystemWithFilter {
* @param {ProcessorImplementationPayload} payload * @param {ProcessorImplementationPayload} payload
*/ */
process_CUTTER_QUAD(payload) { process_CUTTER_QUAD(payload) {
const inputItem = /** @type {ShapeItem} */ (payload.items[0].item); const inputItem = /** @type {ShapeItem} */ (payload.items[0]);
assert(inputItem instanceof ShapeItem, "Input for cut is not a shape"); assert(inputItem instanceof ShapeItem, "Input for cut is not a shape");
const inputDefinition = inputItem.definition; const inputDefinition = inputItem.definition;
@ -375,7 +364,7 @@ export class ItemProcessorSystem extends GameSystemWithFilter {
* @param {ProcessorImplementationPayload} payload * @param {ProcessorImplementationPayload} payload
*/ */
process_ROTATER(payload) { process_ROTATER(payload) {
const inputItem = /** @type {ShapeItem} */ (payload.items[0].item); const inputItem = /** @type {ShapeItem} */ (payload.items[0]);
assert(inputItem instanceof ShapeItem, "Input for rotation is not a shape"); assert(inputItem instanceof ShapeItem, "Input for rotation is not a shape");
const inputDefinition = inputItem.definition; const inputDefinition = inputItem.definition;
@ -389,7 +378,7 @@ export class ItemProcessorSystem extends GameSystemWithFilter {
* @param {ProcessorImplementationPayload} payload * @param {ProcessorImplementationPayload} payload
*/ */
process_ROTATER_CCW(payload) { process_ROTATER_CCW(payload) {
const inputItem = /** @type {ShapeItem} */ (payload.items[0].item); const inputItem = /** @type {ShapeItem} */ (payload.items[0]);
assert(inputItem instanceof ShapeItem, "Input for rotation is not a shape"); assert(inputItem instanceof ShapeItem, "Input for rotation is not a shape");
const inputDefinition = inputItem.definition; const inputDefinition = inputItem.definition;
@ -403,7 +392,7 @@ export class ItemProcessorSystem extends GameSystemWithFilter {
* @param {ProcessorImplementationPayload} payload * @param {ProcessorImplementationPayload} payload
*/ */
process_ROTATER_180(payload) { process_ROTATER_180(payload) {
const inputItem = /** @type {ShapeItem} */ (payload.items[0].item); const inputItem = /** @type {ShapeItem} */ (payload.items[0]);
assert(inputItem instanceof ShapeItem, "Input for rotation is not a shape"); assert(inputItem instanceof ShapeItem, "Input for rotation is not a shape");
const inputDefinition = inputItem.definition; const inputDefinition = inputItem.definition;
@ -417,8 +406,8 @@ export class ItemProcessorSystem extends GameSystemWithFilter {
* @param {ProcessorImplementationPayload} payload * @param {ProcessorImplementationPayload} payload
*/ */
process_STACKER(payload) { process_STACKER(payload) {
const lowerItem = /** @type {ShapeItem} */ (payload.itemsBySlot[0]); const lowerItem = /** @type {ShapeItem} */ (payload.items[0]);
const upperItem = /** @type {ShapeItem} */ (payload.itemsBySlot[1]); const upperItem = /** @type {ShapeItem} */ (payload.items[1]);
assert(lowerItem instanceof ShapeItem, "Input for lower stack is not a shape"); assert(lowerItem instanceof ShapeItem, "Input for lower stack is not a shape");
assert(upperItem instanceof ShapeItem, "Input for upper stack is not a shape"); assert(upperItem instanceof ShapeItem, "Input for upper stack is not a shape");
@ -444,8 +433,8 @@ export class ItemProcessorSystem extends GameSystemWithFilter {
*/ */
process_MIXER(payload) { process_MIXER(payload) {
// Find both colors and combine them // Find both colors and combine them
const item1 = /** @type {ColorItem} */ (payload.items[0].item); const item1 = /** @type {ColorItem} */ (payload.items[0]);
const item2 = /** @type {ColorItem} */ (payload.items[1].item); const item2 = /** @type {ColorItem} */ (payload.items[1]);
assert(item1 instanceof ColorItem, "Input for color mixer is not a color"); assert(item1 instanceof ColorItem, "Input for color mixer is not a color");
assert(item2 instanceof ColorItem, "Input for color mixer is not a color"); assert(item2 instanceof ColorItem, "Input for color mixer is not a color");
@ -467,8 +456,8 @@ export class ItemProcessorSystem extends GameSystemWithFilter {
* @param {ProcessorImplementationPayload} payload * @param {ProcessorImplementationPayload} payload
*/ */
process_PAINTER(payload) { process_PAINTER(payload) {
const shapeItem = /** @type {ShapeItem} */ (payload.itemsBySlot[0]); const shapeItem = /** @type {ShapeItem} */ (payload.items[0]);
const colorItem = /** @type {ColorItem} */ (payload.itemsBySlot[1]); const colorItem = /** @type {ColorItem} */ (payload.items[1]);
const colorizedDefinition = this.root.shapeDefinitionMgr.shapeActionPaintWith( const colorizedDefinition = this.root.shapeDefinitionMgr.shapeActionPaintWith(
shapeItem.definition, shapeItem.definition,
@ -484,9 +473,9 @@ export class ItemProcessorSystem extends GameSystemWithFilter {
* @param {ProcessorImplementationPayload} payload * @param {ProcessorImplementationPayload} payload
*/ */
process_PAINTER_DOUBLE(payload) { process_PAINTER_DOUBLE(payload) {
const shapeItem1 = /** @type {ShapeItem} */ (payload.itemsBySlot[0]); const shapeItem1 = /** @type {ShapeItem} */ (payload.items[0]);
const shapeItem2 = /** @type {ShapeItem} */ (payload.itemsBySlot[1]); const shapeItem2 = /** @type {ShapeItem} */ (payload.items[1]);
const colorItem = /** @type {ColorItem} */ (payload.itemsBySlot[2]); const colorItem = /** @type {ColorItem} */ (payload.items[2]);
assert(shapeItem1 instanceof ShapeItem, "Input for painter is not a shape"); assert(shapeItem1 instanceof ShapeItem, "Input for painter is not a shape");
assert(shapeItem2 instanceof ShapeItem, "Input for painter is not a shape"); assert(shapeItem2 instanceof ShapeItem, "Input for painter is not a shape");
@ -514,14 +503,14 @@ export class ItemProcessorSystem extends GameSystemWithFilter {
* @param {ProcessorImplementationPayload} payload * @param {ProcessorImplementationPayload} payload
*/ */
process_PAINTER_QUAD(payload) { process_PAINTER_QUAD(payload) {
const shapeItem = /** @type {ShapeItem} */ (payload.itemsBySlot[0]); const shapeItem = /** @type {ShapeItem} */ (payload.items[0]);
assert(shapeItem instanceof ShapeItem, "Input for painter is not a shape"); assert(shapeItem instanceof ShapeItem, "Input for painter is not a shape");
/** @type {Array<enumColors>} */ /** @type {Array<enumColors>} */
const colors = [null, null, null, null]; const colors = [null, null, null, null];
for (let i = 0; i < 4; ++i) { for (let i = 0; i < 4; ++i) {
if (payload.itemsBySlot[i + 1]) { if (payload.items[i + 1]) {
colors[i] = /** @type {ColorItem} */ (payload.itemsBySlot[i + 1]).color; colors[i] = /** @type {ColorItem} */ (payload.items[i + 1]).color;
} }
} }
@ -540,7 +529,7 @@ export class ItemProcessorSystem extends GameSystemWithFilter {
*/ */
process_READER(payload) { process_READER(payload) {
// Pass through the item // Pass through the item
const item = payload.itemsBySlot[0]; const item = payload.items[0];
payload.outItems.push({ payload.outItems.push({
item, item,
doNotTrack: true, doNotTrack: true,
@ -560,7 +549,8 @@ export class ItemProcessorSystem extends GameSystemWithFilter {
assert(hubComponent, "Hub item processor has no hub component"); assert(hubComponent, "Hub item processor has no hub component");
for (let i = 0; i < payload.items.length; ++i) { for (let i = 0; i < payload.items.length; ++i) {
const item = /** @type {ShapeItem} */ (payload.items[i].item); if (!payload.items[i]) continue;
const item = /** @type {ShapeItem} */ (payload.items[i]);
this.root.hubGoals.handleDefinitionDelivered(item.definition); this.root.hubGoals.handleDefinitionDelivered(item.definition);
} }
} }
@ -570,7 +560,7 @@ export class ItemProcessorSystem extends GameSystemWithFilter {
*/ */
process_GOAL(payload) { process_GOAL(payload) {
const goalComp = payload.entity.components.GoalAcceptor; const goalComp = payload.entity.components.GoalAcceptor;
const item = payload.items[0].item; const item = payload.items[0];
const now = this.root.time.now(); const now = this.root.time.now();
if (goalComp.item && !item.equals(goalComp.item)) { if (goalComp.item && !item.equals(goalComp.item)) {
@ -584,7 +574,7 @@ export class ItemProcessorSystem extends GameSystemWithFilter {
if (this.root.gameMode.getIsEditor()) { if (this.root.gameMode.getIsEditor()) {
// while playing in editor, assign the item // while playing in editor, assign the item
goalComp.item = payload.items[0].item; goalComp.item = payload.items[0];
} }
goalComp.lastDelivery = { goalComp.lastDelivery = {