1
0
mirror of https://github.com/tobspr/shapez.io.git synced 2025-06-13 13:04:03 +00:00
This commit is contained in:
Kiet 2021-06-22 17:41:23 +02:00 committed by GitHub
commit 524cc38077
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 60 additions and 71 deletions

View File

@ -37,7 +37,7 @@
"colors": "^1.3.3", "colors": "^1.3.3",
"core-js": "3", "core-js": "3",
"crc": "^3.8.0", "crc": "^3.8.0",
"cssnano-preset-advanced": "^4.0.7", "cssnano-preset-advanced": "^5.1.2",
"debounce-promise": "^3.1.2", "debounce-promise": "^3.1.2",
"email-validator": "^2.0.4", "email-validator": "^2.0.4",
"eslint": "7.1.0", "eslint": "7.1.0",
@ -46,12 +46,13 @@
"howler": "^2.1.2", "howler": "^2.1.2",
"html-loader": "^0.5.5", "html-loader": "^0.5.5",
"ignore-loader": "^0.1.2", "ignore-loader": "^0.1.2",
"immutable": "^4.0.0-rc.12",
"logrocket": "^1.0.7", "logrocket": "^1.0.7",
"lz-string": "^1.4.4", "lz-string": "^1.4.4",
"markdown-loader": "^4.0.0", "markdown-loader": "^4.0.0",
"match-all": "^1.2.5", "match-all": "^1.2.5",
"phonegap-plugin-mobile-accessibility": "^1.0.5", "phonegap-plugin-mobile-accessibility": "^1.0.5",
"postcss": ">=5.0.0", "postcss": "^8.3.0",
"promise-polyfill": "^8.1.0", "promise-polyfill": "^8.1.0",
"query-string": "^6.8.1", "query-string": "^6.8.1",
"rusha": "^0.8.13", "rusha": "^0.8.13",
@ -77,19 +78,19 @@
"@octokit/rest": "^18.0.6", "@octokit/rest": "^18.0.6",
"@typescript-eslint/eslint-plugin": "3.0.1", "@typescript-eslint/eslint-plugin": "3.0.1",
"@typescript-eslint/parser": "3.0.1", "@typescript-eslint/parser": "3.0.1",
"autoprefixer": "^9.4.3", "autoprefixer": "^10.2.6",
"babel-plugin-closure-elimination": "^1.3.0", "babel-plugin-closure-elimination": "^1.3.0",
"babel-plugin-console-source": "^2.0.2", "babel-plugin-console-source": "^2.0.2",
"babel-plugin-danger-remove-unused-import": "^1.1.2", "babel-plugin-danger-remove-unused-import": "^1.1.2",
"css-mqpacker": "^7.0.0", "css-mqpacker": "^7.0.0",
"cssnano": "^4.1.10", "cssnano": "^5.0.5",
"eslint-config-prettier": "6.11.0", "eslint-config-prettier": "6.11.0",
"eslint-plugin-prettier": "3.1.3", "eslint-plugin-prettier": "3.1.3",
"faster.js": "^1.1.0", "faster.js": "^1.1.0",
"glob": "^7.1.3", "glob": "^7.1.3",
"imagemin-mozjpeg": "^8.0.0", "imagemin-mozjpeg": "^8.0.0",
"imagemin-pngquant": "^8.0.0", "imagemin-pngquant": "^8.0.0",
"jimp": "^0.6.1", "jimp": "^0.16.1",
"js-yaml": "^3.13.1", "js-yaml": "^3.13.1",
"postcss-assets": "^5.0.0", "postcss-assets": "^5.0.0",
"postcss-preset-env": "^6.5.0", "postcss-preset-env": "^6.5.0",

View File

@ -1,6 +1,7 @@
import { types } from "../../savegame/serialization"; import { types } from "../../savegame/serialization";
import { BaseItem } from "../base_item"; import { BaseItem } from "../base_item";
import { Component } from "../component"; import { Component } from "../component";
const { Set } = require("immutable");
/** @enum {string} */ /** @enum {string} */
export const enumItemProcessorTypes = { export const enumItemProcessorTypes = {
@ -27,6 +28,12 @@ export const enumItemProcessorRequirements = {
painterQuad: "painterQuad", painterQuad: "painterQuad",
}; };
const specialCaseProcessorTypes = Set.of(
enumItemProcessorTypes.hub,
enumItemProcessorTypes.trash,
enumItemProcessorTypes.goal
);
/** @typedef {{ /** @typedef {{
* item: BaseItem, * item: BaseItem,
* requiredSlot?: number, * requiredSlot?: number,
@ -73,6 +80,12 @@ export class ItemProcessorComponent extends Component {
// Type of processing requirement // Type of processing requirement
this.processingRequirement = processingRequirement; this.processingRequirement = processingRequirement;
/**
* Our current inputs. Mapping of slot number to item.
* @type {Map<number, BaseItem>}
*/
this.inputSlotsMap = new Map();
this.clear(); this.clear();
} }
@ -82,11 +95,7 @@ export class ItemProcessorComponent extends Component {
// sure the outputs always match // sure the outputs always match
this.nextOutputSlot = 0; this.nextOutputSlot = 0;
/** this.inputSlotsMap.clear();
* Our current inputs
* @type {Array<{ item: BaseItem, sourceSlot: number }>}
*/
this.inputSlots = [];
/** /**
* 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
@ -109,25 +118,15 @@ export class ItemProcessorComponent extends Component {
* @param {number} sourceSlot * @param {number} sourceSlot
*/ */
tryTakeItem(item, sourceSlot) { tryTakeItem(item, sourceSlot) {
if ( if (specialCaseProcessorTypes.contains(this.type)) {
this.type === enumItemProcessorTypes.hub ||
this.type === enumItemProcessorTypes.trash ||
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.inputSlotsMap.set(sourceSlot, item);
return true; return true;
} }
// Check that we only take one item per slot if (this.inputSlotsMap.has(sourceSlot)) return false;
for (let i = 0; i < this.inputSlots.length; ++i) {
const slot = this.inputSlots[i];
if (slot.sourceSlot === sourceSlot) {
return false;
}
}
this.inputSlots.push({ item, sourceSlot }); this.inputSlotsMap.set(sourceSlot, item);
return true; return true;
} }
} }

View File

@ -31,8 +31,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 }>, * itemsBySlotMap: Map<number, BaseItem>,
* itemsBySlot: Object<number, BaseItem>,
* outItems: Array<ProducedItem> * outItems: Array<ProducedItem>
* }} ProcessorImplementationPayload * }} ProcessorImplementationPayload
*/ */
@ -188,7 +187,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.inputSlotsMap.size >= processorComp.inputsPerCharge;
} }
// QUAD PAINTER // QUAD PAINTER
@ -196,18 +195,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.inputSlotsMap.has(0)) {
return false; return false;
} }
const shapeItem = /** @type {ShapeItem} */ (itemsBySlot[0].item); const shapeItem = /** @type {ShapeItem} */ (processorComp.inputSlotsMap.get(0));
const slotStatus = []; const slotStatus = [];
// Check which slots are enabled // Check which slots are enabled
@ -232,7 +225,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.inputSlotsMap.has(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) {
@ -260,14 +253,8 @@ export class ItemProcessorSystem extends GameSystemWithFilter {
const processorComp = entity.components.ItemProcessor; const processorComp = entity.components.ItemProcessor;
// First, take items // First, take items
const items = processorComp.inputSlots; /** @type {Map<number, BaseItem>} */
processorComp.inputSlots = []; const itemsBySlotMap = processorComp.inputSlotsMap;
/** @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 = [];
@ -279,11 +266,12 @@ export class ItemProcessorSystem extends GameSystemWithFilter {
// Call implementation // Call implementation
handler({ handler({
entity, entity,
items, itemsBySlotMap,
itemsBySlot,
outItems, outItems,
}); });
processorComp.inputSlotsMap.clear();
// Track produced items // Track produced items
for (let i = 0; i < outItems.length; ++i) { for (let i = 0; i < outItems.length; ++i) {
if (!outItems[i].doNotTrack) { if (!outItems[i].doNotTrack) {
@ -318,13 +306,14 @@ 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 [key, value] of payload.itemsBySlotMap.entries()) {
payload.outItems.push({ payload.outItems.push({
item: payload.items[i].item, item: value,
preferredSlot: (nextSlot + i) % availableSlots, preferredSlot: (nextSlot + key) % availableSlots,
doNotTrack: true, doNotTrack: true,
}); });
} }
return true; return true;
} }
@ -332,7 +321,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.itemsBySlotMap.get(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;
@ -353,7 +342,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.itemsBySlotMap.get(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;
@ -374,7 +363,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.itemsBySlotMap.get(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;
@ -388,7 +377,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.itemsBySlotMap.get(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;
@ -402,7 +391,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.itemsBySlotMap.get(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;
@ -416,8 +405,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.itemsBySlotMap.get(0));
const upperItem = /** @type {ShapeItem} */ (payload.itemsBySlot[1]); const upperItem = /** @type {ShapeItem} */ (payload.itemsBySlotMap.get(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");
@ -443,8 +432,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.itemsBySlotMap.get(0));
const item2 = /** @type {ColorItem} */ (payload.items[1].item); const item2 = /** @type {ColorItem} */ (payload.itemsBySlotMap.get(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");
@ -466,8 +455,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.itemsBySlotMap.get(0));
const colorItem = /** @type {ColorItem} */ (payload.itemsBySlot[1]); const colorItem = /** @type {ColorItem} */ (payload.itemsBySlotMap.get(1));
const colorizedDefinition = this.root.shapeDefinitionMgr.shapeActionPaintWith( const colorizedDefinition = this.root.shapeDefinitionMgr.shapeActionPaintWith(
shapeItem.definition, shapeItem.definition,
@ -483,9 +472,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.itemsBySlotMap.get(0));
const shapeItem2 = /** @type {ShapeItem} */ (payload.itemsBySlot[1]); const shapeItem2 = /** @type {ShapeItem} */ (payload.itemsBySlotMap.get(1));
const colorItem = /** @type {ColorItem} */ (payload.itemsBySlot[2]); const colorItem = /** @type {ColorItem} */ (payload.itemsBySlotMap.get(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");
@ -513,14 +502,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.itemsBySlotMap.get(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.itemsBySlotMap.get(i + 1)) {
colors[i] = /** @type {ColorItem} */ (payload.itemsBySlot[i + 1]).color; colors[i] = /** @type {ColorItem} */ (payload.itemsBySlotMap.get(i + 1)).color;
} }
} }
@ -539,7 +528,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.itemsBySlotMap.get(0);
payload.outItems.push({ payload.outItems.push({
item, item,
doNotTrack: true, doNotTrack: true,
@ -558,8 +547,8 @@ export class ItemProcessorSystem extends GameSystemWithFilter {
const hubComponent = payload.entity.components.Hub; const hubComponent = payload.entity.components.Hub;
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 value of payload.itemsBySlotMap.values()) {
const item = /** @type {ShapeItem} */ (payload.items[i].item); const item = /** @type {ShapeItem} */ (value);
this.root.hubGoals.handleDefinitionDelivered(item.definition); this.root.hubGoals.handleDefinitionDelivered(item.definition);
} }
} }
@ -569,12 +558,12 @@ 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.itemsBySlotMap.get(0);
const now = this.root.time.now(); const now = this.root.time.now();
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.itemsBySlotMap.get(0);
goalComp.deliveryHistory.push({ goalComp.deliveryHistory.push({
item, item,
time: now, time: now,