mirror of
				https://github.com/tobspr/shapez.io.git
				synced 2025-06-13 13:04:03 +00:00 
			
		
		
		
	"Logic pain fix" - Fixing quad painter pain... (#607)
* (wip) 4-painter accept pins * fix everything * finish 4-painer fix * refactor processing requirement
This commit is contained in:
		
							parent
							
								
									ec830ed5bc
								
							
						
					
					
						commit
						5487ec9818
					
				| @ -3,11 +3,12 @@ import { enumDirection, Vector } from "../../core/vector"; | |||||||
| import { T } from "../../translations"; | import { T } from "../../translations"; | ||||||
| import { ItemAcceptorComponent } from "../components/item_acceptor"; | import { ItemAcceptorComponent } from "../components/item_acceptor"; | ||||||
| import { ItemEjectorComponent } from "../components/item_ejector"; | import { ItemEjectorComponent } from "../components/item_ejector"; | ||||||
| import { enumItemProcessorTypes, ItemProcessorComponent } from "../components/item_processor"; | import { enumItemProcessorTypes, ItemProcessorComponent, enumItemProcessorRequirements } from "../components/item_processor"; | ||||||
| import { Entity } from "../entity"; | import { Entity } from "../entity"; | ||||||
| import { defaultBuildingVariant, MetaBuilding } from "../meta_building"; | import { defaultBuildingVariant, MetaBuilding } from "../meta_building"; | ||||||
| import { GameRoot } from "../root"; | import { GameRoot } from "../root"; | ||||||
| import { enumHubGoalRewards } from "../tutorial_goals"; | import { enumHubGoalRewards } from "../tutorial_goals"; | ||||||
|  | import { WiredPinsComponent, enumPinSlotType } from "../components/wired_pins"; | ||||||
| 
 | 
 | ||||||
| /** @enum {string} */ | /** @enum {string} */ | ||||||
| export const enumPainterVariants = { mirrored: "mirrored", double: "double", quad: "quad" }; | export const enumPainterVariants = { mirrored: "mirrored", double: "double", quad: "quad" }; | ||||||
| @ -119,6 +120,10 @@ export class MetaPainterBuilding extends MetaBuilding { | |||||||
|         switch (variant) { |         switch (variant) { | ||||||
|             case defaultBuildingVariant: |             case defaultBuildingVariant: | ||||||
|             case enumPainterVariants.mirrored: { |             case enumPainterVariants.mirrored: { | ||||||
|  |                 if (entity.components.WiredPins) { | ||||||
|  |                     entity.removeComponent(WiredPinsComponent) | ||||||
|  |                 } | ||||||
|  | 
 | ||||||
|                 entity.components.ItemAcceptor.setSlots([ |                 entity.components.ItemAcceptor.setSlots([ | ||||||
|                     { |                     { | ||||||
|                         pos: new Vector(0, 0), |                         pos: new Vector(0, 0), | ||||||
| @ -135,13 +140,19 @@ export class MetaPainterBuilding extends MetaBuilding { | |||||||
|                 ]); |                 ]); | ||||||
| 
 | 
 | ||||||
|                 entity.components.ItemProcessor.type = enumItemProcessorTypes.painter; |                 entity.components.ItemProcessor.type = enumItemProcessorTypes.painter; | ||||||
|  |                 entity.components.ItemProcessor.processingRequirement = null; | ||||||
|                 entity.components.ItemProcessor.inputsPerCharge = 2; |                 entity.components.ItemProcessor.inputsPerCharge = 2; | ||||||
|  | 
 | ||||||
|                 entity.components.ItemEjector.setSlots([ |                 entity.components.ItemEjector.setSlots([ | ||||||
|                     { pos: new Vector(1, 0), direction: enumDirection.right }, |                     { pos: new Vector(1, 0), direction: enumDirection.right }, | ||||||
|                 ]); |                 ]); | ||||||
|                 break; |                 break; | ||||||
|             } |             } | ||||||
|             case enumPainterVariants.double: { |             case enumPainterVariants.double: { | ||||||
|  |                 if (entity.components.WiredPins) { | ||||||
|  |                     entity.removeComponent(WiredPinsComponent) | ||||||
|  |                 } | ||||||
|  | 
 | ||||||
|                 entity.components.ItemAcceptor.setSlots([ |                 entity.components.ItemAcceptor.setSlots([ | ||||||
|                     { |                     { | ||||||
|                         pos: new Vector(0, 0), |                         pos: new Vector(0, 0), | ||||||
| @ -161,6 +172,7 @@ export class MetaPainterBuilding extends MetaBuilding { | |||||||
|                 ]); |                 ]); | ||||||
| 
 | 
 | ||||||
|                 entity.components.ItemProcessor.type = enumItemProcessorTypes.painterDouble; |                 entity.components.ItemProcessor.type = enumItemProcessorTypes.painterDouble; | ||||||
|  |                 entity.components.ItemProcessor.processingRequirement = null; | ||||||
|                 entity.components.ItemProcessor.inputsPerCharge = 3; |                 entity.components.ItemProcessor.inputsPerCharge = 3; | ||||||
| 
 | 
 | ||||||
|                 entity.components.ItemEjector.setSlots([ |                 entity.components.ItemEjector.setSlots([ | ||||||
| @ -169,6 +181,33 @@ export class MetaPainterBuilding extends MetaBuilding { | |||||||
|                 break; |                 break; | ||||||
|             } |             } | ||||||
|             case enumPainterVariants.quad: { |             case enumPainterVariants.quad: { | ||||||
|  |                 if (!entity.components.WiredPins) { | ||||||
|  |                     entity.addComponent(new WiredPinsComponent({ | ||||||
|  |                         slots: [ | ||||||
|  |                             { | ||||||
|  |                                 pos: new Vector(0, 0), | ||||||
|  |                                 direction: enumDirection.bottom, | ||||||
|  |                                 type: enumPinSlotType.logicalAcceptor | ||||||
|  |                             }, | ||||||
|  |                             { | ||||||
|  |                                 pos: new Vector(1, 0), | ||||||
|  |                                 direction: enumDirection.bottom, | ||||||
|  |                                 type: enumPinSlotType.logicalAcceptor | ||||||
|  |                             }, | ||||||
|  |                             { | ||||||
|  |                                 pos: new Vector(2, 0), | ||||||
|  |                                 direction: enumDirection.bottom, | ||||||
|  |                                 type: enumPinSlotType.logicalAcceptor | ||||||
|  |                             }, | ||||||
|  |                             { | ||||||
|  |                                 pos: new Vector(3, 0), | ||||||
|  |                                 direction: enumDirection.bottom, | ||||||
|  |                                 type: enumPinSlotType.logicalAcceptor | ||||||
|  |                             }, | ||||||
|  |                         ] | ||||||
|  |                     })); | ||||||
|  |                 } | ||||||
|  | 
 | ||||||
|                 entity.components.ItemAcceptor.setSlots([ |                 entity.components.ItemAcceptor.setSlots([ | ||||||
|                     { |                     { | ||||||
|                         pos: new Vector(0, 0), |                         pos: new Vector(0, 0), | ||||||
| @ -198,6 +237,7 @@ export class MetaPainterBuilding extends MetaBuilding { | |||||||
|                 ]); |                 ]); | ||||||
| 
 | 
 | ||||||
|                 entity.components.ItemProcessor.type = enumItemProcessorTypes.painterQuad; |                 entity.components.ItemProcessor.type = enumItemProcessorTypes.painterQuad; | ||||||
|  |                 entity.components.ItemProcessor.processingRequirement = enumItemProcessorRequirements.painterQuad; | ||||||
|                 entity.components.ItemProcessor.inputsPerCharge = 5; |                 entity.components.ItemProcessor.inputsPerCharge = 5; | ||||||
| 
 | 
 | ||||||
|                 entity.components.ItemEjector.setSlots([ |                 entity.components.ItemEjector.setSlots([ | ||||||
|  | |||||||
| @ -43,7 +43,7 @@ export function initComponentRegistry() { | |||||||
|     assert( |     assert( | ||||||
|         // @ts-ignore
 |         // @ts-ignore
 | ||||||
|         require.context("./components", false, /.*\.js/i).keys().length === |         require.context("./components", false, /.*\.js/i).keys().length === | ||||||
|             gComponentRegistry.getNumEntries(), |         gComponentRegistry.getNumEntries(), | ||||||
|         "Not all components are registered" |         "Not all components are registered" | ||||||
|     ); |     ); | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -22,6 +22,11 @@ export const enumItemProcessorTypes = { | |||||||
|     filter: "filter", |     filter: "filter", | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
|  | /** @enum {string} */ | ||||||
|  | export const enumItemProcessorRequirements = { | ||||||
|  |     painterQuad: "painterQuad" | ||||||
|  | }; | ||||||
|  | 
 | ||||||
| export class ItemProcessorComponent extends Component { | export class ItemProcessorComponent extends Component { | ||||||
|     static getId() { |     static getId() { | ||||||
|         return "ItemProcessor"; |         return "ItemProcessor"; | ||||||
| @ -50,6 +55,7 @@ export class ItemProcessorComponent extends Component { | |||||||
|     duplicateWithoutContents() { |     duplicateWithoutContents() { | ||||||
|         return new ItemProcessorComponent({ |         return new ItemProcessorComponent({ | ||||||
|             processorType: this.type, |             processorType: this.type, | ||||||
|  |             processingRequirement: this.processingRequirement, | ||||||
|             inputsPerCharge: this.inputsPerCharge, |             inputsPerCharge: this.inputsPerCharge, | ||||||
|         }); |         }); | ||||||
|     } |     } | ||||||
| @ -58,10 +64,15 @@ export class ItemProcessorComponent extends Component { | |||||||
|      * |      * | ||||||
|      * @param {object} param0 |      * @param {object} param0 | ||||||
|      * @param {enumItemProcessorTypes=} param0.processorType Which type of processor this is |      * @param {enumItemProcessorTypes=} param0.processorType Which type of processor this is | ||||||
|  |      * @param {enumItemProcessorRequirements=} param0.processingRequirement Applied processing requirement | ||||||
|      * @param {number=} param0.inputsPerCharge How many items this machine needs until it can start working |      * @param {number=} param0.inputsPerCharge How many items this machine needs until it can start working | ||||||
|      * |      * | ||||||
|      */ |      */ | ||||||
|     constructor({ processorType = enumItemProcessorTypes.splitter, inputsPerCharge = 1 }) { |     constructor({ | ||||||
|  |         processorType = enumItemProcessorTypes.splitter, | ||||||
|  |         processingRequirement = null, | ||||||
|  |         inputsPerCharge = 1 | ||||||
|  |     }) { | ||||||
|         super(); |         super(); | ||||||
| 
 | 
 | ||||||
|         // Which slot to emit next, this is only a preference and if it can't emit
 |         // Which slot to emit next, this is only a preference and if it can't emit
 | ||||||
| @ -72,6 +83,9 @@ export class ItemProcessorComponent extends Component { | |||||||
|         // Type of the processor
 |         // Type of the processor
 | ||||||
|         this.type = processorType; |         this.type = processorType; | ||||||
| 
 | 
 | ||||||
|  |         // Type of processing requirement
 | ||||||
|  |         this.processingRequirement = processingRequirement; | ||||||
|  | 
 | ||||||
|         // How many inputs we need for one charge
 |         // How many inputs we need for one charge
 | ||||||
|         this.inputsPerCharge = inputsPerCharge; |         this.inputsPerCharge = inputsPerCharge; | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -601,7 +601,7 @@ export class ShapeDefinition extends BasicSerializableObject { | |||||||
|             for (let quadrantIndex = 0; quadrantIndex < 4; ++quadrantIndex) { |             for (let quadrantIndex = 0; quadrantIndex < 4; ++quadrantIndex) { | ||||||
|                 const item = quadrants[quadrantIndex]; |                 const item = quadrants[quadrantIndex]; | ||||||
|                 if (item) { |                 if (item) { | ||||||
|                     item.color = colors[quadrantIndex]; |                     item.color = colors[quadrantIndex] || item.color; | ||||||
|                 } |                 } | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|  | |||||||
| @ -1,10 +1,10 @@ | |||||||
| import { globalConfig } from "../../core/config"; | import { globalConfig } from "../../core/config"; | ||||||
| import { BaseItem } from "../base_item"; | import { BaseItem } from "../base_item"; | ||||||
| import { enumColorMixingResults } from "../colors"; | import { enumColors, enumColorMixingResults } from "../colors"; | ||||||
| import { enumItemProcessorTypes, ItemProcessorComponent } from "../components/item_processor"; | import { enumItemProcessorTypes, ItemProcessorComponent, enumItemProcessorRequirements } from "../components/item_processor"; | ||||||
| import { Entity } from "../entity"; | import { Entity } from "../entity"; | ||||||
| import { GameSystemWithFilter } from "../game_system_with_filter"; | import { GameSystemWithFilter } from "../game_system_with_filter"; | ||||||
| import { BOOL_TRUE_SINGLETON } from "../items/boolean_item"; | import { BOOL_TRUE_SINGLETON, BOOL_FALSE_SINGLETON } from "../items/boolean_item"; | ||||||
| import { ColorItem, COLOR_ITEM_SINGLETONS } from "../items/color_item"; | import { ColorItem, COLOR_ITEM_SINGLETONS } from "../items/color_item"; | ||||||
| import { ShapeItem } from "../items/shape_item"; | import { ShapeItem } from "../items/shape_item"; | ||||||
| 
 | 
 | ||||||
| @ -68,15 +68,81 @@ export class ItemProcessorSystem extends GameSystemWithFilter { | |||||||
|                 } |                 } | ||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|             // Check if we have an empty queue and can start a new charge
 |             // Check if we have an empty queue and can start a new charge
 | ||||||
|             if (processorComp.itemsToEject.length === 0) { |             if (processorComp.itemsToEject.length === 0) { | ||||||
|                 if (processorComp.inputSlots.length >= processorComp.inputsPerCharge) { |                 if (entity.components.ItemProcessor.processingRequirement) { | ||||||
|  |                     if (this.canProcess(entity)) { | ||||||
|  |                         this.startNewCharge(entity); | ||||||
|  |                     } | ||||||
|  |                 } else if (processorComp.inputSlots.length >= processorComp.inputsPerCharge) { | ||||||
|                     this.startNewCharge(entity); |                     this.startNewCharge(entity); | ||||||
|                 } |                 } | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |     /** | ||||||
|  |      * Checks whether it's possible to process something | ||||||
|  |      * @param {Entity} entity | ||||||
|  |      */ | ||||||
|  |     canProcess(entity) { | ||||||
|  |         switch (entity.components.ItemProcessor.processingRequirement) { | ||||||
|  |             case enumItemProcessorRequirements.painterQuad: { | ||||||
|  |                 // For quad-painter, pins match slots
 | ||||||
|  |                 // boolean true means "disable input"
 | ||||||
|  |                 // a color means "disable if not matched"
 | ||||||
|  | 
 | ||||||
|  |                 const processorComp = entity.components.ItemProcessor; | ||||||
|  |                 const pinsComp = entity.components.WiredPins; | ||||||
|  | 
 | ||||||
|  |                 /** @type {Object.<string, { 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
 | ||||||
|  |                 if (!itemsBySlot[0]) return false; | ||||||
|  |                 const shapeItem = /** @type {ShapeItem} */ (itemsBySlot[0].item); | ||||||
|  | 
 | ||||||
|  |                 // Here we check just basic things`
 | ||||||
|  |                 // Stop processing if anything except TRUE is
 | ||||||
|  |                 // set and there is no item.
 | ||||||
|  |                 for (let i = 0; i < 4; ++i) { | ||||||
|  |                     const netValue = pinsComp.slots[i].linkedNetwork ? | ||||||
|  |                         pinsComp.slots[i].linkedNetwork.currentValue : | ||||||
|  |                         null; | ||||||
|  | 
 | ||||||
|  |                     const currentItem = itemsBySlot[i + 1]; | ||||||
|  | 
 | ||||||
|  |                     if ((netValue == null || !netValue.equals(BOOL_TRUE_SINGLETON)) && currentItem == null) { | ||||||
|  |                         let quadCount = 0; | ||||||
|  | 
 | ||||||
|  |                         for (let j = 0; j < 4; ++j) { | ||||||
|  |                             const layer = shapeItem.definition.layers[j]; | ||||||
|  |                             if (layer && layer[i]) { | ||||||
|  |                                 quadCount++; | ||||||
|  |                             } | ||||||
|  |                         } | ||||||
|  | 
 | ||||||
|  |                         if (quadCount > 0) { | ||||||
|  |                             return false; | ||||||
|  |                         } | ||||||
|  |                     } | ||||||
|  |                 } | ||||||
|  | 
 | ||||||
|  |                 return true; | ||||||
|  |             } | ||||||
|  |             default: | ||||||
|  |                 assertAlways( | ||||||
|  |                     false, | ||||||
|  |                     "Unknown requirement for " + entity.components.ItemProcessor.processingRequirement | ||||||
|  |                 ); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|     /** |     /** | ||||||
|      * Starts a new charge for the entity |      * Starts a new charge for the entity | ||||||
|      * @param {Entity} entity |      * @param {Entity} entity | ||||||
| @ -307,20 +373,56 @@ export class ItemProcessorSystem extends GameSystemWithFilter { | |||||||
| 
 | 
 | ||||||
|             case enumItemProcessorTypes.painterQuad: { |             case enumItemProcessorTypes.painterQuad: { | ||||||
|                 const shapeItem = /** @type {ShapeItem} */ (itemsBySlot[0].item); |                 const shapeItem = /** @type {ShapeItem} */ (itemsBySlot[0].item); | ||||||
|                 const colorItem1 = /** @type {ColorItem} */ (itemsBySlot[1].item); |  | ||||||
|                 const colorItem2 = /** @type {ColorItem} */ (itemsBySlot[2].item); |  | ||||||
|                 const colorItem3 = /** @type {ColorItem} */ (itemsBySlot[3].item); |  | ||||||
|                 const colorItem4 = /** @type {ColorItem} */ (itemsBySlot[4].item); |  | ||||||
| 
 |  | ||||||
|                 assert(shapeItem instanceof ShapeItem, "Input for painter is not a shape"); |                 assert(shapeItem instanceof ShapeItem, "Input for painter is not a shape"); | ||||||
|                 assert(colorItem1 instanceof ColorItem, "Input for painter is not a color"); | 
 | ||||||
|                 assert(colorItem2 instanceof ColorItem, "Input for painter is not a color"); |                 /** @type {Array<ColorItem>} */ | ||||||
|                 assert(colorItem3 instanceof ColorItem, "Input for painter is not a color"); |                 const colorItems = [].fill(null, 0, 4); | ||||||
|                 assert(colorItem4 instanceof ColorItem, "Input for painter is not a color"); | 
 | ||||||
|  |                 for (let i = 0; i < 4; ++i) { | ||||||
|  |                     if (itemsBySlot[i + 1]) { | ||||||
|  |                         colorItems[i] = /** @type {ColorItem} */ (itemsBySlot[i + 1].item); | ||||||
|  |                         assert(colorItems[i] instanceof ColorItem, "Input for painter is not a color"); | ||||||
|  |                     } | ||||||
|  |                 } | ||||||
|  | 
 | ||||||
|  |                 const pinValues = entity.components.WiredPins.slots | ||||||
|  |                     .map(slot => slot.linkedNetwork ? slot.linkedNetwork.currentValue : BOOL_FALSE_SINGLETON); | ||||||
|  | 
 | ||||||
|  |                 // @todo cleanup
 | ||||||
|  |                 const colorTL = colorItems[0]; | ||||||
|  |                 const colorTR = colorItems[1]; | ||||||
|  |                 const colorBR = colorItems[2]; | ||||||
|  |                 const colorBL = colorItems[3]; | ||||||
|  | 
 | ||||||
|  |                 /** @type {Array<boolean>} */ | ||||||
|  |                 let skipped = []; | ||||||
|  |                 for (let i = 0; i < 4; ++i) { | ||||||
|  |                     skipped[i] = pinValues[i] ? pinValues[i].equals(BOOL_TRUE_SINGLETON) : false; | ||||||
|  |                 } | ||||||
|  | 
 | ||||||
|  |                 for (let i = 0; i < 4; ++i) { | ||||||
|  |                     if (colorItems[i] == null) { | ||||||
|  |                         skipped[i] = false; // make sure we never insert null item back
 | ||||||
|  |                     } else if (pinValues[i] instanceof ColorItem) { | ||||||
|  |                         // if pin value is a color, skip anything except that color
 | ||||||
|  |                         // but still require any color, because it would not work on
 | ||||||
|  |                         // slow factories.
 | ||||||
|  |                         if (!colorItems[i].equals(pinValues[i])) { | ||||||
|  |                             skipped[i] = true; | ||||||
|  |                         } | ||||||
|  |                     } | ||||||
|  |                 } | ||||||
|  | 
 | ||||||
|  |                 const toColor = [ | ||||||
|  |                     (!skipped[0] && colorTL) ? colorTL.color : null, | ||||||
|  |                     (!skipped[1] && colorTR) ? colorTR.color : null, | ||||||
|  |                     (!skipped[2] && colorBR) ? colorBR.color : null, | ||||||
|  |                     (!skipped[3] && colorBL) ? colorBL.color : null, | ||||||
|  |                 ]; | ||||||
| 
 | 
 | ||||||
|                 const colorizedDefinition = this.root.shapeDefinitionMgr.shapeActionPaintWith4Colors( |                 const colorizedDefinition = this.root.shapeDefinitionMgr.shapeActionPaintWith4Colors( | ||||||
|                     shapeItem.definition, |                     shapeItem.definition, | ||||||
|                     [colorItem2.color, colorItem3.color, colorItem4.color, colorItem1.color] |                     /** @type {[enumColors, enumColors, enumColors, enumColors]} */(toColor) | ||||||
|                 ); |                 ); | ||||||
| 
 | 
 | ||||||
|                 outItems.push({ |                 outItems.push({ | ||||||
|  | |||||||
		Loading…
	
		Reference in New Issue
	
	Block a user