From c9943c865615d42caf39fa56f8f37b19fc4a25a8 Mon Sep 17 00:00:00 2001 From: MrTJP Date: Mon, 21 Nov 2022 15:31:29 -0500 Subject: [PATCH 01/23] feat: fabrication v2 --- build.gradle | 7 + fabrication/build.gradle | 81 ++++ .../blockstates/ic_workbench.json | 10 + .../blockstates/lithography_table.json | 64 +++ .../blockstates/packaging_table.json | 64 +++ .../blockstates/plotting_table.json | 64 +++ .../models/block/ic_workbench_blueprint.json | 11 + .../block/ic_workbench_no_blueprint.json | 11 + .../models/block/lithography_table_c0.json | 11 + .../models/block/lithography_table_c1.json | 11 + .../models/block/lithography_table_c2.json | 11 + .../models/block/packaging_table_c0.json | 11 + .../models/block/packaging_table_c1.json | 11 + .../models/block/packaging_table_c2.json | 11 + .../models/block/plotting_table_c0.json | 11 + .../models/block/plotting_table_c1.json | 11 + .../models/block/plotting_table_c2.json | 11 + .../models/item/blank_photomask.json | 6 + .../models/item/etched_silicon_wafer.json | 6 + .../models/item/fabricated_gate.json | 3 + .../models/item/ic_blueprint.json | 6 + .../models/item/ic_workbench.json | 3 + .../models/item/invalid_die.json | 6 + .../models/item/lithography_table.json | 3 + .../models/item/packaging_table.json | 3 + .../models/item/photomask_set.json | 6 + .../models/item/plotting_table.json | 3 + .../models/item/rough_silicon_wafer.json | 6 + .../models/item/valid_die.json | 6 + .../fabrication/ProjectRedFabrication.java | 79 ++++ .../block/FabricationMachineBlock.java | 44 ++ .../fabrication/block/ICWorkbenchBlock.java | 46 ++ .../block/LithographyTableBlock.java | 27 ++ .../block/PackagingTableBlock.java | 27 ++ .../fabrication/block/PlottingTableBlock.java | 28 ++ .../FabricationBlockStateModelProvider.java | 94 ++++ .../data/FabricationItemModelProvider.java | 50 +++ .../fabrication/editor/GatePlacementType.java | 7 + .../editor/ICEditorStateMachine.java | 364 ++++++++++++++++ .../fabrication/editor/ICEditorToolType.java | 34 ++ .../fabrication/editor/ICWorkbenchEditor.java | 280 ++++++++++++ .../editor/IICWorkbenchEditorNetwork.java | 40 ++ .../editor/tools/BaseICEditorTool.java | 54 +++ .../fabrication/editor/tools/EraseTool.java | 125 ++++++ .../editor/tools/GatePlacerTool.java | 224 ++++++++++ .../editor/tools/IICEditorTool.java | 80 ++++ .../editor/tools/InteractTool.java | 218 ++++++++++ .../editor/tools/WirePlacerTool.java | 215 +++++++++ .../fabrication/engine/BaseTile.java | 111 +++++ .../fabrication/engine/BaseTileMap.java | 216 +++++++++ .../engine/IBundledConnectableICTile.java | 5 + .../fabrication/engine/ICCompilerLog.java | 409 ++++++++++++++++++ .../fabrication/engine/ICConnectionType.java | 7 + .../engine/ICSimulationContainer.java | 174 ++++++++ .../fabrication/engine/ICTileType.java | 104 +++++ .../fabrication/engine/ICTileTypeOffsets.java | 15 + .../engine/IConnectableICTile.java | 54 +++ .../fabrication/engine/IIOConnectionTile.java | 16 + .../engine/IInsulatedConnectableICTile.java | 5 + .../engine/IRedstoneConnectableICTile.java | 4 + .../fabrication/engine/IRotatableICTile.java | 63 +++ .../engine/PRFabricationEngine.java | 102 +++++ .../fabrication/engine/gates/ANDGateTile.java | 45 ++ .../engine/gates/BufferGateTile.java | 45 ++ .../fabrication/engine/gates/GateTile.java | 207 +++++++++ .../engine/gates/ICGateTileType.java | 46 ++ .../fabrication/engine/gates/IOGateTile.java | 272 ++++++++++++ .../engine/gates/InternalStateGateTile.java | 53 +++ .../engine/gates/MultiplexerGateTile.java | 41 ++ .../engine/gates/NANDGateTile.java | 45 ++ .../fabrication/engine/gates/NORGateTile.java | 45 ++ .../fabrication/engine/gates/NOTGateTile.java | 42 ++ .../fabrication/engine/gates/ORGateTile.java | 45 ++ .../engine/gates/PulseGateTile.java | 101 +++++ .../engine/gates/RandomizerGateTile.java | 122 ++++++ .../engine/gates/RedstoneGateTile.java | 107 +++++ .../engine/gates/RepeaterGateTile.java | 155 +++++++ .../engine/gates/SRLatchGateTile.java | 157 +++++++ .../engine/gates/SidedRedstoneGateTile.java | 164 +++++++ .../engine/gates/SimpleGateTile.java | 127 ++++++ .../engine/gates/TimedStateGateTile.java | 82 ++++ .../engine/gates/ToggleLatchGateTile.java | 129 ++++++ .../gates/TransparentLatchGateTile.java | 114 +++++ .../engine/gates/XNORGateTile.java | 36 ++ .../fabrication/engine/gates/XORGateTile.java | 36 ++ .../engine/wires/BundledWireTile.java | 43 ++ .../engine/wires/ICWireTileType.java | 92 ++++ .../engine/wires/InsulatedWireTile.java | 49 +++ .../engine/wires/RedAlloyWireTile.java | 29 ++ .../engine/wires/RedstoneWireTile.java | 115 +++++ .../fabrication/engine/wires/WireTile.java | 127 ++++++ .../fabrication/gui/CTNListNode.java | 110 +++++ .../fabrication/gui/CompileProblemsTab.java | 37 ++ .../fabrication/gui/CompileStackTab.java | 108 +++++ .../fabrication/gui/CompileTreeTab.java | 37 ++ .../fabrication/gui/EraserToolTab.java | 48 ++ .../fabrication/gui/GatePlacerToolTab.java | 110 +++++ .../fabrication/gui/ICEditorToolManager.java | 161 +++++++ .../fabrication/gui/ICEditorToolTab.java | 242 +++++++++++ .../fabrication/gui/ICRenderNode.java | 234 ++++++++++ .../fabrication/gui/ICRenderTypes.java | 243 +++++++++++ .../gui/ICompileOverlayRenderer.java | 16 + .../fabrication/gui/InteractToolTab.java | 48 ++ .../gui/LinearVectorAnimation.java | 48 ++ .../fabrication/gui/SelectionGridNode.java | 117 +++++ .../fabrication/gui/SimpleUVTab.java | 72 +++ .../fabrication/gui/TabButtonNode.java | 176 ++++++++ .../fabrication/gui/TabControllerNode.java | 148 +++++++ .../fabrication/gui/WirePlacerToolTab.java | 109 +++++ .../gui/screen/ICWorkbenchCompileTab.java | 218 ++++++++++ .../gui/screen/ICWorkbenchEditTab.java | 85 ++++ .../gui/screen/ICWorkbenchScreen.java | 91 ++++ .../inventory/LithographyTableScreen.java | 48 ++ .../inventory/PackagingTableScreen.java | 48 ++ .../screen/inventory/PlottingTableScreen.java | 48 ++ .../fabrication/init/FabricationBlocks.java | 45 ++ .../init/FabricationClientInit.java | 41 ++ .../init/FabricationContainers.java | 19 + .../fabrication/init/FabricationItems.java | 28 ++ .../fabrication/init/FabricationParts.java | 30 ++ .../init/FabricationReferences.java | 78 ++++ .../FabricationMachineContainer.java | 28 ++ .../container/LithographyTableContainer.java | 126 ++++++ .../container/PackagingTableContainer.java | 116 +++++ .../container/PlottingTableContainer.java | 125 ++++++ .../item/BaseSiliconWaferItem.java | 38 ++ .../fabrication/item/BlankPhotomaskItem.java | 12 + .../item/EtchedSiliconWaferItem.java | 87 ++++ .../fabrication/item/ICBlueprintItem.java | 62 +++ .../fabrication/item/InvalidDieItem.java | 12 + .../fabrication/item/PhotomaskSetItem.java | 56 +++ .../item/RoughSiliconWaferItem.java | 10 + .../fabrication/item/ValidDieItem.java | 46 ++ .../lithography/ILithographerNetwork.java | 12 + .../fabrication/lithography/Lithographer.java | 31 ++ .../fabrication/lithography/ProcessNode.java | 25 ++ .../fabrication/lithography/WaferType.java | 30 ++ .../fabrication/part/FabricatedGatePart.java | 212 +++++++++ .../tile/FabricationMachineTile.java | 135 ++++++ .../fabrication/tile/ICWorkbenchTile.java | 242 +++++++++++ .../tile/LithographyTableTile.java | 162 +++++++ .../fabrication/tile/PackagingTableTile.java | 132 ++++++ .../fabrication/tile/PlottingTableTile.java | 137 ++++++ .../src/main/resources/META-INF/mods.toml | 58 +++ .../projectred_fabrication/lang/en_us.json | 11 + .../models/block/domed_machine.json | 18 + .../textures/block/ic_workbench_bottom.png | Bin 0 -> 18835 bytes .../textures/block/ic_workbench_front.png | Bin 0 -> 16562 bytes .../textures/block/ic_workbench_front_bp.png | Bin 0 -> 16758 bytes .../textures/block/ic_workbench_side.png | Bin 0 -> 16303 bytes .../textures/block/ic_workbench_side_bp.png | Bin 0 -> 16506 bytes .../textures/block/ic_workbench_top.png | Bin 0 -> 16401 bytes .../textures/block/ic_workbench_top_bp.png | Bin 0 -> 17034 bytes .../block/lithography_table_bottom.png | Bin 0 -> 2175 bytes .../block/lithography_table_front_0.png | Bin 0 -> 2394 bytes .../block/lithography_table_front_1.png | Bin 0 -> 2397 bytes .../block/lithography_table_front_2.png | Bin 0 -> 2394 bytes .../textures/block/lithography_table_side.png | Bin 0 -> 2297 bytes .../textures/block/lithography_table_top.png | Bin 0 -> 2790 bytes .../textures/block/packaging_table_bottom.png | Bin 0 -> 2175 bytes .../block/packaging_table_front_0.png | Bin 0 -> 2345 bytes .../block/packaging_table_front_1.png | Bin 0 -> 2379 bytes .../block/packaging_table_front_2.png | Bin 0 -> 2375 bytes .../textures/block/packaging_table_side.png | Bin 0 -> 2249 bytes .../textures/block/packaging_table_top.png | Bin 0 -> 2526 bytes .../textures/block/perfboard.png | Bin 0 -> 2505 bytes .../textures/block/perfboard_corner.png | Bin 0 -> 15627 bytes .../textures/block/perfboard_edge.png | Bin 0 -> 15571 bytes .../textures/block/plotting_table_bottom.png | Bin 0 -> 18835 bytes .../textures/block/plotting_table_front_0.png | Bin 0 -> 2946 bytes .../textures/block/plotting_table_front_1.png | Bin 0 -> 2953 bytes .../textures/block/plotting_table_front_2.png | Bin 0 -> 2970 bytes .../block/plotting_table_printhead.png | Bin 0 -> 19026 bytes .../textures/block/plotting_table_side.png | Bin 0 -> 2672 bytes .../textures/block/plotting_table_top.png | Bin 0 -> 16827 bytes .../textures/gui/compile_tab.png | Bin 0 -> 12535 bytes .../textures/gui/ic_workbench.png | Bin 0 -> 29122 bytes .../textures/gui/lithography_table.png | Bin 0 -> 4313 bytes .../textures/gui/packaging_table.png | Bin 0 -> 5045 bytes .../textures/gui/plotting_table.png | Bin 0 -> 4261 bytes .../textures/item/blank_photomask.png | Bin 0 -> 2540 bytes .../textures/item/etched_silicon_wafer.png | Bin 0 -> 2577 bytes .../textures/item/ic_active.png | Bin 0 -> 9867 bytes .../textures/item/ic_active.png.mcmeta | 5 + .../textures/item/ic_blueprint.png | Bin 24170 -> 22784 bytes .../textures/item/ic_inert.png | Bin 0 -> 25927 bytes .../textures/item/invalid_die.png | Bin 0 -> 3137 bytes .../textures/item/photomask_set.png | Bin 0 -> 2813 bytes .../item/rough_silicon_wafer copy.png | Bin 0 -> 2391 bytes .../textures/item/rough_silicon_wafer.png | Bin 0 -> 2412 bytes .../textures/item/valid_die.png | Bin 0 -> 6063 bytes .../textures/item/valid_die.png.mcmeta | 5 + .../textures/item/valid_die_template.png | Bin 0 -> 3129 bytes .../textures/item/valid_die_v1.png | Bin 0 -> 5448 bytes fabrication/src/main/resources/pack.mcmeta | 6 + .../projectred/integration/GateType.java | 20 +- .../client/GateComponentModels.java | 141 +++++- .../integration/client/GateModelRenderer.java | 124 +++++- .../data/IntegrationItemModelProvider.java | 1 + .../init/IntegrationClientInit.java | 1 + .../integration/init/IntegrationParts.java | 1 + .../integration/part/BundledGatePart.java | 6 +- .../integration/part/ComplexGatePart.java | 2 +- .../projectred/integration/part/GatePart.java | 11 +- .../integration/part/RedstoneGatePart.java | 4 +- .../integration/part/SimpleGatePart.java | 2 +- .../obj/array/icbundled.blend | Bin 550688 -> 632108 bytes .../obj/array/icbundled.obj | 26 +- .../projectred_integration/obj/fab_ic.blend | Bin 0 -> 666140 bytes .../projectred_integration/obj/fab_ic.obj | 287 ++++++++++++ .../projectred_integration/obj/icchip.blend | Bin 549068 -> 0 bytes .../projectred_integration/obj/icchip.obj | 104 ----- .../projectred_integration/obj/icglass.blend | Bin 553840 -> 0 bytes .../projectred_integration/obj/icglass.obj | 44 -- .../obj/ichousing.blend | Bin 555176 -> 0 bytes .../projectred_integration/obj/ichousing.obj | 73 ---- .../obj/io_colour_box.blend | Bin 0 -> 621952 bytes .../obj/io_colour_box.obj | 54 +++ .../projectred_integration/obj/io_crimp.blend | Bin 0 -> 626072 bytes .../projectred_integration/obj/io_crimp.obj | 233 ++++++++++ .../textures/block/io_colour_box.png | Bin 0 -> 3158 bytes .../textures/block/io_crimp.png | Bin 0 -> 3472 bytes .../textures/block/io_crimp_old.png | Bin 0 -> 3218 bytes .../textures/block/surface/fabio-0.png | Bin 0 -> 1793 bytes runtime/build.gradle | 2 + settings.gradle | 4 +- 226 files changed, 12124 insertions(+), 258 deletions(-) create mode 100644 fabrication/build.gradle create mode 100644 fabrication/src/main/generated/assets/projectred_fabrication/blockstates/ic_workbench.json create mode 100644 fabrication/src/main/generated/assets/projectred_fabrication/blockstates/lithography_table.json create mode 100644 fabrication/src/main/generated/assets/projectred_fabrication/blockstates/packaging_table.json create mode 100644 fabrication/src/main/generated/assets/projectred_fabrication/blockstates/plotting_table.json create mode 100644 fabrication/src/main/generated/assets/projectred_fabrication/models/block/ic_workbench_blueprint.json create mode 100644 fabrication/src/main/generated/assets/projectred_fabrication/models/block/ic_workbench_no_blueprint.json create mode 100644 fabrication/src/main/generated/assets/projectred_fabrication/models/block/lithography_table_c0.json create mode 100644 fabrication/src/main/generated/assets/projectred_fabrication/models/block/lithography_table_c1.json create mode 100644 fabrication/src/main/generated/assets/projectred_fabrication/models/block/lithography_table_c2.json create mode 100644 fabrication/src/main/generated/assets/projectred_fabrication/models/block/packaging_table_c0.json create mode 100644 fabrication/src/main/generated/assets/projectred_fabrication/models/block/packaging_table_c1.json create mode 100644 fabrication/src/main/generated/assets/projectred_fabrication/models/block/packaging_table_c2.json create mode 100644 fabrication/src/main/generated/assets/projectred_fabrication/models/block/plotting_table_c0.json create mode 100644 fabrication/src/main/generated/assets/projectred_fabrication/models/block/plotting_table_c1.json create mode 100644 fabrication/src/main/generated/assets/projectred_fabrication/models/block/plotting_table_c2.json create mode 100644 fabrication/src/main/generated/assets/projectred_fabrication/models/item/blank_photomask.json create mode 100644 fabrication/src/main/generated/assets/projectred_fabrication/models/item/etched_silicon_wafer.json create mode 100644 fabrication/src/main/generated/assets/projectred_fabrication/models/item/fabricated_gate.json create mode 100644 fabrication/src/main/generated/assets/projectred_fabrication/models/item/ic_blueprint.json create mode 100644 fabrication/src/main/generated/assets/projectred_fabrication/models/item/ic_workbench.json create mode 100644 fabrication/src/main/generated/assets/projectred_fabrication/models/item/invalid_die.json create mode 100644 fabrication/src/main/generated/assets/projectred_fabrication/models/item/lithography_table.json create mode 100644 fabrication/src/main/generated/assets/projectred_fabrication/models/item/packaging_table.json create mode 100644 fabrication/src/main/generated/assets/projectred_fabrication/models/item/photomask_set.json create mode 100644 fabrication/src/main/generated/assets/projectred_fabrication/models/item/plotting_table.json create mode 100644 fabrication/src/main/generated/assets/projectred_fabrication/models/item/rough_silicon_wafer.json create mode 100644 fabrication/src/main/generated/assets/projectred_fabrication/models/item/valid_die.json create mode 100644 fabrication/src/main/java/mrtjp/projectred/fabrication/ProjectRedFabrication.java create mode 100644 fabrication/src/main/java/mrtjp/projectred/fabrication/block/FabricationMachineBlock.java create mode 100644 fabrication/src/main/java/mrtjp/projectred/fabrication/block/ICWorkbenchBlock.java create mode 100644 fabrication/src/main/java/mrtjp/projectred/fabrication/block/LithographyTableBlock.java create mode 100644 fabrication/src/main/java/mrtjp/projectred/fabrication/block/PackagingTableBlock.java create mode 100644 fabrication/src/main/java/mrtjp/projectred/fabrication/block/PlottingTableBlock.java create mode 100644 fabrication/src/main/java/mrtjp/projectred/fabrication/data/FabricationBlockStateModelProvider.java create mode 100644 fabrication/src/main/java/mrtjp/projectred/fabrication/data/FabricationItemModelProvider.java create mode 100644 fabrication/src/main/java/mrtjp/projectred/fabrication/editor/GatePlacementType.java create mode 100644 fabrication/src/main/java/mrtjp/projectred/fabrication/editor/ICEditorStateMachine.java create mode 100644 fabrication/src/main/java/mrtjp/projectred/fabrication/editor/ICEditorToolType.java create mode 100644 fabrication/src/main/java/mrtjp/projectred/fabrication/editor/ICWorkbenchEditor.java create mode 100644 fabrication/src/main/java/mrtjp/projectred/fabrication/editor/IICWorkbenchEditorNetwork.java create mode 100644 fabrication/src/main/java/mrtjp/projectred/fabrication/editor/tools/BaseICEditorTool.java create mode 100644 fabrication/src/main/java/mrtjp/projectred/fabrication/editor/tools/EraseTool.java create mode 100644 fabrication/src/main/java/mrtjp/projectred/fabrication/editor/tools/GatePlacerTool.java create mode 100644 fabrication/src/main/java/mrtjp/projectred/fabrication/editor/tools/IICEditorTool.java create mode 100644 fabrication/src/main/java/mrtjp/projectred/fabrication/editor/tools/InteractTool.java create mode 100644 fabrication/src/main/java/mrtjp/projectred/fabrication/editor/tools/WirePlacerTool.java create mode 100644 fabrication/src/main/java/mrtjp/projectred/fabrication/engine/BaseTile.java create mode 100644 fabrication/src/main/java/mrtjp/projectred/fabrication/engine/BaseTileMap.java create mode 100644 fabrication/src/main/java/mrtjp/projectred/fabrication/engine/IBundledConnectableICTile.java create mode 100644 fabrication/src/main/java/mrtjp/projectred/fabrication/engine/ICCompilerLog.java create mode 100644 fabrication/src/main/java/mrtjp/projectred/fabrication/engine/ICConnectionType.java create mode 100644 fabrication/src/main/java/mrtjp/projectred/fabrication/engine/ICSimulationContainer.java create mode 100644 fabrication/src/main/java/mrtjp/projectred/fabrication/engine/ICTileType.java create mode 100644 fabrication/src/main/java/mrtjp/projectred/fabrication/engine/ICTileTypeOffsets.java create mode 100644 fabrication/src/main/java/mrtjp/projectred/fabrication/engine/IConnectableICTile.java create mode 100644 fabrication/src/main/java/mrtjp/projectred/fabrication/engine/IIOConnectionTile.java create mode 100644 fabrication/src/main/java/mrtjp/projectred/fabrication/engine/IInsulatedConnectableICTile.java create mode 100644 fabrication/src/main/java/mrtjp/projectred/fabrication/engine/IRedstoneConnectableICTile.java create mode 100644 fabrication/src/main/java/mrtjp/projectred/fabrication/engine/IRotatableICTile.java create mode 100644 fabrication/src/main/java/mrtjp/projectred/fabrication/engine/PRFabricationEngine.java create mode 100644 fabrication/src/main/java/mrtjp/projectred/fabrication/engine/gates/ANDGateTile.java create mode 100644 fabrication/src/main/java/mrtjp/projectred/fabrication/engine/gates/BufferGateTile.java create mode 100644 fabrication/src/main/java/mrtjp/projectred/fabrication/engine/gates/GateTile.java create mode 100644 fabrication/src/main/java/mrtjp/projectred/fabrication/engine/gates/ICGateTileType.java create mode 100644 fabrication/src/main/java/mrtjp/projectred/fabrication/engine/gates/IOGateTile.java create mode 100644 fabrication/src/main/java/mrtjp/projectred/fabrication/engine/gates/InternalStateGateTile.java create mode 100644 fabrication/src/main/java/mrtjp/projectred/fabrication/engine/gates/MultiplexerGateTile.java create mode 100644 fabrication/src/main/java/mrtjp/projectred/fabrication/engine/gates/NANDGateTile.java create mode 100644 fabrication/src/main/java/mrtjp/projectred/fabrication/engine/gates/NORGateTile.java create mode 100644 fabrication/src/main/java/mrtjp/projectred/fabrication/engine/gates/NOTGateTile.java create mode 100644 fabrication/src/main/java/mrtjp/projectred/fabrication/engine/gates/ORGateTile.java create mode 100644 fabrication/src/main/java/mrtjp/projectred/fabrication/engine/gates/PulseGateTile.java create mode 100644 fabrication/src/main/java/mrtjp/projectred/fabrication/engine/gates/RandomizerGateTile.java create mode 100644 fabrication/src/main/java/mrtjp/projectred/fabrication/engine/gates/RedstoneGateTile.java create mode 100644 fabrication/src/main/java/mrtjp/projectred/fabrication/engine/gates/RepeaterGateTile.java create mode 100644 fabrication/src/main/java/mrtjp/projectred/fabrication/engine/gates/SRLatchGateTile.java create mode 100644 fabrication/src/main/java/mrtjp/projectred/fabrication/engine/gates/SidedRedstoneGateTile.java create mode 100644 fabrication/src/main/java/mrtjp/projectred/fabrication/engine/gates/SimpleGateTile.java create mode 100644 fabrication/src/main/java/mrtjp/projectred/fabrication/engine/gates/TimedStateGateTile.java create mode 100644 fabrication/src/main/java/mrtjp/projectred/fabrication/engine/gates/ToggleLatchGateTile.java create mode 100644 fabrication/src/main/java/mrtjp/projectred/fabrication/engine/gates/TransparentLatchGateTile.java create mode 100644 fabrication/src/main/java/mrtjp/projectred/fabrication/engine/gates/XNORGateTile.java create mode 100644 fabrication/src/main/java/mrtjp/projectred/fabrication/engine/gates/XORGateTile.java create mode 100644 fabrication/src/main/java/mrtjp/projectred/fabrication/engine/wires/BundledWireTile.java create mode 100644 fabrication/src/main/java/mrtjp/projectred/fabrication/engine/wires/ICWireTileType.java create mode 100644 fabrication/src/main/java/mrtjp/projectred/fabrication/engine/wires/InsulatedWireTile.java create mode 100644 fabrication/src/main/java/mrtjp/projectred/fabrication/engine/wires/RedAlloyWireTile.java create mode 100644 fabrication/src/main/java/mrtjp/projectred/fabrication/engine/wires/RedstoneWireTile.java create mode 100644 fabrication/src/main/java/mrtjp/projectred/fabrication/engine/wires/WireTile.java create mode 100644 fabrication/src/main/java/mrtjp/projectred/fabrication/gui/CTNListNode.java create mode 100644 fabrication/src/main/java/mrtjp/projectred/fabrication/gui/CompileProblemsTab.java create mode 100644 fabrication/src/main/java/mrtjp/projectred/fabrication/gui/CompileStackTab.java create mode 100644 fabrication/src/main/java/mrtjp/projectred/fabrication/gui/CompileTreeTab.java create mode 100644 fabrication/src/main/java/mrtjp/projectred/fabrication/gui/EraserToolTab.java create mode 100644 fabrication/src/main/java/mrtjp/projectred/fabrication/gui/GatePlacerToolTab.java create mode 100644 fabrication/src/main/java/mrtjp/projectred/fabrication/gui/ICEditorToolManager.java create mode 100644 fabrication/src/main/java/mrtjp/projectred/fabrication/gui/ICEditorToolTab.java create mode 100644 fabrication/src/main/java/mrtjp/projectred/fabrication/gui/ICRenderNode.java create mode 100644 fabrication/src/main/java/mrtjp/projectred/fabrication/gui/ICRenderTypes.java create mode 100644 fabrication/src/main/java/mrtjp/projectred/fabrication/gui/ICompileOverlayRenderer.java create mode 100644 fabrication/src/main/java/mrtjp/projectred/fabrication/gui/InteractToolTab.java create mode 100644 fabrication/src/main/java/mrtjp/projectred/fabrication/gui/LinearVectorAnimation.java create mode 100644 fabrication/src/main/java/mrtjp/projectred/fabrication/gui/SelectionGridNode.java create mode 100644 fabrication/src/main/java/mrtjp/projectred/fabrication/gui/SimpleUVTab.java create mode 100644 fabrication/src/main/java/mrtjp/projectred/fabrication/gui/TabButtonNode.java create mode 100644 fabrication/src/main/java/mrtjp/projectred/fabrication/gui/TabControllerNode.java create mode 100644 fabrication/src/main/java/mrtjp/projectred/fabrication/gui/WirePlacerToolTab.java create mode 100644 fabrication/src/main/java/mrtjp/projectred/fabrication/gui/screen/ICWorkbenchCompileTab.java create mode 100644 fabrication/src/main/java/mrtjp/projectred/fabrication/gui/screen/ICWorkbenchEditTab.java create mode 100644 fabrication/src/main/java/mrtjp/projectred/fabrication/gui/screen/ICWorkbenchScreen.java create mode 100644 fabrication/src/main/java/mrtjp/projectred/fabrication/gui/screen/inventory/LithographyTableScreen.java create mode 100644 fabrication/src/main/java/mrtjp/projectred/fabrication/gui/screen/inventory/PackagingTableScreen.java create mode 100644 fabrication/src/main/java/mrtjp/projectred/fabrication/gui/screen/inventory/PlottingTableScreen.java create mode 100644 fabrication/src/main/java/mrtjp/projectred/fabrication/init/FabricationBlocks.java create mode 100644 fabrication/src/main/java/mrtjp/projectred/fabrication/init/FabricationClientInit.java create mode 100644 fabrication/src/main/java/mrtjp/projectred/fabrication/init/FabricationContainers.java create mode 100644 fabrication/src/main/java/mrtjp/projectred/fabrication/init/FabricationItems.java create mode 100644 fabrication/src/main/java/mrtjp/projectred/fabrication/init/FabricationParts.java create mode 100644 fabrication/src/main/java/mrtjp/projectred/fabrication/init/FabricationReferences.java create mode 100644 fabrication/src/main/java/mrtjp/projectred/fabrication/inventory/container/FabricationMachineContainer.java create mode 100644 fabrication/src/main/java/mrtjp/projectred/fabrication/inventory/container/LithographyTableContainer.java create mode 100644 fabrication/src/main/java/mrtjp/projectred/fabrication/inventory/container/PackagingTableContainer.java create mode 100644 fabrication/src/main/java/mrtjp/projectred/fabrication/inventory/container/PlottingTableContainer.java create mode 100644 fabrication/src/main/java/mrtjp/projectred/fabrication/item/BaseSiliconWaferItem.java create mode 100644 fabrication/src/main/java/mrtjp/projectred/fabrication/item/BlankPhotomaskItem.java create mode 100644 fabrication/src/main/java/mrtjp/projectred/fabrication/item/EtchedSiliconWaferItem.java create mode 100644 fabrication/src/main/java/mrtjp/projectred/fabrication/item/ICBlueprintItem.java create mode 100644 fabrication/src/main/java/mrtjp/projectred/fabrication/item/InvalidDieItem.java create mode 100644 fabrication/src/main/java/mrtjp/projectred/fabrication/item/PhotomaskSetItem.java create mode 100644 fabrication/src/main/java/mrtjp/projectred/fabrication/item/RoughSiliconWaferItem.java create mode 100644 fabrication/src/main/java/mrtjp/projectred/fabrication/item/ValidDieItem.java create mode 100644 fabrication/src/main/java/mrtjp/projectred/fabrication/lithography/ILithographerNetwork.java create mode 100644 fabrication/src/main/java/mrtjp/projectred/fabrication/lithography/Lithographer.java create mode 100644 fabrication/src/main/java/mrtjp/projectred/fabrication/lithography/ProcessNode.java create mode 100644 fabrication/src/main/java/mrtjp/projectred/fabrication/lithography/WaferType.java create mode 100644 fabrication/src/main/java/mrtjp/projectred/fabrication/part/FabricatedGatePart.java create mode 100644 fabrication/src/main/java/mrtjp/projectred/fabrication/tile/FabricationMachineTile.java create mode 100644 fabrication/src/main/java/mrtjp/projectred/fabrication/tile/ICWorkbenchTile.java create mode 100644 fabrication/src/main/java/mrtjp/projectred/fabrication/tile/LithographyTableTile.java create mode 100644 fabrication/src/main/java/mrtjp/projectred/fabrication/tile/PackagingTableTile.java create mode 100644 fabrication/src/main/java/mrtjp/projectred/fabrication/tile/PlottingTableTile.java create mode 100644 fabrication/src/main/resources/META-INF/mods.toml create mode 100644 fabrication/src/main/resources/assets/projectred_fabrication/lang/en_us.json create mode 100644 fabrication/src/main/resources/assets/projectred_fabrication/models/block/domed_machine.json create mode 100644 fabrication/src/main/resources/assets/projectred_fabrication/textures/block/ic_workbench_bottom.png create mode 100644 fabrication/src/main/resources/assets/projectred_fabrication/textures/block/ic_workbench_front.png create mode 100644 fabrication/src/main/resources/assets/projectred_fabrication/textures/block/ic_workbench_front_bp.png create mode 100644 fabrication/src/main/resources/assets/projectred_fabrication/textures/block/ic_workbench_side.png create mode 100644 fabrication/src/main/resources/assets/projectred_fabrication/textures/block/ic_workbench_side_bp.png create mode 100644 fabrication/src/main/resources/assets/projectred_fabrication/textures/block/ic_workbench_top.png create mode 100644 fabrication/src/main/resources/assets/projectred_fabrication/textures/block/ic_workbench_top_bp.png create mode 100644 fabrication/src/main/resources/assets/projectred_fabrication/textures/block/lithography_table_bottom.png create mode 100644 fabrication/src/main/resources/assets/projectred_fabrication/textures/block/lithography_table_front_0.png create mode 100644 fabrication/src/main/resources/assets/projectred_fabrication/textures/block/lithography_table_front_1.png create mode 100644 fabrication/src/main/resources/assets/projectred_fabrication/textures/block/lithography_table_front_2.png create mode 100644 fabrication/src/main/resources/assets/projectred_fabrication/textures/block/lithography_table_side.png create mode 100644 fabrication/src/main/resources/assets/projectred_fabrication/textures/block/lithography_table_top.png create mode 100644 fabrication/src/main/resources/assets/projectred_fabrication/textures/block/packaging_table_bottom.png create mode 100644 fabrication/src/main/resources/assets/projectred_fabrication/textures/block/packaging_table_front_0.png create mode 100644 fabrication/src/main/resources/assets/projectred_fabrication/textures/block/packaging_table_front_1.png create mode 100644 fabrication/src/main/resources/assets/projectred_fabrication/textures/block/packaging_table_front_2.png create mode 100644 fabrication/src/main/resources/assets/projectred_fabrication/textures/block/packaging_table_side.png create mode 100644 fabrication/src/main/resources/assets/projectred_fabrication/textures/block/packaging_table_top.png create mode 100644 fabrication/src/main/resources/assets/projectred_fabrication/textures/block/perfboard.png create mode 100644 fabrication/src/main/resources/assets/projectred_fabrication/textures/block/perfboard_corner.png create mode 100644 fabrication/src/main/resources/assets/projectred_fabrication/textures/block/perfboard_edge.png create mode 100644 fabrication/src/main/resources/assets/projectred_fabrication/textures/block/plotting_table_bottom.png create mode 100644 fabrication/src/main/resources/assets/projectred_fabrication/textures/block/plotting_table_front_0.png create mode 100644 fabrication/src/main/resources/assets/projectred_fabrication/textures/block/plotting_table_front_1.png create mode 100644 fabrication/src/main/resources/assets/projectred_fabrication/textures/block/plotting_table_front_2.png create mode 100644 fabrication/src/main/resources/assets/projectred_fabrication/textures/block/plotting_table_printhead.png create mode 100644 fabrication/src/main/resources/assets/projectred_fabrication/textures/block/plotting_table_side.png create mode 100644 fabrication/src/main/resources/assets/projectred_fabrication/textures/block/plotting_table_top.png create mode 100644 fabrication/src/main/resources/assets/projectred_fabrication/textures/gui/compile_tab.png create mode 100644 fabrication/src/main/resources/assets/projectred_fabrication/textures/gui/ic_workbench.png create mode 100755 fabrication/src/main/resources/assets/projectred_fabrication/textures/gui/lithography_table.png create mode 100755 fabrication/src/main/resources/assets/projectred_fabrication/textures/gui/packaging_table.png create mode 100755 fabrication/src/main/resources/assets/projectred_fabrication/textures/gui/plotting_table.png create mode 100755 fabrication/src/main/resources/assets/projectred_fabrication/textures/item/blank_photomask.png create mode 100755 fabrication/src/main/resources/assets/projectred_fabrication/textures/item/etched_silicon_wafer.png create mode 100755 fabrication/src/main/resources/assets/projectred_fabrication/textures/item/ic_active.png create mode 100755 fabrication/src/main/resources/assets/projectred_fabrication/textures/item/ic_active.png.mcmeta rename src/fabrication/resources/assets/projectred-fabrication/textures/gui/ic_workbench.png => fabrication/src/main/resources/assets/projectred_fabrication/textures/item/ic_blueprint.png (68%) mode change 100644 => 100755 create mode 100644 fabrication/src/main/resources/assets/projectred_fabrication/textures/item/ic_inert.png create mode 100644 fabrication/src/main/resources/assets/projectred_fabrication/textures/item/invalid_die.png create mode 100755 fabrication/src/main/resources/assets/projectred_fabrication/textures/item/photomask_set.png create mode 100755 fabrication/src/main/resources/assets/projectred_fabrication/textures/item/rough_silicon_wafer copy.png create mode 100755 fabrication/src/main/resources/assets/projectred_fabrication/textures/item/rough_silicon_wafer.png create mode 100755 fabrication/src/main/resources/assets/projectred_fabrication/textures/item/valid_die.png create mode 100755 fabrication/src/main/resources/assets/projectred_fabrication/textures/item/valid_die.png.mcmeta create mode 100755 fabrication/src/main/resources/assets/projectred_fabrication/textures/item/valid_die_template.png create mode 100755 fabrication/src/main/resources/assets/projectred_fabrication/textures/item/valid_die_v1.png create mode 100644 fabrication/src/main/resources/pack.mcmeta create mode 100644 integration/src/main/resources/assets/projectred_integration/obj/fab_ic.blend create mode 100644 integration/src/main/resources/assets/projectred_integration/obj/fab_ic.obj delete mode 100644 integration/src/main/resources/assets/projectred_integration/obj/icchip.blend delete mode 100644 integration/src/main/resources/assets/projectred_integration/obj/icchip.obj delete mode 100644 integration/src/main/resources/assets/projectred_integration/obj/icglass.blend delete mode 100644 integration/src/main/resources/assets/projectred_integration/obj/icglass.obj delete mode 100644 integration/src/main/resources/assets/projectred_integration/obj/ichousing.blend delete mode 100644 integration/src/main/resources/assets/projectred_integration/obj/ichousing.obj create mode 100644 integration/src/main/resources/assets/projectred_integration/obj/io_colour_box.blend create mode 100644 integration/src/main/resources/assets/projectred_integration/obj/io_colour_box.obj create mode 100644 integration/src/main/resources/assets/projectred_integration/obj/io_crimp.blend create mode 100644 integration/src/main/resources/assets/projectred_integration/obj/io_crimp.obj create mode 100644 integration/src/main/resources/assets/projectred_integration/textures/block/io_colour_box.png create mode 100644 integration/src/main/resources/assets/projectred_integration/textures/block/io_crimp.png create mode 100644 integration/src/main/resources/assets/projectred_integration/textures/block/io_crimp_old.png create mode 100644 integration/src/main/resources/assets/projectred_integration/textures/block/surface/fabio-0.png diff --git a/build.gradle b/build.gradle index 4f31cdb05..c403b7683 100644 --- a/build.gradle +++ b/build.gradle @@ -2,6 +2,7 @@ import java.time.Instant plugins { id 'java' id 'maven-publish' + id 'com.github.johnrengelman.shadow' } // Get mod version from CI, else suffix a timestamp (calculated here bc timestamp can change if done separately in each subproject) @@ -61,6 +62,11 @@ subprojects { p -> } } +// Defined explicitly so publishing can access shadowJar property +project(':fabrication') { + apply plugin: 'com.github.johnrengelman.shadow' +} + publishing { repositories { maven { @@ -76,6 +82,7 @@ publishing { artifact project(':core').jar artifact project(':expansion').jar artifact project(':exploration').jar + artifact project(':fabrication').shadowJar artifact project(':illumination').jar artifact project(':integration').jar artifact project(':transmission').jar diff --git a/fabrication/build.gradle b/fabrication/build.gradle new file mode 100644 index 000000000..d65d4e240 --- /dev/null +++ b/fabrication/build.gradle @@ -0,0 +1,81 @@ +plugins { + id 'net.minecraftforge.gradle' + id 'com.github.johnrengelman.shadow' +// id 'com.matthewprenger.cursegradle' +} + +String mod_id = 'projectred_fabrication' + +minecraft { + mappings channel: mcp_mappings, version: mc_version + accessTransformer = file("../core/src/main/resources/META-INF/accesstransformer.cfg") + runs { + data { + property 'mixin.env.remapRefMap', 'true' + property 'mixin.env.refMapRemappingFile', "${buildDir}/createSrgToMcp/output.srg" + + ideaModule "${rootProject.name}.${project.name}.main" + + workingDirectory file('run') + args '--mod', mod_id, '--all', '--output', file("src/main/generated"), '--existing', file("src/main/resources") + mods { + '${mod_id}' { source sourceSets.main } + } + } + } +} + +dependencies { + minecraft "net.minecraftforge:forge:${mc_version}-${forge_version}" + + implementation fg.deobf("codechicken:CodeChickenLib:${mc_version}-${ccl_version}:universal") + implementation fg.deobf("codechicken:CBMultipart:${mc_version}-${cbm_version}:universal") + + implementation project(":core") + + // Note: Fails if transitives are included. Possible ForgeGradle bug + implementation(project(":integration")) { transitive = false } + implementation(project(":transmission")) { transitive = false } + + // Dependencies to be packed into jar + shadow("io.github.mrtjp:fabrication-engine:${fabrication_version}") { transitive = false } +} + +// Jar settings +jar.enabled = false +shadowJar { + // Jar configurations + archiveClassifier = jar.archiveClassifier + configurations = [project.configurations.shadow] + + // Attach reobf task + finalizedBy 'reobfShadowJar' +} + +build.dependsOn shadowJar + +reobf { + jar { enabled = false } // Disable unshaded jar + shadowJar { } // Enable shadow jar reobf +} + +//TODO +//curseforge { +// apiKey = System.getenv('CURSE_TOKEN') ?: 'XXX' +// +// // Fabrication +// project { +// id = '230111' +// releaseType = System.getenv('CURSE_RELEASE_TYPE') ?: 'alpha' +// changelogType = 'markdown' +// changelog = rootProject.file('CHANGELOG.md') +// relations { +// requiredDependency 'project-red-core' +// requiredDependency 'project-red-integration' +// requiredDependency 'project-red-transmission' +// } +// // Java/ForgeGradle integrations don't work after 1.18.2 port +// addGameVersion "${mc_version}" +// addGameVersion "Java ${java_lang_version}" +// } +//} diff --git a/fabrication/src/main/generated/assets/projectred_fabrication/blockstates/ic_workbench.json b/fabrication/src/main/generated/assets/projectred_fabrication/blockstates/ic_workbench.json new file mode 100644 index 000000000..955878173 --- /dev/null +++ b/fabrication/src/main/generated/assets/projectred_fabrication/blockstates/ic_workbench.json @@ -0,0 +1,10 @@ +{ + "variants": { + "blueprint=false": { + "model": "projectred_fabrication:block/ic_workbench_no_blueprint" + }, + "blueprint=true": { + "model": "projectred_fabrication:block/ic_workbench_blueprint" + } + } +} \ No newline at end of file diff --git a/fabrication/src/main/generated/assets/projectred_fabrication/blockstates/lithography_table.json b/fabrication/src/main/generated/assets/projectred_fabrication/blockstates/lithography_table.json new file mode 100644 index 000000000..ef4ecdbbf --- /dev/null +++ b/fabrication/src/main/generated/assets/projectred_fabrication/blockstates/lithography_table.json @@ -0,0 +1,64 @@ +{ + "variants": { + "charged=false,rotation=0,working=false": { + "model": "projectred_fabrication:block/lithography_table_c0" + }, + "charged=true,rotation=0,working=false": { + "model": "projectred_fabrication:block/lithography_table_c1" + }, + "charged=false,rotation=1,working=false": { + "model": "projectred_fabrication:block/lithography_table_c0", + "y": 90 + }, + "charged=true,rotation=1,working=false": { + "model": "projectred_fabrication:block/lithography_table_c1", + "y": 90 + }, + "charged=false,rotation=2,working=false": { + "model": "projectred_fabrication:block/lithography_table_c0", + "y": 180 + }, + "charged=true,rotation=2,working=false": { + "model": "projectred_fabrication:block/lithography_table_c1", + "y": 180 + }, + "charged=false,rotation=3,working=false": { + "model": "projectred_fabrication:block/lithography_table_c0", + "y": 270 + }, + "charged=true,rotation=3,working=false": { + "model": "projectred_fabrication:block/lithography_table_c1", + "y": 270 + }, + "charged=false,rotation=0,working=true": { + "model": "projectred_fabrication:block/lithography_table_c0" + }, + "charged=true,rotation=0,working=true": { + "model": "projectred_fabrication:block/lithography_table_c2" + }, + "charged=false,rotation=1,working=true": { + "model": "projectred_fabrication:block/lithography_table_c0", + "y": 90 + }, + "charged=true,rotation=1,working=true": { + "model": "projectred_fabrication:block/lithography_table_c2", + "y": 90 + }, + "charged=false,rotation=2,working=true": { + "model": "projectred_fabrication:block/lithography_table_c0", + "y": 180 + }, + "charged=true,rotation=2,working=true": { + "model": "projectred_fabrication:block/lithography_table_c2", + "y": 180 + }, + "charged=false,rotation=3,working=true": { + "model": "projectred_fabrication:block/lithography_table_c0", + "y": 270 + }, + "charged=true,rotation=3,working=true": { + "model": "projectred_fabrication:block/lithography_table_c2", + "y": 270 + } + } +} \ No newline at end of file diff --git a/fabrication/src/main/generated/assets/projectred_fabrication/blockstates/packaging_table.json b/fabrication/src/main/generated/assets/projectred_fabrication/blockstates/packaging_table.json new file mode 100644 index 000000000..931d6ef18 --- /dev/null +++ b/fabrication/src/main/generated/assets/projectred_fabrication/blockstates/packaging_table.json @@ -0,0 +1,64 @@ +{ + "variants": { + "charged=false,rotation=0,working=false": { + "model": "projectred_fabrication:block/packaging_table_c0" + }, + "charged=true,rotation=0,working=false": { + "model": "projectred_fabrication:block/packaging_table_c1" + }, + "charged=false,rotation=1,working=false": { + "model": "projectred_fabrication:block/packaging_table_c0", + "y": 90 + }, + "charged=true,rotation=1,working=false": { + "model": "projectred_fabrication:block/packaging_table_c1", + "y": 90 + }, + "charged=false,rotation=2,working=false": { + "model": "projectred_fabrication:block/packaging_table_c0", + "y": 180 + }, + "charged=true,rotation=2,working=false": { + "model": "projectred_fabrication:block/packaging_table_c1", + "y": 180 + }, + "charged=false,rotation=3,working=false": { + "model": "projectred_fabrication:block/packaging_table_c0", + "y": 270 + }, + "charged=true,rotation=3,working=false": { + "model": "projectred_fabrication:block/packaging_table_c1", + "y": 270 + }, + "charged=false,rotation=0,working=true": { + "model": "projectred_fabrication:block/packaging_table_c0" + }, + "charged=true,rotation=0,working=true": { + "model": "projectred_fabrication:block/packaging_table_c2" + }, + "charged=false,rotation=1,working=true": { + "model": "projectred_fabrication:block/packaging_table_c0", + "y": 90 + }, + "charged=true,rotation=1,working=true": { + "model": "projectred_fabrication:block/packaging_table_c2", + "y": 90 + }, + "charged=false,rotation=2,working=true": { + "model": "projectred_fabrication:block/packaging_table_c0", + "y": 180 + }, + "charged=true,rotation=2,working=true": { + "model": "projectred_fabrication:block/packaging_table_c2", + "y": 180 + }, + "charged=false,rotation=3,working=true": { + "model": "projectred_fabrication:block/packaging_table_c0", + "y": 270 + }, + "charged=true,rotation=3,working=true": { + "model": "projectred_fabrication:block/packaging_table_c2", + "y": 270 + } + } +} \ No newline at end of file diff --git a/fabrication/src/main/generated/assets/projectred_fabrication/blockstates/plotting_table.json b/fabrication/src/main/generated/assets/projectred_fabrication/blockstates/plotting_table.json new file mode 100644 index 000000000..28816b4d5 --- /dev/null +++ b/fabrication/src/main/generated/assets/projectred_fabrication/blockstates/plotting_table.json @@ -0,0 +1,64 @@ +{ + "variants": { + "charged=false,rotation=0,working=false": { + "model": "projectred_fabrication:block/plotting_table_c0" + }, + "charged=true,rotation=0,working=false": { + "model": "projectred_fabrication:block/plotting_table_c1" + }, + "charged=false,rotation=1,working=false": { + "model": "projectred_fabrication:block/plotting_table_c0", + "y": 90 + }, + "charged=true,rotation=1,working=false": { + "model": "projectred_fabrication:block/plotting_table_c1", + "y": 90 + }, + "charged=false,rotation=2,working=false": { + "model": "projectred_fabrication:block/plotting_table_c0", + "y": 180 + }, + "charged=true,rotation=2,working=false": { + "model": "projectred_fabrication:block/plotting_table_c1", + "y": 180 + }, + "charged=false,rotation=3,working=false": { + "model": "projectred_fabrication:block/plotting_table_c0", + "y": 270 + }, + "charged=true,rotation=3,working=false": { + "model": "projectred_fabrication:block/plotting_table_c1", + "y": 270 + }, + "charged=false,rotation=0,working=true": { + "model": "projectred_fabrication:block/plotting_table_c0" + }, + "charged=true,rotation=0,working=true": { + "model": "projectred_fabrication:block/plotting_table_c2" + }, + "charged=false,rotation=1,working=true": { + "model": "projectred_fabrication:block/plotting_table_c0", + "y": 90 + }, + "charged=true,rotation=1,working=true": { + "model": "projectred_fabrication:block/plotting_table_c2", + "y": 90 + }, + "charged=false,rotation=2,working=true": { + "model": "projectred_fabrication:block/plotting_table_c0", + "y": 180 + }, + "charged=true,rotation=2,working=true": { + "model": "projectred_fabrication:block/plotting_table_c2", + "y": 180 + }, + "charged=false,rotation=3,working=true": { + "model": "projectred_fabrication:block/plotting_table_c0", + "y": 270 + }, + "charged=true,rotation=3,working=true": { + "model": "projectred_fabrication:block/plotting_table_c2", + "y": 270 + } + } +} \ No newline at end of file diff --git a/fabrication/src/main/generated/assets/projectred_fabrication/models/block/ic_workbench_blueprint.json b/fabrication/src/main/generated/assets/projectred_fabrication/models/block/ic_workbench_blueprint.json new file mode 100644 index 000000000..c0bedfc40 --- /dev/null +++ b/fabrication/src/main/generated/assets/projectred_fabrication/models/block/ic_workbench_blueprint.json @@ -0,0 +1,11 @@ +{ + "parent": "minecraft:block/cube", + "textures": { + "down": "projectred_fabrication:block/ic_workbench_bottom", + "up": "projectred_fabrication:block/ic_workbench_top_bp", + "north": "projectred_fabrication:block/ic_workbench_front_bp", + "south": "projectred_fabrication:block/ic_workbench_front_bp", + "east": "projectred_fabrication:block/ic_workbench_side_bp", + "west": "projectred_fabrication:block/ic_workbench_side_bp" + } +} \ No newline at end of file diff --git a/fabrication/src/main/generated/assets/projectred_fabrication/models/block/ic_workbench_no_blueprint.json b/fabrication/src/main/generated/assets/projectred_fabrication/models/block/ic_workbench_no_blueprint.json new file mode 100644 index 000000000..9f8161361 --- /dev/null +++ b/fabrication/src/main/generated/assets/projectred_fabrication/models/block/ic_workbench_no_blueprint.json @@ -0,0 +1,11 @@ +{ + "parent": "minecraft:block/cube", + "textures": { + "down": "projectred_fabrication:block/ic_workbench_bottom", + "up": "projectred_fabrication:block/ic_workbench_top", + "north": "projectred_fabrication:block/ic_workbench_front", + "south": "projectred_fabrication:block/ic_workbench_front", + "east": "projectred_fabrication:block/ic_workbench_side", + "west": "projectred_fabrication:block/ic_workbench_side" + } +} \ No newline at end of file diff --git a/fabrication/src/main/generated/assets/projectred_fabrication/models/block/lithography_table_c0.json b/fabrication/src/main/generated/assets/projectred_fabrication/models/block/lithography_table_c0.json new file mode 100644 index 000000000..fb25e6820 --- /dev/null +++ b/fabrication/src/main/generated/assets/projectred_fabrication/models/block/lithography_table_c0.json @@ -0,0 +1,11 @@ +{ + "parent": "projectred_fabrication:block/domed_machine", + "textures": { + "down": "projectred_fabrication:block/lithography_table_bottom", + "up": "projectred_fabrication:block/lithography_table_top", + "north": "projectred_fabrication:block/lithography_table_front_0", + "south": "projectred_fabrication:block/lithography_table_side", + "west": "projectred_fabrication:block/lithography_table_side", + "east": "projectred_fabrication:block/lithography_table_side" + } +} \ No newline at end of file diff --git a/fabrication/src/main/generated/assets/projectred_fabrication/models/block/lithography_table_c1.json b/fabrication/src/main/generated/assets/projectred_fabrication/models/block/lithography_table_c1.json new file mode 100644 index 000000000..bb9a8f32d --- /dev/null +++ b/fabrication/src/main/generated/assets/projectred_fabrication/models/block/lithography_table_c1.json @@ -0,0 +1,11 @@ +{ + "parent": "projectred_fabrication:block/domed_machine", + "textures": { + "down": "projectred_fabrication:block/lithography_table_bottom", + "up": "projectred_fabrication:block/lithography_table_top", + "north": "projectred_fabrication:block/lithography_table_front_1", + "south": "projectred_fabrication:block/lithography_table_side", + "west": "projectred_fabrication:block/lithography_table_side", + "east": "projectred_fabrication:block/lithography_table_side" + } +} \ No newline at end of file diff --git a/fabrication/src/main/generated/assets/projectred_fabrication/models/block/lithography_table_c2.json b/fabrication/src/main/generated/assets/projectred_fabrication/models/block/lithography_table_c2.json new file mode 100644 index 000000000..10a1cf2d7 --- /dev/null +++ b/fabrication/src/main/generated/assets/projectred_fabrication/models/block/lithography_table_c2.json @@ -0,0 +1,11 @@ +{ + "parent": "projectred_fabrication:block/domed_machine", + "textures": { + "down": "projectred_fabrication:block/lithography_table_bottom", + "up": "projectred_fabrication:block/lithography_table_top", + "north": "projectred_fabrication:block/lithography_table_front_2", + "south": "projectred_fabrication:block/lithography_table_side", + "west": "projectred_fabrication:block/lithography_table_side", + "east": "projectred_fabrication:block/lithography_table_side" + } +} \ No newline at end of file diff --git a/fabrication/src/main/generated/assets/projectred_fabrication/models/block/packaging_table_c0.json b/fabrication/src/main/generated/assets/projectred_fabrication/models/block/packaging_table_c0.json new file mode 100644 index 000000000..fcacfaa76 --- /dev/null +++ b/fabrication/src/main/generated/assets/projectred_fabrication/models/block/packaging_table_c0.json @@ -0,0 +1,11 @@ +{ + "parent": "projectred_fabrication:block/domed_machine", + "textures": { + "down": "projectred_fabrication:block/packaging_table_bottom", + "up": "projectred_fabrication:block/packaging_table_top", + "north": "projectred_fabrication:block/packaging_table_front_0", + "south": "projectred_fabrication:block/packaging_table_side", + "west": "projectred_fabrication:block/packaging_table_side", + "east": "projectred_fabrication:block/packaging_table_side" + } +} \ No newline at end of file diff --git a/fabrication/src/main/generated/assets/projectred_fabrication/models/block/packaging_table_c1.json b/fabrication/src/main/generated/assets/projectred_fabrication/models/block/packaging_table_c1.json new file mode 100644 index 000000000..d985a4bb7 --- /dev/null +++ b/fabrication/src/main/generated/assets/projectred_fabrication/models/block/packaging_table_c1.json @@ -0,0 +1,11 @@ +{ + "parent": "projectred_fabrication:block/domed_machine", + "textures": { + "down": "projectred_fabrication:block/packaging_table_bottom", + "up": "projectred_fabrication:block/packaging_table_top", + "north": "projectred_fabrication:block/packaging_table_front_1", + "south": "projectred_fabrication:block/packaging_table_side", + "west": "projectred_fabrication:block/packaging_table_side", + "east": "projectred_fabrication:block/packaging_table_side" + } +} \ No newline at end of file diff --git a/fabrication/src/main/generated/assets/projectred_fabrication/models/block/packaging_table_c2.json b/fabrication/src/main/generated/assets/projectred_fabrication/models/block/packaging_table_c2.json new file mode 100644 index 000000000..66772ed43 --- /dev/null +++ b/fabrication/src/main/generated/assets/projectred_fabrication/models/block/packaging_table_c2.json @@ -0,0 +1,11 @@ +{ + "parent": "projectred_fabrication:block/domed_machine", + "textures": { + "down": "projectred_fabrication:block/packaging_table_bottom", + "up": "projectred_fabrication:block/packaging_table_top", + "north": "projectred_fabrication:block/packaging_table_front_2", + "south": "projectred_fabrication:block/packaging_table_side", + "west": "projectred_fabrication:block/packaging_table_side", + "east": "projectred_fabrication:block/packaging_table_side" + } +} \ No newline at end of file diff --git a/fabrication/src/main/generated/assets/projectred_fabrication/models/block/plotting_table_c0.json b/fabrication/src/main/generated/assets/projectred_fabrication/models/block/plotting_table_c0.json new file mode 100644 index 000000000..b2bb9b870 --- /dev/null +++ b/fabrication/src/main/generated/assets/projectred_fabrication/models/block/plotting_table_c0.json @@ -0,0 +1,11 @@ +{ + "parent": "projectred_fabrication:block/domed_machine", + "textures": { + "down": "projectred_fabrication:block/plotting_table_bottom", + "up": "projectred_fabrication:block/plotting_table_top", + "north": "projectred_fabrication:block/plotting_table_front_0", + "south": "projectred_fabrication:block/plotting_table_side", + "west": "projectred_fabrication:block/plotting_table_side", + "east": "projectred_fabrication:block/plotting_table_side" + } +} \ No newline at end of file diff --git a/fabrication/src/main/generated/assets/projectred_fabrication/models/block/plotting_table_c1.json b/fabrication/src/main/generated/assets/projectred_fabrication/models/block/plotting_table_c1.json new file mode 100644 index 000000000..fe0ae0b29 --- /dev/null +++ b/fabrication/src/main/generated/assets/projectred_fabrication/models/block/plotting_table_c1.json @@ -0,0 +1,11 @@ +{ + "parent": "projectred_fabrication:block/domed_machine", + "textures": { + "down": "projectred_fabrication:block/plotting_table_bottom", + "up": "projectred_fabrication:block/plotting_table_top", + "north": "projectred_fabrication:block/plotting_table_front_1", + "south": "projectred_fabrication:block/plotting_table_side", + "west": "projectred_fabrication:block/plotting_table_side", + "east": "projectred_fabrication:block/plotting_table_side" + } +} \ No newline at end of file diff --git a/fabrication/src/main/generated/assets/projectred_fabrication/models/block/plotting_table_c2.json b/fabrication/src/main/generated/assets/projectred_fabrication/models/block/plotting_table_c2.json new file mode 100644 index 000000000..a807658f0 --- /dev/null +++ b/fabrication/src/main/generated/assets/projectred_fabrication/models/block/plotting_table_c2.json @@ -0,0 +1,11 @@ +{ + "parent": "projectred_fabrication:block/domed_machine", + "textures": { + "down": "projectred_fabrication:block/plotting_table_bottom", + "up": "projectred_fabrication:block/plotting_table_top", + "north": "projectred_fabrication:block/plotting_table_front_2", + "south": "projectred_fabrication:block/plotting_table_side", + "west": "projectred_fabrication:block/plotting_table_side", + "east": "projectred_fabrication:block/plotting_table_side" + } +} \ No newline at end of file diff --git a/fabrication/src/main/generated/assets/projectred_fabrication/models/item/blank_photomask.json b/fabrication/src/main/generated/assets/projectred_fabrication/models/item/blank_photomask.json new file mode 100644 index 000000000..a318d7cdf --- /dev/null +++ b/fabrication/src/main/generated/assets/projectred_fabrication/models/item/blank_photomask.json @@ -0,0 +1,6 @@ +{ + "parent": "minecraft:item/generated", + "textures": { + "layer0": "projectred_fabrication:item/blank_photomask" + } +} \ No newline at end of file diff --git a/fabrication/src/main/generated/assets/projectred_fabrication/models/item/etched_silicon_wafer.json b/fabrication/src/main/generated/assets/projectred_fabrication/models/item/etched_silicon_wafer.json new file mode 100644 index 000000000..69cbe5a84 --- /dev/null +++ b/fabrication/src/main/generated/assets/projectred_fabrication/models/item/etched_silicon_wafer.json @@ -0,0 +1,6 @@ +{ + "parent": "minecraft:item/generated", + "textures": { + "layer0": "projectred_fabrication:item/etched_silicon_wafer" + } +} \ No newline at end of file diff --git a/fabrication/src/main/generated/assets/projectred_fabrication/models/item/fabricated_gate.json b/fabrication/src/main/generated/assets/projectred_fabrication/models/item/fabricated_gate.json new file mode 100644 index 000000000..1bcbb312f --- /dev/null +++ b/fabrication/src/main/generated/assets/projectred_fabrication/models/item/fabricated_gate.json @@ -0,0 +1,3 @@ +{ + "parent": "minecraft:item/generated" +} \ No newline at end of file diff --git a/fabrication/src/main/generated/assets/projectred_fabrication/models/item/ic_blueprint.json b/fabrication/src/main/generated/assets/projectred_fabrication/models/item/ic_blueprint.json new file mode 100644 index 000000000..225226ad0 --- /dev/null +++ b/fabrication/src/main/generated/assets/projectred_fabrication/models/item/ic_blueprint.json @@ -0,0 +1,6 @@ +{ + "parent": "minecraft:item/generated", + "textures": { + "layer0": "projectred_fabrication:item/ic_blueprint" + } +} \ No newline at end of file diff --git a/fabrication/src/main/generated/assets/projectred_fabrication/models/item/ic_workbench.json b/fabrication/src/main/generated/assets/projectred_fabrication/models/item/ic_workbench.json new file mode 100644 index 000000000..f5601fe48 --- /dev/null +++ b/fabrication/src/main/generated/assets/projectred_fabrication/models/item/ic_workbench.json @@ -0,0 +1,3 @@ +{ + "parent": "projectred_fabrication:block/ic_workbench_blueprint" +} \ No newline at end of file diff --git a/fabrication/src/main/generated/assets/projectred_fabrication/models/item/invalid_die.json b/fabrication/src/main/generated/assets/projectred_fabrication/models/item/invalid_die.json new file mode 100644 index 000000000..46649c024 --- /dev/null +++ b/fabrication/src/main/generated/assets/projectred_fabrication/models/item/invalid_die.json @@ -0,0 +1,6 @@ +{ + "parent": "minecraft:item/generated", + "textures": { + "layer0": "projectred_fabrication:item/invalid_die" + } +} \ No newline at end of file diff --git a/fabrication/src/main/generated/assets/projectred_fabrication/models/item/lithography_table.json b/fabrication/src/main/generated/assets/projectred_fabrication/models/item/lithography_table.json new file mode 100644 index 000000000..e193a4f08 --- /dev/null +++ b/fabrication/src/main/generated/assets/projectred_fabrication/models/item/lithography_table.json @@ -0,0 +1,3 @@ +{ + "parent": "projectred_fabrication:block/lithography_table_c0" +} \ No newline at end of file diff --git a/fabrication/src/main/generated/assets/projectred_fabrication/models/item/packaging_table.json b/fabrication/src/main/generated/assets/projectred_fabrication/models/item/packaging_table.json new file mode 100644 index 000000000..134d48a3a --- /dev/null +++ b/fabrication/src/main/generated/assets/projectred_fabrication/models/item/packaging_table.json @@ -0,0 +1,3 @@ +{ + "parent": "projectred_fabrication:block/packaging_table_c0" +} \ No newline at end of file diff --git a/fabrication/src/main/generated/assets/projectred_fabrication/models/item/photomask_set.json b/fabrication/src/main/generated/assets/projectred_fabrication/models/item/photomask_set.json new file mode 100644 index 000000000..96317cdcc --- /dev/null +++ b/fabrication/src/main/generated/assets/projectred_fabrication/models/item/photomask_set.json @@ -0,0 +1,6 @@ +{ + "parent": "minecraft:item/generated", + "textures": { + "layer0": "projectred_fabrication:item/photomask_set" + } +} \ No newline at end of file diff --git a/fabrication/src/main/generated/assets/projectred_fabrication/models/item/plotting_table.json b/fabrication/src/main/generated/assets/projectred_fabrication/models/item/plotting_table.json new file mode 100644 index 000000000..31c51d729 --- /dev/null +++ b/fabrication/src/main/generated/assets/projectred_fabrication/models/item/plotting_table.json @@ -0,0 +1,3 @@ +{ + "parent": "projectred_fabrication:block/plotting_table_c0" +} \ No newline at end of file diff --git a/fabrication/src/main/generated/assets/projectred_fabrication/models/item/rough_silicon_wafer.json b/fabrication/src/main/generated/assets/projectred_fabrication/models/item/rough_silicon_wafer.json new file mode 100644 index 000000000..d005df176 --- /dev/null +++ b/fabrication/src/main/generated/assets/projectred_fabrication/models/item/rough_silicon_wafer.json @@ -0,0 +1,6 @@ +{ + "parent": "minecraft:item/generated", + "textures": { + "layer0": "projectred_fabrication:item/rough_silicon_wafer" + } +} \ No newline at end of file diff --git a/fabrication/src/main/generated/assets/projectred_fabrication/models/item/valid_die.json b/fabrication/src/main/generated/assets/projectred_fabrication/models/item/valid_die.json new file mode 100644 index 000000000..3f7d01b80 --- /dev/null +++ b/fabrication/src/main/generated/assets/projectred_fabrication/models/item/valid_die.json @@ -0,0 +1,6 @@ +{ + "parent": "minecraft:item/generated", + "textures": { + "layer0": "projectred_fabrication:item/valid_die" + } +} \ No newline at end of file diff --git a/fabrication/src/main/java/mrtjp/projectred/fabrication/ProjectRedFabrication.java b/fabrication/src/main/java/mrtjp/projectred/fabrication/ProjectRedFabrication.java new file mode 100644 index 000000000..2abf3e74f --- /dev/null +++ b/fabrication/src/main/java/mrtjp/projectred/fabrication/ProjectRedFabrication.java @@ -0,0 +1,79 @@ +package mrtjp.projectred.fabrication; + +import codechicken.lib.gui.SimpleCreativeTab; +import codechicken.multipart.api.MultipartType; +import mrtjp.projectred.fabrication.data.FabricationBlockStateModelProvider; +import mrtjp.projectred.fabrication.data.FabricationItemModelProvider; +import mrtjp.projectred.fabrication.init.*; +import net.minecraft.data.DataGenerator; +import net.minecraft.world.inventory.MenuType; +import net.minecraft.world.item.Item; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.entity.BlockEntityType; +import net.minecraftforge.api.distmarker.Dist; +import net.minecraftforge.common.data.ExistingFileHelper; +import net.minecraftforge.eventbus.api.IEventBus; +import net.minecraftforge.fml.DistExecutor; +import net.minecraftforge.fml.common.Mod; +import net.minecraftforge.fml.event.lifecycle.FMLCommonSetupEvent; +import net.minecraftforge.fml.javafmlmod.FMLJavaModLoadingContext; +import net.minecraftforge.forge.event.lifecycle.GatherDataEvent; +import net.minecraftforge.registries.DeferredRegister; +import net.minecraftforge.registries.ForgeRegistries; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; + +import static mrtjp.projectred.fabrication.ProjectRedFabrication.MOD_ID; + +@Mod (MOD_ID) +public class ProjectRedFabrication { + + public static final String MOD_ID = "projectred_fabrication"; + + public static final Logger LOGGER = LogManager.getLogger(MOD_ID); + + public static final DeferredRegister BLOCKS = DeferredRegister.create(ForgeRegistries.BLOCKS, MOD_ID); + public static final DeferredRegister ITEMS = DeferredRegister.create(ForgeRegistries.ITEMS, MOD_ID); + public static final DeferredRegister> TILE_ENTITIES = DeferredRegister.create(ForgeRegistries.BLOCK_ENTITIES, MOD_ID); + public static final DeferredRegister> CONTAINERS = DeferredRegister.create(ForgeRegistries.CONTAINERS, MOD_ID); + public static final DeferredRegister> PARTS = DeferredRegister.create(MultipartType.MULTIPART_TYPES, MOD_ID); + + public static final SimpleCreativeTab FABRICATION_GROUP = new SimpleCreativeTab(MOD_ID, () -> new ItemStack(FabricationReferences.IC_WORKBENCH_BLOCK)); + + static { + FabricationBlocks.register(); + FabricationContainers.register(); + FabricationItems.register(); + FabricationParts.register(); + } + + public ProjectRedFabrication() { + final IEventBus modEventBus = FMLJavaModLoadingContext.get().getModEventBus(); + + modEventBus.addListener(this::commonSetup); + modEventBus.addListener(this::onGatherDataEvent); + + DistExecutor.safeRunWhenOn(Dist.CLIENT, () -> FabricationClientInit::init); + + BLOCKS.register(modEventBus); + ITEMS.register(modEventBus); + TILE_ENTITIES.register(modEventBus); + CONTAINERS.register(modEventBus); + PARTS.register(modEventBus); + } + + private void commonSetup(final FMLCommonSetupEvent event) { + + } + + private void onGatherDataEvent(final GatherDataEvent event) { + DataGenerator generator = event.getGenerator(); + ExistingFileHelper fileHelper = event.getExistingFileHelper(); + + if (event.includeClient()) { + generator.addProvider(new FabricationBlockStateModelProvider(generator, fileHelper)); + generator.addProvider(new FabricationItemModelProvider(generator, fileHelper)); + } + } +} diff --git a/fabrication/src/main/java/mrtjp/projectred/fabrication/block/FabricationMachineBlock.java b/fabrication/src/main/java/mrtjp/projectred/fabrication/block/FabricationMachineBlock.java new file mode 100644 index 000000000..0e05517ea --- /dev/null +++ b/fabrication/src/main/java/mrtjp/projectred/fabrication/block/FabricationMachineBlock.java @@ -0,0 +1,44 @@ +package mrtjp.projectred.fabrication.block; + +import codechicken.lib.vec.Rotation; +import mrtjp.projectred.core.block.ProjectRedBlock; +import net.minecraft.core.BlockPos; +import net.minecraft.world.item.context.BlockPlaceContext; +import net.minecraft.world.level.BlockGetter; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.block.state.StateDefinition; +import net.minecraft.world.phys.shapes.VoxelShape; + +import javax.annotation.Nullable; + +public abstract class FabricationMachineBlock extends ProjectRedBlock { + + protected static final VoxelShape BOTTOM_AABB = Block.box(0.0D, 0.0D, 0.0D, 16.0D, 10.0D, 16.0D); + + public FabricationMachineBlock(Properties properties) { + super(properties); + } + + @Nullable + @Override + public BlockState getStateForPlacement(BlockPlaceContext context) { + int r = Rotation.rotationTo(0, context.getHorizontalDirection().ordinal()); + return this.defaultBlockState() + .setValue(ROTATION, r) + .setValue(CHARGED, false) + .setValue(WORKING, false); + } + + @Override + protected void createBlockStateDefinition(StateDefinition.Builder builder) { + builder.add(ROTATION); + builder.add(CHARGED); + builder.add(WORKING); + } + + @Override + public VoxelShape getOcclusionShape(BlockState state, BlockGetter world, BlockPos pos) { + return BOTTOM_AABB; + } +} diff --git a/fabrication/src/main/java/mrtjp/projectred/fabrication/block/ICWorkbenchBlock.java b/fabrication/src/main/java/mrtjp/projectred/fabrication/block/ICWorkbenchBlock.java new file mode 100644 index 000000000..629cfff28 --- /dev/null +++ b/fabrication/src/main/java/mrtjp/projectred/fabrication/block/ICWorkbenchBlock.java @@ -0,0 +1,46 @@ +package mrtjp.projectred.fabrication.block; + +import mrtjp.projectred.core.block.ProjectRedBlock; +import mrtjp.projectred.fabrication.init.FabricationReferences; +import mrtjp.projectred.fabrication.tile.ICWorkbenchTile; +import net.minecraft.core.BlockPos; +import net.minecraft.world.item.context.BlockPlaceContext; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.entity.BlockEntity; +import net.minecraft.world.level.block.entity.BlockEntityType; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.block.state.StateDefinition; +import net.minecraft.world.level.block.state.properties.BooleanProperty; +import org.jetbrains.annotations.Nullable; + +public class ICWorkbenchBlock extends ProjectRedBlock { + + public static final BooleanProperty BLUEPRINT_PROPERTY = BooleanProperty.create("blueprint"); + + public ICWorkbenchBlock() { + super(STONE_PROPERTIES); + } + + @Nullable + @Override + public BlockState getStateForPlacement(BlockPlaceContext context) { + return defaultBlockState() + .setValue(BLUEPRINT_PROPERTY, false); + } + + @Nullable + @Override + public BlockEntity newBlockEntity(BlockPos pos, BlockState state) { + return new ICWorkbenchTile(pos, state); + } + + @Override + protected BlockEntityType getBlockEntityType() { + return FabricationReferences.IC_WORKBENCH_TILE; + } + + @Override + protected void createBlockStateDefinition(StateDefinition.Builder builder) { + builder.add(BLUEPRINT_PROPERTY); + } +} diff --git a/fabrication/src/main/java/mrtjp/projectred/fabrication/block/LithographyTableBlock.java b/fabrication/src/main/java/mrtjp/projectred/fabrication/block/LithographyTableBlock.java new file mode 100644 index 000000000..517a75f97 --- /dev/null +++ b/fabrication/src/main/java/mrtjp/projectred/fabrication/block/LithographyTableBlock.java @@ -0,0 +1,27 @@ +package mrtjp.projectred.fabrication.block; + +import mrtjp.projectred.fabrication.init.FabricationReferences; +import mrtjp.projectred.fabrication.tile.LithographyTableTile; +import net.minecraft.core.BlockPos; +import net.minecraft.world.level.block.entity.BlockEntity; +import net.minecraft.world.level.block.entity.BlockEntityType; +import net.minecraft.world.level.block.state.BlockState; +import org.jetbrains.annotations.Nullable; + +public class LithographyTableBlock extends FabricationMachineBlock { + + public LithographyTableBlock() { + super(STONE_PROPERTIES); + } + + @Nullable + @Override + public BlockEntity newBlockEntity(BlockPos pos, BlockState state) { + return new LithographyTableTile(pos, state); + } + + @Override + protected BlockEntityType getBlockEntityType() { + return FabricationReferences.LITHOGRAPHY_TABLE_TILE; + } +} diff --git a/fabrication/src/main/java/mrtjp/projectred/fabrication/block/PackagingTableBlock.java b/fabrication/src/main/java/mrtjp/projectred/fabrication/block/PackagingTableBlock.java new file mode 100644 index 000000000..e8ec75cc3 --- /dev/null +++ b/fabrication/src/main/java/mrtjp/projectred/fabrication/block/PackagingTableBlock.java @@ -0,0 +1,27 @@ +package mrtjp.projectred.fabrication.block; + +import mrtjp.projectred.fabrication.init.FabricationReferences; +import mrtjp.projectred.fabrication.tile.PackagingTableTile; +import net.minecraft.core.BlockPos; +import net.minecraft.world.level.block.entity.BlockEntity; +import net.minecraft.world.level.block.entity.BlockEntityType; +import net.minecraft.world.level.block.state.BlockState; +import org.jetbrains.annotations.Nullable; + +public class PackagingTableBlock extends FabricationMachineBlock { + + public PackagingTableBlock() { + super(STONE_PROPERTIES); + } + + @Nullable + @Override + public BlockEntity newBlockEntity(BlockPos pos, BlockState state) { + return new PackagingTableTile(pos, state); + } + + @Override + protected BlockEntityType getBlockEntityType() { + return FabricationReferences.PACKAGING_TABLE_TILE; + } +} diff --git a/fabrication/src/main/java/mrtjp/projectred/fabrication/block/PlottingTableBlock.java b/fabrication/src/main/java/mrtjp/projectred/fabrication/block/PlottingTableBlock.java new file mode 100644 index 000000000..a4257d119 --- /dev/null +++ b/fabrication/src/main/java/mrtjp/projectred/fabrication/block/PlottingTableBlock.java @@ -0,0 +1,28 @@ +package mrtjp.projectred.fabrication.block; + +import mrtjp.projectred.core.block.ProjectRedBlock; +import mrtjp.projectred.fabrication.init.FabricationReferences; +import mrtjp.projectred.fabrication.tile.PlottingTableTile; +import net.minecraft.core.BlockPos; +import net.minecraft.world.level.block.entity.BlockEntity; +import net.minecraft.world.level.block.entity.BlockEntityType; +import net.minecraft.world.level.block.state.BlockState; +import org.jetbrains.annotations.Nullable; + +public class PlottingTableBlock extends FabricationMachineBlock { + + public PlottingTableBlock() { + super(ProjectRedBlock.STONE_PROPERTIES); + } + + @Nullable + @Override + public BlockEntity newBlockEntity(BlockPos pos, BlockState state) { + return new PlottingTableTile(pos, state); + } + + @Override + protected BlockEntityType getBlockEntityType() { + return FabricationReferences.PLOTTING_TABLE_TILE; + } +} diff --git a/fabrication/src/main/java/mrtjp/projectred/fabrication/data/FabricationBlockStateModelProvider.java b/fabrication/src/main/java/mrtjp/projectred/fabrication/data/FabricationBlockStateModelProvider.java new file mode 100644 index 000000000..54c205594 --- /dev/null +++ b/fabrication/src/main/java/mrtjp/projectred/fabrication/data/FabricationBlockStateModelProvider.java @@ -0,0 +1,94 @@ +package mrtjp.projectred.fabrication.data; + +import mrtjp.projectred.core.block.ProjectRedBlock; +import mrtjp.projectred.fabrication.ProjectRedFabrication; +import mrtjp.projectred.fabrication.block.FabricationMachineBlock; +import mrtjp.projectred.fabrication.block.ICWorkbenchBlock; +import net.minecraft.data.DataGenerator; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.level.block.Block; +import net.minecraftforge.client.model.generators.BlockModelBuilder; +import net.minecraftforge.client.model.generators.BlockStateProvider; +import net.minecraftforge.client.model.generators.ConfiguredModel; +import net.minecraftforge.client.model.generators.ModelFile; +import net.minecraftforge.common.data.ExistingFileHelper; + +import static mrtjp.projectred.fabrication.ProjectRedFabrication.MOD_ID; +import static mrtjp.projectred.fabrication.init.FabricationReferences.*; + +public class FabricationBlockStateModelProvider extends BlockStateProvider { + + public FabricationBlockStateModelProvider(DataGenerator gen, ExistingFileHelper exFileHelper) { + super(gen, ProjectRedFabrication.MOD_ID, exFileHelper); + } + + @Override + public String getName() { + return "ProjectRed-Fabrication Block Models"; + } + + @Override + protected void registerStatesAndModels() { + + BlockModelBuilder noBP = models().cube(IC_WORKBENCH_BLOCK.getRegistryName().getPath() + "_no_blueprint", + new ResourceLocation(MOD_ID, "block/ic_workbench_bottom"), + new ResourceLocation(MOD_ID, "block/ic_workbench_top"), + new ResourceLocation(MOD_ID, "block/ic_workbench_front"), + new ResourceLocation(MOD_ID, "block/ic_workbench_front"), + new ResourceLocation(MOD_ID, "block/ic_workbench_side"), + new ResourceLocation(MOD_ID, "block/ic_workbench_side")); + + BlockModelBuilder withBP = models().cube(IC_WORKBENCH_BLOCK.getRegistryName().getPath() + "_blueprint", + new ResourceLocation(MOD_ID, "block/ic_workbench_bottom"), + new ResourceLocation(MOD_ID, "block/ic_workbench_top_bp"), + new ResourceLocation(MOD_ID, "block/ic_workbench_front_bp"), + new ResourceLocation(MOD_ID, "block/ic_workbench_front_bp"), + new ResourceLocation(MOD_ID, "block/ic_workbench_side_bp"), + new ResourceLocation(MOD_ID, "block/ic_workbench_side_bp")); + + getVariantBuilder(IC_WORKBENCH_BLOCK) + .partialState().with(ICWorkbenchBlock.BLUEPRINT_PROPERTY, false).modelForState().modelFile(noBP).addModel(); + + getVariantBuilder(IC_WORKBENCH_BLOCK) + .partialState().with(ICWorkbenchBlock.BLUEPRINT_PROPERTY, true).modelForState().modelFile(withBP).addModel(); + + addFabricationMachineVariants(PLOTTING_TABLE_BLOCK); + addFabricationMachineVariants(LITHOGRAPHY_TABLE_BLOCK); + addFabricationMachineVariants(PACKAGING_TABLE_BLOCK); + } + + private void addFabricationMachineVariants(Block block) { + addRotatableDomedMachineVariants(block, + createDomedMachineModelFileForBlock(block, 2), + createDomedMachineModelFileForBlock(block, 1), + createDomedMachineModelFileForBlock(block, 0)); + } + + private void addRotatableDomedMachineVariants(Block block, ModelFile workingModel, ModelFile chargedModel, ModelFile idleModel) { + getVariantBuilder(block) + .forAllStates(state -> { + int r = state.getValue(ProjectRedBlock.ROTATION); + boolean isWorking = state.getValue(FabricationMachineBlock.WORKING); + boolean isCharged = state.getValue(FabricationMachineBlock.CHARGED); + + ModelFile modelFile = isWorking && isCharged ? workingModel : isCharged ? chargedModel : idleModel; + + return ConfiguredModel.builder() + .modelFile(modelFile) + .rotationY(r * 90) + .build(); + }); + } + + private BlockModelBuilder createDomedMachineModelFileForBlock(Block block, int chargeState) { + String textureName = block.getRegistryName().getPath(); + return models() + .withExistingParent(textureName + "_c" + chargeState, modLoc("block/domed_machine")) + .texture("down", modLoc("block/" + textureName + "_bottom")) + .texture("up", modLoc("block/" + textureName + "_top")) + .texture("north", modLoc("block/" + textureName + "_front_" + chargeState)) + .texture("south", modLoc("block/" + textureName + "_side")) + .texture("west", modLoc("block/" + textureName + "_side")) + .texture("east", modLoc("block/" + textureName + "_side")); + } +} diff --git a/fabrication/src/main/java/mrtjp/projectred/fabrication/data/FabricationItemModelProvider.java b/fabrication/src/main/java/mrtjp/projectred/fabrication/data/FabricationItemModelProvider.java new file mode 100644 index 000000000..0626ecf04 --- /dev/null +++ b/fabrication/src/main/java/mrtjp/projectred/fabrication/data/FabricationItemModelProvider.java @@ -0,0 +1,50 @@ +package mrtjp.projectred.fabrication.data; + +import codechicken.lib.datagen.ItemModelProvider; +import net.minecraft.data.DataGenerator; +import net.minecraft.world.level.block.Block; +import net.minecraftforge.client.model.generators.ModelFile; +import net.minecraftforge.common.data.ExistingFileHelper; + +import static mrtjp.projectred.fabrication.ProjectRedFabrication.MOD_ID; +import static mrtjp.projectred.fabrication.init.FabricationReferences.*; + +public class FabricationItemModelProvider extends ItemModelProvider { + + public FabricationItemModelProvider(DataGenerator generator, ExistingFileHelper existingFileHelper) { + super(generator, MOD_ID, existingFileHelper); + } + + @Override + public String getName() { + return "ProjectRed-Fabrication Item Models"; + } + + @Override + protected void registerModels() { + + getSimple(IC_WORKBENCH_BLOCK) + .parent(new ModelFile.UncheckedModelFile(modLoc("block/" + name(IC_WORKBENCH_BLOCK) + "_blueprint"))) + .noTexture(); + + domedMachine(PLOTTING_TABLE_BLOCK); + domedMachine(LITHOGRAPHY_TABLE_BLOCK); + domedMachine(PACKAGING_TABLE_BLOCK); + + generated(IC_BLUEPRINT_ITEM); + generated(BLANK_PHOTOMASK_ITEM); + generated(PHOTOMASK_SET_ITEM); + generated(ROUGH_SILICON_WAFER_ITEM); + generated(ETCHED_SILICON_WAFER_ITEM); + generated(VALID_DIE_ITEM); + generated(INVALID_DIE_ITEM); + + generated(FABRICATED_GATE_ITEM).noTexture(); // Dummy model to suppress warnings (actually rendered runtime via IItemRenderer) + } + + private void domedMachine(Block block) { + getSimple(block) + .parent(new ModelFile.UncheckedModelFile(modLoc("block/" + name(block) + "_c0"))) + .noTexture(); + } +} diff --git a/fabrication/src/main/java/mrtjp/projectred/fabrication/editor/GatePlacementType.java b/fabrication/src/main/java/mrtjp/projectred/fabrication/editor/GatePlacementType.java new file mode 100644 index 000000000..71ebfec80 --- /dev/null +++ b/fabrication/src/main/java/mrtjp/projectred/fabrication/editor/GatePlacementType.java @@ -0,0 +1,7 @@ +package mrtjp.projectred.fabrication.editor; + +public enum GatePlacementType { + INTERNAL, + IO_EDGE, + TOP_LAYER +} diff --git a/fabrication/src/main/java/mrtjp/projectred/fabrication/editor/ICEditorStateMachine.java b/fabrication/src/main/java/mrtjp/projectred/fabrication/editor/ICEditorStateMachine.java new file mode 100644 index 000000000..c1796bcdd --- /dev/null +++ b/fabrication/src/main/java/mrtjp/projectred/fabrication/editor/ICEditorStateMachine.java @@ -0,0 +1,364 @@ +package mrtjp.projectred.fabrication.editor; + +import codechicken.lib.data.MCDataInput; +import codechicken.lib.data.MCDataOutput; +import mrtjp.fengine.api.ICFlatMap; +import mrtjp.fengine.api.ICStepThroughAssembler; +import mrtjp.projectred.fabrication.engine.ICCompilerLog; +import mrtjp.projectred.fabrication.engine.ICSimulationContainer; +import mrtjp.projectred.fabrication.engine.PRFabricationEngine; +import net.minecraft.nbt.CompoundTag; + +import java.util.Collections; +import java.util.function.Function; + +import static mrtjp.projectred.fabrication.ProjectRedFabrication.LOGGER; + +public class ICEditorStateMachine { + + public static final int KEY_STATE_CHANGED = 0; + public static final int KEY_COMPILER_LOG_NODE_ADDED = 1; + public static final int KEY_COMPILER_LOG_NODE_EXECUTED = 2; + + public static final int KEY_CLIENT_COMPILE_CLICKED = 10; + + private final ICWorkbenchEditor editor; + + private static final int STATE_INITIAL = 0; + private static final int STATE_AWAITING_COMPILE = 1; + private static final int STATE_COMPILING = 2; + private static final int STATE_SIMULATING = 3; + + private final State[] states = { + new StateInitial(), + new StateAwaitingCompile(), + new StateCompiling(), + new StateSimulating() + }; + + private int currentState = STATE_INITIAL; + + private final StateMachineCallback callback; + + private final ICSimulationContainer simulationContainer = new ICSimulationContainer(); + private final ICCompilerLog compilerLog = new ICCompilerLog(this); + + private boolean autoCompileOnChange = false; //TODO client-side toggle + + public ICEditorStateMachine(ICWorkbenchEditor editor, StateMachineCallback callback) { + this.editor = editor; + this.callback = callback; + } + + public ICCompilerLog getCompilerLog() { + return compilerLog; + } + + public void save(CompoundTag tag) { + tag.putByte("comp_state", (byte) currentState); + simulationContainer.save(tag); + compilerLog.save(tag); + } + + public void load(CompoundTag tag) { + currentState = tag.getByte("comp_state") & 0xFF; + simulationContainer.load(tag); + compilerLog.load(tag); + } + + public void writeDesc(MCDataOutput out) { + out.writeByte(currentState); + simulationContainer.writeDesc(out); + compilerLog.writeDesc(out); + } + + public void readDesc(MCDataInput in) { + currentState = in.readUByte(); + simulationContainer.readDesc(in); + compilerLog.readDesc(in); + } + + public void reset() { + enterState(STATE_INITIAL, true); + } + + public void readStateMachineStream(MCDataInput in, int key) { + switch (key) { + case KEY_STATE_CHANGED: + enterStateOnClient(in.readUByte()); + break; + case KEY_COMPILER_LOG_NODE_ADDED: + case KEY_COMPILER_LOG_NODE_EXECUTED: + compilerLog.readLogStream(in, key); + break; + case KEY_CLIENT_COMPILE_CLICKED: + onCompileTriggered(); + break; + default: + throw new IllegalArgumentException("Unknown compiler stream key: " + key); + } + } + + public MCDataOutput getStateMachineStream(int key) { + return editor.getStateMachineStream(key); + } + + //region State Machine events + public void onTick(long time) { + states[currentState].onTick(time); + } + + public void onTileMapChanged() { + states[currentState].onTileMapChanged(); + } + + public void onCompileTriggered() { + states[currentState].onCompileTriggered(); + } + + public void onInputRegistersChanged(int rotation, Function changeFunction) { + states[currentState].onInputRegistersChanged(rotation, changeFunction); + } + //endregion + + //region Client-side utilities + public void sendCompileButtonClicked() { + // Notifies server to call onCompileTriggered + getStateMachineStream(KEY_CLIENT_COMPILE_CLICKED); + } + public boolean canTriggerCompile() { + return states[currentState].canTransitionTo(STATE_COMPILING); + } + public boolean isCompiling() { + return currentState == STATE_COMPILING; + } + //endregion + + private void enterState(int id, boolean force) { + if (currentState == id) return; + + if (!force && !states[currentState].canTransitionTo(id)) + throw new RuntimeException("Illegal state change requested"); + + int oldState = currentState; + + states[currentState].onStateLeaving(id); + currentState = id; + states[currentState].onStateEntered(oldState); + + LOGGER.info("State transition: " + oldState + " -> " + currentState); + } + + private void enterStateAndSend(int id) { + // Shift state + enterState(id, false); + + // Notify clients to also shift states + getStateMachineStream(KEY_STATE_CHANGED).writeByte(currentState); + } + + private void enterStateOnClient(int id) { + int oldState = currentState; + + states[currentState].onClientStateLeaving(id); + currentState = id; + states[currentState].onClientStateEntered(oldState); + + LOGGER.info("Client state transition: " + oldState + " -> " + currentState); + } + + public interface StateMachineCallback { + + void onCompileStart(); + + void onCompileComplete(); + + void onSimulationComplete(int changeMask, ICSimulationContainer container); + } + + private interface State { + + //region Server-side events + default void onTick(long time) { } + + default void onTileMapChanged() { } + + default void onCompileTriggered() { } + + default void onInputRegistersChanged(int rotation, Function changeFunction) { } + + boolean canTransitionTo(int id); + + default void onStateEntered(int previousStateId) { } + + default void onStateLeaving(int nextStateId) { } + //endregion + + //region Client-side events + default void onClientStateEntered(int previousStateId) { } + + default void onClientStateLeaving(int nextStateId) { } + //endregion + } + + private class StateInitial implements State { + + @Override + public void onTileMapChanged() { + enterStateAndSend(STATE_AWAITING_COMPILE); + } + + @Override + public boolean canTransitionTo(int id) { + return id == STATE_AWAITING_COMPILE; + } + + @Override + public void onStateEntered(int previousStateId) { + compilerLog.clear(); + } + + @Override + public void onClientStateEntered(int previousStateId) { + compilerLog.clear(); + } + } + + private class StateAwaitingCompile implements State { + + @Override + public void onTick(long time) { + if (autoCompileOnChange) { + enterStateAndSend(STATE_COMPILING); + } + } + + @Override + public void onCompileTriggered() { + enterStateAndSend(STATE_COMPILING); + } + + @Override + public boolean canTransitionTo(int id) { + return id == STATE_COMPILING; + } + } + + private class StateCompiling implements State { + + private ICStepThroughAssembler assembler = null; + + @Override + public void onTick(long time) { + if (assembler == null) { + LOGGER.warn("Compiler assembler is null!"); + restartAssembly(); + return; + } + + if (!assembler.isDone()) { + assembler.stepIn(); + } + + if (assembler.isDone()) { + ICFlatMap map = assembler.result(); + assembler = null; //TODO make assemblers clearable + simulationContainer.setFlatMap(map); + enterStateAndSend(STATE_SIMULATING); + if (callback != null) callback.onCompileComplete(); + } + } + + @Override + public void onTileMapChanged() { + restartAssembly(); + } + + @Override + public boolean canTransitionTo(int id) { + return id == STATE_SIMULATING; + } + + @Override + public void onStateEntered(int previousStateId) { + restartAssembly(); + } + + @Override + public void onStateLeaving(int nextStateId) { + assembler = null; + } + + @Override + public void onClientStateEntered(int previousStateId) { + compilerLog.clear(); + } + + private void restartAssembly() { + assembler = PRFabricationEngine.instance.newStepThroughAssembler(); + assembler.setEventReceiver(compilerLog); + compilerLog.clear(); + + assembler.addTileMap(editor.getTileMap(), Collections.emptyMap()); + if (callback != null) callback.onCompileStart(); + } + } + + private class StateSimulating implements State { + + private long lastTime = -1; + + @Override + public void onTick(long time) { + + // Note: Because this is always -1 initially, 1 tick will be missed on every chunk load. Not a big deal for + // IC Workbench tile, because there are no external interaction. But FabricatedGateParts get around this + // by saving the elapsed time to NBT, and then use IChunkLoadTile hook to convert the elapsed to new lastTime. + // May be worth implementing IChunkLoadTile on workbench tile, but this is okay for now. + if (lastTime == -1) { + lastTime = time; + return; + } + + long elapsedTime = time - lastTime; + lastTime = time; + + simulationContainer.progressTime(elapsedTime); + simulationContainer.pushTime(); + propagateAndNotify(); + } + + @Override + public void onInputRegistersChanged(int rotation, Function changeFunction) { + short oldInput = simulationContainer.getInput(rotation); + short newInput = changeFunction.apply(oldInput); + LOGGER.info("oldInput: " + oldInput + ", newInput: " + newInput); + if (oldInput != newInput) { + simulationContainer.setInput(rotation, newInput); + simulationContainer.pushInputs(1 << rotation); + propagateAndNotify(); + } + } + + private void propagateAndNotify() { + simulationContainer.simulate(); + int changeMask = simulationContainer.pullOutputs(); + if (callback != null) callback.onSimulationComplete(changeMask, simulationContainer); + } + + @Override + public void onTileMapChanged() { + enterStateAndSend(STATE_AWAITING_COMPILE); //TODO enter initial if tile map was emptied + } + + @Override + public boolean canTransitionTo(int id) { + return id == STATE_AWAITING_COMPILE; + } + + @Override + public void onStateEntered(int previousStateId) { + lastTime = -1; + } + } +} diff --git a/fabrication/src/main/java/mrtjp/projectred/fabrication/editor/ICEditorToolType.java b/fabrication/src/main/java/mrtjp/projectred/fabrication/editor/ICEditorToolType.java new file mode 100644 index 000000000..ae549faf2 --- /dev/null +++ b/fabrication/src/main/java/mrtjp/projectred/fabrication/editor/ICEditorToolType.java @@ -0,0 +1,34 @@ +package mrtjp.projectred.fabrication.editor; + +import mrtjp.projectred.fabrication.editor.tools.*; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.function.Supplier; +import java.util.stream.Collectors; + +public enum ICEditorToolType { + INTERACT_TOOL(InteractTool::new), + ERASE_TOOL(EraseTool::new), + GATE_PLACER_TOOL(GatePlacerTool::new), + + WIRE_PLACER_TOOL(WirePlacerTool::new), + + ; + + private final Supplier factory; + + ICEditorToolType(Supplier factory) { + this.factory = factory; + } + + public IICEditorTool createTool() { + return factory.get(); + } + + public static ArrayList createToolList() { + return Arrays.stream(ICEditorToolType.values()) + .map(ICEditorToolType::createTool) + .collect(Collectors.toCollection(ArrayList::new)); + } +} diff --git a/fabrication/src/main/java/mrtjp/projectred/fabrication/editor/ICWorkbenchEditor.java b/fabrication/src/main/java/mrtjp/projectred/fabrication/editor/ICWorkbenchEditor.java new file mode 100644 index 000000000..ac9397199 --- /dev/null +++ b/fabrication/src/main/java/mrtjp/projectred/fabrication/editor/ICWorkbenchEditor.java @@ -0,0 +1,280 @@ +package mrtjp.projectred.fabrication.editor; + +import codechicken.lib.data.MCDataInput; +import codechicken.lib.data.MCDataOutput; +import mrtjp.fengine.TileCoord; +import mrtjp.projectred.fabrication.editor.tools.IICEditorTool; +import mrtjp.projectred.fabrication.engine.BaseTile; +import mrtjp.projectred.fabrication.engine.BaseTileMap; +import mrtjp.projectred.fabrication.engine.ICSimulationContainer; +import mrtjp.projectred.fabrication.engine.ICTileType; +import net.minecraft.nbt.CompoundTag; + +import javax.annotation.Nullable; +import java.util.*; + +import static mrtjp.projectred.fabrication.ProjectRedFabrication.LOGGER; + +public class ICWorkbenchEditor implements ICEditorStateMachine.StateMachineCallback { + + private static final int STREAM_ID_GENERAL = 0; + private static final int STREAM_ID_TILE_UPDATES = 1; + private static final int STREAM_ID_FSM = 2; + + private static final int KEY_ADD_TILE = 1; + private static final int KEY_REMOVE_TILE = 2; + private static final int KEY_TOOL = 10; + + private final IICWorkbenchEditorNetwork network; + private final BaseTileMap tileMap = new BaseTileMap(this); + private final ICEditorStateMachine stateMachine = new ICEditorStateMachine(this, this); + + private final ArrayList toolList = ICEditorToolType.createToolList(); + private final List neighborChangeList = new LinkedList<>(); + + private boolean isActive = false; + private String icName = "untitled"; + + public ICWorkbenchEditor(IICWorkbenchEditorNetwork network) { + this.network = network; + for (IICEditorTool t : toolList) t.bindEditor(this); + } + + public ArrayList getToolList() { + return toolList; + } + + public BaseTileMap getTileMap() { + return tileMap; + } + + public ICEditorStateMachine getStateMachine() { + return stateMachine; + } + + public boolean isActive() { + return isActive; + } + + //region ICWorkbenchTile utilities + public void save(CompoundTag tag) { + LOGGER.info("ICWorkbenchEditor: saving to NBT"); + tag.putBoolean("active", isActive); + tag.putString("ic_name", icName); + tileMap.save(tag); + stateMachine.save(tag); + } + + public void load(CompoundTag tag) { + LOGGER.info("ICWorkbenchEditor: reading form NBT"); + isActive = tag.getBoolean("active"); + icName = tag.getString("ic_name"); + tileMap.load(tag); + stateMachine.load(tag); + } + + public void writeDesc(MCDataOutput out) { + LOGGER.info("ICWorkbenchEditor: writing description"); + out.writeBoolean(isActive); + out.writeString(icName); + tileMap.writeDesc(out); + stateMachine.writeDesc(out); + } + + public void readDesc(MCDataInput in) { + LOGGER.info("ICWorkbenchEditor: Reading description"); + isActive = in.readBoolean(); + icName = in.readString(); + tileMap.readDesc(in); + stateMachine.readDesc(in); + } + + private void clear() { + LOGGER.info("ICWorkbenchEditor: Preparing load of initial data (Should be server only)"); + tileMap.removeAll(); + stateMachine.reset(); + } + + public void readBlueprintTagAndActivate(@Nullable CompoundTag tag) { + + clear(); + isActive = true; + if (tag == null) { + LOGGER.info("ICWorkbenchEditor: No blueprint tag found. Activating fresh session"); + return; + } + + LOGGER.info("ICWorkbenchEditor: Reading blueprint tag"); + icName = tag.getString("ic_name"); + tileMap.load(tag); + stateMachine.load(tag); + } + + public void writeBlueprintTagAndDeactivate(CompoundTag tag) { + LOGGER.info("ICWorkbenchEditor: Writing blueprint tag"); + isActive = false; + tag.putString("ic_name", icName); + tileMap.save(tag); + stateMachine.save(tag); + tag.putInt("tilecount", tileMap.getTileCount()); //TODO better tooltips + clear(); + } + //endregion + + public void readBufferedStream(MCDataInput in, int streamKey, int frameKey) { + switch (streamKey) { + case STREAM_ID_GENERAL: + readGeneralStream(in, frameKey); + break; + case STREAM_ID_TILE_UPDATES: + readTileStream(in, frameKey); + break; + case STREAM_ID_FSM: + stateMachine.readStateMachineStream(in, frameKey); + break; + default: + LOGGER.error("Unknown stream key " + streamKey); + } + } + + private void readTileStream(MCDataInput in, int frameKey) { + + TileCoord positionToUpdate = new TileCoord(in.readByte(), in.readByte(), in.readByte()); + int key = in.readUByte(); + Optional tileToUpdate = tileMap.getBaseTile(positionToUpdate); + if (!tileToUpdate.isPresent() || tileToUpdate.get().getTileType().getID() != frameKey) { + LOGGER.error("Tile Update error: No tile with id " + frameKey + " at position " + positionToUpdate + ". Reading into temporary tile"); + BaseTile tmp = ICTileType.createFromId(frameKey); + if (tmp == null) { + LOGGER.error("Unknown tile id " + frameKey + " in tile update stream"); + } else { + tmp.read(in, key); + } + return; + } + tileToUpdate.get().read(in, key); + } + + private void readGeneralStream(MCDataInput in, int frameKey) { + switch (frameKey) { + case KEY_ADD_TILE: + BaseTile tile = ICTileType.createFromId(in.readUByte()); //TODO check if not null? + tileMap.addTile(new TileCoord(in.readByte(), in.readByte(), in.readByte()), tile); + tile.readDesc(in); + break; + case KEY_REMOVE_TILE: + tileMap.removeTile(new TileCoord(in.readByte(), in.readByte(), in.readByte())); //TODO check if removed? + break; + case KEY_TOOL: + toolList.get(in.readUByte()).readPacket(in); + break; + default: + LOGGER.error("Unknown key " + frameKey + " in general stream"); + } + } + + public void tick() { + + // Alert neighbors of changes if necessary + if (!neighborChangeList.isEmpty()) { + Queue changesRemaining = new LinkedList<>(neighborChangeList); + neighborChangeList.clear(); + + Set tilesNotified = new HashSet<>(); + TileCoord next = changesRemaining.poll(); + while (next != null) { + if (!tilesNotified.contains(next)) { + tilesNotified.add(next); + Optional tile = tileMap.getBaseTile(next); + tile.ifPresent(BaseTile::onNeighborChanged); + } + next = changesRemaining.poll(); + } + } + + // Run compiler or simulator + if (!network.isClientSide()) stateMachine.onTick(network.getGameTime()); + } + + public MCDataOutput getToolStream(IICEditorTool tool) { + MCDataOutput out = network.getBufferedStream(STREAM_ID_GENERAL, KEY_TOOL); + out.writeByte(tool.getToolType().ordinal()); + return out; + } + + public MCDataOutput getTileStream(BaseTile tile, int key) { + // Use tile ID as frame key + MCDataOutput out = network.getBufferedStream(STREAM_ID_TILE_UPDATES, tile.getTileType().getID()); + out.writeByte(tile.getPos().x).writeByte(tile.getPos().y).writeByte(tile.getPos().z); + out.writeByte(key); + return out; + } + + public MCDataOutput getStateMachineStream(int key) { + return network.getBufferedStream(STREAM_ID_FSM, key); + } + + public void addTile(BaseTile tile, TileCoord pos) { + if (network.isClientSide()) throw new RuntimeException("Tiles can only be added server-side"); + + if (!tileMap.addTile(pos, tile)) { + LOGGER.error("Failed to add tile to pos " + pos); + return; + } + tile.onAdded(); + + // Send the new tile to clients + MCDataOutput out = network.getBufferedStream(STREAM_ID_GENERAL, KEY_ADD_TILE); + out.writeByte(tile.getTileType().getID()); + out.writeByte(pos.x).writeByte(pos.y).writeByte(pos.z); + tile.writeDesc(out); + + markTileChange(); + } + + public void removeTile(TileCoord pos) { + if (network.isClientSide()) throw new RuntimeException("Tiles can only be removed server-side"); + + Optional tileToRemove = tileMap.getBaseTile(pos); + if (!tileToRemove.isPresent()) { + LOGGER.error("No tile present to remove at pos " + pos); + return; + } + tileToRemove.get().onRemoved(); + tileMap.removeTile(pos); + + // Send the tile removed action to clients + MCDataOutput out = network.getBufferedStream(STREAM_ID_GENERAL, KEY_REMOVE_TILE); + out.writeByte(pos.x).writeByte(pos.y).writeByte(pos.z); + + markTileChange(); + } + + public void queueNeighborChange(TileCoord pos) { + neighborChangeList.add(pos); + } + + public void markTileChange() { + network.markSave(); + stateMachine.onTileMapChanged(); + } + + //region State Machine callbacks + @Override + public void onCompileStart() { + LOGGER.info("Compiling..."); + } + + @Override + public void onCompileComplete() { + LOGGER.info("Compilation complete"); + } + + @Override + public void onSimulationComplete(int changeMask, ICSimulationContainer container) { + for (BaseTileMap.BaseTileEntry entry : tileMap.getBaseTileEntries()) { + entry.getTile().onSimRegistersChanged(changeMask, container); + } + } + //endregion +} diff --git a/fabrication/src/main/java/mrtjp/projectred/fabrication/editor/IICWorkbenchEditorNetwork.java b/fabrication/src/main/java/mrtjp/projectred/fabrication/editor/IICWorkbenchEditorNetwork.java new file mode 100644 index 000000000..894ec3f70 --- /dev/null +++ b/fabrication/src/main/java/mrtjp/projectred/fabrication/editor/IICWorkbenchEditorNetwork.java @@ -0,0 +1,40 @@ +package mrtjp.projectred.fabrication.editor; + +import codechicken.lib.data.MCDataOutput; + +/** + * Interface implemented on an IC Workbench tile containing network-related methods that the editor uses + * to send data to and from clients that have the editor open. + */ +public interface IICWorkbenchEditorNetwork { + + /** + * Returns a buffered output stream that can be freely written. It is automatically + * sent at regular intervals. If client, packet is sent to server. If server, packets are + * sent to all clients watching the editor UI. + * + * The stream is always terminated with a frame of value 255 before being sent. The other side + * must read through the stream until a terminator frame byte of 255 is read. + * + * @param streamKey Identifier for the buffered stream (between 0 and 255) + * @param frameKey Frame byte for each group of data. Cannot be 255, as that is used for end-of-packet terminator. + * @return The buffered stream + */ + MCDataOutput getBufferedStream(int streamKey, int frameKey); + + /** + * @return True if this is the client + */ + boolean isClientSide(); + + /** + * Called by the editor when something inside this editor has changed that would cause the tile's + * NBT data to change + */ + void markSave(); + + /** + * @return The world game time + */ + long getGameTime(); +} diff --git a/fabrication/src/main/java/mrtjp/projectred/fabrication/editor/tools/BaseICEditorTool.java b/fabrication/src/main/java/mrtjp/projectred/fabrication/editor/tools/BaseICEditorTool.java new file mode 100644 index 000000000..660c09c05 --- /dev/null +++ b/fabrication/src/main/java/mrtjp/projectred/fabrication/editor/tools/BaseICEditorTool.java @@ -0,0 +1,54 @@ +package mrtjp.projectred.fabrication.editor.tools; + +import codechicken.lib.vec.Vector3; +import mrtjp.fengine.TileCoord; +import mrtjp.projectred.fabrication.editor.ICWorkbenchEditor; +import net.minecraft.network.chat.Component; +import net.minecraftforge.api.distmarker.Dist; +import net.minecraftforge.api.distmarker.OnlyIn; + +import java.util.List; + +public abstract class BaseICEditorTool implements IICEditorTool { + + protected ICWorkbenchEditor editor; + + @Override + public void bindEditor(ICWorkbenchEditor editor) { + this.editor = editor; + } + + @Override + @OnlyIn(Dist.CLIENT) + public void buildTooltip(Vector3 mousePosition, boolean isFirstHit, List tooltip) { + + if (!isFirstHit) return; + + TileCoord pos = IICEditorTool.toNearestPosition(mousePosition); + editor.getTileMap().getBaseTile(pos).ifPresent(tile -> tile.buildToolTip(tooltip)); + } + + protected boolean isInBody(TileCoord coord) { + TileCoord minBounds = editor.getTileMap().getMinBounds(); + TileCoord maxBounds = editor.getTileMap().getMaxBounds(); + + return coord.x > minBounds.x && coord.x < maxBounds.x && + coord.y > minBounds.y && coord.y < maxBounds.y && + coord.z > minBounds.z && coord.z < maxBounds.z; + } + + protected boolean isOnIOEdge(TileCoord coord) { + TileCoord minBounds = editor.getTileMap().getMinBounds(); + TileCoord maxBounds = editor.getTileMap().getMaxBounds(); + + if (coord.y != 0) return false; + + int edges = 0; + if (coord.x == minBounds.x) edges++; + if (coord.x == maxBounds.x) edges++; + if (coord.z == minBounds.z) edges++; + if (coord.z == maxBounds.z) edges++; + + return edges == 1; + } +} diff --git a/fabrication/src/main/java/mrtjp/projectred/fabrication/editor/tools/EraseTool.java b/fabrication/src/main/java/mrtjp/projectred/fabrication/editor/tools/EraseTool.java new file mode 100644 index 000000000..a00f5f7ab --- /dev/null +++ b/fabrication/src/main/java/mrtjp/projectred/fabrication/editor/tools/EraseTool.java @@ -0,0 +1,125 @@ +package mrtjp.projectred.fabrication.editor.tools; + +import codechicken.lib.colour.EnumColour; +import codechicken.lib.data.MCDataInput; +import codechicken.lib.data.MCDataOutput; +import codechicken.lib.render.CCRenderState; +import codechicken.lib.vec.Vector3; +import com.mojang.blaze3d.vertex.PoseStack; +import mrtjp.fengine.TileCoord; +import mrtjp.projectred.fabrication.editor.ICEditorToolType; +import mrtjp.projectred.fabrication.gui.ICRenderTypes; +import net.minecraft.client.Minecraft; +import net.minecraft.client.renderer.MultiBufferSource; +import net.minecraftforge.api.distmarker.Dist; +import net.minecraftforge.api.distmarker.OnlyIn; +import org.lwjgl.glfw.GLFW; + +import static mrtjp.projectred.fabrication.editor.tools.IICEditorTool.toNearestPosition; + +public class EraseTool extends BaseICEditorTool { + + private final Vector3 initialMouseDown = new Vector3(); + private boolean leftMouseDown; + + @Override + public ICEditorToolType getToolType() { + return ICEditorToolType.ERASE_TOOL; + } + + @Override + public void readPacket(MCDataInput input) { + + TileCoord start = new TileCoord(input.readByte(), input.readByte(), input.readByte()); + TileCoord end = new TileCoord(input.readByte(), input.readByte(), input.readByte()); + + TileCoord min = start.min(end); + TileCoord max = start.max(end); + + // Delete all tiles in range + for (int x = min.x; x <= max.x; x++) { + for (int z = min.z; z <= max.z; z++) { + TileCoord pos = new TileCoord(x, start.y, z); + if (editor.getTileMap().getBaseTile(pos).isPresent()) editor.removeTile(pos); + } + } + } + + private void executeTool(Vector3 startMouseDown, Vector3 endMouseDown) { + MCDataOutput out = editor.getToolStream(this); + + TileCoord start = toNearestPosition(startMouseDown); + TileCoord end = toNearestPosition(endMouseDown); + + out.writeByte(start.x).writeByte(start.y).writeByte(start.z); + out.writeByte(end.x).writeByte(end.y).writeByte(end.z); + } + + @Override + public boolean toolStart(Vector3 mousePosition, int glfwMouseButton) { + if (glfwMouseButton == GLFW.GLFW_MOUSE_BUTTON_LEFT) { + leftMouseDown = true; + initialMouseDown.set(mousePosition); + return true; + } + return false; + } + + @Override + public boolean toolReleased(Vector3 mousePosition, int glfwMouseButton) { + if (glfwMouseButton == GLFW.GLFW_MOUSE_BUTTON_LEFT && leftMouseDown) { + leftMouseDown = false; + executeTool(initialMouseDown, mousePosition); + return true; + } + return false; + } + + @Override + public void toolLayerChanged(int previousLayer, int newLayer) { + if (leftMouseDown) { + initialMouseDown.y = newLayer; + } + } + + @Override + public boolean toolDragged(Vector3 mousePosition, Vector3 delta, int glfwMouseButton) { + if (glfwMouseButton == GLFW.GLFW_MOUSE_BUTTON_LEFT) { + return leftMouseDown; + } + return false; + } + + @Override + public boolean toolScrolled(Vector3 mousePosition, double scroll) { + return false; + } + + @Override + public void toolCanceled(Vector3 mousePosition) { + leftMouseDown = false; + } + + @Override + public void toolActivated() { + leftMouseDown = false; + } + + @Override + public void toolDeactivated() { + leftMouseDown = false; + } + + @Override + @OnlyIn (Dist.CLIENT) + public void renderOverlay(Vector3 mousePosition, boolean isFirstHit, CCRenderState ccrs, MultiBufferSource getter, PoseStack matrixStack) { + Vector3 a = leftMouseDown ? initialMouseDown : mousePosition; + Vector3 b = mousePosition; + + ccrs.reset(); + ccrs.bind(ICRenderTypes.selectionRenderType, Minecraft.getInstance().renderBuffers().bufferSource(), matrixStack); + ccrs.baseColour = EnumColour.PINK.rgba(leftMouseDown ? 200 : 32); + + ICRenderTypes.renderSelection(ccrs, a, b, 3 / 16D, 2 / 16D); + } +} diff --git a/fabrication/src/main/java/mrtjp/projectred/fabrication/editor/tools/GatePlacerTool.java b/fabrication/src/main/java/mrtjp/projectred/fabrication/editor/tools/GatePlacerTool.java new file mode 100644 index 000000000..6ed15bd98 --- /dev/null +++ b/fabrication/src/main/java/mrtjp/projectred/fabrication/editor/tools/GatePlacerTool.java @@ -0,0 +1,224 @@ +package mrtjp.projectred.fabrication.editor.tools; + +import codechicken.lib.data.MCDataInput; +import codechicken.lib.data.MCDataOutput; +import codechicken.lib.math.MathHelper; +import codechicken.lib.render.CCRenderState; +import codechicken.lib.vec.Translation; +import codechicken.lib.vec.Vector3; +import com.mojang.blaze3d.vertex.PoseStack; +import mrtjp.fengine.TileCoord; +import mrtjp.projectred.fabrication.editor.GatePlacementType; +import mrtjp.projectred.fabrication.editor.ICEditorToolType; +import mrtjp.projectred.fabrication.engine.gates.GateTile; +import mrtjp.projectred.fabrication.engine.gates.ICGateTileType; +import mrtjp.projectred.fabrication.gui.ICRenderTypes; +import mrtjp.projectred.integration.client.GateModelRenderer; +import net.minecraft.client.Minecraft; +import net.minecraft.client.renderer.LightTexture; +import net.minecraft.client.renderer.MultiBufferSource; +import net.minecraft.network.chat.Component; +import net.minecraftforge.api.distmarker.Dist; +import net.minecraftforge.api.distmarker.OnlyIn; +import org.lwjgl.glfw.GLFW; + +import java.util.List; + +import static mrtjp.projectred.fabrication.editor.tools.IICEditorTool.toNearestPosition; + +public class GatePlacerTool extends BaseICEditorTool { + + private final Vector3 initialMouseDown = new Vector3(); + private boolean leftMouseDown; + + // Tool config + private boolean overwrite = false; + private ICGateTileType gateType = ICGateTileType.OR; + + public ICGateTileType getGateType() { + return gateType; + } + + public void setGateType(ICGateTileType gateType) { + this.gateType = gateType; + leftMouseDown = false; + } + + @Override + public ICEditorToolType getToolType() { + return ICEditorToolType.GATE_PLACER_TOOL; + } + + @Override + public void readPacket(MCDataInput input) { + + boolean overwrite = input.readBoolean(); + ICGateTileType gateType = ICGateTileType.values()[input.readUByte()]; + int x = input.readByte(); + int y = input.readByte(); + int z = input.readByte(); + int r = input.readUByte(); + + TileCoord pos = new TileCoord(x, y, z); + if (!editor.getTileMap().isInBounds(pos)) return; + if (editor.getTileMap().getTile(pos).isPresent()) { + if (!overwrite) return; + editor.getTileMap().removeTile(pos); + } + + GateTile t = (GateTile) gateType.tileType.create(); + t.preparePlacement(r); + editor.addTile(t, pos); + } + + private void sendPlaceGatePacket(TileCoord pos, int r) { + MCDataOutput out = editor.getToolStream(this); + out.writeBoolean(overwrite); + out.writeByte(gateType.ordinal()); + + out.writeByte(pos.x).writeByte(pos.y).writeByte(pos.z); + out.writeByte(r); + } + + private boolean isValidStart(TileCoord pos) { + + if (!editor.getTileMap().isInBounds(pos)) return false; + if (editor.getTileMap().getTile(pos).isPresent() && !overwrite) return false; + + if (gateType.placementType == GatePlacementType.INTERNAL && !isInBody(pos)) return false; + if (gateType.placementType == GatePlacementType.IO_EDGE && !isOnIOEdge(pos)) return false; + + return true; + } + + @Override + public boolean toolStart(Vector3 mousePosition, int glfwMouseButton) { + if (glfwMouseButton == GLFW.GLFW_MOUSE_BUTTON_LEFT) { + TileCoord start = toNearestPosition(mousePosition); + if (isValidStart(start)) { + leftMouseDown = true; + initialMouseDown.set(mousePosition); + return true; + } + } + return false; + } + + @Override + public boolean toolReleased(Vector3 mousePosition, int glfwMouseButton) { + if (glfwMouseButton == GLFW.GLFW_MOUSE_BUTTON_LEFT && leftMouseDown) { + leftMouseDown = false; + TileCoord posA = toNearestPosition(initialMouseDown); + sendPlaceGatePacket(posA, getPlacementRotation(initialMouseDown, mousePosition)); + return true; + } + return false; + } + + @Override + public boolean toolDragged(Vector3 mousePosition, Vector3 delta, int glfwMouseButton) { + if (glfwMouseButton == GLFW.GLFW_MOUSE_BUTTON_LEFT) { + return leftMouseDown; + } + return false; + } + + @Override + public boolean toolScrolled(Vector3 mousePosition, double scroll) { + return false; + } + + @Override + public void toolLayerChanged(int previousLayer, int newLayer) { + if (leftMouseDown) { + initialMouseDown.y = newLayer; + } + } + + @Override + public void toolCanceled(Vector3 mousePosition) { + leftMouseDown = false; + } + + @Override + public void toolActivated() { + leftMouseDown = false; + } + + @Override + public void toolDeactivated() { + leftMouseDown = false; + } + + @Override + @OnlyIn(Dist.CLIENT) + public void renderOverlay(Vector3 mousePosition, boolean isFirstHit, CCRenderState ccrs, MultiBufferSource getter, PoseStack matrixStack) { + + if (!isFirstHit) return; + + ccrs.reset(); + ccrs.brightness = LightTexture.pack(15, 15); + ccrs.bind(ICRenderTypes.layersRenderType, Minecraft.getInstance().renderBuffers().bufferSource(), matrixStack); + + if (!leftMouseDown) { + ccrs.alphaOverride = 64; + TileCoord mousePos = toNearestPosition(mousePosition); + int rot = getHoverRotation(mousePosition); + if (isValidStart(mousePos)) renderHover(mousePos, rot, ccrs); + } else { + ccrs.alphaOverride = 128; + TileCoord placementPos = toNearestPosition(initialMouseDown); + int rot = getPlacementRotation(initialMouseDown, mousePosition); + renderHover(placementPos, rot, ccrs); + } + } + + @Override + @OnlyIn(Dist.CLIENT) + public void buildTooltip(Vector3 mousePosition, boolean isFirstHit, List tooltip) { + super.buildTooltip(mousePosition, isFirstHit, tooltip); + } + + public void renderHover(TileCoord pos, int r, CCRenderState ccrs) { + GateModelRenderer.instance().renderInventory(ccrs, null, gateType.renderIndex, r, new Translation(pos.x, pos.y, pos.z)); + } + + private int getHoverRotation(Vector3 hoverPos) { + if (gateType.placementType == GatePlacementType.IO_EDGE) { + return getEdgeRotation(toNearestPosition(hoverPos)); + } + return 0; + } + + private int getPlacementRotation(Vector3 initialPos, Vector3 mousePos) { + if (gateType.placementType == GatePlacementType.IO_EDGE) { + return getEdgeRotation(toNearestPosition(initialPos)); + } + // TODO this can be done by comparing x and z components of the initial -> mouse vector + + Vector3 i = initialPos.copy().floor().add(0.5); // Move initial to center of its closest block space + Vector3 a = mousePos.copy().subtract(i); + a.y = 0; // Project onto XY + Vector3 b = new Vector3(1, 0, 0); + + if (a.mag() < 1.2) return 0; // Don't rotate if mouse is too close + + double angle = b.angle(a); // Angle between 0 - pi + if (a.z > 0) angle = (2 * MathHelper.pi) - angle; // Full circular angle 0 - 2*pi + angle = (angle + 1 / 4D * MathHelper.pi) % (2 * MathHelper.pi); // Add 45 degrees + angle = 2 * MathHelper.pi - angle; // Invert, because rotations are counter-clockwise + + // Convert to rotation + double percentage = angle / (2 * MathHelper.pi); + return ((int) (4 * percentage) + 2) % 4; + } + + private int getEdgeRotation(TileCoord pos) { + if (pos.z == editor.getTileMap().getMinBounds().z) return 0; + if (pos.x == editor.getTileMap().getMaxBounds().x) return 1; + if (pos.z == editor.getTileMap().getMaxBounds().z) return 2; + if (pos.x == editor.getTileMap().getMinBounds().x) return 3; + + return 0; + } +} diff --git a/fabrication/src/main/java/mrtjp/projectred/fabrication/editor/tools/IICEditorTool.java b/fabrication/src/main/java/mrtjp/projectred/fabrication/editor/tools/IICEditorTool.java new file mode 100644 index 000000000..2ac55c8bb --- /dev/null +++ b/fabrication/src/main/java/mrtjp/projectred/fabrication/editor/tools/IICEditorTool.java @@ -0,0 +1,80 @@ +package mrtjp.projectred.fabrication.editor.tools; + +import codechicken.lib.data.MCDataInput; +import codechicken.lib.render.CCRenderState; +import codechicken.lib.vec.Cuboid6; +import codechicken.lib.vec.Vector3; +import com.mojang.blaze3d.vertex.PoseStack; +import mrtjp.fengine.TileCoord; +import mrtjp.projectred.fabrication.editor.ICEditorToolType; +import mrtjp.projectred.fabrication.editor.ICWorkbenchEditor; +import net.minecraft.client.renderer.MultiBufferSource; +import net.minecraft.network.chat.Component; +import net.minecraftforge.api.distmarker.Dist; +import net.minecraftforge.api.distmarker.OnlyIn; + +import java.util.List; + +public interface IICEditorTool { + + ICEditorToolType getToolType(); + + void bindEditor(ICWorkbenchEditor editor); + + void readPacket(MCDataInput input); + + boolean toolStart(Vector3 mousePosition, int glfwMouseButton); + + boolean toolReleased(Vector3 mousePosition, int glfwMouseButton); + + boolean toolDragged(Vector3 mousePosition, Vector3 delta, int glfwMouseButton); + + boolean toolScrolled(Vector3 mousePosition, double scroll); + + void toolLayerChanged(int previousLayer, int newLayer); + + void toolCanceled(Vector3 mousePosition); + + void toolActivated(); + + void toolDeactivated(); + + @OnlyIn(Dist.CLIENT) + void renderOverlay(Vector3 mousePosition, boolean isFirstHit, CCRenderState ccrs, MultiBufferSource getter, PoseStack matrixStack); + + @OnlyIn(Dist.CLIENT) + void buildTooltip(Vector3 mousePosition, boolean isFirstHit, List tooltip); + + static TileCoord toNearestPosition(Vector3 v) { + return new TileCoord((int) Math.floor(v.x), (int) Math.floor(v.y), (int) Math.floor(v.z)); + } + + static boolean isSamePosition(Vector3 a, Vector3 b) { + return Math.floor(a.x) == Math.floor(b.x) && + Math.floor(a.y) == Math.floor(b.y) && + Math.floor(a.z) == Math.floor(b.z); + } + + static Cuboid6 toNearestCuboid(Vector3 v) { + return new Cuboid6(v.copy().floor(), v.copy().ceil()); + } + + static Cuboid6 toSelectionCuboid(Vector3 a, Vector3 b) { + return toNearestCuboid(a).enclose(toNearestCuboid(b)); + } + + /** + * Converts Cuboid from internal tile space to world space + * + * @param pos Position of the tile + * @param c Internal cuboid within bounds [0,0,0 -> 6,16,16] + * @return Cuboid in world space + */ + static Cuboid6 internalToGlobalCuboid(TileCoord pos, Cuboid6 c) { + Cuboid6 box = c.copy(); + box.min.multiply(1/16D); + box.max.multiply(1/16D); + box.add(pos.x, pos.y, pos.z); + return box; + } +} diff --git a/fabrication/src/main/java/mrtjp/projectred/fabrication/editor/tools/InteractTool.java b/fabrication/src/main/java/mrtjp/projectred/fabrication/editor/tools/InteractTool.java new file mode 100644 index 000000000..dfc012aa0 --- /dev/null +++ b/fabrication/src/main/java/mrtjp/projectred/fabrication/editor/tools/InteractTool.java @@ -0,0 +1,218 @@ +package mrtjp.projectred.fabrication.editor.tools; + +import codechicken.lib.colour.EnumColour; +import codechicken.lib.data.MCDataInput; +import codechicken.lib.render.BlockRenderer; +import codechicken.lib.render.CCRenderState; +import codechicken.lib.render.RenderUtils; +import codechicken.lib.vec.Cuboid6; +import codechicken.lib.vec.Matrix4; +import codechicken.lib.vec.Vector3; +import com.mojang.blaze3d.vertex.PoseStack; +import mrtjp.fengine.TileCoord; +import mrtjp.projectred.fabrication.editor.ICEditorToolType; +import mrtjp.projectred.fabrication.engine.BaseTile; +import mrtjp.projectred.fabrication.gui.ICRenderTypes; +import net.minecraft.client.Minecraft; +import net.minecraft.client.renderer.MultiBufferSource; +import net.minecraft.network.chat.Component; +import net.minecraftforge.api.distmarker.Dist; +import net.minecraftforge.api.distmarker.OnlyIn; +import org.lwjgl.glfw.GLFW; + +import java.util.List; +import java.util.Optional; + +import static mrtjp.projectred.fabrication.editor.tools.IICEditorTool.*; + +public class InteractTool extends BaseICEditorTool { + + private final Vector3 initialMouseDown = new Vector3(); + private boolean leftMouseDown; + + @Override + public ICEditorToolType getToolType() { + return ICEditorToolType.INTERACT_TOOL; + } + + @Override + public void readPacket(MCDataInput input) { + + TileCoord pos = new TileCoord(input.readByte(), input.readByte(), input.readByte()); + byte b = input.readByte(); + + int z = b & 0x7F; + boolean leftClick = (b & 0x80) != 0; + + Optional tile = editor.getTileMap().getBaseTile(pos); + tile.ifPresent(t -> { + if (leftClick) + t.onInteractionZoneClicked(z); + else + t.onInteractionZoneActivated(z); + }); + } + + private void executeTool(Vector3 startMouseDown, Vector3 endMouseDown) { + TileCoord start = toNearestPosition(startMouseDown); + TileCoord end = toNearestPosition(endMouseDown); + if (!start.equals(end)) return; + + InteractionZone zone = getTargetInteractionZone(endMouseDown); + if (zone == null) return; + + byte b = (byte) ((zone.index & 0x7F) | 0x80); //TODO right clicky + + editor.getToolStream(this) + .writeByte(start.x).writeByte(start.y).writeByte(start.z) + .writeByte(b); + } + + @Override + public boolean toolStart(Vector3 mousePosition, int glfwMouseButton) { + if (glfwMouseButton == GLFW.GLFW_MOUSE_BUTTON_LEFT) { + leftMouseDown = true; + initialMouseDown.set(mousePosition); + return true; + } + return false; + } + + @Override + public boolean toolReleased(Vector3 mousePosition, int glfwMouseButton) { + if (glfwMouseButton == GLFW.GLFW_MOUSE_BUTTON_LEFT && leftMouseDown) { + leftMouseDown = false; + executeTool(initialMouseDown, mousePosition); + return true; + } + return false; + } + + @Override + public boolean toolDragged(Vector3 mousePosition, Vector3 delta, int glfwMouseButton) { + if (glfwMouseButton == GLFW.GLFW_MOUSE_BUTTON_LEFT) { + return leftMouseDown; + } + return false; + } + + @Override + public boolean toolScrolled(Vector3 mousePosition, double scroll) { + return false; + } + + @Override + public void toolLayerChanged(int previousLayer, int newLayer) { + if (leftMouseDown) { + initialMouseDown.y = newLayer; + } + } + + @Override + public void toolCanceled(Vector3 mousePosition) { + leftMouseDown = false; + } + + @Override + public void toolActivated() { + leftMouseDown = false; + } + + @Override + public void toolDeactivated() { + leftMouseDown = false; + } + + @Override + @OnlyIn(Dist.CLIENT) + public void buildTooltip(Vector3 mousePosition, boolean isFirstHit, List tooltip) { + + if (!isFirstHit) return; + + InteractionZone zone = getTargetInteractionZone(mousePosition); + if (zone == null) { + super.buildTooltip(mousePosition, isFirstHit, tooltip); + return; + } + + TileCoord pos = toNearestPosition(mousePosition); + editor.getTileMap().getBaseTile(pos).ifPresent(tile -> + tile.buildInteractionToolTip(tooltip, zone.index)); + } + + @Override + @OnlyIn(Dist.CLIENT) + public void renderOverlay(Vector3 mousePosition, boolean isFirstHit, CCRenderState ccrs, MultiBufferSource getter, PoseStack matrixStack) { + + if (!isFirstHit) return; + + // Selection box for entire tile area + Vector3 a = leftMouseDown ? initialMouseDown : mousePosition; + Vector3 b = mousePosition; + int alpha = leftMouseDown ? isSamePosition(a, b) ? 255 : 128 : 32; + + ccrs.reset(); + ccrs.bind(ICRenderTypes.selectionRenderType, Minecraft.getInstance().renderBuffers().bufferSource(), matrixStack); + ccrs.baseColour = EnumColour.LIGHT_BLUE.rgba(alpha); + +// ICRenderTypes.renderSelection(ccrs, a, a, 3 / 16D, 2 / 16D); // TODO Selection box that sits AROUND the tile + + // Render tile interaction zone + TileCoord coord = toNearestPosition(b); + editor.getTileMap().getBaseTile(coord).ifPresent(tile -> { + List zones = tile.getInteractionZones(); + + Cuboid6 currentZoneBox = null; + + // Render the interaction zone overlay + for (Cuboid6 zone : zones) { + Cuboid6 box = internalToGlobalCuboid(coord, zone); + + boolean isInitialInZone = box.contains(a); + boolean isCurrentInZone = box.contains(b); + + if (isCurrentInZone) currentZoneBox = box; + + ccrs.baseColour = EnumColour.LIGHT_BLUE.rgba(leftMouseDown && isInitialInZone ? isCurrentInZone ? 255 : 128 : 32); + BlockRenderer.renderCuboid(ccrs, box, 1); + } + + // Render bounding box for interaction zone + if (currentZoneBox != null) { + RenderUtils.bufferHitBox(new Matrix4(matrixStack.last().pose()), Minecraft.getInstance().renderBuffers().bufferSource(), currentZoneBox); + } + }); + } + + private TileCoord getTargetTileCoord(Vector3 mousePosition) { + return toNearestPosition(leftMouseDown ? initialMouseDown : mousePosition); + } + + private InteractionZone getTargetInteractionZone(Vector3 mousePosition) { + TileCoord coord = getTargetTileCoord(mousePosition); + BaseTile tile = editor.getTileMap().getBaseTile(coord).orElse(null); + + if (tile == null) return null; + + int i = 0; + for (Cuboid6 zone : tile.getInteractionZones()) { + Cuboid6 box = internalToGlobalCuboid(coord, zone); + if (box.contains(mousePosition)) return new InteractionZone(coord, zone, i); + i++; + } + + return null; + } + + private static class InteractionZone { + public final TileCoord tileCoord; + public final Cuboid6 bounds; + public final int index; + + public InteractionZone(TileCoord tileCoord, Cuboid6 bounds, int index) { + this.tileCoord = tileCoord; + this.bounds = bounds; + this.index = index; + } + } +} diff --git a/fabrication/src/main/java/mrtjp/projectred/fabrication/editor/tools/WirePlacerTool.java b/fabrication/src/main/java/mrtjp/projectred/fabrication/editor/tools/WirePlacerTool.java new file mode 100644 index 000000000..6a11f0847 --- /dev/null +++ b/fabrication/src/main/java/mrtjp/projectred/fabrication/editor/tools/WirePlacerTool.java @@ -0,0 +1,215 @@ +package mrtjp.projectred.fabrication.editor.tools; + +import codechicken.lib.data.MCDataInput; +import codechicken.lib.data.MCDataOutput; +import codechicken.lib.render.CCRenderState; +import codechicken.lib.vec.Translation; +import codechicken.lib.vec.Vector3; +import com.mojang.blaze3d.vertex.PoseStack; +import mrtjp.fengine.TileCoord; +import mrtjp.projectred.fabrication.editor.ICEditorToolType; +import mrtjp.projectred.fabrication.engine.IRotatableICTile; +import mrtjp.projectred.fabrication.engine.wires.ICWireTileType; +import mrtjp.projectred.fabrication.engine.wires.WireTile; +import mrtjp.projectred.fabrication.gui.ICRenderTypes; +import mrtjp.projectred.transmission.client.WireModelRenderer; +import net.minecraft.client.Minecraft; +import net.minecraft.client.renderer.LightTexture; +import net.minecraft.client.renderer.MultiBufferSource; +import net.minecraftforge.api.distmarker.Dist; +import net.minecraftforge.api.distmarker.OnlyIn; +import org.lwjgl.glfw.GLFW; + +import java.util.HashSet; +import java.util.LinkedList; +import java.util.List; +import java.util.Set; + +import static mrtjp.projectred.fabrication.editor.tools.IICEditorTool.toNearestPosition; + +public class WirePlacerTool extends BaseICEditorTool { + + private final Vector3 initialMouseDown = new Vector3(); + private final List selectedPositionsList = new LinkedList<>(); + private final Set selectedPositions = new HashSet<>(); + + private boolean leftMouseDown; + + // Tool config + private boolean overwrite = false; + private ICWireTileType wireType = ICWireTileType.RED_ALLOY; + + public void setWireType(ICWireTileType wireType) { + this.wireType = wireType; + } + + public ICWireTileType getWireType() { + return wireType; + } + + @Override + public ICEditorToolType getToolType() { + return ICEditorToolType.WIRE_PLACER_TOOL; + } + + @Override + public void readPacket(MCDataInput in) { + + boolean overwrite = in.readBoolean(); + ICWireTileType wireType = ICWireTileType.values()[in.readUByte()]; + int numPositions = in.readUByte(); + int y = in.readByte(); + + for (int i = 0; i < numPositions; i++) { + TileCoord pos = new TileCoord(in.readByte(), y, in.readByte()); + + if (editor.getTileMap().getTile(pos).isPresent()) { + if (!overwrite) continue; + editor.removeTile(pos); + } + + WireTile tile = (WireTile) wireType.tileType.create(); + editor.addTile(tile, pos); + } + } + + protected void sendPlaceWires() { + if (selectedPositionsList.isEmpty()) return; + + MCDataOutput out = editor.getToolStream(this); + out.writeBoolean(overwrite); + out.writeByte(wireType.ordinal()); + out.writeByte(selectedPositionsList.size()); + out.writeByte(selectedPositionsList.get(0).y); // All on same layer + + for (TileCoord t : selectedPositionsList) { + out.writeByte(t.x).writeByte(t.z); + } + } + + protected void addToSelection(Vector3 mousePosition) { + TileCoord pos = toNearestPosition(mousePosition); + if (!selectedPositions.contains(pos) && !editor.getTileMap().getBaseTile(pos).isPresent()) { + selectedPositions.add(pos); + selectedPositionsList.add(pos); + } + } + + @Override + public boolean toolStart(Vector3 mousePosition, int glfwMouseButton) { + if (glfwMouseButton == GLFW.GLFW_MOUSE_BUTTON_LEFT) { + leftMouseDown = true; + initialMouseDown.set(mousePosition); + addToSelection(mousePosition); + return true; + } + return false; + } + + @Override + public boolean toolReleased(Vector3 mousePosition, int glfwMouseButton) { + if (glfwMouseButton == GLFW.GLFW_MOUSE_BUTTON_LEFT && leftMouseDown) { + addToSelection(mousePosition); + sendPlaceWires(); + + leftMouseDown = false; + selectedPositions.clear(); + selectedPositionsList.clear(); + + return true; + } + return false; + } + + @Override + public boolean toolDragged(Vector3 mousePosition, Vector3 delta, int glfwMouseButton) { + if (glfwMouseButton == GLFW.GLFW_MOUSE_BUTTON_LEFT && leftMouseDown) { + addToSelection(mousePosition); + return true; + } + return false; + } + + @Override + public boolean toolScrolled(Vector3 mousePosition, double scroll) { + return false; + } + + @Override + public void toolLayerChanged(int previousLayer, int newLayer) { + if (leftMouseDown) { + int diff = newLayer - previousLayer; + + // Shift entire selection to the new layer + initialMouseDown.y += diff; + + List oldSelection = new LinkedList<>(selectedPositionsList); + selectedPositions.clear(); + selectedPositionsList.clear(); + + for (TileCoord t : oldSelection) { + TileCoord newPos = t.add(0, diff, 0); + selectedPositions.add(newPos); + selectedPositionsList.add(newPos); + } + } + } + + @Override + public void toolCanceled(Vector3 mousePosition) { + leftMouseDown = false; + selectedPositions.clear(); + selectedPositionsList.clear(); + } + + @Override + public void toolActivated() { + leftMouseDown = false; + selectedPositions.clear(); + selectedPositionsList.clear(); + } + + @Override + public void toolDeactivated() { + leftMouseDown = false; + selectedPositions.clear(); + selectedPositionsList.clear(); + } + + @Override + @OnlyIn(Dist.CLIENT) + public void renderOverlay(Vector3 mousePosition, boolean isFirstHit, CCRenderState ccrs, MultiBufferSource getter, PoseStack matrixStack) { + + if (leftMouseDown) { + addToSelection(mousePosition); + } + + ccrs.reset(); + ccrs.bind(ICRenderTypes.layersRenderType, Minecraft.getInstance().renderBuffers().bufferSource(), matrixStack); + ccrs.alphaOverride = leftMouseDown ? 128 : 64; + ccrs.brightness = LightTexture.pack(15, 15); + + if (!leftMouseDown) { + renderWireAt(toNearestPosition(mousePosition), ccrs, 0); + } + + for (TileCoord pos : selectedPositionsList) { + int rmask = 0; + for (int r = 0; r < 4; r++) { + int s = IRotatableICTile.rotationToDir(r); + if (selectedPositions.contains(pos.offset(s))) { + rmask |= 1 << r; + } + } + renderWireAt(pos, ccrs, rmask); + } + } + + private void renderWireAt(TileCoord pos, CCRenderState ccrs, int rmask) { + int wireConnMask = rmask << 4; + int modelKey = WireModelRenderer.modelKey(0, wireType.multipartType.getThickness(), wireConnMask); +// RenderWire.render(modelKey, (255 & 0xFF) / 2 + 60 << 24 | 0xFF, renderType.getTextures().get(0), ccrs, new Translation(pos.x, pos.y, pos.z)); + WireModelRenderer.render(ccrs, modelKey, -1, wireType.multipartType.getTextures().get(0), new Translation(pos.x, pos.y, pos.z)); + } + +} diff --git a/fabrication/src/main/java/mrtjp/projectred/fabrication/engine/BaseTile.java b/fabrication/src/main/java/mrtjp/projectred/fabrication/engine/BaseTile.java new file mode 100644 index 000000000..3a0a00172 --- /dev/null +++ b/fabrication/src/main/java/mrtjp/projectred/fabrication/engine/BaseTile.java @@ -0,0 +1,111 @@ +package mrtjp.projectred.fabrication.engine; + +import codechicken.lib.data.MCDataInput; +import codechicken.lib.data.MCDataOutput; +import codechicken.lib.render.CCRenderState; +import codechicken.lib.vec.Cuboid6; +import codechicken.lib.vec.Transformation; +import mrtjp.fengine.TileCoord; +import mrtjp.fengine.tiles.FETile; +import mrtjp.projectred.fabrication.editor.ICWorkbenchEditor; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.network.chat.Component; +import net.minecraft.network.chat.TextComponent; +import net.minecraftforge.api.distmarker.Dist; +import net.minecraftforge.api.distmarker.OnlyIn; + +import java.util.Collections; +import java.util.List; + +public abstract class BaseTile implements FETile { + + private final ICTileType tileType; + + private BaseTileMap map; + private TileCoord pos; + + public BaseTile(ICTileType tileType) { + this.tileType = tileType; + } + + public void bindMap(BaseTileMap map, TileCoord pos) { + this.map = map; + this.pos = pos; + } + + public void unbindMap() { + map = null; + pos = null; + } + + public BaseTileMap getMap() { + return map; + } + + public ICWorkbenchEditor getEditor() { + return map.getEditor(); + } + + public TileCoord getPos() { + return pos; + } + + public ICTileType getTileType() { + return tileType; + } + + public abstract void save(CompoundTag tag); + + public abstract void load(CompoundTag tag); + + public abstract void writeDesc(MCDataOutput out); + + public abstract void readDesc(MCDataInput in); + + public MCDataOutput getWriteStream(int key) { + return getEditor().getTileStream(this, key); + } + + public void read(MCDataInput in, int key) { + switch (key) { + case 0: + readDesc(in); + default: + // Unknown key + } + } + + public void sendDescUpdate() { + writeDesc(getWriteStream(0)); + } + + public void update() { } + + public void onAdded() { } + + public void onRemoved() { } + + public void onNeighborChanged() { } + + public void onSimRegistersChanged(int rMask, ICSimulationContainer container) { } + + public void onInteractionZoneClicked(int i) { } + + public void onInteractionZoneActivated(int i) { } + + @OnlyIn(Dist.CLIENT) + public void buildToolTip(List toolTip) { + toolTip.add(new TextComponent(tileType.getName())); + } + + @OnlyIn(Dist.CLIENT) + public void renderTile(CCRenderState ccrs, Transformation t, float partialFrame) { } + + @OnlyIn(Dist.CLIENT) + public List getInteractionZones() { + return Collections.emptyList(); + } + + @OnlyIn(Dist.CLIENT) + public void buildInteractionToolTip(List toolTip, int i) { } +} diff --git a/fabrication/src/main/java/mrtjp/projectred/fabrication/engine/BaseTileMap.java b/fabrication/src/main/java/mrtjp/projectred/fabrication/engine/BaseTileMap.java new file mode 100644 index 000000000..7c3d0368d --- /dev/null +++ b/fabrication/src/main/java/mrtjp/projectred/fabrication/engine/BaseTileMap.java @@ -0,0 +1,216 @@ +package mrtjp.projectred.fabrication.engine; + +import codechicken.lib.data.MCDataInput; +import codechicken.lib.data.MCDataOutput; +import mrtjp.fengine.TileCoord; +import mrtjp.fengine.tiles.FETile; +import mrtjp.fengine.tiles.FETileMap; +import mrtjp.projectred.fabrication.editor.ICWorkbenchEditor; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.nbt.ListTag; + +import java.util.*; +import java.util.stream.Collectors; + +public class BaseTileMap implements FETileMap { + + private final Map tileMap = new HashMap<>(); + private final ICWorkbenchEditor editor; + + private final Set ioTiles = new HashSet<>(); + + private TileCoord minBounds = new TileCoord(-8, -8, -8); + private TileCoord maxBounds = new TileCoord(7, 7, 7); + + public BaseTileMap(ICWorkbenchEditor editor) { + this.editor = editor; + } + + public ICWorkbenchEditor getEditor() { + return editor; + } + + public TileCoord getMinBounds() { + return minBounds; + } + + public TileCoord getMaxBounds() { + return maxBounds; + } + + public void setBounds(TileCoord minBounds, TileCoord maxBounds) { + this.minBounds = minBounds; + this.maxBounds = maxBounds; + } + + public boolean isInBounds(TileCoord coord) { + return coord.x >= minBounds.x && coord.x <= maxBounds.x && + coord.y >= minBounds.y && coord.y <= maxBounds.y && + coord.z >= minBounds.z && coord.z <= maxBounds.z; + } + + public boolean addTile(TileCoord coord, BaseTile tile) { + + if (!tileMap.containsKey(coord)) { + tileMap.put(coord, tile); + tile.bindMap(this, coord); + cacheType(tile); + return true; + } + return false; + } + + public Optional removeTile(TileCoord coord) { + + BaseTile removed = tileMap.remove(coord); + if (removed != null) { + removed.unbindMap(); + uncacheType(removed); + } + return Optional.ofNullable(removed); + } + + public Optional getBaseTile(TileCoord coord) { + return Optional.ofNullable(tileMap.get(coord)); + } + + public int getTileCount() { + return tileMap.size(); + } + + public Collection getBaseTileEntries() { + return tileMap.entrySet().stream() + .map(e -> new BaseTileEntry(e.getKey(), e.getValue())) + .collect(Collectors.toList()); + } + + // TODO keep track of tiles by layer + public Collection getTilesOnLayer(int y) { + return getBaseTileEntries().stream() + .filter(t -> t.getCoord().y == y) + .collect(Collectors.toList()); + } + + public void removeAll() { + ioTiles.clear(); + + for (BaseTile t : tileMap.values()) t.unbindMap(); + tileMap.clear(); + } + + private void cacheType(BaseTile tile) { + if (tile instanceof IIOConnectionTile) ioTiles.add((IIOConnectionTile) tile); + } + + private void uncacheType(BaseTile tile) { + if (tile instanceof IIOConnectionTile) ioTiles.remove(tile); + } + + private byte calcBundledIOMask() { + // OOOO IIII + int bmask = 0; + + for (IIOConnectionTile t : ioTiles) { + if (t.getConnectionType() == ICConnectionType.BUNDLED) { + int m = (t.isInputIOMode() ? 0x1 : 0x10) << t.getIOSide(); + bmask |= m; + } + } + + return (byte) bmask; + } + + public void save(CompoundTag tag) { + + ListTag tileList = new ListTag(); + for (Map.Entry entry : tileMap.entrySet()) { + CompoundTag tileTag = new CompoundTag(); + tileTag.putByte("_id", (byte) entry.getValue().getTileType().getID()); + tileTag.putByte("_x", (byte) entry.getKey().x); + tileTag.putByte("_y", (byte) entry.getKey().y); + tileTag.putByte("_z", (byte) entry.getKey().z); + entry.getValue().save(tileTag); + tileList.add(tileTag); + } + tag.put("tiles", tileList); + + tag.putByte("rsmask", (byte) 0); //TODO + tag.putByte("bmask", calcBundledIOMask()); + } + + public void load(CompoundTag tag) { + removeAll(); + + ListTag tileList = tag.getList("tiles", 10); + for (int i = 0; i < tileList.size(); i++) { + CompoundTag tileTag = tileList.getCompound(i); + int id = tileTag.getByte("_id") & 0xFF; + int x = tileTag.getByte("_x"); + int y = tileTag.getByte("_y"); + int z = tileTag.getByte("_z"); + BaseTile tile = ICTileType.createFromId(id); + addTile(new TileCoord(x, y, z), tile); + tile.load(tileTag); + } + } + + public void writeDesc(MCDataOutput out) { + + for (Map.Entry entry : tileMap.entrySet()) { + out.writeByte(entry.getValue().getTileType().getID()); + out.writeByte(entry.getKey().x); + out.writeByte(entry.getKey().y); + out.writeByte(entry.getKey().z); + entry.getValue().writeDesc(out); + } + out.writeByte(255); + } + + public void readDesc(MCDataInput in) { + removeAll(); + + int id = in.readUByte(); + while (id != 255) { + BaseTile tile = ICTileType.createFromId(id); + TileCoord coord = new TileCoord(in.readByte(), in.readByte(), in.readByte()); + addTile(coord, tile); + tile.readDesc(in); + + id = in.readUByte(); + } + } + + public static class BaseTileEntry { + private final TileCoord coord; + private final BaseTile tile; + + public BaseTileEntry(TileCoord coord, BaseTile tile) { + this.coord = coord; + this.tile = tile; + } + + public BaseTile getTile() { + return tile; + } + + public TileCoord getCoord() { + return coord; + } + } + + @Override + public Optional getTile(TileCoord coord) { + return Optional.ofNullable(tileMap.get(coord)); + } + + @Override + public Collection getEntries() { + + return tileMap.entrySet().stream().map(e -> new TileMapEntry() { + //@formatter:off + @Override public TileCoord getCoord() { return e.getKey(); } + @Override public FETile getTile() { return e.getValue(); } + //@formatter:on + }).collect(Collectors.toList()); + } +} diff --git a/fabrication/src/main/java/mrtjp/projectred/fabrication/engine/IBundledConnectableICTile.java b/fabrication/src/main/java/mrtjp/projectred/fabrication/engine/IBundledConnectableICTile.java new file mode 100644 index 000000000..513e1f4dd --- /dev/null +++ b/fabrication/src/main/java/mrtjp/projectred/fabrication/engine/IBundledConnectableICTile.java @@ -0,0 +1,5 @@ +package mrtjp.projectred.fabrication.engine; + +public interface IBundledConnectableICTile { + int getBundledColour(); +} diff --git a/fabrication/src/main/java/mrtjp/projectred/fabrication/engine/ICCompilerLog.java b/fabrication/src/main/java/mrtjp/projectred/fabrication/engine/ICCompilerLog.java new file mode 100644 index 000000000..9da0bd50a --- /dev/null +++ b/fabrication/src/main/java/mrtjp/projectred/fabrication/engine/ICCompilerLog.java @@ -0,0 +1,409 @@ +package mrtjp.projectred.fabrication.engine; + +import codechicken.lib.data.MCDataInput; +import codechicken.lib.data.MCDataOutput; +import mrtjp.fengine.TileCoord; +import mrtjp.fengine.api.ICStepThroughAssembler; +import mrtjp.projectred.fabrication.editor.ICEditorStateMachine; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.nbt.ListTag; +import net.minecraft.nbt.Tag; + +import java.util.*; +import java.util.stream.Collectors; + +import static mrtjp.projectred.fabrication.editor.ICEditorStateMachine.KEY_COMPILER_LOG_NODE_ADDED; +import static mrtjp.projectred.fabrication.editor.ICEditorStateMachine.KEY_COMPILER_LOG_NODE_EXECUTED; + +public class ICCompilerLog implements ICStepThroughAssembler.EventReceiver { + + private final ICEditorStateMachine stateMachine; + + private final CompileTree compileTree = new CompileTree(); + + private final List currentPath = new LinkedList<>(); + private int completedSteps = 0; //TODO ideally this would be a feature in the compile tree object + + public ICCompilerLog(ICEditorStateMachine stateMachine) { + this.stateMachine = stateMachine; + } + + public void save(CompoundTag tag) { + CompoundTag treeTag = new CompoundTag(); + compileTree.save(treeTag); + tag.put("compile_tree", treeTag); + tag.putInt("completed_steps", completedSteps); + tag.putIntArray("current_path", currentPath); + } + + public void load(CompoundTag tag) { + compileTree.load(tag.getCompound("compile_tree")); + completedSteps = tag.getInt("completed_steps"); + currentPath.clear(); + currentPath.addAll(Arrays.stream(tag.getIntArray("current_path")).boxed().collect(Collectors.toList())); + } + + public void writeDesc(MCDataOutput out) { + compileTree.writeDesc(out); + out.writeInt(completedSteps); + out.writeInt(currentPath.size()); + for (int i : currentPath) out.writeInt(i); + } + + public void readDesc(MCDataInput in) { + compileTree.readDesc(in); + completedSteps = in.readInt(); + currentPath.clear(); + int size = in.readInt(); + for (int i = 0; i < size; i++) currentPath.add(in.readInt()); + } + + public void clear() { + compileTree.clear(); + currentPath.clear(); + completedSteps = 0; + } + + //region ICStepThroughAssembler.EventReceiver + @Override + public void onStepAdded(ICStepThroughAssembler.AssemblerStepDescriptor descriptor) { + CompileTreeNode node = compileTree.findOrCreateNode(descriptor.getTreePath()); + node.step = descriptor.getStepType(); + + sendNodeAdded(node, descriptor.getTreePath()); + } + + @Override + public void onStepExecuted(ICStepThroughAssembler.AssemblerStepResult result) { + CompileTreeNode node = compileTree.findOrCreateNode(result.getTreePath()); + node.tileCoords.addAll(result.getTileCoords()); + node.registerIds.addAll(result.getRegisterIds()); + node.gateIds.addAll(result.getGateIds()); + node.registerRemaps.putAll(result.getRemappedRegisterIds()); + + currentPath.clear(); + currentPath.addAll(result.getTreePath()); + completedSteps++; + + sendNodeExecuted(node, result.getTreePath()); + } + //endregion + + //region Packet handling + public void readLogStream(MCDataInput in, int key) { + switch (key) { + case KEY_COMPILER_LOG_NODE_ADDED: + readNodeAdded(in); + break; + case KEY_COMPILER_LOG_NODE_EXECUTED: + readNodeExecuted(in); + break; + default: + throw new IllegalArgumentException("Unknown compiler stream key: " + key); + } + } + //endregion + + //region Server-side utilities + private void sendNodeAdded(CompileTreeNode node, List treePath) { + MCDataOutput out = stateMachine.getStateMachineStream(KEY_COMPILER_LOG_NODE_ADDED); + out.writeByte(treePath.size()); + for (int i : treePath) { + out.writeByte(i); + } + out.writeByte(node.step.ordinal()); + } + + private void sendNodeExecuted(CompileTreeNode node, List treePath) { + MCDataOutput out = stateMachine.getStateMachineStream(KEY_COMPILER_LOG_NODE_EXECUTED); + out.writeByte(treePath.size()); + for (int i : treePath) { + out.writeByte(i); + } + node.write(out); + } + //endregion + + //region Client-side utilities + private void readNodeAdded(MCDataInput in) { + int pathLength = in.readUByte(); + List path = new ArrayList<>(pathLength); + for (int i = 0; i < pathLength; i++) { + path.add((int) in.readUByte()); + } + CompileTreeNode node = compileTree.findOrCreateNode(path); + node.step = ICStepThroughAssembler.AssemblerStepType.values()[in.readUByte()]; + } + + private void readNodeExecuted(MCDataInput in) { + int pathLength = in.readUByte(); + List path = new ArrayList<>(pathLength); + for (int i = 0; i < pathLength; i++) { + path.add((int) in.readUByte()); + } + CompileTreeNode node = compileTree.findOrCreateNode(path); + node.read(in); + + currentPath.clear(); + currentPath.addAll(path); + completedSteps++; + } + + public List getCurrentStack() { + return compileTree.getStack(currentPath); + } + + public int getProgressScaled(int scale) { + int size = compileTree.size(); + return size == 0 ? 0 : completedSteps * scale / size; + } + //endregion + + public static class CompileTreeNode { + + public final List children = new ArrayList<>(); + + public ICStepThroughAssembler.AssemblerStepType step; + public final List tileCoords = new ArrayList<>(); + public final List registerIds = new ArrayList<>(); + public final List gateIds = new ArrayList<>(); + public final Map registerRemaps = new HashMap<>(); + + public void save(CompoundTag tag) { + tag.putByte("step", (byte) step.ordinal()); + + ListTag tileCoordsTag = new ListTag(); + for (TileCoord coord : tileCoords) { + CompoundTag coordTag = new CompoundTag(); + coordTag.putInt("x", coord.x); + coordTag.putInt("y", coord.y); + coordTag.putInt("z", coord.z); + tileCoordsTag.add(coordTag); + } + tag.put("tileCoords", tileCoordsTag); + + tag.putIntArray("registerIds", registerIds); + tag.putIntArray("gateIds", gateIds); + + ListTag remapsTag = new ListTag(); + for (Map.Entry entry : registerRemaps.entrySet()) { + CompoundTag remapTag = new CompoundTag(); + remapTag.putInt("k", entry.getKey()); + remapTag.putInt("v", entry.getValue()); + remapsTag.add(remapTag); + } + tag.put("registerRemaps", remapsTag); + + ListTag childrenTag = new ListTag(); + for (CompileTreeNode child : children) { + CompoundTag childTag = new CompoundTag(); + child.save(childTag); + childrenTag.add(childTag); + } + tag.put("children", childrenTag); + } + + public void load(CompoundTag tag) { + step = ICStepThroughAssembler.AssemblerStepType.values()[tag.getByte("step")]; + + ListTag tileCoordsTag = tag.getList("tileCoords", Tag.TAG_COMPOUND); + for (Tag coordTag : tileCoordsTag) { + CompoundTag coordTagCompound = (CompoundTag) coordTag; + tileCoords.add(new TileCoord( + coordTagCompound.getInt("x"), + coordTagCompound.getInt("y"), + coordTagCompound.getInt("z") + )); + } + + registerIds.addAll(Arrays.stream(tag.getIntArray("registerIds")).boxed().collect(Collectors.toList())); + gateIds.addAll(Arrays.stream(tag.getIntArray("gateIds")).boxed().collect(Collectors.toList())); + + ListTag remapsTag = tag.getList("registerRemaps", Tag.TAG_COMPOUND); + for (Tag remapTag : remapsTag) { + CompoundTag remapTagCompound = (CompoundTag) remapTag; + registerRemaps.put(remapTagCompound.getInt("k"), remapTagCompound.getInt("v")); + } + + children.clear(); + ListTag childrenTag = tag.getList("children", Tag.TAG_COMPOUND); + for (Tag childTag : childrenTag) { + CompileTreeNode child = new CompileTreeNode(); + child.load((CompoundTag) childTag); + children.add(child); + } + } + + public void write(MCDataOutput out) { + out.writeByte(step.ordinal()); + out.writeByte(tileCoords.size()); + for (TileCoord coord : tileCoords) { + out.writeByte(coord.x).writeByte(coord.y).writeByte(coord.z); + } + out.writeByte(registerIds.size()); + for (int i : registerIds) { + out.writeVarInt(i); + } + out.writeByte(gateIds.size()); + for (int i : gateIds) { + out.writeVarInt(i); + } + out.writeByte(registerRemaps.size()); + registerRemaps.forEach((k, v) -> { + out.writeVarInt(k); + out.writeVarInt(v); + }); + } + + public void read(MCDataInput in) { + step = ICStepThroughAssembler.AssemblerStepType.values()[in.readUByte()]; + int size = in.readUByte(); + tileCoords.clear(); + for (int i = 0; i < size; i++) { + tileCoords.add(new TileCoord(in.readByte(), in.readByte(), in.readByte())); + } + size = in.readUByte(); + registerIds.clear(); + for (int i = 0; i < size; i++) { + registerIds.add(in.readVarInt()); + } + size = in.readVarInt(); + gateIds.clear(); + for (int i = 0; i < size; i++) { + gateIds.add(in.readVarInt()); + } + size = in.readVarInt(); + registerRemaps.clear(); + for (int i = 0; i < size; i++) { + registerRemaps.put(in.readVarInt(), in.readVarInt()); + } + } + + protected void writeDesc(MCDataOutput out) { + write(out); + out.writeByte(children.size()); + for (CompileTreeNode child : children) { + child.writeDesc(out); + } + } + + protected void readDesc(MCDataInput in) { + read(in); + children.clear(); + int size = in.readUByte(); + for (int i = 0; i < size; i++) { + CompileTreeNode child = new CompileTreeNode(); + child.readDesc(in); + children.add(child); + } + } + } + + public static class CompileTree { + + private final List rootNodes = new ArrayList<>(); + + private int size = 0; + + /** + * Find the node at the given path, creating empty nodes when necessary + */ + public CompileTreeNode findOrCreateNode(List path) { + Iterator pathIterator = path.iterator(); + + int ri = pathIterator.next(); + CompileTreeNode node = ri < rootNodes.size() ? rootNodes.get(ri) : null; + if (node == null) { + node = new CompileTreeNode(); + rootNodes.add(ri, node); + size++; + } + + while (pathIterator.hasNext()) { + int i = pathIterator.next(); + CompileTreeNode next = i < node.children.size() ? node.children.get(i) : null; + if (next == null) { + next = new CompileTreeNode(); + node.children.add(i, next); + size++; + } + node = next; + } + return node; + } + + public List getStack(List path) { + if (path.isEmpty()) return Collections.emptyList(); + + List stack = new ArrayList<>(path.size()); + Iterator pathIterator = path.iterator(); + + int ri = pathIterator.next(); + CompileTreeNode node = ri < rootNodes.size() ? rootNodes.get(ri) : null; + if (node == null) { + return stack; + } + stack.add(node); + + while (pathIterator.hasNext()) { + int i = pathIterator.next(); + CompileTreeNode next = i < node.children.size() ? node.children.get(i) : null; + if (next == null) { + return stack; + } + stack.add(next); + node = next; + } + return stack; + } + + public int size() { + return size; + } + + public void clear() { + rootNodes.clear(); + size = 0; + } + + public void save(CompoundTag tag) { + tag.putInt("size", size); + ListTag rootNodesTag = new ListTag(); + for (CompileTreeNode rootNode : rootNodes) { + CompoundTag rootNodeTag = new CompoundTag(); + rootNode.save(rootNodeTag); + rootNodesTag.add(rootNodeTag); + } + tag.put("rootNodes", rootNodesTag); + } + + public void load(CompoundTag tag) { + size = tag.getInt("size"); + ListTag rootNodesTag = tag.getList("rootNodes", Tag.TAG_COMPOUND); + for (Tag rootNodeTag : rootNodesTag) { + CompileTreeNode rootNode = new CompileTreeNode(); + rootNode.load((CompoundTag) rootNodeTag); + rootNodes.add(rootNode); + } + } + + public void writeDesc(MCDataOutput out) { + out.writeVarInt(size); + out.writeByte(rootNodes.size()); + for (CompileTreeNode node : rootNodes) { + node.writeDesc(out); + } + } + + public void readDesc(MCDataInput in) { + size = in.readVarInt(); + int size = in.readUByte(); + rootNodes.clear(); + for (int i = 0; i < size; i++) { + CompileTreeNode node = new CompileTreeNode(); + node.readDesc(in); + rootNodes.add(node); + } + } + } +} diff --git a/fabrication/src/main/java/mrtjp/projectred/fabrication/engine/ICConnectionType.java b/fabrication/src/main/java/mrtjp/projectred/fabrication/engine/ICConnectionType.java new file mode 100644 index 000000000..cdd9349d1 --- /dev/null +++ b/fabrication/src/main/java/mrtjp/projectred/fabrication/engine/ICConnectionType.java @@ -0,0 +1,7 @@ +package mrtjp.projectred.fabrication.engine; + +public enum ICConnectionType { + REDSTONE, + BUNDLED, + ANALOG; +} diff --git a/fabrication/src/main/java/mrtjp/projectred/fabrication/engine/ICSimulationContainer.java b/fabrication/src/main/java/mrtjp/projectred/fabrication/engine/ICSimulationContainer.java new file mode 100644 index 000000000..5cbc1362d --- /dev/null +++ b/fabrication/src/main/java/mrtjp/projectred/fabrication/engine/ICSimulationContainer.java @@ -0,0 +1,174 @@ +package mrtjp.projectred.fabrication.engine; + +import codechicken.lib.data.MCDataInput; +import codechicken.lib.data.MCDataOutput; +import mrtjp.fengine.api.ICFlatMap; +import mrtjp.fengine.simulate.ICSimulation; +import net.minecraft.nbt.CompoundTag; + +public class ICSimulationContainer { + + private String flatMap = PRFabricationEngine.EMPTY_FLAT_MAP_SERIALIZED; //TODO this does not really belong here + private ICSimulation simulation = PRFabricationEngine.EMPTY_SIMULATION; + + /** + * Inputs to the simulation indexed by rotation (0-3). + *

+ * Each input is a mask of 16 bits, which represents one of the + * 16 bundled colours inside the tile map. + */ + private final short[] inputs = new short[] { 0, 0, 0, 0 }; + + /** + * Outputs from the simulation indexed by rotation (0-3). + */ + private final short[] outputs = new short[] { 0, 0, 0, 0 }; + + private long systemTime = 0L; + + public void setInput(int rotation, short mask) { + inputs[rotation] = mask; + } + + public int setInputs(short[] inputs) { + + int changeMask = 0; + for (int r = 0; r < 4; r++) { + if (this.inputs[r] != inputs[r]) { + this.inputs[r] = inputs[r]; + changeMask |= 1 << r; + } + } + + return changeMask; + } + + public short getInput(int rotation) { + return inputs[rotation]; + } + + public void setSystemTime(long systemTime) { + this.systemTime = systemTime; + } + + public void progressTime(long time) { + systemTime += time; + } + + public short getOutput(int rotation) { + return outputs[rotation]; + } + + public void setFlatMap(ICFlatMap flatMap) { + this.flatMap = PRFabricationEngine.instance.serializeFlatMap(flatMap); + this.simulation = new ICSimulation(flatMap); + + pushInputs(0xF); + pushTime(); + + simulation.computeAll(null); + } + + public void save(CompoundTag tag) { + tag.putString("flatMap", flatMap); + tag.putString("simulation", PRFabricationEngine.instance.serializeSimulation(simulation)); + for (int i = 0; i < 4; i++) { + tag.putShort("in" + i, inputs[i]); + tag.putShort("out" + i, outputs[i]); + } + tag.putLong("systemTime", systemTime); + } + + public void load(CompoundTag tag) { + this.flatMap = tag.getString("flatMap"); + ICSimulation simulation = PRFabricationEngine.instance.deserializeSimulation(tag.getString("simulation")); + if (simulation != null) { + this.simulation = simulation; + } + for (int i = 0; i < 4; i++) { + inputs[i] = tag.getShort("in" + i); + outputs[i] = tag.getShort("out" + i); + } + systemTime = tag.getLong("systemTime"); + } + + public void writeDesc(MCDataOutput out) { + //TODO write simulation log + } + + public void readDesc(MCDataInput in) { + // TODO read simulation log + } + + public void pushInputs(int rmask) { + + for (int r = 0; r < 4; r++) { + if ((rmask & (1 << r)) != 0) { + for (int i = 0; i < 16; i++) { + int regId = PRFabricationEngine.inputRegisterId(r, i); + byte value = (inputs[r] & (1 << i)) != 0 ? (byte) 1 : 0; + simulation.queueRegByteVal(regId, value); + } + } + } + } + + public void pullInputs(int rmask) { + + for (int r = 0; r < 4; r++) { + if ((rmask & (1 << r)) != 0) { + inputs[r] = 0; + for (int i = 0; i < 16; i++) { + int regId = PRFabricationEngine.inputRegisterId(r, i); + if (simulation.getRegByteVal(regId) != 0) inputs[r] |= (1 << i); + } + } + } + } + + public void pushTime() { + + simulation.queueRegByteVal(PRFabricationEngine.REG_TIME_3, (byte) (systemTime >>> 24)); + simulation.queueRegByteVal(PRFabricationEngine.REG_TIME_2, (byte) (systemTime >>> 16)); + simulation.queueRegByteVal(PRFabricationEngine.REG_TIME_1, (byte) (systemTime >>> 8)); + simulation.queueRegByteVal(PRFabricationEngine.REG_TIME_0, (byte) (systemTime)); + } + + public void pullTime() { + + systemTime = 0; + systemTime |= (long) (simulation.getRegByteVal(PRFabricationEngine.REG_TIME_3) & 0xFF) << 24; + systemTime |= (simulation.getRegByteVal(PRFabricationEngine.REG_TIME_2) & 0xFF) << 16; + systemTime |= (simulation.getRegByteVal(PRFabricationEngine.REG_TIME_1) & 0xFF) << 8; + systemTime |= (simulation.getRegByteVal(PRFabricationEngine.REG_TIME_0) & 0xFF); + } + + public int pullOutputs() { + + short[] newOutputs = new short[4]; + for (int r = 0; r < 4; r++) { + for (int i = 0; i < 16; i++) { + int regId = PRFabricationEngine.outputRegisterId(r, i); + int value = simulation.getRegByteVal(regId) != 0 ? 1 : 0; + newOutputs[r] |= value << i; + } + } + + int changeMask = 0; + for (int r = 0; r < 4; r++) { + if (outputs[r] != newOutputs[r]) { + outputs[r] = newOutputs[r]; + changeMask |= (1 << r); + } + } + return changeMask; + } + + public byte pullRegisterValue(int regId) { + return simulation.getRegByteVal(regId); + } + + public void simulate() { + simulation.propagate(null); + } +} diff --git a/fabrication/src/main/java/mrtjp/projectred/fabrication/engine/ICTileType.java b/fabrication/src/main/java/mrtjp/projectred/fabrication/engine/ICTileType.java new file mode 100644 index 000000000..31b16c304 --- /dev/null +++ b/fabrication/src/main/java/mrtjp/projectred/fabrication/engine/ICTileType.java @@ -0,0 +1,104 @@ +package mrtjp.projectred.fabrication.engine; + +import mrtjp.projectred.fabrication.engine.gates.*; +import mrtjp.projectred.fabrication.engine.wires.BundledWireTile; +import mrtjp.projectred.fabrication.engine.wires.InsulatedWireTile; +import mrtjp.projectred.fabrication.engine.wires.RedAlloyWireTile; + +import java.util.function.Supplier; + +import static mrtjp.projectred.fabrication.engine.ICTileTypeOffsets.*; + +public enum ICTileType { + + //@formatter:off + IO_GATE(ID_OFFSET_IOGATE, "IO Gate", IOGateTile::new), + + OR_GATE (ID_OFFSET_GATE, "OR Gate", ORGateTile::new), + NOR_GATE (ID_OFFSET_GATE + 1, "NOR Gate", NORGateTile::new), + NOT_GATE (ID_OFFSET_GATE + 2, "NOT Gate", NOTGateTile::new), + AND_GATE (ID_OFFSET_GATE + 3, "AND Gate", ANDGateTile::new), + NAND_GATE (ID_OFFSET_GATE + 4, "NAND Gate", NANDGateTile::new), + XOR_GATE (ID_OFFSET_GATE + 5, "XOR Gate", XORGateTile::new), + XNOR_GATE (ID_OFFSET_GATE + 6, "XOR Gate", XNORGateTile::new), + BUFFER_GATE (ID_OFFSET_GATE + 7, "Buffer Gate", BufferGateTile::new), + MULTIPLEXER_GATE (ID_OFFSET_GATE + 8, "Multiplexer Gate", MultiplexerGateTile::new), + PULSE_GATE (ID_OFFSET_GATE + 9, "Pulse Gate", PulseGateTile::new), + REPEATER_GATE (ID_OFFSET_GATE + 10, "Repeater Gate", RepeaterGateTile::new), + RANDOMIZER_GATE (ID_OFFSET_GATE + 11, "Randomizer Gate", RandomizerGateTile::new), + SR_LATCH_GATE (ID_OFFSET_GATE + 12, "SR Latch Gate", SRLatchGateTile::new), + TOGGLE_LATCH_GATE (ID_OFFSET_GATE + 13, "Toggle Latch Gate", ToggleLatchGateTile::new), + TRANSPARENT_LATCH_GATE(ID_OFFSET_GATE + 14, "Transparent Latch Gate", TransparentLatchGateTile::new), + + RED_ALLOY_WIRE (ID_OFFSET_WIRE_RED, "Red Alloy Wire", RedAlloyWireTile::new), + INSULATED_WHITE_WIRE (ID_OFFSET_WIRE_RED + 1, "White Insulated Wire", () -> new InsulatedWireTile(0)), + INSULATED_ORANGE_WIRE (ID_OFFSET_WIRE_RED + 2, "Orange Insulated Wire", () -> new InsulatedWireTile(1)), + INSULATED_MAGENTA_WIRE (ID_OFFSET_WIRE_RED + 3, "Magenta Insulated Wire", () -> new InsulatedWireTile(2)), + INSULATED_LIGHT_BLUE_WIRE(ID_OFFSET_WIRE_RED + 4, "Light Blue Insulated Wire", () -> new InsulatedWireTile(3)), + INSULATED_YELLOW_WIRE (ID_OFFSET_WIRE_RED + 5, "Yellow Insulated Wire", () -> new InsulatedWireTile(4)), + INSULATED_LIME_WIRE (ID_OFFSET_WIRE_RED + 6, "Lime Insulated Wire", () -> new InsulatedWireTile(5)), + INSULATED_PINK_WIRE (ID_OFFSET_WIRE_RED + 7, "Pink Insulated Wire", () -> new InsulatedWireTile(6)), + INSULATED_GRAY_WIRE (ID_OFFSET_WIRE_RED + 8, "Gray Insulated Wire", () -> new InsulatedWireTile(7)), + INSULATED_LIGHT_GRAY_WIRE(ID_OFFSET_WIRE_RED + 9, "Light Gray Insulated Wire", () -> new InsulatedWireTile(8)), + INSULATED_CYAN_WIRE (ID_OFFSET_WIRE_RED + 10, "Cyan Insulated Wire", () -> new InsulatedWireTile(9)), + INSULATED_PURPLE_WIRE (ID_OFFSET_WIRE_RED + 11, "Purple Insulated Wire", () -> new InsulatedWireTile(10)), + INSULATED_BLUE_WIRE (ID_OFFSET_WIRE_RED + 12, "Blue Insulated Wire", () -> new InsulatedWireTile(11)), + INSULATED_BROWN_WIRE (ID_OFFSET_WIRE_RED + 13, "Brown Insulated Wire", () -> new InsulatedWireTile(12)), + INSULATED_GREEN_WIRE (ID_OFFSET_WIRE_RED + 14, "Green Insulated Wire", () -> new InsulatedWireTile(13)), + INSULATED_RED_WIRE (ID_OFFSET_WIRE_RED + 15, "Red Insulated Wire", () -> new InsulatedWireTile(14)), + INSULATED_BLACK_WIRE (ID_OFFSET_WIRE_RED + 16, "Black Insulated Wire", () -> new InsulatedWireTile(15)), + + BUNDLED_NEUTRAL_WIRE (ID_OFFSET_WIRE_BUNDLED, "Bundled Wire", () -> new BundledWireTile(-1)), + BUNDLED_WHITE_WIRE (ID_OFFSET_WIRE_BUNDLED + 1, "White Bundled Wire", () -> new BundledWireTile(0)), + BUNDLED_ORANGE_WIRE (ID_OFFSET_WIRE_BUNDLED + 2, "Orange Bundled Wire", () -> new BundledWireTile(1)), + BUNDLED_MAGENTA_WIRE (ID_OFFSET_WIRE_BUNDLED + 3, "Magenta Bundled Wire", () -> new BundledWireTile(2)), + BUNDLED_LIGHT_BLUE_WIRE(ID_OFFSET_WIRE_BUNDLED + 4, "Light Blue Bundled Wire", () -> new BundledWireTile(3)), + BUNDLED_YELLOW_WIRE (ID_OFFSET_WIRE_BUNDLED + 5, "Yellow Bundled Wire", () -> new BundledWireTile(4)), + BUNDLED_LIME_WIRE (ID_OFFSET_WIRE_BUNDLED + 6, "Lime Bundled Wire", () -> new BundledWireTile(5)), + BUNDLED_PINK_WIRE (ID_OFFSET_WIRE_BUNDLED + 7, "Pink Bundled Wire", () -> new BundledWireTile(6)), + BUNDLED_GRAY_WIRE (ID_OFFSET_WIRE_BUNDLED + 8, "Gray Bundled Wire", () -> new BundledWireTile(7)), + BUNDLED_LIGHT_GRAY_WIRE(ID_OFFSET_WIRE_BUNDLED + 9, "Light Gray Bundled Wire", () -> new BundledWireTile(8)), + BUNDLED_CYAN_WIRE (ID_OFFSET_WIRE_BUNDLED + 10, "Cyan Bundled Wire", () -> new BundledWireTile(9)), + BUNDLED_PURPLE_WIRE (ID_OFFSET_WIRE_BUNDLED + 11, "Purple Bundled Wire", () -> new BundledWireTile(10)), + BUNDLED_BLUE_WIRE (ID_OFFSET_WIRE_BUNDLED + 12, "Blue Bundled Wire", () -> new BundledWireTile(11)), + BUNDLED_BROWN_WIRE (ID_OFFSET_WIRE_BUNDLED + 13, "Brown Bundled Wire", () -> new BundledWireTile(12)), + BUNDLED_GREEN_WIRE (ID_OFFSET_WIRE_BUNDLED + 14, "Green Bundled Wire", () -> new BundledWireTile(13)), + BUNDLED_RED_WIRE (ID_OFFSET_WIRE_BUNDLED + 15, "Red Bundled Wire", () -> new BundledWireTile(14)), + BUNDLED_BLACK_WIRE (ID_OFFSET_WIRE_BUNDLED + 16, "Black Bundled Wire", () -> new BundledWireTile(15)); + //@formatter:on + + private static final ICTileType[] VALUES_BY_ID; + + static { + VALUES_BY_ID = new ICTileType[ID_OFFSET_MAX + 1]; + for (ICTileType type : ICTileType.values()) { + VALUES_BY_ID[type.getID()] = type; + } + } + + private final int id; + private final String name; + private final Supplier factory; + + ICTileType(int id, String name, Supplier factory) { + this.id = id; + this.name = name; //TODO localize + this.factory = factory; + } + + public String getName() { + return name; + } + + public BaseTile create() { + return factory.get(); + } + + public int getID() { + return id; + } + + public static BaseTile createFromId(int id) { + return VALUES_BY_ID[id].create(); + } +} diff --git a/fabrication/src/main/java/mrtjp/projectred/fabrication/engine/ICTileTypeOffsets.java b/fabrication/src/main/java/mrtjp/projectred/fabrication/engine/ICTileTypeOffsets.java new file mode 100644 index 000000000..8753a60c0 --- /dev/null +++ b/fabrication/src/main/java/mrtjp/projectred/fabrication/engine/ICTileTypeOffsets.java @@ -0,0 +1,15 @@ +package mrtjp.projectred.fabrication.engine; + +public class ICTileTypeOffsets { + public static final int MAX_IO_GATES = 16; + public static final int MAX_GATES = 64; + public static final int MAX_REDSTONE_WIRES = 20; + public static final int MAX_BUNDLED_WIRES = 20; + + public static final int ID_OFFSET_IOGATE = 0; + public static final int ID_OFFSET_GATE = ID_OFFSET_IOGATE + MAX_IO_GATES; + public static final int ID_OFFSET_WIRE_RED = ID_OFFSET_GATE + MAX_GATES; + public static final int ID_OFFSET_WIRE_BUNDLED = ID_OFFSET_WIRE_RED + MAX_REDSTONE_WIRES; + + public static final int ID_OFFSET_MAX = ID_OFFSET_WIRE_BUNDLED + MAX_BUNDLED_WIRES; +} diff --git a/fabrication/src/main/java/mrtjp/projectred/fabrication/engine/IConnectableICTile.java b/fabrication/src/main/java/mrtjp/projectred/fabrication/engine/IConnectableICTile.java new file mode 100644 index 000000000..94d5c2bf3 --- /dev/null +++ b/fabrication/src/main/java/mrtjp/projectred/fabrication/engine/IConnectableICTile.java @@ -0,0 +1,54 @@ +package mrtjp.projectred.fabrication.engine; + +public interface IConnectableICTile { + + int getConnMask(); + + void setConnMask(int connMask); + + IConnectableICTile getTileTowardsDir(int dir); + + default int dirFrom(int dir) { + return dir^1; + } + + default boolean maskConnectsToDir(int dir) { + return (getConnMask() & 1 << dir) != 0; + } + + default boolean updateConns() { + int newConn = 0; + for (int s = 0; s < 6; s++) { + if (discoverAndConnect(s)) newConn |= 1 << s; + } + if (newConn != getConnMask()) { + setConnMask(newConn); + onMaskChanged(); + return true; + } + return false; + } + + default boolean discoverAndConnect(int dir) { + IConnectableICTile tileTowardsDir = getTileTowardsDir(dir); + if (tileTowardsDir == null) return false; + + return canConnectTo(tileTowardsDir, dir) && tileTowardsDir.connect(this, dirFrom(dir)); + } + + default boolean connect(IConnectableICTile target, int towardsDir) { + if (canConnectTo(target, towardsDir)) { + int newConn = getConnMask() | 1 << towardsDir; + if (newConn != getConnMask()) { + setConnMask(newConn); + onMaskChanged(); + } + return true; + } + return false; + } + + boolean canConnectTo(IConnectableICTile target, int towardsDir); + + void onMaskChanged(); +} diff --git a/fabrication/src/main/java/mrtjp/projectred/fabrication/engine/IIOConnectionTile.java b/fabrication/src/main/java/mrtjp/projectred/fabrication/engine/IIOConnectionTile.java new file mode 100644 index 000000000..259ddef5f --- /dev/null +++ b/fabrication/src/main/java/mrtjp/projectred/fabrication/engine/IIOConnectionTile.java @@ -0,0 +1,16 @@ +package mrtjp.projectred.fabrication.engine; + +public interface IIOConnectionTile { + + /** + * @return True if this tile is an input + */ + boolean isInputIOMode(); + + /** + * @return Rotation index (0-3) representing the edge through which this IO signal is passing + */ + int getIOSide(); + + ICConnectionType getConnectionType(); +} diff --git a/fabrication/src/main/java/mrtjp/projectred/fabrication/engine/IInsulatedConnectableICTile.java b/fabrication/src/main/java/mrtjp/projectred/fabrication/engine/IInsulatedConnectableICTile.java new file mode 100644 index 000000000..6765e4c70 --- /dev/null +++ b/fabrication/src/main/java/mrtjp/projectred/fabrication/engine/IInsulatedConnectableICTile.java @@ -0,0 +1,5 @@ +package mrtjp.projectred.fabrication.engine; + +public interface IInsulatedConnectableICTile { + int getInsulatedColour(); +} diff --git a/fabrication/src/main/java/mrtjp/projectred/fabrication/engine/IRedstoneConnectableICTile.java b/fabrication/src/main/java/mrtjp/projectred/fabrication/engine/IRedstoneConnectableICTile.java new file mode 100644 index 000000000..05abfd701 --- /dev/null +++ b/fabrication/src/main/java/mrtjp/projectred/fabrication/engine/IRedstoneConnectableICTile.java @@ -0,0 +1,4 @@ +package mrtjp.projectred.fabrication.engine; + +public interface IRedstoneConnectableICTile { +} diff --git a/fabrication/src/main/java/mrtjp/projectred/fabrication/engine/IRotatableICTile.java b/fabrication/src/main/java/mrtjp/projectred/fabrication/engine/IRotatableICTile.java new file mode 100644 index 000000000..35a74aede --- /dev/null +++ b/fabrication/src/main/java/mrtjp/projectred/fabrication/engine/IRotatableICTile.java @@ -0,0 +1,63 @@ +package mrtjp.projectred.fabrication.engine; + +public interface IRotatableICTile { + + int getRotation(); + + void setRotation(int r); + + default int toInternalRotation(int absRot) { + return (absRot + 6 - getRotation()) % 4; + } + + default int toAbsoluteRotation(int r) { + return (r + 2 + getRotation()) % 4; + } + + default int toInternalMask(int absMask) { + return shiftMask(absMask, toInternalRotation(0)); + } + + default int toAbsoluteMask(int intMask) { + return shiftMask(intMask, toAbsoluteRotation(0)); + } + + //@formatter:off + static int rotationToDir(int r) { + switch (r) { + case 0: return 3; + case 1: return 4; + case 2: return 2; + case 3: return 5; + default: return -1; + } + } + + static int dirToRotation(int dir) { + switch (dir) { + case 2: return 2; + case 3: return 0; + case 4: return 1; + case 5: return 3; + default: return -1; + } + } + //@formatter:on + + static int dirMaskToRotationMask(int connMask) { + int rMask = 0; + for (int r = 0; r < 4; r++) { + int s = rotationToDir(r); + if ((connMask & 1 << s) != 0) rMask |= 1 << r; + } + return rMask; + } + + static int shiftMask(int mask, int r) { + return (mask & ~0xF) | (mask << r | mask >> 4-r) & 0xF; + } + + static int flipMaskZ(int mask) { + return mask & 5 | mask << 2 & 8 | mask >> 2 & 2; + } +} diff --git a/fabrication/src/main/java/mrtjp/projectred/fabrication/engine/PRFabricationEngine.java b/fabrication/src/main/java/mrtjp/projectred/fabrication/engine/PRFabricationEngine.java new file mode 100644 index 000000000..0c820e352 --- /dev/null +++ b/fabrication/src/main/java/mrtjp/projectred/fabrication/engine/PRFabricationEngine.java @@ -0,0 +1,102 @@ +package mrtjp.projectred.fabrication.engine; + +import mrtjp.fengine.api.FabricationEngine; +import mrtjp.fengine.api.ICAssembler; +import mrtjp.fengine.api.ICFlatMap; +import mrtjp.fengine.api.ICStepThroughAssembler; +import mrtjp.fengine.simulate.ByteRegister; +import mrtjp.fengine.simulate.ICGate; +import mrtjp.fengine.simulate.ICSimulation; +import mrtjp.fengine.simulate.StaticByteRegister; +import mrtjp.projectred.fabrication.engine.gates.*; + +import java.util.HashMap; +import java.util.Map; + +public class PRFabricationEngine extends FabricationEngine { + + // Static register allocations + public static final int REG_IN_BASE = 0; + public static final int REG_OUT_BASE = 64; + + public static final int REG_TIME_3 = 128; // Upper 8 bits of time + public static final int REG_TIME_2 = 129; + public static final int REG_TIME_1 = 130; + public static final int REG_TIME_0 = 131; // Lower 8 bits of time + + public static final int REG_ZERO = 132; + public static final int REG_ONE = 133; + + public static final PRFabricationEngine instance = new PRFabricationEngine(); + + public static final ICFlatMap EMPTY_FLAT_MAP = instance.newAssembler().result(); + public static final ICSimulation EMPTY_SIMULATION = new ICSimulation(EMPTY_FLAT_MAP); + + public static final String EMPTY_FLAT_MAP_SERIALIZED = instance.serializeFlatMap(EMPTY_FLAT_MAP); + public static final String EMPTY_SIMULATION_SERIALIZED = instance.serializeSimulation(EMPTY_SIMULATION); + + public static int inputRegisterId(int r, int i) { + return REG_IN_BASE + r * 16 + i; + } + + public static int outputRegisterId(int r, int i) { + return REG_OUT_BASE + r * 16 + i; + } + + @Override + public ICAssembler newAssembler() { + ICAssembler assembler = super.newAssembler(); + addStaticRegisters(assembler); + return assembler; + } + + @Override + public ICStepThroughAssembler newStepThroughAssembler() { + ICStepThroughAssembler assembler = super.newStepThroughAssembler(); + addStaticRegisters(assembler); + return assembler; + } + + private void addStaticRegisters(ICAssembler assembler) { + // Add Static registers + for (int i = 0; i < 16; i++) { + for (int r = 0; r < 4; r++) { + assembler.addRegister(inputRegisterId(r, i), new ByteRegister()); + assembler.addRegister(outputRegisterId(r, i), new ByteRegister()); + } + } + + // Add time registers + assembler.addRegister(REG_TIME_3, new ByteRegister()); + assembler.addRegister(REG_TIME_2, new ByteRegister()); + assembler.addRegister(REG_TIME_1, new ByteRegister()); + assembler.addRegister(REG_TIME_0, new ByteRegister()); + + // Add zero and one registers + assembler.addRegister(REG_ZERO, new StaticByteRegister((byte) 0)); + assembler.addRegister(REG_ONE, new StaticByteRegister((byte) 1)); + } + + @Override + public Map, String> getGateSerializationMap() { + Map, String> map = new HashMap<>(); + + map.put(ORGateTile.ORGate.class, "pr_or"); //TODO create an enum to keep track of these. Label must be permanent to avoid breaking saves. + map.put(NORGateTile.NORGate.class, "pr_nor"); + map.put(NOTGateTile.NOTGate.class, "pr_not"); + map.put(ANDGateTile.ANDGate.class, "pr_and"); + map.put(NANDGateTile.NANDGate.class, "pr_nand"); + map.put(XORGateTile.XORGate.class, "pr_xor"); + map.put(XNORGateTile.XNORGate.class, "pr_xnor"); + map.put(BufferGateTile.BufferGate.class, "pr_buff"); + map.put(MultiplexerGateTile.MultiplexerGate.class, "pr_mlpx"); + map.put(PulseGateTile.PulseGate.class, "pr_pulse"); + map.put(RepeaterGateTile.RepeaterGate.class, "pr_repeater"); + map.put(RandomizerGateTile.RandomizerGate.class, "pr_rand"); + map.put(SRLatchGateTile.SRLatchGate.class, "pr_srlatch"); + map.put(ToggleLatchGateTile.ToggleLatchGate.class, "pr_tglatch"); + map.put(TransparentLatchGateTile.TransparentLatchGate.class, "pr_trlatch"); + + return map; + } +} diff --git a/fabrication/src/main/java/mrtjp/projectred/fabrication/engine/gates/ANDGateTile.java b/fabrication/src/main/java/mrtjp/projectred/fabrication/engine/gates/ANDGateTile.java new file mode 100644 index 000000000..a0035e581 --- /dev/null +++ b/fabrication/src/main/java/mrtjp/projectred/fabrication/engine/gates/ANDGateTile.java @@ -0,0 +1,45 @@ +package mrtjp.projectred.fabrication.engine.gates; + +import mrtjp.fengine.simulate.ICGate; +import mrtjp.fengine.simulate.ICSimulation; + +public class ANDGateTile extends SimpleGateTile { + + public ANDGateTile() { + super(ICGateTileType.AND); + } + + @Override + protected int redstoneOutputMask() { + return 1; + } + + @Override + protected int redstoneInputMask() { + return ~getShape() << 1 & 0xE; + } + + @Override + protected int getDeadSides() { + return 3; + } + + @Override + public ICGate createGate() { + return new ANDGate(); + } + + public static class ANDGate implements ICGate { + + @Override + public void compute(ICSimulation ic, int[] inputs, int[] outputs) { + for (int i = 0; i < inputs.length; i++) { + if (ic.getRegByteVal(inputs[i]) == 0) { + ic.queueRegByteVal(outputs[0], (byte) 0); + return; + } + } + ic.queueRegByteVal(outputs[0], (byte) 1); + } + } +} diff --git a/fabrication/src/main/java/mrtjp/projectred/fabrication/engine/gates/BufferGateTile.java b/fabrication/src/main/java/mrtjp/projectred/fabrication/engine/gates/BufferGateTile.java new file mode 100644 index 000000000..78da9fc63 --- /dev/null +++ b/fabrication/src/main/java/mrtjp/projectred/fabrication/engine/gates/BufferGateTile.java @@ -0,0 +1,45 @@ +package mrtjp.projectred.fabrication.engine.gates; + +import mrtjp.fengine.simulate.ICGate; +import mrtjp.fengine.simulate.ICSimulation; + +public class BufferGateTile extends SimpleGateTile { + + public BufferGateTile() { + super(ICGateTileType.BUFFER); + } + + @Override + protected int redstoneOutputMask() { + return ~((getShape() & 1) << 1 | (getShape() & 2) << 2) & 0xB; + } + + @Override + protected int redstoneInputMask() { + return 4; + } + + @Override + protected int getDeadSides() { + return 2; + } + + @Override + protected int getMaxDeadSides() { + return 2; + } + + @Override + public ICGate createGate() { + return new BufferGate(); + } + + public static class BufferGate implements ICGate { + + @Override + public void compute(ICSimulation ic, int[] inputs, int[] outputs) { + for (int i = 0; i < outputs.length; i++) + ic.queueRegByteVal(outputs[i], ic.getRegByteVal(inputs[0]) != 0 ? (byte) 1 : (byte) 0); + } + } +} diff --git a/fabrication/src/main/java/mrtjp/projectred/fabrication/engine/gates/GateTile.java b/fabrication/src/main/java/mrtjp/projectred/fabrication/engine/gates/GateTile.java new file mode 100644 index 000000000..500004473 --- /dev/null +++ b/fabrication/src/main/java/mrtjp/projectred/fabrication/engine/gates/GateTile.java @@ -0,0 +1,207 @@ +package mrtjp.projectred.fabrication.engine.gates; + +import codechicken.lib.data.MCDataInput; +import codechicken.lib.data.MCDataOutput; +import codechicken.lib.render.CCRenderState; +import codechicken.lib.vec.Transformation; +import mrtjp.projectred.fabrication.engine.BaseTile; +import mrtjp.projectred.fabrication.engine.IConnectableICTile; +import mrtjp.projectred.fabrication.engine.IRotatableICTile; +import mrtjp.projectred.integration.client.GateModelRenderer; +import mrtjp.projectred.integration.part.IGateRenderData; +import net.minecraft.nbt.CompoundTag; + +import java.util.Optional; + +public abstract class GateTile extends BaseTile implements IConnectableICTile, IRotatableICTile, IGateRenderData { + + public static final int PACKET_ROTATION = 1; + public static final int PACKET_SHAPE = 2; + public static final int PACKET_CLIENT_ROTATE_REQUEST = 3; + public static final int PACKET_CLIENT_CONFIGURE_REQUEST = 4; + + private byte connMask = 0; + private byte gateShape = 0; + private byte gateRotation = 0; + + private final ICGateTileType gateTileType; + + public GateTile(ICGateTileType gateTileType) { + super(gateTileType.tileType); + this.gateTileType = gateTileType; + } + + public int getShape() { + return gateShape & 0xFF; + } + + public void setShape(int shape) { + gateShape = (byte) shape; + } + + public void preparePlacement(int r) { + setRotation(r); + } + + @Override + public void save(CompoundTag tag) { + tag.putByte("orient", gateRotation); + tag.putByte("shape", gateShape); + tag.putByte("connMask", connMask); + } + + @Override + public void load(CompoundTag tag) { + gateRotation = tag.getByte("orient"); + gateShape = tag.getByte("shape"); + connMask = tag.getByte("connMask"); + } + + @Override + public void writeDesc(MCDataOutput out) { + out.writeByte(gateRotation); + out.writeByte(gateShape); + } + + @Override + public void readDesc(MCDataInput in) { + gateRotation = in.readByte(); + gateShape = in.readByte(); + } + + @Override + public void read(MCDataInput in, int key) { + switch (key) { + case PACKET_ROTATION: + gateRotation = in.readByte(); + break; + case PACKET_SHAPE: + gateShape = in.readByte(); + break; + case PACKET_CLIENT_ROTATE_REQUEST: + rotateAndSend(); + break; + case PACKET_CLIENT_CONFIGURE_REQUEST: + configureAndSend(); + break; + default: + super.read(in, key); + } + } + + protected void sendRotationUpdate() { + getWriteStream(PACKET_ROTATION).writeByte(gateRotation); + } + + protected void sendShapeUpdate() { + getWriteStream(PACKET_SHAPE).writeByte(gateShape); + } + + protected void rotateAndSend() { + setRotation((getRotation()+1)%4); + updateConns(); + sendRotationUpdate(); + notifyNeighbors(0xF); + getEditor().markTileChange(); + } + + protected void configureAndSend() { + if (cycleShape()) { + updateConns(); + sendShapeUpdate(); + notifyNeighbors(0xF); + getEditor().markTileChange(); + } + } + + @Override + public void onNeighborChanged() { + super.onNeighborChanged(); + if (updateConns()) + getEditor().markTileChange(); + } + + @Override + public void onAdded() { + super.onAdded(); + updateConns(); + onGatePlaced(); + } + + @Override + public void onRemoved() { + super.onRemoved(); + notifyNeighbors(0xF); + } + + @Override + public void renderTile(CCRenderState ccrs, Transformation t, float partialFrame) { + GateModelRenderer r = GateModelRenderer.instance(); + r.renderStatic(ccrs, gateTileType.renderIndex, this, getRotation() & 0x3, t); + r.renderDynamic(ccrs, gateTileType.renderIndex, this, getRotation() & 0x3, t, partialFrame); + } + + protected void notifyNeighbors(int rMask) { + int absRMask = toAbsoluteMask(rMask); + for (int r = 0; r < 4; r++) if ((absRMask & 1 << r) != 0) { + int absDir = IRotatableICTile.rotationToDir(r); + getEditor().queueNeighborChange(getPos().offset(absDir)); + } + } + + //region IRotatableICTile implementation + @Override + public int getRotation() { + return gateRotation & 0x3; + } + + @Override + public void setRotation(int r) { + gateRotation = (byte) (gateRotation & 0xFC | r); + } + //endregion + + //region IConnectableICTile implementation + @Override + public int getConnMask() { + return connMask & 0xFF; + } + + @Override + public void setConnMask(int connMask) { + this.connMask = (byte) connMask; + } + + @Override + public IConnectableICTile getTileTowardsDir(int dir) { + Optional tile = getMap().getBaseTile(getPos().offset(dir)); + if (tile.isPresent() && tile.get() instanceof IConnectableICTile) return (IConnectableICTile) tile.get(); + return null; + } + + @Override + public boolean canConnectTo(IConnectableICTile target, int towardsDir) { + return canGateConnectTo(target, toInternalRotation(IRotatableICTile.dirToRotation(towardsDir))); + } + + @Override + public void onMaskChanged() { + // Gate rendering does not require connMask, so don't send to clients + } + //endregion + + //region IGateRenderKey implementation + @Override + public int shape() { + return this.gateShape; + } + //endregion + + //region GateTile logic override points + protected void onGatePlaced() { } + + protected abstract boolean canGateConnectTo(IConnectableICTile target, int r); + + protected abstract boolean cycleShape(); + //endregion +} diff --git a/fabrication/src/main/java/mrtjp/projectred/fabrication/engine/gates/ICGateTileType.java b/fabrication/src/main/java/mrtjp/projectred/fabrication/engine/gates/ICGateTileType.java new file mode 100644 index 000000000..0f72ee247 --- /dev/null +++ b/fabrication/src/main/java/mrtjp/projectred/fabrication/engine/gates/ICGateTileType.java @@ -0,0 +1,46 @@ +package mrtjp.projectred.fabrication.engine.gates; + +import mrtjp.projectred.fabrication.editor.GatePlacementType; +import mrtjp.projectred.fabrication.engine.ICTileType; +import mrtjp.projectred.integration.GateType; +import mrtjp.projectred.integration.client.GateModelRenderer; + +import static mrtjp.projectred.fabrication.editor.GatePlacementType.INTERNAL; +import static mrtjp.projectred.fabrication.editor.GatePlacementType.IO_EDGE; + +public enum ICGateTileType { + IO(ICTileType.IO_GATE, GateModelRenderer.getNonPartRenderIndex(0), IO_EDGE), + + + OR(ICTileType.OR_GATE, GateModelRenderer.getRenderIndex(GateType.OR)), + NOR(ICTileType.NOR_GATE, GateModelRenderer.getRenderIndex(GateType.NOR)), + NOT(ICTileType.NOT_GATE, GateModelRenderer.getRenderIndex(GateType.NOT)), + AND(ICTileType.AND_GATE, GateModelRenderer.getRenderIndex(GateType.AND)), + NAND(ICTileType.NAND_GATE, GateModelRenderer.getRenderIndex(GateType.NAND)), + XOR(ICTileType.XOR_GATE, GateModelRenderer.getRenderIndex(GateType.XOR)), + XNOR(ICTileType.XNOR_GATE, GateModelRenderer.getRenderIndex(GateType.XNOR)), + BUFFER(ICTileType.BUFFER_GATE, GateModelRenderer.getRenderIndex(GateType.BUFFER)), + MULTIPLEXER(ICTileType.MULTIPLEXER_GATE, GateModelRenderer.getRenderIndex(GateType.MULTIPLEXER)), + PULSE(ICTileType.PULSE_GATE, GateModelRenderer.getRenderIndex(GateType.PULSE)), + REPEATER(ICTileType.REPEATER_GATE, GateModelRenderer.getRenderIndex(GateType.REPEATER)), + RANDOMIZER(ICTileType.RANDOMIZER_GATE, GateModelRenderer.getRenderIndex(GateType.RANDOMIZER)), + SR_LATCH(ICTileType.SR_LATCH_GATE, GateModelRenderer.getRenderIndex(GateType.SR_LATCH)), + TOGGLE_LATCH(ICTileType.TOGGLE_LATCH_GATE, GateModelRenderer.getRenderIndex(GateType.TOGGLE_LATCH)), + TRANSPARENT_LATCH(ICTileType.TRANSPARENT_LATCH_GATE, GateModelRenderer.getRenderIndex(GateType.TRANSPARENT_LATCH)); + + ; + + public final ICTileType tileType; + public final int renderIndex; + public final GatePlacementType placementType; + + ICGateTileType(ICTileType tileType, int renderIndex) { + this(tileType, renderIndex, INTERNAL); + } + + ICGateTileType(ICTileType tileType, int renderIndex, GatePlacementType placementType) { + this.tileType = tileType; + this.renderIndex = renderIndex; + this.placementType = placementType; + } +} diff --git a/fabrication/src/main/java/mrtjp/projectred/fabrication/engine/gates/IOGateTile.java b/fabrication/src/main/java/mrtjp/projectred/fabrication/engine/gates/IOGateTile.java new file mode 100644 index 000000000..4b78c5375 --- /dev/null +++ b/fabrication/src/main/java/mrtjp/projectred/fabrication/engine/gates/IOGateTile.java @@ -0,0 +1,272 @@ +package mrtjp.projectred.fabrication.engine.gates; + +import codechicken.lib.colour.EnumColour; +import codechicken.lib.data.MCDataInput; +import codechicken.lib.data.MCDataOutput; +import codechicken.lib.vec.Cuboid6; +import codechicken.lib.vec.Rotation; +import codechicken.lib.vec.Transformation; +import codechicken.lib.vec.Vector3; +import mrtjp.fengine.api.IPathFinder; +import mrtjp.fengine.assemble.PathFinderResult; +import mrtjp.projectred.fabrication.engine.ICConnectionType; +import mrtjp.projectred.fabrication.engine.ICSimulationContainer; +import mrtjp.projectred.fabrication.engine.IIOConnectionTile; +import mrtjp.projectred.fabrication.engine.IRotatableICTile; +import net.minecraft.ChatFormatting; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.network.chat.Component; +import net.minecraft.network.chat.TextComponent; +import net.minecraft.network.chat.TranslatableComponent; +import net.minecraftforge.api.distmarker.Dist; +import net.minecraftforge.api.distmarker.OnlyIn; + +import java.util.LinkedList; +import java.util.List; +import java.util.Optional; + +import static mrtjp.projectred.fabrication.ProjectRedFabrication.LOGGER; +import static mrtjp.projectred.fabrication.engine.PRFabricationEngine.*; + +public class IOGateTile extends RedstoneGateTile implements IIOConnectionTile { + + public static final int COLOUR_PACKET = 6; + + private int regId = REG_ZERO; + private byte colour = 0; + + public IOGateTile() { + super(ICGateTileType.IO); + } + + @Override + public void save(CompoundTag tag) { + super.save(tag); + tag.putInt("reg", regId); + tag.putByte("colour", colour); + } + + @Override + public void load(CompoundTag tag) { + super.load(tag); + regId = tag.getInt("reg"); + colour = tag.getByte("colour"); + } + + @Override + public void writeDesc(MCDataOutput out) { + super.writeDesc(out); + out.writeByte(colour); + } + + @Override + public void readDesc(MCDataInput in) { + super.readDesc(in); + colour = in.readByte(); + } + + @Override + public void read(MCDataInput in, int key) { + switch (key) { + case COLOUR_PACKET: + colour = in.readByte(); + break; + default: + super.read(in, key); + } + } + + protected void sendColourUpdate() { + getWriteStream(COLOUR_PACKET).writeByte(colour); + } + + @Override + public boolean isInputIOMode() { + return getShape() == 0; + } + + @Override + public int getIOSide() { + return getRotation(); + } + + @Override + public ICConnectionType getConnectionType() { + return ICConnectionType.BUNDLED; + } + + protected void toggleWorldInput() { + LOGGER.info("Toggling world input"); + getEditor().getStateMachine().onInputRegistersChanged(getIOSide(), i -> (short) (i ^ (1< getInteractionZones() { + List zones = new LinkedList<>(); + + zones.add(new Cuboid6(1, 2, 0, 15, 3, 5)); // Toggle state of IO register + zones.add(new Cuboid6(2, 2, 5, 6, 3, 8)); // Toggle IO mode + zones.add(new Cuboid6(1, 2, 8.5, 5, 4, 12.5)); // Toggle colour + + Transformation rotation = Rotation.quarterRotations[getRotation()].at(new Vector3(8, 8, 8)); + zones.forEach(c -> c.apply(rotation)); + + return zones; + } + + @Override + @OnlyIn(Dist.CLIENT) + public void buildInteractionToolTip(List toolTip, int i) { + + switch (i) { //TODO localize + case 0: + toolTip.add(new TextComponent("Toggle state")); + toolTip.add(new TextComponent(((getState() & 0x44) != 0 ? "0x1" : "0x0")).withStyle(ChatFormatting.GRAY)); + break; + case 1: + toolTip.add(new TextComponent("Toggle IO mode")); + toolTip.add(new TextComponent((isInputIOMode() ? "input" : "output")).withStyle(ChatFormatting.GRAY)); + break; + case 2: + toolTip.add(new TextComponent("Toggle colour")); + toolTip.add(new TranslatableComponent(EnumColour.values()[colour & 0xFF].getUnlocalizedName()).withStyle(ChatFormatting.GRAY)); + break; + default: + } + } + + @Override + public void onInteractionZoneClicked(int i) { + + switch (i) { + case 0: + toggleWorldInput(); + break; + case 1: + configureAndSend(); + break; + case 2: + incrementColour(); + break; + default: + } + } + + // IGateRenderKey overrides + + @Override + public int state2() { + return colour & 0xFF; + } + + // RedstoneGateTile overrides + + @Override + protected boolean cycleShape() { + setShape((getShape() + 1) % 2); + return true; + } + + @Override + protected int redstoneOutputMask() { + return isInputIOMode() ? 0x0 : 0x4; + } + + @Override + protected int redstoneInputMask() { + return isInputIOMode() ? 0x4 : 0x0; + } + + // BaseTile overrides + + @Override + public void onSimRegistersChanged(int rMask, ICSimulationContainer container) { + int oldState = getState(); + int newState = pullInputMask(container) & 0xF | pullOutputMask(container) << 4; + if (oldState != newState) { + setState(newState); + sendStateUpdate(); + } + } + + protected int pullInputMask(ICSimulationContainer container) { + return !isInputIOMode() && container.pullRegisterValue(regId) != 0 ? 0x4 : 0; + } + + protected int pullOutputMask(ICSimulationContainer container) { + return isInputIOMode() && container.pullRegisterValue(regId) != 0 ? 0x4 : 0; + } + + // FETile overrides + + @Override + public void allocate(Allocator allocator) { + if (isInputIOMode()) { // Input from world, output into simulation + regId = allocator.allocRegisterID(getStaticInputRegister(colour)); + } else { // Input from simulation, output into world + regId = REG_ZERO; // Will be located, then remapped to target static register + } + } + + @Override + public void locate(IPathFinder pathFinder) { + if (!isInputIOMode()) { + int absR = toAbsoluteRotation(2); + int absDir = IRotatableICTile.rotationToDir(absR); + PathFinderResult pfr = pathFinder.doPathFinding((d, p) -> d == absDir); + if (pfr.outputRegisters.size() > 1) { + // TODO log this somewhere + System.out.println("ERR: Unexpected multiple drivers: " + pfr.outputRegisters); + } + if (!pfr.outputRegisters.isEmpty()) { + regId = pfr.outputRegisters.get(0); + } + } + } + + @Override + public void registerRemaps(RemapRegistry remapRegistry) { + if (!isInputIOMode() && regId != REG_ZERO) { + remapRegistry.addRemap(regId, getStaticOutputRegister(colour)); + } + } + + @Override + public void consumeRemaps(RemapProvider remapProvider) { + regId = remapProvider.getRemappedRegisterID(regId); + } + + @Override + public void collect(Collector collector) { + // Static registers are pre-added during assembler instantiation +// if (isInputIOMode()) { +// collector.addRegister(regId, new ByteRegister()); +// } + } + + @Override + public Optional getOutputRegister(int outDir, int outPort) { + int gateOutputDir = IRotatableICTile.rotationToDir(toAbsoluteRotation(2)); + return isInputIOMode() && outDir == gateOutputDir ? Optional.of(regId) : Optional.empty(); + } + + @Override + public Optional getInputRegister(int inDir, int inPort) { + int gateInputDir = IRotatableICTile.rotationToDir(toAbsoluteRotation(2)); + return !isInputIOMode() && inDir == gateInputDir ? Optional.of(regId) : Optional.empty(); + } +} diff --git a/fabrication/src/main/java/mrtjp/projectred/fabrication/engine/gates/InternalStateGateTile.java b/fabrication/src/main/java/mrtjp/projectred/fabrication/engine/gates/InternalStateGateTile.java new file mode 100644 index 000000000..102a7ef97 --- /dev/null +++ b/fabrication/src/main/java/mrtjp/projectred/fabrication/engine/gates/InternalStateGateTile.java @@ -0,0 +1,53 @@ +package mrtjp.projectred.fabrication.engine.gates; + +import mrtjp.fengine.simulate.ByteRegister; +import net.minecraft.nbt.CompoundTag; + +public abstract class InternalStateGateTile extends SidedRedstoneGateTile { + + protected int stateReg = -1; + + public InternalStateGateTile(ICGateTileType gateType) { + super(gateType); + } + + @Override + public void save(CompoundTag tag) { + super.save(tag); + tag.putInt("regS", stateReg); + } + + @Override + public void load(CompoundTag tag) { + super.load(tag); + stateReg = tag.getInt("regS"); + } + + @Override + protected void clearRegisterIds() { + super.clearRegisterIds(); + stateReg = -1; + } + + //region FETile overrides + + @Override + public void allocate(Allocator allocator) { + super.allocate(allocator); + stateReg = allocator.allocRegisterID(); + } + + @Override + public void consumeRemaps(RemapProvider remapProvider) { + super.consumeRemaps(remapProvider); + stateReg = remapProvider.getRemappedRegisterID(stateReg); + } + + @Override + public void collect(Collector collector) { + super.collect(collector); + collector.addRegister(stateReg, new ByteRegister()); + } + + //endregion +} diff --git a/fabrication/src/main/java/mrtjp/projectred/fabrication/engine/gates/MultiplexerGateTile.java b/fabrication/src/main/java/mrtjp/projectred/fabrication/engine/gates/MultiplexerGateTile.java new file mode 100644 index 000000000..bb6f59c75 --- /dev/null +++ b/fabrication/src/main/java/mrtjp/projectred/fabrication/engine/gates/MultiplexerGateTile.java @@ -0,0 +1,41 @@ +package mrtjp.projectred.fabrication.engine.gates; + +import mrtjp.fengine.simulate.ICGate; +import mrtjp.fengine.simulate.ICSimulation; + +public class MultiplexerGateTile extends SimpleGateTile { + + public MultiplexerGateTile() { + super(ICGateTileType.MULTIPLEXER); + } + + @Override + protected int redstoneOutputMask() { + return 1; + } + + @Override + protected int redstoneInputMask() { + return 0xE; + } + + @Override + public ICGate createGate() { + return new MultiplexerGate(); + } + + public static class MultiplexerGate implements ICGate { + + @Override + public void compute(ICSimulation ic, int[] inputs, int[] outputs) { + + boolean in0 = ic.getRegByteVal(inputs[0]) != 0; + boolean in1 = ic.getRegByteVal(inputs[1]) != 0; + boolean in2 = ic.getRegByteVal(inputs[2]) != 0; + + ic.queueRegByteVal(outputs[0], in0 ? + (byte) (in1 ? 1 : 0) : + (byte) (in2 ? 1 : 0)); + } + } +} diff --git a/fabrication/src/main/java/mrtjp/projectred/fabrication/engine/gates/NANDGateTile.java b/fabrication/src/main/java/mrtjp/projectred/fabrication/engine/gates/NANDGateTile.java new file mode 100644 index 000000000..dc62f098d --- /dev/null +++ b/fabrication/src/main/java/mrtjp/projectred/fabrication/engine/gates/NANDGateTile.java @@ -0,0 +1,45 @@ +package mrtjp.projectred.fabrication.engine.gates; + +import mrtjp.fengine.simulate.ICGate; +import mrtjp.fengine.simulate.ICSimulation; + +public class NANDGateTile extends SimpleGateTile { + + public NANDGateTile() { + super(ICGateTileType.NAND); + } + + @Override + protected int redstoneOutputMask() { + return 1; + } + + @Override + protected int redstoneInputMask() { + return ~getShape() << 1 & 0xE; + } + + @Override + protected int getDeadSides() { + return 3; + } + + @Override + public ICGate createGate() { + return new NANDGate(); + } + + public static class NANDGate implements ICGate { + + @Override + public void compute(ICSimulation ic, int[] inputs, int[] outputs) { + for (int i = 0; i < inputs.length; i++) { + if (ic.getRegByteVal(inputs[i]) == 0) { + ic.queueRegByteVal(outputs[0], (byte) 1); + return; + } + } + ic.queueRegByteVal(outputs[0], (byte) 0); + } + } +} diff --git a/fabrication/src/main/java/mrtjp/projectred/fabrication/engine/gates/NORGateTile.java b/fabrication/src/main/java/mrtjp/projectred/fabrication/engine/gates/NORGateTile.java new file mode 100644 index 000000000..72c2e8754 --- /dev/null +++ b/fabrication/src/main/java/mrtjp/projectred/fabrication/engine/gates/NORGateTile.java @@ -0,0 +1,45 @@ +package mrtjp.projectred.fabrication.engine.gates; + +import mrtjp.fengine.simulate.ICGate; +import mrtjp.fengine.simulate.ICSimulation; + +public class NORGateTile extends SimpleGateTile { + + public NORGateTile() { + super(ICGateTileType.NOR); + } + + @Override + protected int redstoneOutputMask() { + return 1; + } + + @Override + protected int redstoneInputMask() { + return ~getShape() << 1 & 0xE; + } + + @Override + protected int getDeadSides() { + return 3; + } + + @Override + public ICGate createGate() { + return new NORGate(); + } + + public static class NORGate implements ICGate { + + @Override + public void compute(ICSimulation ic, int[] inputs, int[] outputs) { + for (int i = 0; i < inputs.length; i++) { + if (ic.getRegByteVal(inputs[i]) != 0) { + ic.queueRegByteVal(outputs[0], (byte) 0); + return; + } + } + ic.queueRegByteVal(outputs[0], (byte) 1); + } + } +} diff --git a/fabrication/src/main/java/mrtjp/projectred/fabrication/engine/gates/NOTGateTile.java b/fabrication/src/main/java/mrtjp/projectred/fabrication/engine/gates/NOTGateTile.java new file mode 100644 index 000000000..0a0a90e87 --- /dev/null +++ b/fabrication/src/main/java/mrtjp/projectred/fabrication/engine/gates/NOTGateTile.java @@ -0,0 +1,42 @@ +package mrtjp.projectred.fabrication.engine.gates; + +import mrtjp.fengine.simulate.ICGate; +import mrtjp.fengine.simulate.ICSimulation; + +public class NOTGateTile extends SimpleGateTile { + + public NOTGateTile() { + super(ICGateTileType.NOT); + } + + @Override + protected int redstoneOutputMask() { + return ~((getShape() & 1) << 1 | (getShape() & 2) >> 1 | (getShape() & 4) << 1) & 0xB; + } + + @Override + protected int redstoneInputMask() { + return 4; + } + + @Override + protected int getDeadSides() { + return 3; + } + + @Override + public ICGate createGate() { + return new NOTGate(); + } + + public static class NOTGate implements ICGate { + + @Override + public void compute(ICSimulation ic, int[] inputs, int[] outputs) { + boolean isHigh = ic.getRegByteVal(inputs[0]) != 0; + for (int i = 0; i < outputs.length; i++) { + ic.queueRegByteVal(outputs[i], isHigh ? 0 : (byte) 1); + } + } + } +} diff --git a/fabrication/src/main/java/mrtjp/projectred/fabrication/engine/gates/ORGateTile.java b/fabrication/src/main/java/mrtjp/projectred/fabrication/engine/gates/ORGateTile.java new file mode 100644 index 000000000..357dfb014 --- /dev/null +++ b/fabrication/src/main/java/mrtjp/projectred/fabrication/engine/gates/ORGateTile.java @@ -0,0 +1,45 @@ +package mrtjp.projectred.fabrication.engine.gates; + +import mrtjp.fengine.simulate.ICGate; +import mrtjp.fengine.simulate.ICSimulation; + +public class ORGateTile extends SimpleGateTile { + + public ORGateTile() { + super(ICGateTileType.OR); + } + + @Override + protected int redstoneOutputMask() { + return 1; + } + + @Override + protected int redstoneInputMask() { + return ~getShape() << 1 & 0xE; + } + + @Override + protected int getDeadSides() { + return 3; + } + + @Override + public ICGate createGate() { + return new ORGate(); + } + + public static class ORGate implements ICGate { + + @Override + public void compute(ICSimulation ic, int[] inputs, int[] outputs) { + for (int i = 0; i < inputs.length; i++) { + if (ic.getRegByteVal(inputs[i]) != 0) { + ic.queueRegByteVal(outputs[0], (byte) 1); + return; + } + } + ic.queueRegByteVal(outputs[0], (byte) 0); + } + } +} diff --git a/fabrication/src/main/java/mrtjp/projectred/fabrication/engine/gates/PulseGateTile.java b/fabrication/src/main/java/mrtjp/projectred/fabrication/engine/gates/PulseGateTile.java new file mode 100644 index 000000000..0bc644343 --- /dev/null +++ b/fabrication/src/main/java/mrtjp/projectred/fabrication/engine/gates/PulseGateTile.java @@ -0,0 +1,101 @@ +package mrtjp.projectred.fabrication.engine.gates; + +import mrtjp.fengine.simulate.ICGate; +import mrtjp.fengine.simulate.ICSimulation; + +import java.util.ArrayList; +import java.util.List; + +import static mrtjp.projectred.fabrication.ProjectRedFabrication.LOGGER; +import static mrtjp.projectred.fabrication.engine.PRFabricationEngine.*; + +public class PulseGateTile extends TimedStateGateTile { + + public PulseGateTile() { + super(ICGateTileType.PULSE); + } + + //region RedstoneGateTile overrides + + @Override + protected boolean cycleShape() { + return false; + } + + @Override + protected int redstoneInputMask() { + return 4; + } + + @Override + protected int redstoneOutputMask() { + return 1; + } + + //endregion + + @Override + protected void collectGate(Collector collector, int gateId, int[] inputRegisters, int[] outputRegisters) { + + List inputRegs = new ArrayList<>(); + List outputRegs = new ArrayList<>(); + + inputRegs.add(stateReg); + inputRegs.add(timeReg3); + inputRegs.add(timeReg2); + inputRegs.add(timeReg1); + inputRegs.add(timeReg0); + inputRegs.add(inputRegisters[2]); + + inputRegs.add(REG_TIME_3); + inputRegs.add(REG_TIME_2); + inputRegs.add(REG_TIME_1); + inputRegs.add(REG_TIME_0); + + outputRegs.add(stateReg); + outputRegs.add(timeReg3); + outputRegs.add(timeReg2); + outputRegs.add(timeReg1); + outputRegs.add(timeReg0); + outputRegs.add(outputRegisters[0]); + + collector.addGate(gateId, new PulseGate(), inputRegs, outputRegs); + } + + public static class PulseGate implements ICGate { + + @Override + public void compute(ICSimulation ic, int[] inputs, int[] outputs) { + + int stateVal = ic.getRegByteVal(inputs[0]); + switch (stateVal) { + case 0: { // Waiting for high input + if (ic.getRegByteVal(inputs[5]) != 0) { // if input is high + ic.queueRegByteVal(outputs[0], (byte) 1); // go to state 1 + ic.queueRegByteVal(outputs[5], (byte) 1); // set output high + ic.queueRegLongVal(outputs[1], outputs[2], outputs[3], outputs[4], + ic.getRegLongVal(inputs[6], inputs[7], inputs[8], inputs[9]) + 2); // set time to t + 2 + } + break; + } + case 1: { // Waiting for timer to expire + if (ic.getRegLongVal(inputs[6], inputs[7], inputs[8], inputs[9]) >= ic.getRegLongVal(inputs[1], inputs[2], inputs[3], inputs[4])) { // if t is at scheduled time + ic.queueRegByteVal(outputs[0], (byte) (ic.getRegByteVal(inputs[5]) == 0 ? 0 : 2)); // if input high, got to state 2, else state 0 + ic.queueRegByteVal(outputs[5], (byte) 0); // set output low + ic.queueRegLongVal(outputs[1], outputs[2], outputs[3], outputs[4], -1); // disable timer + } + break; + } + case 2: { // Waiting for low input state + if (ic.getRegByteVal(inputs[5]) == 0) { // if input is low + ic.queueRegByteVal(outputs[0], (byte) 0); // go to state 0 + } + break; + } + default: + LOGGER.error("Invalid state: " + stateVal); + ic.queueRegByteVal(outputs[0], (byte) 0); // go to state 0 + } + } + } +} diff --git a/fabrication/src/main/java/mrtjp/projectred/fabrication/engine/gates/RandomizerGateTile.java b/fabrication/src/main/java/mrtjp/projectred/fabrication/engine/gates/RandomizerGateTile.java new file mode 100644 index 000000000..c7a7f6111 --- /dev/null +++ b/fabrication/src/main/java/mrtjp/projectred/fabrication/engine/gates/RandomizerGateTile.java @@ -0,0 +1,122 @@ +package mrtjp.projectred.fabrication.engine.gates; + +import mrtjp.fengine.simulate.ICGate; +import mrtjp.fengine.simulate.ICSimulation; + +import java.util.ArrayList; +import java.util.List; +import java.util.Random; + +import static mrtjp.projectred.fabrication.ProjectRedFabrication.LOGGER; +import static mrtjp.projectred.fabrication.engine.PRFabricationEngine.*; + +public class RandomizerGateTile extends TimedStateGateTile { + + public RandomizerGateTile() { + super(ICGateTileType.RANDOMIZER); + } + + //region GateTile overrides + + //TODO interaction zones + + //endregion + + //region RedstoneGateTile overrides + + @Override + protected boolean cycleShape() { + return false; + } + + @Override + protected int redstoneInputMask() { + return 4; + } + + @Override + protected int redstoneOutputMask() { + return 0xB; + } + + //endregion + + @Override + protected void collectGate(Collector collector, int gateId, int[] inputRegisters, int[] outputRegisters) { + + List inputRegs = new ArrayList<>(); + List outputRegs = new ArrayList<>(); + + inputRegs.add(stateReg); + inputRegs.add(timeReg3); + inputRegs.add(timeReg2); + inputRegs.add(timeReg1); + inputRegs.add(timeReg0); + inputRegs.add(inputRegisters[2]); + + inputRegs.add(REG_TIME_3); + inputRegs.add(REG_TIME_2); + inputRegs.add(REG_TIME_1); + inputRegs.add(REG_TIME_0); + + outputRegs.add(stateReg); + outputRegs.add(timeReg3); + outputRegs.add(timeReg2); + outputRegs.add(timeReg1); + outputRegs.add(timeReg0); + outputRegs.add(outputRegisters[3] != -1 ? outputRegisters[3] : REG_ZERO); + outputRegs.add(outputRegisters[0] != -1 ? outputRegisters[0] : REG_ZERO); + outputRegs.add(outputRegisters[1] != -1 ? outputRegisters[1] : REG_ZERO); + + collector.addGate(gateId, new RandomizerGateTile.RandomizerGate(), inputRegs, outputRegs); + } + + public static class RandomizerGate implements ICGate { + + private static final Random RAND = new Random(); + + private static byte readState(ICSimulation ic, int[] inputs) { return ic.getRegByteVal(inputs[0]); } + private static long readSchedTime(ICSimulation ic, int[] inputs) { return ic.getRegLongVal(inputs[1], inputs[2], inputs[3], inputs[4]); } + private static byte readInput(ICSimulation ic, int[] inputs) { return ic.getRegByteVal(inputs[5]); } + private static long readSysTime(ICSimulation ic, int[] inputs) { return ic.getRegLongVal(inputs[6], inputs[7], inputs[8], inputs[9]); } + + private static void writeState(ICSimulation ic, int[] outputs, byte state) { ic.queueRegByteVal(outputs[0], state); } + private static void writeSchedTime(ICSimulation ic, int[] outputs, long time) { ic.queueRegLongVal(outputs[1], outputs[2], outputs[3], outputs[4], time); } + private static void writeOutMask(ICSimulation ic, int[] outputs, int mask) { + ic.queueRegByteVal(outputs[5], (byte) ((mask & 1) != 0 ? 1 : 0)); + ic.queueRegByteVal(outputs[6], (byte) ((mask & 2) != 0 ? 1 : 0)); + ic.queueRegByteVal(outputs[7], (byte) ((mask & 4) != 0 ? 1 : 0)); + } + + @Override + public void compute(ICSimulation ic, int[] inputs, int[] outputs) { + + switch (readState(ic, inputs)) { + case 0: { // Waiting for high input + if (readInput(ic, inputs) != 0) { // if input is high + writeState(ic, outputs, (byte) 1); // set state to 1 + writeOutMask(ic, outputs, RAND.nextInt(8)); // set outputs to random state + writeSchedTime(ic, outputs, readSysTime(ic, inputs) + 2); // set scheduled time to t + 2 + } + break; + } + case 1: { // Wait for timer state + if (readSysTime(ic, inputs) >= readSchedTime(ic, inputs)) { // if time is up + if (readInput(ic, inputs) != 0) { // if input is high + // stay in state 1 + writeOutMask(ic, outputs, RAND.nextInt(8)); // set outputs to random state + writeSchedTime(ic, outputs, readSysTime(ic, inputs) + 2); // set scheduled time to t + 2 + } else { + writeState(ic, outputs, (byte) 0); // set state to 0 + writeOutMask(ic, outputs, 0); // set outputs to 0 + } + } + break; + } + default: + LOGGER.error("Invalid state: " + readState(ic, inputs)); + writeState(ic, outputs, (byte) 0); // go to state 0 + } + } + } +} diff --git a/fabrication/src/main/java/mrtjp/projectred/fabrication/engine/gates/RedstoneGateTile.java b/fabrication/src/main/java/mrtjp/projectred/fabrication/engine/gates/RedstoneGateTile.java new file mode 100644 index 000000000..932626ba5 --- /dev/null +++ b/fabrication/src/main/java/mrtjp/projectred/fabrication/engine/gates/RedstoneGateTile.java @@ -0,0 +1,107 @@ +package mrtjp.projectred.fabrication.engine.gates; + +import codechicken.lib.data.MCDataInput; +import codechicken.lib.data.MCDataOutput; +import mrtjp.projectred.fabrication.engine.IConnectableICTile; +import mrtjp.projectred.fabrication.engine.IRedstoneConnectableICTile; +import net.minecraft.nbt.CompoundTag; + +public abstract class RedstoneGateTile extends GateTile implements IRedstoneConnectableICTile { + + public static final int STATE_PACKET = 5; + + /** + * Mapped inputs and outputs of the gate. + * OOOO IIII + * High nybble is output. + * Low nybble is input + */ + private byte gateState = 0; + + public RedstoneGateTile(ICGateTileType gateType) { + super(gateType); + } + + public void setState(int state) { + gateState = (byte) state; + } + + public int getState() { + return gateState & 0xFF; + } + + @Override + public void save(CompoundTag tag) { + super.save(tag); + tag.putByte("state", gateState); + } + + @Override + public void load(CompoundTag tag) { + super.load(tag); + gateState = tag.getByte("state"); + } + + @Override + public void writeDesc(MCDataOutput out) { + super.writeDesc(out); + out.writeByte(gateState); + } + + @Override + public void readDesc(MCDataInput in) { + super.readDesc(in); + gateState = in.readByte(); + } + + @Override + public void read(MCDataInput in, int key) { + switch (key) { + case STATE_PACKET: + gateState = in.readByte(); + break; + default: + super.read(in, key); + } + } + + protected void sendStateUpdate() { + getWriteStream(STATE_PACKET).writeByte(gateState); + } + + //region IGateRenderKey implementation + @Override + public int state() { + return gateState & 0xFF; + } + //endregion + + //region RedstoneGateTile logic override points + @Override + protected boolean canGateConnectTo(IConnectableICTile target, int r) { + if (target instanceof IRedstoneConnectableICTile) + return canConnectRedstone(r); + return false; + } + + protected boolean canConnectRedstone(int r) { + return canInputRedstone(r) || canOutputRedstone(r); + } + + protected boolean canOutputRedstone(int r) { + return (redstoneOutputMask() & 1 << r) != 0; + } + + protected boolean canInputRedstone(int r) { + return (redstoneInputMask() & 1 << r) != 0; + } + + protected int redstoneOutputMask() { + return 0; + } + + protected int redstoneInputMask() { + return 0; + } + //endregion +} diff --git a/fabrication/src/main/java/mrtjp/projectred/fabrication/engine/gates/RepeaterGateTile.java b/fabrication/src/main/java/mrtjp/projectred/fabrication/engine/gates/RepeaterGateTile.java new file mode 100644 index 000000000..4064bacf5 --- /dev/null +++ b/fabrication/src/main/java/mrtjp/projectred/fabrication/engine/gates/RepeaterGateTile.java @@ -0,0 +1,155 @@ +package mrtjp.projectred.fabrication.engine.gates; + +import codechicken.lib.vec.Cuboid6; +import codechicken.lib.vec.Rotation; +import codechicken.lib.vec.Transformation; +import codechicken.lib.vec.Vector3; +import mrtjp.fengine.simulate.ICGate; +import mrtjp.fengine.simulate.ICSimulation; +import net.minecraft.ChatFormatting; +import net.minecraft.network.chat.Component; +import net.minecraft.network.chat.TextComponent; +import net.minecraftforge.api.distmarker.Dist; +import net.minecraftforge.api.distmarker.OnlyIn; + +import java.util.ArrayList; +import java.util.LinkedList; +import java.util.List; + +import static mrtjp.projectred.fabrication.ProjectRedFabrication.LOGGER; +import static mrtjp.projectred.fabrication.engine.PRFabricationEngine.*; + +public class RepeaterGateTile extends TimedStateGateTile { + + private static final int[] DELAYS = { 2, 4, 6, 8, 16, 32, 64, 128, 256 }; + + public RepeaterGateTile() { + super(ICGateTileType.REPEATER); + } + + //region GateTile overrides + + @Override + public List getInteractionZones() { + List zones = new LinkedList<>(); + zones.add(new Cuboid6(1, 2, 1, 15, 3, 15)); + Transformation rotation = Rotation.quarterRotations[getRotation()].at(new Vector3(8, 8, 8)); + zones.forEach(c -> c.apply(rotation)); + return zones; + } + + @Override + @OnlyIn(Dist.CLIENT) + public void buildInteractionToolTip(List toolTip, int i) { + + toolTip.add(new TextComponent("Toggle delay")); + toolTip.add(new TextComponent(DELAYS[getShape()] + " ticks").withStyle(ChatFormatting.GRAY)); //TODO localize + } + + @Override + public void onInteractionZoneClicked(int i) { + configureAndSend(); + } + + //endregion + + //region RedstoneGateTile overrides + + @Override + protected boolean cycleShape() { + setShape((getShape() + 1) % DELAYS.length); + return true; + } + + @Override + protected int redstoneInputMask() { + return 4; + } + + @Override + protected int redstoneOutputMask() { + return 1; + } + + //endregion + + @Override + protected void collectGate(Collector collector, int gateId, int[] inputRegisters, int[] outputRegisters) { + + List inputRegs = new ArrayList<>(); + List outputRegs = new ArrayList<>(); + + inputRegs.add(stateReg); + inputRegs.add(timeReg3); + inputRegs.add(timeReg2); + inputRegs.add(timeReg1); + inputRegs.add(timeReg0); + inputRegs.add(inputRegisters[2]); + + inputRegs.add(REG_TIME_3); + inputRegs.add(REG_TIME_2); + inputRegs.add(REG_TIME_1); + inputRegs.add(REG_TIME_0); + + outputRegs.add(stateReg); + outputRegs.add(timeReg3); + outputRegs.add(timeReg2); + outputRegs.add(timeReg1); + outputRegs.add(timeReg0); + outputRegs.add(outputRegisters[0]); + + collector.addGate(gateId, new RepeaterGate(DELAYS[getShape()]), inputRegs, outputRegs); + } + + public static class RepeaterGate implements ICGate { + + private final int delay; + + public RepeaterGate(int delay) { + this.delay = delay; + } + + @Override + public void compute(ICSimulation ic, int[] inputs, int[] outputs) { + + int stateVal = ic.getRegByteVal(inputs[0]); + switch (stateVal) { + case 0: { // Waiting for high input + if (ic.getRegByteVal(inputs[5]) != 0) { // if input is high + ic.queueRegByteVal(outputs[0], (byte) 1); // go to state 1 + ic.queueRegLongVal(outputs[1], outputs[2], outputs[3], outputs[4], + ic.getRegLongVal(inputs[6], inputs[7], inputs[8], inputs[9]) + delay); // set timer to t + delay + } + break; + } + case 1: { // Waiting for timer to go high + if (ic.getRegLongVal(inputs[6], inputs[7], inputs[8], inputs[9]) >= ic.getRegLongVal(inputs[1], inputs[2], inputs[3], inputs[4])) { // if timer expired + ic.queueRegByteVal(outputs[0], (byte) 2); // go to state 2 + ic.queueRegByteVal(outputs[5], (byte) 1); // set output high + ic.queueRegLongVal(outputs[1], outputs[2], outputs[3], outputs[4], -1); // disable timer + } + break; + } + case 2: { // Waiting for low input + if (ic.getRegByteVal(inputs[5]) == 0) { // if input is low + ic.queueRegByteVal(outputs[0], (byte) 3); // go to state 3 + ic.queueRegLongVal(outputs[1], outputs[2], outputs[3], outputs[4], + ic.getRegLongVal(inputs[6], inputs[7], inputs[8], inputs[9]) + delay); // set timer to t + delay + } + break; + } + case 3: { // Waiting for timer to go low + if (ic.getRegLongVal(inputs[6], inputs[7], inputs[8], inputs[9]) >= ic.getRegLongVal(inputs[1], inputs[2], inputs[3], inputs[4])) { // if timer expired + ic.queueRegByteVal(outputs[0], (byte) 0); // go to state 0 + ic.queueRegByteVal(outputs[5], (byte) 0); // set output low + ic.queueRegLongVal(outputs[1], outputs[2], outputs[3], outputs[4], -1); // disable timer + } + break; + } + default: + LOGGER.error("Invalid state: " + stateVal); + ic.queueRegByteVal(outputs[0], (byte) 0); // go to state 0 + } + } + } +} diff --git a/fabrication/src/main/java/mrtjp/projectred/fabrication/engine/gates/SRLatchGateTile.java b/fabrication/src/main/java/mrtjp/projectred/fabrication/engine/gates/SRLatchGateTile.java new file mode 100644 index 000000000..624a443a8 --- /dev/null +++ b/fabrication/src/main/java/mrtjp/projectred/fabrication/engine/gates/SRLatchGateTile.java @@ -0,0 +1,157 @@ +package mrtjp.projectred.fabrication.engine.gates; + +import mrtjp.fengine.simulate.ICGate; +import mrtjp.fengine.simulate.ICSimulation; + +import java.util.ArrayList; +import java.util.List; +import java.util.Random; + +import static mrtjp.projectred.fabrication.ProjectRedFabrication.LOGGER; +import static mrtjp.projectred.fabrication.engine.PRFabricationEngine.REG_ZERO; + +public class SRLatchGateTile extends InternalStateGateTile { + + public SRLatchGateTile() { + super(ICGateTileType.SR_LATCH); + } + + //region GateTile overrides + + //TODO interaction zones + + //endregion + + //region RedstoneGateTile overrides + + @Override + protected boolean cycleShape() { + setShape((getShape() + 1) % 4); + return true; + } + + @Override + protected int redstoneInputMask() { + return 0xA; + } + + @Override + protected int redstoneOutputMask() { + return (getShape() >> 1) == 0 ? 0xF : 5; + } + + //endregion + + @Override + protected void collectGate(Collector collector, int gateId, int[] inputRegisters, int[] outputRegisters) { + + List inputRegs = new ArrayList<>(); + List outputRegs = new ArrayList<>(); + + boolean reflected = (getShape() & 1) != 0; + boolean backfeed = (getShape() & 2) == 0; + + inputRegs.add(stateReg); + inputRegs.add(inputRegisters[reflected ? 3 : 1]); //inA + inputRegs.add(inputRegisters[reflected ? 1 : 3]); //inB + + outputRegs.add(stateReg); + outputRegs.add(outputRegisters[2]); //outA + outputRegs.add(outputRegisters[0]); //outB + outputRegs.add(backfeed ? outputRegisters[reflected ? 3 : 1] : REG_ZERO); //backfeedA + outputRegs.add(backfeed ? outputRegisters[reflected ? 1 : 3] : REG_ZERO); //backfeedB + + collector.addGate(gateId, new SRLatchGate(), inputRegs, outputRegs); + } + + public static class SRLatchGate implements ICGate { + + private static final Random RAND = new Random(); + + private static byte readState(ICSimulation ic, int[] inputs) { return ic.getRegByteVal(inputs[0]); } + + private static int readInputMask(ICSimulation ic, int[] inputs) { + int mask = 0; + if (ic.getRegByteVal(inputs[1]) != 0) mask |= 1; + if (ic.getRegByteVal(inputs[2]) != 0) mask |= 2; + return mask; + } + + private static void writeState(ICSimulation ic, int[] outputs, byte state) { ic.queueRegByteVal(outputs[0], state); } + + private static void writeOutputMask(ICSimulation ic, int[] outputs, int mask) { + ic.queueRegByteVal(outputs[1], (byte) ((mask & 1) != 0 ? 1 : 0)); // outA + ic.queueRegByteVal(outputs[3], (byte) ((mask & 1) != 0 ? 1 : 0)); // backfeedA + ic.queueRegByteVal(outputs[2], (byte) ((mask & 2) != 0 ? 1 : 0)); // outB + ic.queueRegByteVal(outputs[4], (byte) ((mask & 2) != 0 ? 1 : 0)); // backfeedB + } + + private static void enterStateA(ICSimulation ic, int[] outputs) { + writeState(ic, outputs, (byte) 1); + writeOutputMask(ic, outputs, 0x1); + } + + private static void enterStateB(ICSimulation ic, int[] outputs) { + writeState(ic, outputs, (byte) 2); + writeOutputMask(ic, outputs, 0x2); + } + + private static void enterUndefState(ICSimulation ic, int[] outputs) { + writeState(ic, outputs, (byte) 3); + writeOutputMask(ic, outputs, 0x0); + } + + @Override + public void compute(ICSimulation ic, int[] inputs, int[] outputs) { + int inputMask = readInputMask(ic, inputs); + switch (readState(ic, inputs)) { + case 0: { + if (inputMask == 2) { + enterStateB(ic, outputs); + } else if (inputMask == 3) { + enterUndefState(ic, outputs); + } else { + enterStateA(ic, outputs); + } + } + + case 1: { // A state + if (inputMask == 2) { + enterStateB(ic, outputs); + } else if (inputMask == 3) { + enterUndefState(ic, outputs); + } + break; + } + + case 2: { // B state + if (inputMask == 1) { + enterStateA(ic, outputs); + } else if (inputMask == 3) { + enterUndefState(ic, outputs); + } + break; + } + + case 3: { // Undefined state + if (inputMask == 0) { + if (RAND.nextBoolean()) { + enterStateA(ic, outputs); + } else { + enterStateB(ic, outputs); + } + } else if (inputMask == 1) { + enterStateA(ic, outputs); + } else if (inputMask == 2) { + enterStateB(ic, outputs); + } + break; + } + + default: + LOGGER.error("Invalid state: " + readState(ic, inputs)); + writeState(ic, outputs, (byte) 0); // go to state 0 + } + } + } +} diff --git a/fabrication/src/main/java/mrtjp/projectred/fabrication/engine/gates/SidedRedstoneGateTile.java b/fabrication/src/main/java/mrtjp/projectred/fabrication/engine/gates/SidedRedstoneGateTile.java new file mode 100644 index 000000000..9b352c718 --- /dev/null +++ b/fabrication/src/main/java/mrtjp/projectred/fabrication/engine/gates/SidedRedstoneGateTile.java @@ -0,0 +1,164 @@ +package mrtjp.projectred.fabrication.engine.gates; + +import mrtjp.fengine.api.IPathFinder; +import mrtjp.fengine.assemble.PathFinderResult; +import mrtjp.fengine.simulate.ByteRegister; +import mrtjp.projectred.fabrication.engine.ICSimulationContainer; +import mrtjp.projectred.fabrication.engine.IRotatableICTile; +import net.minecraft.nbt.CompoundTag; + +import java.util.Arrays; +import java.util.Optional; + +import static mrtjp.projectred.fabrication.engine.PRFabricationEngine.REG_ZERO; + +public abstract class SidedRedstoneGateTile extends RedstoneGateTile { + + private final int[] inputRegisters = new int[] { -1, -1, -1, -1 }; + private final int[] outputRegisters = new int[] { -1, -1, -1, -1 }; + private int gateId = -1; + + public SidedRedstoneGateTile(ICGateTileType gateType) { + super(gateType); + } + + @Override + public void save(CompoundTag tag) { + super.save(tag); + for (int i = 0; i < 4; i++) { + tag.putInt("regIn" + i, inputRegisters[i]); + tag.putInt("regOut" + i, outputRegisters[i]); + } + tag.putInt("gate", gateId); + } + + @Override + public void load(CompoundTag tag) { + super.load(tag); + for (int i = 0; i < 4; i++) { + inputRegisters[i] = tag.getInt("regIn" + i); + outputRegisters[i] = tag.getInt("regOut" + i); + } + gateId = tag.getInt("gate"); + } + + @Override + public void onSimRegistersChanged(int rMask, ICSimulationContainer container) { + int oldState = getState(); + int newState = pullInputMask(container) & 0xF | pullOutputMask(container) << 4; + if (oldState != newState) { + setState(newState); + sendStateUpdate(); + } + } + + protected int pullInputMask(ICSimulationContainer container) { + int mask = 0; + for (int r = 0; r < 4; r++) { + if (canInputRedstone(r)) { + int regId = inputRegisters[r]; + if (container.pullRegisterValue(regId) != 0) mask |= 1 << r; + } + } + return mask; + } + + protected int pullOutputMask(ICSimulationContainer container) { + int mask = 0; + for (int r = 0; r < 4; r++) { + if (canOutputRedstone(r)) { + int regId = outputRegisters[r]; + if (container.pullRegisterValue(regId) != 0) mask |= 1 << r; + } + } + return mask; + } + + //region FETile overrides + + @Override + public void allocate(Allocator allocator) { + clearRegisterIds(); + + for (int r = 0; r < 4; r++) { + if (canOutputRedstone(r)) outputRegisters[r] = allocator.allocRegisterID(); + } + + gateId = allocator.allocGateID(); + } + + @Override + public void locate(IPathFinder pathFinder) { + + for (int r = 0; r < 4; r++) { + if (canInputRedstone(r)) { + inputRegisters[r] = searchInputRegister(r, pathFinder); + } + } + } + + @Override + public void consumeRemaps(RemapProvider remapProvider) { + + for (int r = 0; r < 4; r++) { + if (inputRegisters[r] != -1) inputRegisters[r] = remapProvider.getRemappedRegisterID(inputRegisters[r]); + if (outputRegisters[r] != -1) outputRegisters[r] = remapProvider.getRemappedRegisterID(outputRegisters[r]); + } + } + + @Override + public void collect(Collector collector) { + + for (int r = 0; r < 4; r++) { + if (outputRegisters[r] != -1) collector.addRegister(outputRegisters[r], new ByteRegister()); + } + + collectGate(collector, gateId, inputRegisters, outputRegisters); + } + + @Override + public Optional getOutputRegister(int outDir, int outPort) { + int absR = IRotatableICTile.dirToRotation(outDir); + int r = toInternalRotation(absR); + + if (r == -1 || outputRegisters[r] == -1) return Optional.empty(); + return Optional.of(outputRegisters[r]); + } + + @Override + public Optional getInputRegister(int inDir, int inPort) { + int absR = IRotatableICTile.dirToRotation(inDir); + int r = toInternalRotation(absR); + + if (r == -1 || inputRegisters[r] == -1) return Optional.empty(); + return Optional.of(inputRegisters[r]); + } + + //endregion + + protected void clearRegisterIds() { + Arrays.fill(inputRegisters, -1); + Arrays.fill(outputRegisters, -1); + } + + private int searchInputRegister(int r, IPathFinder pathFinder) { + int absR = toAbsoluteRotation(r); + int absDir = IRotatableICTile.rotationToDir(absR); + PathFinderResult pfr = pathFinder.doPathFinding((d, p) -> d == absDir); + if (pfr.outputRegisters.size() > 1) { + // TODO log this somewhere + System.out.println("ERR: Unexpected multiple drivers: " + pfr.outputRegisters); + } + if (!pfr.outputRegisters.isEmpty()) { + return pfr.outputRegisters.get(0); + } + + return REG_ZERO; + } + + //region SidedRedstoneGateTile logic override points + + protected abstract void collectGate(Collector collector, int gateId, int[] inputRegisters, int[] outputRegisters); + + //endregion +} diff --git a/fabrication/src/main/java/mrtjp/projectred/fabrication/engine/gates/SimpleGateTile.java b/fabrication/src/main/java/mrtjp/projectred/fabrication/engine/gates/SimpleGateTile.java new file mode 100644 index 000000000..1d2ef294f --- /dev/null +++ b/fabrication/src/main/java/mrtjp/projectred/fabrication/engine/gates/SimpleGateTile.java @@ -0,0 +1,127 @@ +package mrtjp.projectred.fabrication.engine.gates; + +import codechicken.lib.vec.*; +import mrtjp.fengine.simulate.ICGate; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.network.chat.Component; +import net.minecraft.network.chat.TextComponent; +import net.minecraftforge.api.distmarker.Dist; +import net.minecraftforge.api.distmarker.OnlyIn; + +import java.util.ArrayList; +import java.util.LinkedList; +import java.util.List; + +public abstract class SimpleGateTile extends SidedRedstoneGateTile { + + public static int[] DEAD_SIDES_MASKS = new int[] { 1, 2, 3, 0, 5, 6, 3 }; + + public SimpleGateTile(ICGateTileType gateType) { + super(gateType); + } + + @Override + public void save(CompoundTag tag) { + super.save(tag); + } + + @Override + public void load(CompoundTag tag) { + super.load(tag); + } + + @Override + protected boolean cycleShape() { + int oldShape = getShape(); + setShape(progressDeadSideShape(oldShape)); + return oldShape != getShape(); + } + + private int progressDeadSideShape(int shape) { + if (getDeadSides() == 0) return shape; + + int s = DEAD_SIDES_MASKS[shape]; + s = ensureMaxDeadSides(s); + return s; + } + + private int ensureMaxDeadSides(int s) { + while (Integer.bitCount(s) > getMaxDeadSides() || 32 - Integer.numberOfLeadingZeros(s) > getDeadSides()) { + s = DEAD_SIDES_MASKS[s]; + } + return s; + } + + //region BaseTile overrides + + @Override + public List getInteractionZones() { + List zones = new LinkedList<>(); + if (getDeadSides() > 0) { + zones.add(new Cuboid6(10, 2, 6, 16, 2.5, 10)); + zones.add(new Cuboid6(6, 2, 10, 10, 2.5, 16)); + zones.add(new Cuboid6(0, 2, 6, 6, 2.5, 10)); + + Transformation rotation = Rotation.quarterRotations[getRotation()].at(new Vector3(8, 8, 8)); + Transformation t = isReflected() ? new Scale(1, -1, 1).with(rotation) : rotation; + zones.forEach(c -> c.apply(t)); + } + + return zones; + } + + @Override + @OnlyIn(Dist.CLIENT) + public void buildInteractionToolTip(List toolTip, int i) { + + boolean isEnabled = (getShape() & (1 << (i-1))) == 0; + toolTip.add(new TextComponent("side " + (isEnabled ? "enabled" : "disabled"))); // TODO localize + } + + @Override + public void onInteractionZoneClicked(int i) { + if (getDeadSides() == 0) return; + + int oldShape = getShape(); + int shape = oldShape ^ (1 << i); + shape = ensureMaxDeadSides(shape); + + if (oldShape != shape) { + setShape(shape); + sendShapeUpdate(); + notifyNeighbors(0xF); + getEditor().markTileChange(); + } + } + //endregion + + //region SimpleGateTile logic override points + + protected int getDeadSides() { + return 0; + } + + protected int getMaxDeadSides() { + return getDeadSides() - 1; + } + + protected boolean isReflected() { + return false; + } + + protected abstract ICGate createGate(); + + protected void collectGate(Collector collector, int gateId, int[] inputRegisters, int[] outputRegisters) { + + List inputRegistersList = new ArrayList<>(); + List outputRegistersList = new ArrayList<>(); + for (int r = 0; r < 4; r++) { + if (inputRegisters[r] != -1) inputRegistersList.add(inputRegisters[r]); + if (outputRegisters[r] != -1) outputRegistersList.add(outputRegisters[r]); + } + + collector.addGate(gateId, createGate(), inputRegistersList, outputRegistersList); + } + + //endregion +} diff --git a/fabrication/src/main/java/mrtjp/projectred/fabrication/engine/gates/TimedStateGateTile.java b/fabrication/src/main/java/mrtjp/projectred/fabrication/engine/gates/TimedStateGateTile.java new file mode 100644 index 000000000..b599f62b1 --- /dev/null +++ b/fabrication/src/main/java/mrtjp/projectred/fabrication/engine/gates/TimedStateGateTile.java @@ -0,0 +1,82 @@ +package mrtjp.projectred.fabrication.engine.gates; + +import mrtjp.fengine.simulate.ByteRegister; +import net.minecraft.nbt.CompoundTag; + +public abstract class TimedStateGateTile extends SidedRedstoneGateTile { + + protected int stateReg = -1; + protected int timeReg3 = -1; + protected int timeReg2 = -1; + protected int timeReg1 = -1; + protected int timeReg0 = -1; + + public TimedStateGateTile(ICGateTileType gateType) { + super(gateType); + } + + @Override + public void save(CompoundTag tag) { + super.save(tag); + tag.putInt("regS", stateReg); + tag.putInt("regT3", timeReg3); + tag.putInt("regT2", timeReg2); + tag.putInt("regT1", timeReg1); + tag.putInt("regT0", timeReg0); + } + + @Override + public void load(CompoundTag tag) { + super.load(tag); + stateReg = tag.getInt("regS"); + timeReg3 = tag.getInt("regT3"); + timeReg2 = tag.getInt("regT2"); + timeReg1 = tag.getInt("regT1"); + timeReg0 = tag.getInt("regT0"); + } + + @Override + protected void clearRegisterIds() { + super.clearRegisterIds(); + stateReg = -1; + timeReg3 = -1; + timeReg2 = -1; + timeReg1 = -1; + timeReg0 = -1; + } + + //region FETile overrides + + @Override + public void allocate(Allocator allocator) { + super.allocate(allocator); + stateReg = allocator.allocRegisterID(); + timeReg3 = allocator.allocRegisterID(); + timeReg2 = allocator.allocRegisterID(); + timeReg1 = allocator.allocRegisterID(); + timeReg0 = allocator.allocRegisterID(); + } + + @Override + public void consumeRemaps(RemapProvider remapProvider) { + super.consumeRemaps(remapProvider); + stateReg = remapProvider.getRemappedRegisterID(stateReg); + timeReg3 = remapProvider.getRemappedRegisterID(timeReg3); + timeReg2 = remapProvider.getRemappedRegisterID(timeReg2); + timeReg1 = remapProvider.getRemappedRegisterID(timeReg1); + timeReg0 = remapProvider.getRemappedRegisterID(timeReg0); + } + + @Override + public void collect(Collector collector) { + super.collect(collector); + + collector.addRegister(stateReg, new ByteRegister()); + collector.addRegister(timeReg3, new ByteRegister()); + collector.addRegister(timeReg2, new ByteRegister()); + collector.addRegister(timeReg1, new ByteRegister()); + collector.addRegister(timeReg0, new ByteRegister()); + } + + //endregion +} diff --git a/fabrication/src/main/java/mrtjp/projectred/fabrication/engine/gates/ToggleLatchGateTile.java b/fabrication/src/main/java/mrtjp/projectred/fabrication/engine/gates/ToggleLatchGateTile.java new file mode 100644 index 000000000..f9061826c --- /dev/null +++ b/fabrication/src/main/java/mrtjp/projectred/fabrication/engine/gates/ToggleLatchGateTile.java @@ -0,0 +1,129 @@ +package mrtjp.projectred.fabrication.engine.gates; + +import mrtjp.fengine.simulate.ICGate; +import mrtjp.fengine.simulate.ICSimulation; + +import java.util.ArrayList; +import java.util.List; + +import static mrtjp.projectred.fabrication.ProjectRedFabrication.LOGGER; + +public class ToggleLatchGateTile extends InternalStateGateTile { + + public ToggleLatchGateTile() { + super(ICGateTileType.TOGGLE_LATCH); + } + + //region GateTile overrides + + //TODO interaction zones + + //endregion + + //region RedstoneGateTile overrides + + @Override + protected boolean cycleShape() { + setShape((getShape() + 1) % 2); + return true; + } + + @Override + protected int redstoneInputMask() { + return 0xA; + } + + @Override + protected int redstoneOutputMask() { + return 5; + } + + //endregion + + @Override + protected void collectGate(Collector collector, int gateId, int[] inputRegisters, int[] outputRegisters) { + + List inputRegs = new ArrayList<>(); + List outputRegs = new ArrayList<>(); + + inputRegs.add(stateReg); + inputRegs.add(inputRegisters[3]); //inA + inputRegs.add(inputRegisters[1]); //inB + + outputRegs.add(stateReg); + outputRegs.add(outputRegisters[0]); //outA + outputRegs.add(outputRegisters[2]); //outB + + collector.addGate(gateId, new ToggleLatchGate(getShape()), inputRegs, outputRegs); + } + + public static class ToggleLatchGate implements ICGate { + + private final int defaultState; + + public ToggleLatchGate(int defaultState) { + this.defaultState = defaultState; + } + + private static byte readState(ICSimulation ic, int[] inputs) { return ic.getRegByteVal(inputs[0]); } + + private static int readInputMask(ICSimulation ic, int[] inputs) { + int mask = 0; + if (ic.getRegByteVal(inputs[1]) != 0) mask |= 1; //inA + if (ic.getRegByteVal(inputs[2]) != 0) mask |= 2; //inB + return mask; + } + + private static void writeState(ICSimulation ic, int[] outputs, byte state) { ic.queueRegByteVal(outputs[0], state); } + + private static void writeOutputMask(ICSimulation ic, int[] outputs, int mask) { + ic.queueRegByteVal(outputs[1], (byte) ((mask & 1) != 0 ? 1 : 0)); // outA + ic.queueRegByteVal(outputs[2], (byte) ((mask & 2) != 0 ? 1 : 0)); // outB + } + + @Override + public void compute(ICSimulation ic, int[] inputs, int[] outputs) { + int s = readState(ic, inputs); + int state = s & 0xF; + int inputMask = readInputMask(ic, inputs); + int prevInputMask = (s >> 4) & 0xF; + int highMask = inputMask & ~prevInputMask; + int nextState = state; + + switch (state) { + case 0: { // Initial state + if (defaultState == 0) { + nextState = 1; // Enter A state + writeOutputMask(ic, outputs, 0x1); + } else { + nextState = 2; // Enter B state + writeOutputMask(ic, outputs, 0x2); + } + break; + } + + case 1: { // A state + if (highMask == 1 || highMask == 2) { + nextState = 2; // Enter B state + writeOutputMask(ic, outputs, 0x2); + } + break; + } + + case 2: { // B state + if (highMask == 1 || highMask == 2) { + nextState = 1; // Enter A state + writeOutputMask(ic, outputs, 0x1); + } + break; + } + + default: + LOGGER.error("Invalid state: " + readState(ic, inputs)); + nextState = 0; + } + + writeState(ic, outputs, (byte) (inputMask << 4 | nextState)); + } + } +} diff --git a/fabrication/src/main/java/mrtjp/projectred/fabrication/engine/gates/TransparentLatchGateTile.java b/fabrication/src/main/java/mrtjp/projectred/fabrication/engine/gates/TransparentLatchGateTile.java new file mode 100644 index 000000000..712d950e8 --- /dev/null +++ b/fabrication/src/main/java/mrtjp/projectred/fabrication/engine/gates/TransparentLatchGateTile.java @@ -0,0 +1,114 @@ +package mrtjp.projectred.fabrication.engine.gates; + +import mrtjp.fengine.simulate.ICGate; +import mrtjp.fengine.simulate.ICSimulation; + +import java.util.ArrayList; +import java.util.List; + +import static mrtjp.projectred.fabrication.ProjectRedFabrication.LOGGER; + +public class TransparentLatchGateTile extends InternalStateGateTile { + + public TransparentLatchGateTile() { + super(ICGateTileType.TRANSPARENT_LATCH); + } + + //region GateTile overrides + + //TODO interaction zones + + //endregion + + //region RedstoneGateTile overrides + + @Override + protected boolean cycleShape() { + setShape((getShape() + 1) % 2); + return true; + } + + @Override + protected int redstoneInputMask() { + return getShape() == 0 ? 0xC : 0x6; + } + + @Override + protected int redstoneOutputMask() { + return getShape() == 0 ? 0x3 : 0x9; + } + + //endregion + + @Override + protected void collectGate(Collector collector, int gateId, int[] inputRegisters, int[] outputRegisters) { + + List inputRegs = new ArrayList<>(); + List outputRegs = new ArrayList<>(); + + inputRegs.add(stateReg); + inputRegs.add(inputRegisters[getShape() == 0 ? 3 : 1]); //dataIn + inputRegs.add(inputRegisters[2]); //writeEnable + + outputRegs.add(stateReg); + outputRegs.add(outputRegisters[0]); //out1 + outputRegs.add(outputRegisters[getShape() == 0 ? 1 : 3]); //out2 + + collector.addGate(gateId, new TransparentLatchGate(), inputRegs, outputRegs); + } + + public static class TransparentLatchGate implements ICGate { + + private static byte readState(ICSimulation ic, int[] inputs) { return ic.getRegByteVal(inputs[0]); } + + private static byte readData(ICSimulation ic, int[] inputs) { + return ic.getRegByteVal(inputs[1]); + } + + private static boolean writeEnabled(ICSimulation ic, int[] inputs) { + return ic.getRegByteVal(inputs[2]) != 0; + } + + private static void writeState(ICSimulation ic, int[] outputs, byte state) { ic.queueRegByteVal(outputs[0], state); } + + private static void writeData(ICSimulation ic, int[] outputs, byte data) { + ic.queueRegByteVal(outputs[1], data); + ic.queueRegByteVal(outputs[2], data); + } + + @Override + public void compute(ICSimulation ic, int[] inputs, int[] outputs) { + + switch (readState(ic, inputs)) { + case 0: { // Initial state + if (writeEnabled(ic, inputs)) { + writeState(ic, outputs, (byte) 2); // Enter write state + } else { + writeState(ic, outputs, (byte) 1); // Enter lock state + } + break; + } + + case 1: { // Lock state + if (writeEnabled(ic, inputs)) { + writeState(ic, outputs, (byte) 2); // Enter write state + } + break; + } + + case 2: { // Write state + if (writeEnabled(ic, inputs)) { + writeData(ic, outputs, readData(ic, inputs)); + } else { + writeState(ic, outputs, (byte) 1); // Enter lock state + } + break; + } + + default: + LOGGER.error("Invalid state: " + readState(ic, inputs)); + writeState(ic, outputs, (byte) 0); + } + } + } +} diff --git a/fabrication/src/main/java/mrtjp/projectred/fabrication/engine/gates/XNORGateTile.java b/fabrication/src/main/java/mrtjp/projectred/fabrication/engine/gates/XNORGateTile.java new file mode 100644 index 000000000..4d989efbe --- /dev/null +++ b/fabrication/src/main/java/mrtjp/projectred/fabrication/engine/gates/XNORGateTile.java @@ -0,0 +1,36 @@ +package mrtjp.projectred.fabrication.engine.gates; + +import mrtjp.fengine.simulate.ICGate; +import mrtjp.fengine.simulate.ICSimulation; + +public class XNORGateTile extends SimpleGateTile { + + public XNORGateTile() { + super(ICGateTileType.XNOR); + } + + @Override + protected int redstoneOutputMask() { + return 1; + } + + @Override + protected int redstoneInputMask() { + return 10; + } + + @Override + public ICGate createGate() { + return new XNORGate(); + } + + public static class XNORGate implements ICGate { + + @Override + public void compute(ICSimulation ic, int[] inputs, int[] outputs) { + boolean in0 = ic.getRegByteVal(inputs[0]) != 0; + boolean in1 = ic.getRegByteVal(inputs[1]) != 0; + ic.queueRegByteVal(outputs[0], in0 == in1 ? (byte) 1 : (byte) 0); + } + } +} diff --git a/fabrication/src/main/java/mrtjp/projectred/fabrication/engine/gates/XORGateTile.java b/fabrication/src/main/java/mrtjp/projectred/fabrication/engine/gates/XORGateTile.java new file mode 100644 index 000000000..f111958fd --- /dev/null +++ b/fabrication/src/main/java/mrtjp/projectred/fabrication/engine/gates/XORGateTile.java @@ -0,0 +1,36 @@ +package mrtjp.projectred.fabrication.engine.gates; + +import mrtjp.fengine.simulate.ICGate; +import mrtjp.fengine.simulate.ICSimulation; + +public class XORGateTile extends SimpleGateTile { + + public XORGateTile() { + super(ICGateTileType.XOR); + } + + @Override + protected int redstoneOutputMask() { + return 1; + } + + @Override + protected int redstoneInputMask() { + return 10; + } + + @Override + public ICGate createGate() { + return new XORGate(); + } + + public static class XORGate implements ICGate { + + @Override + public void compute(ICSimulation ic, int[] inputs, int[] outputs) { + boolean in0 = ic.getRegByteVal(inputs[0]) != 0; + boolean in1 = ic.getRegByteVal(inputs[1]) != 0; + ic.queueRegByteVal(outputs[0], in0 != in1 ? (byte) 1 : (byte) 0); + } + } +} diff --git a/fabrication/src/main/java/mrtjp/projectred/fabrication/engine/wires/BundledWireTile.java b/fabrication/src/main/java/mrtjp/projectred/fabrication/engine/wires/BundledWireTile.java new file mode 100644 index 000000000..e54f414e8 --- /dev/null +++ b/fabrication/src/main/java/mrtjp/projectred/fabrication/engine/wires/BundledWireTile.java @@ -0,0 +1,43 @@ +package mrtjp.projectred.fabrication.engine.wires; + +import mrtjp.fengine.api.PropagationFunction; +import mrtjp.projectred.fabrication.engine.IBundledConnectableICTile; +import mrtjp.projectred.fabrication.engine.ICTileType; +import mrtjp.projectred.fabrication.engine.IConnectableICTile; +import mrtjp.projectred.fabrication.engine.IInsulatedConnectableICTile; +import mrtjp.projectred.transmission.WireType; + +public class BundledWireTile extends WireTile implements IBundledConnectableICTile { + + public BundledWireTile(int colour) { + super(colour == -1 ? ICTileType.BUNDLED_NEUTRAL_WIRE : ICWireTileType.BUNDLED_COLOURED[colour].tileType, + WireType.values()[WireType.BUNDLED_WHITE.ordinal() + colour]); + } + + @Override + public int getBundledColour() { + return getWireType().getColourIdx(); + } + + @Override + public boolean canConnectTo(IConnectableICTile target, int towardsDir) { + + if (target instanceof IBundledConnectableICTile) { + int targetColour = ((IBundledConnectableICTile) target).getBundledColour(); + int thisColour = getBundledColour(); + return targetColour == thisColour || targetColour == -1 || thisColour == -1; // -1 means neutral + } + + if (target instanceof IInsulatedConnectableICTile) + return true; + + return false; + } + + @Override + public PropagationFunction propagationFunc(int inDir, int inPort) { + // Accept any colour, but only forward to that specific colour + return ((outDir, outPort) -> + outPort == inPort && maskConnectsToDir(inDir) && maskConnectsToDir(outDir)); + } +} diff --git a/fabrication/src/main/java/mrtjp/projectred/fabrication/engine/wires/ICWireTileType.java b/fabrication/src/main/java/mrtjp/projectred/fabrication/engine/wires/ICWireTileType.java new file mode 100644 index 000000000..52916c64f --- /dev/null +++ b/fabrication/src/main/java/mrtjp/projectred/fabrication/engine/wires/ICWireTileType.java @@ -0,0 +1,92 @@ +package mrtjp.projectred.fabrication.engine.wires; + +import mrtjp.projectred.fabrication.engine.ICTileType; +import mrtjp.projectred.transmission.WireType; + +public enum ICWireTileType { + + //@formatter:off + RED_ALLOY(ICTileType.RED_ALLOY_WIRE, WireType.RED_ALLOY), + + INSULATED_WHITE (ICTileType.INSULATED_WHITE_WIRE, WireType.INSULATED_WHITE), + INSULATED_ORANGE (ICTileType.INSULATED_ORANGE_WIRE, WireType.INSULATED_ORANGE), + INSULATED_MAGENTA (ICTileType.INSULATED_MAGENTA_WIRE, WireType.INSULATED_MAGENTA), + INSULATED_LIGHT_BLUE(ICTileType.INSULATED_LIGHT_BLUE_WIRE, WireType.INSULATED_LIGHT_BLUE), + INSULATED_YELLOW (ICTileType.INSULATED_YELLOW_WIRE, WireType.INSULATED_YELLOW), + INSULATED_LIME (ICTileType.INSULATED_LIME_WIRE, WireType.INSULATED_LIME), + INSULATED_PINK (ICTileType.INSULATED_PINK_WIRE, WireType.INSULATED_PINK), + INSULATED_GRAY (ICTileType.INSULATED_GRAY_WIRE, WireType.INSULATED_GRAY), + INSULATED_LIGHT_GRAY(ICTileType.INSULATED_LIGHT_GRAY_WIRE, WireType.INSULATED_LIGHT_GRAY), + INSULATED_CYAN (ICTileType.INSULATED_CYAN_WIRE, WireType.INSULATED_CYAN), + INSULATED_PURPLE (ICTileType.INSULATED_PURPLE_WIRE, WireType.INSULATED_PURPLE), + INSULATED_BLUE (ICTileType.INSULATED_BLUE_WIRE, WireType.INSULATED_BLUE), + INSULATED_BROWN (ICTileType.INSULATED_BROWN_WIRE, WireType.INSULATED_BROWN), + INSULATED_GREEN (ICTileType.INSULATED_GREEN_WIRE, WireType.INSULATED_GREEN), + INSULATED_RED (ICTileType.INSULATED_RED_WIRE, WireType.INSULATED_RED), + INSULATED_BLACK (ICTileType.INSULATED_BLACK_WIRE, WireType.INSULATED_BLACK), + + BUNDLED_NEUTRAL (ICTileType.BUNDLED_NEUTRAL_WIRE, WireType.BUNDLED_NEUTRAL), + + BUNDLED_WHITE (ICTileType.BUNDLED_WHITE_WIRE, WireType.BUNDLED_WHITE), + BUNDLED_ORANGE (ICTileType.BUNDLED_ORANGE_WIRE, WireType.BUNDLED_ORANGE), + BUNDLED_MAGENTA (ICTileType.BUNDLED_MAGENTA_WIRE, WireType.BUNDLED_MAGENTA), + BUNDLED_LIGHT_BLUE(ICTileType.BUNDLED_LIGHT_BLUE_WIRE, WireType.BUNDLED_LIGHT_BLUE), + BUNDLED_YELLOW (ICTileType.BUNDLED_YELLOW_WIRE, WireType.BUNDLED_YELLOW), + BUNDLED_LIME (ICTileType.BUNDLED_LIME_WIRE, WireType.BUNDLED_LIME), + BUNDLED_PINK (ICTileType.BUNDLED_PINK_WIRE, WireType.BUNDLED_PINK), + BUNDLED_GRAY (ICTileType.BUNDLED_GRAY_WIRE, WireType.BUNDLED_GRAY), + BUNDLED_LIGHT_GRAY(ICTileType.BUNDLED_LIGHT_GRAY_WIRE, WireType.BUNDLED_LIGHT_GRAY), + BUNDLED_CYAN (ICTileType.BUNDLED_CYAN_WIRE, WireType.BUNDLED_CYAN), + BUNDLED_PURPLE (ICTileType.BUNDLED_PURPLE_WIRE, WireType.BUNDLED_PURPLE), + BUNDLED_BLUE (ICTileType.BUNDLED_BLUE_WIRE, WireType.BUNDLED_BLUE), + BUNDLED_BROWN (ICTileType.BUNDLED_BROWN_WIRE, WireType.BUNDLED_BROWN), + BUNDLED_GREEN (ICTileType.BUNDLED_GREEN_WIRE, WireType.BUNDLED_GREEN), + BUNDLED_RED (ICTileType.BUNDLED_RED_WIRE, WireType.BUNDLED_RED), + BUNDLED_BLACK (ICTileType.BUNDLED_BLACK_WIRE, WireType.BUNDLED_BLACK), + ; + //@formatter:on + + public static final ICWireTileType[] INSULATED = { + INSULATED_WHITE, + INSULATED_ORANGE, + INSULATED_MAGENTA, + INSULATED_LIGHT_BLUE, + INSULATED_YELLOW, + INSULATED_LIME, + INSULATED_PINK, + INSULATED_GRAY, + INSULATED_LIGHT_GRAY, + INSULATED_CYAN, + INSULATED_PURPLE, + INSULATED_BLUE, + INSULATED_BROWN, + INSULATED_GREEN, + INSULATED_RED, + INSULATED_BLACK }; + + public static final ICWireTileType[] BUNDLED_COLOURED = { + BUNDLED_WHITE, + BUNDLED_ORANGE, + BUNDLED_MAGENTA, + BUNDLED_LIGHT_BLUE, + BUNDLED_YELLOW, + BUNDLED_LIME, + BUNDLED_PINK, + BUNDLED_GRAY, + BUNDLED_LIGHT_GRAY, + BUNDLED_CYAN, + BUNDLED_PURPLE, + BUNDLED_BLUE, + BUNDLED_BROWN, + BUNDLED_GREEN, + BUNDLED_RED, + BUNDLED_BLACK }; + + public final ICTileType tileType; + public final WireType multipartType; + + ICWireTileType(ICTileType tileType, WireType multipartType) { + this.tileType = tileType; + this.multipartType = multipartType; + } +} diff --git a/fabrication/src/main/java/mrtjp/projectred/fabrication/engine/wires/InsulatedWireTile.java b/fabrication/src/main/java/mrtjp/projectred/fabrication/engine/wires/InsulatedWireTile.java new file mode 100644 index 000000000..2551da506 --- /dev/null +++ b/fabrication/src/main/java/mrtjp/projectred/fabrication/engine/wires/InsulatedWireTile.java @@ -0,0 +1,49 @@ +package mrtjp.projectred.fabrication.engine.wires; + +import mrtjp.fengine.api.PropagationFunction; +import mrtjp.projectred.fabrication.engine.IBundledConnectableICTile; +import mrtjp.projectred.fabrication.engine.IConnectableICTile; +import mrtjp.projectred.fabrication.engine.IInsulatedConnectableICTile; +import mrtjp.projectred.fabrication.engine.IRedstoneConnectableICTile; +import mrtjp.projectred.transmission.WireType; + +public class InsulatedWireTile extends RedstoneWireTile implements IInsulatedConnectableICTile, IRedstoneConnectableICTile { + + public InsulatedWireTile(int colour) { + super(ICWireTileType.INSULATED[colour].tileType, WireType.values()[WireType.INSULATED_WHITE.ordinal() + colour]); + } + + @Override + protected int getRenderHue() { + return -1; // Insulated wires don't render hue + } + + @Override + public int getInsulatedColour() { + return getWireType().getColourIdx(); + } + + @Override + protected int getTextureIndex() { + return signal != 0 ? 1 : 0; + } + + @Override + public boolean canConnectTo(IConnectableICTile target, int towardsDir) { + if (target instanceof IInsulatedConnectableICTile) + return ((IInsulatedConnectableICTile) target).getInsulatedColour() == getInsulatedColour(); + + if (target instanceof IBundledConnectableICTile) + return true; + + return super.canConnectTo(target, towardsDir); + } + + @Override + public PropagationFunction propagationFunc(int inDir, int inPort) { + // Accept only matching colour, and forward only to that colour + return ((outDir, outPort) -> + inPort == getInsulatedColour() && outPort == inPort && + maskConnectsToDir(inDir) && maskConnectsToDir(outDir)); + } +} diff --git a/fabrication/src/main/java/mrtjp/projectred/fabrication/engine/wires/RedAlloyWireTile.java b/fabrication/src/main/java/mrtjp/projectred/fabrication/engine/wires/RedAlloyWireTile.java new file mode 100644 index 000000000..58a4992b3 --- /dev/null +++ b/fabrication/src/main/java/mrtjp/projectred/fabrication/engine/wires/RedAlloyWireTile.java @@ -0,0 +1,29 @@ +package mrtjp.projectred.fabrication.engine.wires; + +import mrtjp.fengine.api.PropagationFunction; +import mrtjp.projectred.fabrication.engine.ICTileType; +import mrtjp.projectred.transmission.WireType; + +public class RedAlloyWireTile extends RedstoneWireTile { + + public RedAlloyWireTile() { + super(ICTileType.RED_ALLOY_WIRE, WireType.RED_ALLOY); + } + + @Override + protected int getRenderHue() { + return (signal&0xFF)/2+60<<24|0xFF; + } + + @Override + protected int getTextureIndex() { + return 0; + } + + @Override + public PropagationFunction propagationFunc(int inDir, int inPort) { + // Accept any colour, forward to all colours + return ((outDir, outPort) -> maskConnectsToDir(inDir) && maskConnectsToDir(outDir)); + } + +} diff --git a/fabrication/src/main/java/mrtjp/projectred/fabrication/engine/wires/RedstoneWireTile.java b/fabrication/src/main/java/mrtjp/projectred/fabrication/engine/wires/RedstoneWireTile.java new file mode 100644 index 000000000..9cbf30787 --- /dev/null +++ b/fabrication/src/main/java/mrtjp/projectred/fabrication/engine/wires/RedstoneWireTile.java @@ -0,0 +1,115 @@ +package mrtjp.projectred.fabrication.engine.wires; + +import codechicken.lib.data.MCDataInput; +import codechicken.lib.data.MCDataOutput; +import mrtjp.fengine.api.IPathFinderManifest; +import mrtjp.projectred.fabrication.engine.ICSimulationContainer; +import mrtjp.projectred.fabrication.engine.ICTileType; +import mrtjp.projectred.fabrication.engine.IConnectableICTile; +import mrtjp.projectred.fabrication.engine.IRedstoneConnectableICTile; +import mrtjp.projectred.transmission.WireType; +import net.minecraft.nbt.CompoundTag; + +import java.util.HashSet; +import java.util.Set; + +public abstract class RedstoneWireTile extends WireTile implements IRedstoneConnectableICTile { + + private static final int PACKET_SIGNAL = 2; + + protected final Set inputRegisters = new HashSet<>(); + + protected byte signal = 0; + + public RedstoneWireTile(ICTileType tileType, WireType renderType) { + super(tileType, renderType); + } + @Override + public void save(CompoundTag tag) { + super.save(tag); + tag.putByte("signal", signal); + tag.putByte("numInputReg", (byte) inputRegisters.size()); + + int i = 0; + for (Integer inputReg : inputRegisters) tag.putInt("inR" + (i++), inputReg); + } + + @Override + public void load(CompoundTag tag) { + super.load(tag); + signal = tag.getByte("signal"); + + int numInputReg = tag.getByte("numInputReg") & 0xFF; + for (int i = 0; i < numInputReg; i++) inputRegisters.add(tag.getInt("inR" + i)); + } + + @Override + public void writeDesc(MCDataOutput out) { + super.writeDesc(out); + out.writeByte(signal); + } + + @Override + public void readDesc(MCDataInput in) { + super.readDesc(in); + signal = in.readByte(); + } + + @Override + public void read(MCDataInput in, int key) { + switch (key) { + case PACKET_SIGNAL: + signal = in.readByte(); + break; + default: + super.read(in, key); + } + } + + protected void sendSignalUpdate() { + getWriteStream(PACKET_SIGNAL).writeByte(signal); + } + + @Override + public boolean canConnectTo(IConnectableICTile target, int towardsDir) { + if (target instanceof IRedstoneConnectableICTile) + return true; + + return false; + } + + @Override + public void onSimRegistersChanged(int rMask, ICSimulationContainer container) { + + byte oldSignal = signal; + signal = 0; + + for (Integer inputReg : inputRegisters) { + boolean isHigh = container.pullRegisterValue(inputReg) > 0; + signal = isHigh ? (byte) 255 : 0; + if (isHigh) break; + } + + if (oldSignal != signal) sendSignalUpdate(); + } + + + @Override + public void searchManifest(IPathFinderManifest manifest) { + inputRegisters.clear(); + inputRegisters.addAll(manifest.getOutputRegisters()); + } + + @Override + public void consumeRemaps(RemapProvider remapProvider) { + + Set remappedInputs = new HashSet<>(); + for (Integer inputReg : inputRegisters) { + int remapped = remapProvider.getRemappedRegisterID(inputReg); + remappedInputs.add(remapped); + } + + inputRegisters.clear(); + inputRegisters.addAll(remappedInputs); + } +} diff --git a/fabrication/src/main/java/mrtjp/projectred/fabrication/engine/wires/WireTile.java b/fabrication/src/main/java/mrtjp/projectred/fabrication/engine/wires/WireTile.java new file mode 100644 index 000000000..39ed80f95 --- /dev/null +++ b/fabrication/src/main/java/mrtjp/projectred/fabrication/engine/wires/WireTile.java @@ -0,0 +1,127 @@ +package mrtjp.projectred.fabrication.engine.wires; + +import codechicken.lib.data.MCDataInput; +import codechicken.lib.data.MCDataOutput; +import codechicken.lib.render.CCRenderState; +import codechicken.lib.vec.Transformation; +import mrtjp.projectred.fabrication.engine.BaseTile; +import mrtjp.projectred.fabrication.engine.ICTileType; +import mrtjp.projectred.fabrication.engine.IConnectableICTile; +import mrtjp.projectred.fabrication.engine.IRotatableICTile; +import mrtjp.projectred.transmission.WireType; +import mrtjp.projectred.transmission.client.WireModelRenderer; +import net.minecraft.nbt.CompoundTag; + +import java.util.Optional; + +public abstract class WireTile extends BaseTile implements IConnectableICTile { + + private static final int PACKET_CONN_MASK = 1; + + private final WireType renderType; + + public WireTile(ICTileType tileType, WireType renderType) { + super(tileType); + this.renderType = renderType; + } + + private byte connMask = 0; + + public WireType getWireType() { + return renderType; + } + + @Override + public int getConnMask() { + return connMask & 0xFF; + } + + @Override + public void setConnMask(int connMask) { + this.connMask = (byte) connMask; + } + + @Override + public void save(CompoundTag tag) { + tag.putByte("connMask", connMask); + } + + @Override + public void load(CompoundTag tag) { + connMask = tag.getByte("connMask"); + } + + @Override + public void writeDesc(MCDataOutput out) { + out.writeByte(connMask); + } + + @Override + public void readDesc(MCDataInput in) { + connMask = in.readByte(); + } + + @Override + public void read(MCDataInput in, int key) { + switch (key) { + case PACKET_CONN_MASK: + connMask = in.readByte(); + break; + default: + super.read(in, key); + } + } + + protected void sendConnUpdate() { + getWriteStream(PACKET_CONN_MASK).writeByte(connMask); + } + + @Override + public void onMaskChanged() { + sendConnUpdate(); + getEditor().markTileChange(); + } + + @Override + public void onNeighborChanged() { + super.onNeighborChanged(); + updateConns(); + } + + @Override + public void onAdded() { + super.onAdded(); + updateConns(); + } + + @Override + public void onRemoved() { + super.onRemoved(); + for (int s = 0; s < 6; s++) { + getEditor().queueNeighborChange(getPos().offset(s)); + } + } + + @Override + public IConnectableICTile getTileTowardsDir(int dir) { + Optional tile = getMap().getBaseTile(getPos().offset(dir)); + if (tile.isPresent() && tile.get() instanceof IConnectableICTile) return (IConnectableICTile) tile.get(); + return null; + } + + protected int getRenderHue() { + return -1; + } + + protected int getTextureIndex() { + return 0; + } + + @Override + public void renderTile(CCRenderState ccrs, Transformation t, float partialFrame) { + int rmask = IRotatableICTile.dirMaskToRotationMask(getConnMask()); + int wireConnMask = rmask << 4; + int modelKey = WireModelRenderer.modelKey(0, getWireType().getThickness(), wireConnMask); + WireModelRenderer.render(ccrs, modelKey, getRenderHue(), getWireType().getTextures().get(getTextureIndex()), t); + } +} diff --git a/fabrication/src/main/java/mrtjp/projectred/fabrication/gui/CTNListNode.java b/fabrication/src/main/java/mrtjp/projectred/fabrication/gui/CTNListNode.java new file mode 100644 index 000000000..2a161fcc5 --- /dev/null +++ b/fabrication/src/main/java/mrtjp/projectred/fabrication/gui/CTNListNode.java @@ -0,0 +1,110 @@ +package mrtjp.projectred.fabrication.gui; + +import com.mojang.blaze3d.systems.RenderSystem; +import com.mojang.blaze3d.vertex.PoseStack; +import mrtjp.projectred.fabrication.engine.ICCompilerLog.CompileTreeNode; +import mrtjp.projectred.fabrication.gui.screen.ICWorkbenchCompileTab; +import mrtjp.projectred.lib.Point; +import mrtjp.projectred.lib.Rect; +import mrtjp.projectred.redui.AbstractGuiNode; +import net.minecraft.client.gui.GuiComponent; +import net.minecraft.network.chat.Component; +import net.minecraft.network.chat.TextComponent; + +import java.util.LinkedList; +import java.util.List; + +public class CTNListNode extends AbstractGuiNode { + + private final List nodeList = new LinkedList<>(); + + private final AbstractGuiNode listParent = new AbstractGuiNode() { + + }; + + public CTNListNode() { + initSubNodes(); + } + + private void initSubNodes() { + addChild(listParent); + } + + public void setNodeList(List nodeList) { + this.nodeList.clear(); + this.nodeList.addAll(nodeList); + refreshListItems(); + } + + private void refreshListItems() { + listParent.removeAllChildren(); + listParent.setPosition(0, 0); + + int y = 0; + for (CompileTreeNode node : nodeList) { + CompileTreeNodeListItem item = new CompileTreeNodeListItem(node); + item.setPosition(0, y); + listParent.addChild(item); + y += item.calculateAccumulatedFrame().height(); + } + } + + @Override + public void onSubTreePreDrawBack() { + // This node's frame converted to GL11 window coordinates + Rect gl11Rect = calculateGL11Frame(); + + // Enable scissor using the calculated rect + RenderSystem.enableScissor(gl11Rect.x(), gl11Rect.y(), gl11Rect.width(), gl11Rect.height()); + } + + @Override + public void onSubTreePostDrawBack() { + // Disable scissor + RenderSystem.disableScissor(); + } + + private class CompileTreeNodeListItem extends AbstractGuiNode { + + private final CompileTreeNode node; + + public CompileTreeNodeListItem(CompileTreeNode node) { + this.node = node; + + setSize(67, 16); + } + + @Override + public void drawBack(PoseStack stack, Point mouse, float partialFrame) { + RenderSystem.setShaderTexture(0, ICWorkbenchCompileTab.TAB_BACKGROUND); + + GuiComponent.blit(stack, getFrame().x(), getFrame().y(), 1, 358, getFrame().width(), getFrame().height(), 512, 512); + + String s = node.step.toString(); + if (s.length() > 10) { + s = s.substring(s.length() - 10); + } + getRoot().getFontRenderer().draw(stack, s, getFrame().x() + 2, getFrame().y() + 2, 0xFFFFFF); + } + + @Override + public void drawFront(PoseStack stack, Point mouse, float partialFrame) { + + if (!isFirstHit(mouse)) return; + + List toolTip = new LinkedList<>(); + toolTip.add(new TextComponent(node.step.toString())); //TODO localize + toolTip.add(new TextComponent("Positions: " + node.tileCoords.size())); + toolTip.add(new TextComponent("Registers: " + node.registerIds.size())); + toolTip.add(new TextComponent("Gates: " + node.gateIds.size())); + toolTip.add(new TextComponent("Remaps: " + node.registerRemaps.size())); + + renderTooltip(stack, mouse, toolTip); + } + + @Override + public boolean checkHit(Point absPoint) { + return super.checkHit(absPoint) && CTNListNode.this.convertParentRectToScreen(CTNListNode.this.getFrame()).contains(absPoint); + } + } +} diff --git a/fabrication/src/main/java/mrtjp/projectred/fabrication/gui/CompileProblemsTab.java b/fabrication/src/main/java/mrtjp/projectred/fabrication/gui/CompileProblemsTab.java new file mode 100644 index 000000000..f95bf2e98 --- /dev/null +++ b/fabrication/src/main/java/mrtjp/projectred/fabrication/gui/CompileProblemsTab.java @@ -0,0 +1,37 @@ +package mrtjp.projectred.fabrication.gui; + +import codechicken.lib.render.CCRenderState; +import codechicken.lib.vec.Vector3; +import com.mojang.blaze3d.vertex.PoseStack; +import mrtjp.projectred.fabrication.editor.ICWorkbenchEditor; +import mrtjp.projectred.redui.AbstractGuiNode; +import net.minecraft.client.renderer.MultiBufferSource; +import net.minecraft.network.chat.Component; + +import java.util.List; + +public class CompileProblemsTab extends AbstractGuiNode implements ICompileOverlayRenderer { + + private final ICWorkbenchEditor editor; + + public CompileProblemsTab(ICWorkbenchEditor editor) { + this.editor = editor; + setSize(91, 134); + initSubNodes(); + } + + private void initSubNodes() { + } + + //region ICompileTabOverlayRenderer + @Override + public void renderOverlay(ICRenderNode renderNode, Vector3 mousePosition, boolean isFirstHit, CCRenderState ccrs, MultiBufferSource getter, PoseStack matrixStack) { + + } + + @Override + public void buildTooltip(ICRenderNode renderNode, Vector3 mousePosition, List tooltip) { + + } + //endregion +} diff --git a/fabrication/src/main/java/mrtjp/projectred/fabrication/gui/CompileStackTab.java b/fabrication/src/main/java/mrtjp/projectred/fabrication/gui/CompileStackTab.java new file mode 100644 index 000000000..3002fae1e --- /dev/null +++ b/fabrication/src/main/java/mrtjp/projectred/fabrication/gui/CompileStackTab.java @@ -0,0 +1,108 @@ +package mrtjp.projectred.fabrication.gui; + +import codechicken.lib.colour.EnumColour; +import codechicken.lib.render.CCRenderState; +import codechicken.lib.vec.Vector3; +import com.mojang.blaze3d.systems.RenderSystem; +import com.mojang.blaze3d.vertex.PoseStack; +import mrtjp.fengine.TileCoord; +import mrtjp.projectred.fabrication.editor.ICWorkbenchEditor; +import mrtjp.projectred.fabrication.engine.ICCompilerLog; +import mrtjp.projectred.fabrication.gui.screen.ICWorkbenchCompileTab; +import mrtjp.projectred.lib.Point; +import mrtjp.projectred.lib.Rect; +import mrtjp.projectred.redui.AbstractGuiNode; +import mrtjp.projectred.redui.ScrollBarNode; +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.GuiComponent; +import net.minecraft.client.renderer.MultiBufferSource; +import net.minecraft.network.chat.Component; + +import java.util.List; + +public class CompileStackTab extends AbstractGuiNode implements ICompileOverlayRenderer { + + private final ICWorkbenchEditor editor; + + private final CTNListNode ctnListNode = new CTNListNode(); + + public CompileStackTab(ICWorkbenchEditor editor) { + this.editor = editor; + + setSize(91, 134); + initSubNodes(); + } + + private void initSubNodes() { + + // Stack + ctnListNode.setPosition(6, 31); + ctnListNode.setSize(67, 95); + addChild(ctnListNode); + + // Scrollbar //TODO + ScrollBar scrollBar = new ScrollBar(); + scrollBar.setPosition(77, 31); + scrollBar.setZPosition(0.2); + scrollBar.setSize(8, 95); + scrollBar.setSliderSize(8, 16); + addChild(scrollBar); + } + + @Override + public void drawBack(PoseStack stack, Point mouse, float partialFrame) { + RenderSystem.setShaderTexture(0, ICWorkbenchCompileTab.TAB_BACKGROUND); + GuiComponent.blit(stack, getFrame().x(), getFrame().y(), 0, 223, getFrame().width(), getFrame().height(), 512, 512); + } + + @Override + public void update() { + if (!isHidden()) { + List execStack = editor.getStateMachine().getCompilerLog().getCurrentStack(); + ctnListNode.setNodeList(execStack); + } + } + + private void renderCompileTreeNode(ICCompilerLog.CompileTreeNode node, CCRenderState ccrs, MultiBufferSource getter, PoseStack matrixStack) { + ccrs.reset(); + ccrs.bind(ICRenderTypes.selectionRenderType, Minecraft.getInstance().renderBuffers().bufferSource(), matrixStack); + ccrs.baseColour = EnumColour.LIGHT_BLUE.rgba(200); + + for (TileCoord pos : node.tileCoords) { + Vector3 p = new Vector3(pos.x, pos.y, pos.z); + ICRenderTypes.renderSelection(ccrs, p, p.copy().add(0.01), 3 / 16D, 2 / 16D); + } + } + + //region ICompileTabOverlayRenderer + @Override + public void renderOverlay(ICRenderNode renderNode, Vector3 mousePosition, boolean isFirstHit, CCRenderState ccrs, MultiBufferSource getter, PoseStack matrixStack) { + for (ICCompilerLog.CompileTreeNode node : editor.getStateMachine().getCompilerLog().getCurrentStack()) { + renderCompileTreeNode(node, ccrs, getter, matrixStack); + } + } + + @Override + public void buildTooltip(ICRenderNode renderNode, Vector3 mousePosition, List tooltip) { + + } + //endregion + + private class ScrollBar extends ScrollBarNode { + + public ScrollBar() { + super(ScrollAxis.VERTICAL); + } + + @Override + protected void drawSlider(PoseStack stack, Rect sliderFrame) { + RenderSystem.setShaderTexture(0, ICWorkbenchCompileTab.TAB_BACKGROUND); + GuiComponent.blit(stack, sliderFrame.x(), sliderFrame.y(), 305, 58, sliderFrame.width(), sliderFrame.height(), 512, 512); + } + + @Override + protected void adjustContent(double scrollPercentage) { + //TODO adjust scroll + } + } +} diff --git a/fabrication/src/main/java/mrtjp/projectred/fabrication/gui/CompileTreeTab.java b/fabrication/src/main/java/mrtjp/projectred/fabrication/gui/CompileTreeTab.java new file mode 100644 index 000000000..644ea41f2 --- /dev/null +++ b/fabrication/src/main/java/mrtjp/projectred/fabrication/gui/CompileTreeTab.java @@ -0,0 +1,37 @@ +package mrtjp.projectred.fabrication.gui; + +import codechicken.lib.render.CCRenderState; +import codechicken.lib.vec.Vector3; +import com.mojang.blaze3d.vertex.PoseStack; +import mrtjp.projectred.fabrication.editor.ICWorkbenchEditor; +import mrtjp.projectred.redui.AbstractGuiNode; +import net.minecraft.client.renderer.MultiBufferSource; +import net.minecraft.network.chat.Component; + +import java.util.List; + +public class CompileTreeTab extends AbstractGuiNode implements ICompileOverlayRenderer { + + private final ICWorkbenchEditor editor; + + public CompileTreeTab(ICWorkbenchEditor editor) { + this.editor = editor; + setSize(91, 134); + initSubNodes(); + } + + private void initSubNodes() { + } + + //region ICompileTabOverlayRenderer + @Override + public void renderOverlay(ICRenderNode renderNode, Vector3 mousePosition, boolean isFirstHit, CCRenderState ccrs, MultiBufferSource getter, PoseStack matrixStack) { + + } + + @Override + public void buildTooltip(ICRenderNode renderNode, Vector3 mousePosition, List tooltip) { + + } + //endregion +} diff --git a/fabrication/src/main/java/mrtjp/projectred/fabrication/gui/EraserToolTab.java b/fabrication/src/main/java/mrtjp/projectred/fabrication/gui/EraserToolTab.java new file mode 100644 index 000000000..3cace497b --- /dev/null +++ b/fabrication/src/main/java/mrtjp/projectred/fabrication/gui/EraserToolTab.java @@ -0,0 +1,48 @@ +package mrtjp.projectred.fabrication.gui; + +import com.mojang.blaze3d.systems.RenderSystem; +import com.mojang.blaze3d.vertex.PoseStack; +import mrtjp.projectred.fabrication.editor.tools.EraseTool; +import mrtjp.projectred.fabrication.gui.screen.ICWorkbenchScreen; +import mrtjp.projectred.lib.Point; +import net.minecraft.client.gui.GuiComponent; +import net.minecraft.network.chat.Component; +import net.minecraft.network.chat.TextComponent; + +import java.util.List; + +public class EraserToolTab extends ICEditorToolTab { + + private final EraseTool tool; + + public EraserToolTab(ICEditorToolManager manager, EraseTool tool) { + super(manager, tool); + this.tool = tool; + construct(); + } + + private void construct() { + + } + + @Override + public TabButtonNode createButtonNode() { + return new TabButtonNode(this, TabButtonNode.TabSide.LEFT) { + @Override + public void renderIcon(PoseStack stack, Point mouse, float partialFrame) { + RenderSystem.setShaderTexture(0, ICWorkbenchScreen.BACKGROUND); + GuiComponent.blit(stack, getFrame().x() + 3, getFrame().y() + 3, 390, 16, 14, 14, 512, 512); + } + + @Override + public void buildTooltip(List tooltip) { + tooltip.add(new TextComponent("Eraser")); //TODO Localize + } + + @Override + public boolean hasBody() { + return false; + } + }; + } +} diff --git a/fabrication/src/main/java/mrtjp/projectred/fabrication/gui/GatePlacerToolTab.java b/fabrication/src/main/java/mrtjp/projectred/fabrication/gui/GatePlacerToolTab.java new file mode 100644 index 000000000..1114ca85f --- /dev/null +++ b/fabrication/src/main/java/mrtjp/projectred/fabrication/gui/GatePlacerToolTab.java @@ -0,0 +1,110 @@ +package mrtjp.projectred.fabrication.gui; + +import codechicken.lib.math.MathHelper; +import codechicken.lib.render.CCRenderState; +import codechicken.lib.vec.Rotation; +import codechicken.lib.vec.Scale; +import codechicken.lib.vec.TransformationList; +import codechicken.lib.vec.Translation; +import com.mojang.blaze3d.systems.RenderSystem; +import com.mojang.blaze3d.vertex.PoseStack; +import mrtjp.projectred.fabrication.editor.tools.GatePlacerTool; +import mrtjp.projectred.fabrication.engine.gates.ICGateTileType; +import mrtjp.projectred.fabrication.gui.screen.ICWorkbenchScreen; +import mrtjp.projectred.integration.client.GateModelRenderer; +import mrtjp.projectred.lib.Point; +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.GuiComponent; +import net.minecraft.client.renderer.MultiBufferSource; +import net.minecraft.client.renderer.RenderType; +import net.minecraft.client.renderer.texture.OverlayTexture; +import net.minecraft.network.chat.Component; +import net.minecraft.network.chat.TextComponent; + +import java.util.List; + +public class GatePlacerToolTab extends ICEditorToolTab { + + private final GatePlacerTool tool; + + public GatePlacerToolTab(ICEditorToolManager manager, GatePlacerTool tool) { + super(manager, tool); + this.tool = tool; + construct(); + } + + private void addGateButton(ICGateTileType type) { + ButtonController buttonController = new ButtonController() { + @Override public void getTooltip(List tooltip) { tooltip.add(new TextComponent(type.toString())); } + @Override public void onClick() { tool.setGateType(type); } + @Override public boolean isSelected() { return tool.getGateType() == type; } + + @Override + public void renderIcon(PoseStack stack, Point absPos, float partialFrame) { + MultiBufferSource.BufferSource getter = Minecraft.getInstance().renderBuffers().bufferSource(); + CCRenderState ccrs = CCRenderState.instance(); + ccrs.reset(); + ccrs.bind(RenderType.cutout(), getter, stack); + ccrs.overlay = OverlayTexture.NO_OVERLAY; + ccrs.brightness = 0xF000F0; + + double scale = 10/16D; + TransformationList t = new TransformationList( + new Rotation(90.0F * MathHelper.torad, 1.0F, 0.0F, 0.0F), + new Scale(16.0F * scale, -16.0F * scale, 16.0F * scale), + new Translation(absPos.x + 8 - scale*8, absPos.y + 8 - scale*8, 0.0F) + ); + + //TODO dont use null? + GateModelRenderer.instance().renderInventory(ccrs, null, type.renderIndex, 0, t); + + getter.endBatch(); + } + }; + + this.addSingleButton(buttonController); + } + + private void construct() { + + addGroup("IO"); + addGateButton(ICGateTileType.IO); + + addGroup("Basic"); + addGateButton(ICGateTileType.OR); + addGateButton(ICGateTileType.NOR); + addGateButton(ICGateTileType.NOT); + addGateButton(ICGateTileType.AND); + addGateButton(ICGateTileType.NAND); + addGateButton(ICGateTileType.XOR); + addGateButton(ICGateTileType.XNOR); + addGateButton(ICGateTileType.BUFFER); + addGateButton(ICGateTileType.MULTIPLEXER); + + addGroup("Timing"); + addGateButton(ICGateTileType.PULSE); + addGateButton(ICGateTileType.REPEATER); + addGateButton(ICGateTileType.RANDOMIZER); + + addGroup("Latches"); + addGateButton(ICGateTileType.SR_LATCH); + addGateButton(ICGateTileType.TOGGLE_LATCH); + addGateButton(ICGateTileType.TRANSPARENT_LATCH); + } + + @Override + public TabButtonNode createButtonNode() { + return new TabButtonNode(this, TabButtonNode.TabSide.LEFT) { + @Override + public void renderIcon(PoseStack stack, Point mouse, float partialFrame) { + RenderSystem.setShaderTexture(0, ICWorkbenchScreen.BACKGROUND); + GuiComponent.blit(stack, getFrame().x() + 3, getFrame().y() + 3, 390, 31, 14, 14, 512, 512); + } + + @Override + public void buildTooltip(List tooltip) { + tooltip.add(new TextComponent("Logic")); //TODO Localize + } + }; + } +} diff --git a/fabrication/src/main/java/mrtjp/projectred/fabrication/gui/ICEditorToolManager.java b/fabrication/src/main/java/mrtjp/projectred/fabrication/gui/ICEditorToolManager.java new file mode 100644 index 000000000..10a3e5e12 --- /dev/null +++ b/fabrication/src/main/java/mrtjp/projectred/fabrication/gui/ICEditorToolManager.java @@ -0,0 +1,161 @@ +package mrtjp.projectred.fabrication.gui; + +import codechicken.lib.render.CCRenderState; +import codechicken.lib.vec.Vector3; +import com.mojang.blaze3d.vertex.PoseStack; +import mrtjp.projectred.fabrication.editor.ICEditorToolType; +import mrtjp.projectred.fabrication.editor.tools.IICEditorTool; +import net.minecraft.client.renderer.MultiBufferSource; +import net.minecraft.network.chat.Component; +import org.lwjgl.glfw.GLFW; + +import java.util.ArrayList; +import java.util.List; + +public class ICEditorToolManager implements ICRenderNode.IICRenderNodeEventReceiver { + + private final Vector3 initialLeftMousePosition = new Vector3(); + private final Vector3 initialRightMousePosition = new Vector3(); + + private boolean leftMouseDown = false; + private boolean rightMouseDown = false; + + private final ArrayList toolList; + private IICEditorTool selectedTool; + + private boolean upPressed = false; + private boolean rightPressed = false; + private boolean downPressed = false; + private boolean leftPressed = false; + + public ICEditorToolManager(ArrayList toolList) { + this.toolList = toolList; + selectedTool = toolList.get(0); + } + + public void swapTools(ICEditorToolType nextToolType) { + IICEditorTool nextTool = toolList.get(nextToolType.ordinal()); + if (nextTool != selectedTool) { + selectedTool.toolDeactivated(); + selectedTool = nextTool; + selectedTool.toolActivated(); + } + } + + public boolean keyPressed(int glfwKeyCode, int glfwFlags) { + switch (glfwKeyCode) { + case GLFW.GLFW_KEY_W: + upPressed = true; + break; + case GLFW.GLFW_KEY_A: + leftPressed = true; + break; + case GLFW.GLFW_KEY_S: + downPressed = true; + break; + case GLFW.GLFW_KEY_D: + rightPressed = true; + break; + default: + return false; + } + return true; + } + + public boolean keyReleased(int glfwKeyCode, int glfwFlags) { + switch (glfwKeyCode) { + case GLFW.GLFW_KEY_W: + upPressed = false; + break; + case GLFW.GLFW_KEY_A: + leftPressed = false; + break; + case GLFW.GLFW_KEY_S: + downPressed = false; + break; + case GLFW.GLFW_KEY_D: + rightPressed = false; + break; + default: + return false; + } + return true; + } + + public void update(ICRenderNode renderNode) { + Vector3 cameraDelta = new Vector3(); + double deltaPerTick = 0.5D; + + cameraDelta.z = (upPressed ? -deltaPerTick : 0) + (downPressed ? deltaPerTick : 0); + cameraDelta.x = (leftPressed ? -deltaPerTick : 0) + (rightPressed ? deltaPerTick : 0); + + renderNode.applyCameraDelta(cameraDelta); + } + + @Override + public void mouseButtonPressed(ICRenderNode renderNode, Vector3 mousePosition, int glfwMouseButton) { + switch (glfwMouseButton) { + case GLFW.GLFW_MOUSE_BUTTON_LEFT: + leftMouseDown = true; + initialLeftMousePosition.set(mousePosition); + break; + case GLFW.GLFW_MOUSE_BUTTON_RIGHT: + rightMouseDown = true; + initialRightMousePosition.set(mousePosition); + break; + default: + // ignore + } + + selectedTool.toolStart(mousePosition, glfwMouseButton); + } + + @Override + public void mouseButtonReleased(ICRenderNode renderNode, Vector3 mousePosition, int glfwMouseButton) { + switch (glfwMouseButton) { + case GLFW.GLFW_MOUSE_BUTTON_LEFT: + leftMouseDown = false; + break; + case GLFW.GLFW_MOUSE_BUTTON_RIGHT: + rightMouseDown = false; + break; + default: + // ignore + } + + selectedTool.toolReleased(mousePosition, glfwMouseButton); + } + + @Override + public void mouseButtonDragged(ICRenderNode renderNode, Vector3 mousePosition, Vector3 delta, int glfwMouseButton) { + if (!selectedTool.toolDragged(mousePosition, delta, glfwMouseButton)) { + // No default handling of mouse drag events + } + } + + @Override + public void mouseScrolled(ICRenderNode renderNode, Vector3 mousePosition, double scroll) { + if (!selectedTool.toolScrolled(mousePosition, scroll)) { + renderNode.moveZoomAt(mousePosition, scroll * 0.3D); + } + } + + @Override + public void layerChanged(ICRenderNode renderNode, int previousLayer, int newLayer) { + // Update bump the initial position up or down if a drag is in progress + if (leftMouseDown) initialLeftMousePosition.y = newLayer; + if (rightMouseDown) initialRightMousePosition.y = newLayer; + + selectedTool.toolLayerChanged(previousLayer, newLayer); + } + + @Override + public void onRenderOverlay(ICRenderNode renderNode, Vector3 mousePosition, boolean isFirstHit, CCRenderState ccrs, MultiBufferSource getter, PoseStack matrixStack) { + selectedTool.renderOverlay(mousePosition, isFirstHit, ccrs, getter, matrixStack); + } + + @Override + public void buildTooltip(ICRenderNode renderNode, Vector3 mousePosition, boolean isFirstHit, List tooltip) { + selectedTool.buildTooltip(mousePosition, isFirstHit, tooltip); + } +} diff --git a/fabrication/src/main/java/mrtjp/projectred/fabrication/gui/ICEditorToolTab.java b/fabrication/src/main/java/mrtjp/projectred/fabrication/gui/ICEditorToolTab.java new file mode 100644 index 000000000..d884e2413 --- /dev/null +++ b/fabrication/src/main/java/mrtjp/projectred/fabrication/gui/ICEditorToolTab.java @@ -0,0 +1,242 @@ +package mrtjp.projectred.fabrication.gui; + +import com.mojang.blaze3d.systems.RenderSystem; +import com.mojang.blaze3d.vertex.PoseStack; +import mrtjp.projectred.fabrication.editor.tools.IICEditorTool; +import mrtjp.projectred.fabrication.gui.screen.ICWorkbenchScreen; +import mrtjp.projectred.lib.Point; +import mrtjp.projectred.redui.AbstractGuiNode; +import net.minecraft.client.gui.Font; +import net.minecraft.client.gui.GuiComponent; +import net.minecraft.client.resources.sounds.SimpleSoundInstance; +import net.minecraft.network.chat.Component; +import net.minecraft.network.chat.TextComponent; +import net.minecraft.sounds.SoundEvents; + +import java.util.LinkedList; +import java.util.List; + +public class ICEditorToolTab extends AbstractGuiNode implements TabControllerNode.IToolbarTab { + + private static final int GROUP_U = 390; + private static final int GROUP_V = 61; + private static final int GROUP_WIDTH = 64; + private static final int GROUP_HEIGHT = 16; + + private static final int FULL_BUTTON_U = 390; + private static final int FULL_BUTTON_V = 77; + private static final int FULL_BUTTON_WIDTH = 64; + private static final int FULL_BUTTON_HEIGHT = 16; + + private static final int SINGLE_BUTTON_U = FULL_BUTTON_U + 64; + private static final int SINGLE_BUTTON_V = FULL_BUTTON_V; + private static final int SINGLE_BUTTON_WIDTH = 16; + private static final int SINGLE_BUTTON_HEIGHT = 16; + + private static final int BUTTON_SELECTED_SHIFT_U = 0; + private static final int BUTTON_SELECTED_SHIFT_V = 16; + private static final int BUTTON_MOUSEOVER_SHIFT_U = 0; + private static final int BUTTON_MOUSEOVER_SHIFT_V = 32; + + protected final ICEditorToolManager manager; + protected final IICEditorTool tool; + + private int rowIndex = 0; + private int columnIndex = 0; + + public ICEditorToolTab(ICEditorToolManager manager, IICEditorTool tool) { + this.manager = manager; + this.tool = tool; + + this.setSize(84, 222); + } + + private void setAndIncrGridPos(AbstractGuiNode node, int cellWidth) { + if (columnIndex + cellWidth > 4) { + columnIndex = 0; + rowIndex++; + } + + node.setPosition(7 + columnIndex * SINGLE_BUTTON_WIDTH, 18 + rowIndex * SINGLE_BUTTON_HEIGHT); + + columnIndex += cellWidth; + if (columnIndex > 4) { + columnIndex = 0; + rowIndex++; + } + } + + protected void addGroup(String groupName) { + + GroupHeaderNode header = new GroupHeaderNode(groupName); + setAndIncrGridPos(header, 4); + addChild(header); + } + + protected void addFullRowButton(ButtonController controller) { + + FullRowButtonNode button = new FullRowButtonNode(controller); + setAndIncrGridPos(button, 4); + addChild(button); + } + + protected void addSingleButton(ButtonController controller) { + + SingleColumnButtonNode button = new SingleColumnButtonNode(controller); + setAndIncrGridPos(button, 1); + addChild(button); + } + + @Override + public void drawBack(PoseStack stack, Point mouse, float partialFrame) { + RenderSystem.setShaderTexture(0, ICWorkbenchScreen.BACKGROUND); + + GuiComponent.blit(stack, getPosition().x, getPosition().y, 305, 0, 84, 222, 512, 512); + + //TODO: Render tool name on header + } + + @Override + public void onTabClosed() { + setHidden(true); + } + + @Override + public void onTabOpened() { + setHidden(false); + manager.swapTools(tool.getToolType()); + } + + @Override + public void onTabMinimized() { + setHidden(true); + } + + @Override + public TabButtonNode createButtonNode() { + return new TabButtonNode(this, TabButtonNode.TabSide.LEFT) { + + @Override + public void renderIcon(PoseStack stack, Point mouse, float partialFrame) { + } + + @Override + public void buildTooltip(List tooltip) { + tooltip.add(new TextComponent("//TODO implement tab")); + } + }; + } + + interface ButtonController { + void getTooltip(List tooltip); + void onClick(); + boolean isSelected(); + void renderIcon(PoseStack stack, Point absPos, float partialFrame); + } + + private static class GroupHeaderNode extends AbstractGuiNode { + + private final String title; + + public GroupHeaderNode(String title) { + this.title = title; + this.setSize(GROUP_WIDTH, GROUP_HEIGHT); + } + + @Override + public void drawBack(PoseStack stack, Point mouse, float partialFrame) { + RenderSystem.setShaderTexture(0, ICWorkbenchScreen.BACKGROUND); + + GuiComponent.blit(stack, getPosition().x, getPosition().y, GROUP_U, GROUP_V, getFrame().width(), getFrame().height(), 512, 512); + + Font fontRenderer = getRoot().getFontRenderer(); + fontRenderer.draw(stack, title, getPosition().x + 2, getPosition().y + GROUP_HEIGHT / 2 - fontRenderer.lineHeight/2, 0xFFFFFF); + } + } + + private static class AbstractButtonNode extends AbstractGuiNode { + + private final ButtonController controller; + private final Point uvBg; + private final Point uvBgSelectedShift; + private final Point uvMouseOverShift; + + public AbstractButtonNode(ButtonController controller, int width, int height, Point uvBg, Point uvBgSelectedShift, Point uvMouseOverShift) { + this.controller = controller; + this.setSize(width, height); + this.uvBg = uvBg; + this.uvBgSelectedShift = uvBgSelectedShift; + this.uvMouseOverShift = uvMouseOverShift; + } + + @Override + public void drawBack(PoseStack stack, Point mouse, float partialFrame) { + RenderSystem.enableBlend(); + RenderSystem.setShaderTexture(0, ICWorkbenchScreen.BACKGROUND); + + boolean mouseover = getFrame().contains(mouse) && isFirstHit(mouse); + boolean selected = controller.isSelected(); + + int x = getPosition().x; + int y = getPosition().y; + int w = getFrame().width(); + int h = getFrame().height(); + + // Background + int uBackground = uvBg.x + (selected ? uvBgSelectedShift.x : 0); + int vBackground = uvBg.y + (selected ? uvBgSelectedShift.y : 0); + GuiComponent.blit(stack, x, y, uBackground, vBackground, w, h, 512, 512); + + // Mouseover layer + if (selected || mouseover) { + int uMouseOver = uvBg.x + uvMouseOverShift.x; + int vMouseOver = uvBg.y + uvMouseOverShift.y; + GuiComponent.blit(stack, x, y, uMouseOver, vMouseOver, w, h, 512, 512); + } + + RenderSystem.disableBlend(); + + // Icon + controller.renderIcon(stack, getPosition(), partialFrame); + } + + @Override + public void drawFront(PoseStack stack, Point mouse, float partialFrame) { + + if (!isFirstHit(mouse)) return; + + List tooltip = new LinkedList<>(); + controller.getTooltip(tooltip); + + renderTooltip(stack, mouse, tooltip); + } + + @Override + public boolean mouseClicked(Point p, int glfwMouseButton, boolean consumed) { + if (!consumed && isFirstHit(p)) { + getRoot().getMinecraft().getSoundManager().play(SimpleSoundInstance.forUI(SoundEvents.UI_BUTTON_CLICK, 1)); + controller.onClick(); + return true; + } + return false; + } + } + + private static class SingleColumnButtonNode extends AbstractButtonNode { + public SingleColumnButtonNode(ButtonController controller) { + super(controller, SINGLE_BUTTON_WIDTH, SINGLE_BUTTON_HEIGHT, + new Point(SINGLE_BUTTON_U, SINGLE_BUTTON_V), + new Point(BUTTON_SELECTED_SHIFT_U, BUTTON_SELECTED_SHIFT_V), + new Point(BUTTON_MOUSEOVER_SHIFT_U, BUTTON_MOUSEOVER_SHIFT_V)); + } + } + + private static class FullRowButtonNode extends AbstractButtonNode { + public FullRowButtonNode(ButtonController controller) { + super(controller, FULL_BUTTON_WIDTH, FULL_BUTTON_HEIGHT, + new Point(FULL_BUTTON_U, FULL_BUTTON_V), + new Point(BUTTON_SELECTED_SHIFT_U, BUTTON_SELECTED_SHIFT_V), + new Point(BUTTON_MOUSEOVER_SHIFT_U, BUTTON_MOUSEOVER_SHIFT_V)); + } + } +} diff --git a/fabrication/src/main/java/mrtjp/projectred/fabrication/gui/ICRenderNode.java b/fabrication/src/main/java/mrtjp/projectred/fabrication/gui/ICRenderNode.java new file mode 100644 index 000000000..cee33a659 --- /dev/null +++ b/fabrication/src/main/java/mrtjp/projectred/fabrication/gui/ICRenderNode.java @@ -0,0 +1,234 @@ +package mrtjp.projectred.fabrication.gui; + +import codechicken.lib.math.MathHelper; +import codechicken.lib.render.CCRenderState; +import codechicken.lib.vec.Cuboid6; +import codechicken.lib.vec.RedundantTransformation; +import codechicken.lib.vec.Vector3; +import com.mojang.blaze3d.vertex.PoseStack; +import mrtjp.fengine.TileCoord; +import mrtjp.projectred.fabrication.editor.ICWorkbenchEditor; +import mrtjp.projectred.fabrication.engine.BaseTileMap; +import mrtjp.projectred.lib.Point; +import mrtjp.projectred.lib.Vec2; +import mrtjp.projectred.redui.ViewportRenderNode; +import net.minecraft.client.Minecraft; +import net.minecraft.client.renderer.LightTexture; +import net.minecraft.client.renderer.MultiBufferSource; +import net.minecraft.network.chat.Component; +import org.lwjgl.glfw.GLFW; + +import java.util.LinkedList; +import java.util.List; + +public class ICRenderNode extends ViewportRenderNode { + + private static final int ZOOM_ANIMATION_TIME_MS = 100; + private static final int LAYER_ANIMATION_TIME_MS = 200; + private static final int CAMERA_ANIMATION_TIME_MS = 100; + + private final ICWorkbenchEditor editor; + private final IICRenderNodeEventReceiver eventReceiver; + + private final Vector3 cameraPosition = new Vector3(); + + private final LinearVectorAnimation cameraLayerAnimator = new LinearVectorAnimation(); + private final LinearVectorAnimation cameraZoomAnimator = new LinearVectorAnimation(0, 3, 0); + + private int currentLayer = 0; + + private Point lastMousePos = Point.ZERO; + + public ICRenderNode(ICWorkbenchEditor editor, IICRenderNodeEventReceiver eventReceiver) { + this.editor = editor; + this.eventReceiver = eventReceiver; + } + + public void setLayer(int layer) { + int previousLayer = currentLayer; + this.currentLayer = layer; + cameraLayerAnimator.addDeltaWithNewDuration(new Vector3(0, layer-previousLayer, 0), LAYER_ANIMATION_TIME_MS); + eventReceiver.layerChanged(this, previousLayer, currentLayer); + } + + public void moveZoomAt(Vector3 zoomPos, double zoomDelta) { + + Vector3 zoomVec = zoomPos.copy().subtract(cameraPosition).normalize(); + zoomVec.multiply(zoomDelta); + cameraZoomAnimator.addDeltaWithNewDuration(zoomVec, ZOOM_ANIMATION_TIME_MS); + } + + public void applyCameraDelta(Vector3 delta) { + cameraZoomAnimator.addDeltaWithNewDuration(delta, CAMERA_ANIMATION_TIME_MS); + } + + @Override + public void frameUpdate(Point mouse, float partialFrame) { + long t = System.currentTimeMillis(); + cameraZoomAnimator.tick(t); + cameraLayerAnimator.tick(t); + + // Store mouse position for mouse drag calculations + lastMousePos = mouse; + + // Combine components to calculate final position + cameraPosition.set(0); + cameraZoomAnimator.apply(cameraPosition); + cameraLayerAnimator.apply(cameraPosition); + } + + @Override + protected double getTargetPlaneDistance() { + return cameraPosition.y - currentLayer - 2/16D; + } + + @Override + protected double getVerticalFOV() { + return 70D * MathHelper.torad; + } + + @Override + protected double getMaxRenderDist() { + return 20D; + } + + @Override + protected Vector3 getCameraPosition() { + return cameraPosition; + } + + @Override + protected void renderInViewport(PoseStack renderStack, Vec2 ndcMouse, float partialFrame, boolean isFirstHit) { + + CCRenderState ccrs = CCRenderState.instance(); + MultiBufferSource.BufferSource getter = Minecraft.getInstance().renderBuffers().bufferSource(); + + Vector3 worldPos = ndcMouseToWorld(ndcMouse); + + // At most, render 1 layer below and 1 render above (for transition effects) + for (int y = currentLayer-1; y <= currentLayer+1; y++) { + + ccrs.reset(); + // Linearly ramp down alpha as we move away from the current layer + ccrs.alphaOverride = 255 - (int) (255 * Math.min(Math.abs(y - cameraLayerAnimator.vector.y), 1)); + ccrs.brightness = LightTexture.pack(15, 15); + + // Render grid + renderStack.pushPose(); + renderStack.translate(0, y, 0); + TileCoord minBounds = editor.getTileMap().getMinBounds(); + TileCoord maxBounds = editor.getTileMap().getMaxBounds(); + Cuboid6 bounds = new Cuboid6(minBounds.x, minBounds.y, minBounds.z, maxBounds.x + 1, maxBounds.y + 1, maxBounds.z + 1); + + ICRenderTypes.renderICGrid(renderStack, getter, bounds, ccrs); //TODO the cuboid going in here is kinda awkward + + renderStack.popPose(); + + // Render tiles + for (BaseTileMap.BaseTileEntry entry : editor.getTileMap().getTilesOnLayer(y)) { + renderStack.pushPose(); + renderStack.translate(entry.getCoord().x, y, entry.getCoord().z); + ccrs.bind(ICRenderTypes.layersRenderType, getter, renderStack); + + entry.getTile().renderTile(ccrs, RedundantTransformation.INSTANCE, partialFrame); + + renderStack.popPose(); + } + + if (y == currentLayer) { + eventReceiver.onRenderOverlay(this, worldPos, isFirstHit, ccrs, getter, renderStack); + } + } + + // Force-end the batch to make sure it happens before the custom viewport is altered + getter.endBatch(); + } + + @Override + public void update() { + super.update(); + eventReceiver.update(this); + } + + @Override + protected List getToolTip(Point mousePosition, boolean isFirstHit) { + + List tooltip = new LinkedList<>(); + eventReceiver.buildTooltip(this, mouseToWorld(mousePosition), isFirstHit, tooltip); + + return tooltip; + } + + @Override + public boolean onKeyPressed(int glfwKeyCode, int glfwScanCode, int glfwFlags, boolean consumed) { + if (!consumed) { + if (glfwKeyCode == GLFW.GLFW_KEY_UP) { + setLayer(currentLayer + 1); + return true; + } + + if (glfwKeyCode == GLFW.GLFW_KEY_DOWN) { + setLayer(currentLayer - 1); + return true; + } + } + return false; + } + + @Override + public boolean mouseClicked(Point p, int glfwMouseButton, boolean consumed) { + lastMousePos = p; + if (!consumed && isFirstHit(p)) { + eventReceiver.mouseButtonPressed(this, mouseToWorld(p), glfwMouseButton); + return true; + } + return false; + } + + @Override + public boolean mouseReleased(Point p, int glfwMouseButton, long timeHeld, boolean consumed) { + lastMousePos = p; + eventReceiver.mouseButtonReleased(this, mouseToWorld(p), glfwMouseButton); + return true; + } + + @Override + public boolean mouseDragged(Point p, int glfwMouseButton, long timeHeld, boolean consumed) { + Vector3 worldPos = mouseToWorld(p); + Vector3 delta = worldPos.copy().subtract(mouseToWorld(lastMousePos)); + + eventReceiver.mouseButtonDragged(this, worldPos, delta, glfwMouseButton); + + lastMousePos = p; + return true; + } + + @Override + public boolean mouseScrolled(Point p, double scroll, boolean consumed) { + lastMousePos = p; + if (!consumed && isFirstHit(p)) { + eventReceiver.mouseScrolled(this, mouseToWorld(p), scroll); + return true; + } + return false; + } + + public interface IICRenderNodeEventReceiver { + + default void update(ICRenderNode renderNode) { } + + default void mouseButtonPressed(ICRenderNode renderNode, Vector3 mousePosition, int glfwMouseButton) { } + + default void mouseButtonReleased(ICRenderNode renderNode, Vector3 mousePosition, int glfwMouseButton) { } + + default void mouseButtonDragged(ICRenderNode renderNode, Vector3 mousePosition, Vector3 delta, int glfwMouseButton) { } + + default void mouseScrolled(ICRenderNode renderNode, Vector3 mousePosition, double scroll) { } + + default void layerChanged(ICRenderNode renderNode, int previousLayer, int newLayer) { } + + void onRenderOverlay(ICRenderNode renderNode, Vector3 mousePosition, boolean isFirstHit, CCRenderState ccrs, MultiBufferSource getter, PoseStack matrixStack); + + void buildTooltip(ICRenderNode renderNode, Vector3 mousePosition, boolean isFirstHit, List tooltip); + } +} diff --git a/fabrication/src/main/java/mrtjp/projectred/fabrication/gui/ICRenderTypes.java b/fabrication/src/main/java/mrtjp/projectred/fabrication/gui/ICRenderTypes.java new file mode 100644 index 000000000..26dfcb015 --- /dev/null +++ b/fabrication/src/main/java/mrtjp/projectred/fabrication/gui/ICRenderTypes.java @@ -0,0 +1,243 @@ +package mrtjp.projectred.fabrication.gui; + +import codechicken.lib.render.BlockRenderer; +import codechicken.lib.render.CCRenderState; +import codechicken.lib.texture.AtlasRegistrar; +import codechicken.lib.vec.Cuboid6; +import codechicken.lib.vec.Vector3; +import com.mojang.blaze3d.vertex.DefaultVertexFormat; +import com.mojang.blaze3d.vertex.PoseStack; +import com.mojang.blaze3d.vertex.VertexFormat; +import com.mojang.math.Vector3f; +import mrtjp.projectred.fabrication.ProjectRedFabrication; +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.Font; +import net.minecraft.client.renderer.MultiBufferSource; +import net.minecraft.client.renderer.RenderStateShard; +import net.minecraft.client.renderer.RenderType; +import net.minecraft.client.renderer.texture.TextureAtlasSprite; +import net.minecraft.resources.ResourceLocation; + +import java.util.HashMap; +import java.util.Map; + +import static mrtjp.projectred.fabrication.ProjectRedFabrication.MOD_ID; + +public class ICRenderTypes { + + public static ResourceLocation PERFBOARD_TEXTURE = new ResourceLocation(MOD_ID, "textures/block/perfboard.png"); + public static ResourceLocation PERFBOARD_EDGE_TEXTURE = new ResourceLocation(MOD_ID, "textures/block/perfboard_edge.png"); + public static ResourceLocation PERFBOARD_CORNER_TEXTURE = new ResourceLocation(MOD_ID, "textures/block/perfboard_corner.png"); + + public static RenderType layersRenderType = RenderType.create(MOD_ID + ":ic_block", DefaultVertexFormat.BLOCK, VertexFormat.Mode.QUADS, 10000, false, true, + RenderType.CompositeState.builder() + .setShaderState(RenderStateShard.RENDERTYPE_CUTOUT_SHADER) //TODO only default one that discards alpha frags + .setTextureState(RenderStateShard.BLOCK_SHEET) + .setTransparencyState(RenderStateShard.TRANSLUCENT_TRANSPARENCY) + .setDepthTestState(RenderStateShard.LEQUAL_DEPTH_TEST) + .setCullState(RenderStateShard.CULL) + .setLightmapState(RenderStateShard.LIGHTMAP) + .setOverlayState(RenderStateShard.NO_OVERLAY) + .setLayeringState(RenderStateShard.NO_LAYERING) + .setOutputState(RenderStateShard.MAIN_TARGET) + .setTexturingState(RenderStateShard.DEFAULT_TEXTURING) + .setWriteMaskState(RenderStateShard.COLOR_DEPTH_WRITE) + .setLineState(RenderStateShard.DEFAULT_LINE) + .createCompositeState(true)); + + public static RenderType selectionRenderType = RenderType.create(MOD_ID + ":ic_selection", DefaultVertexFormat.POSITION_COLOR, VertexFormat.Mode.QUADS, 256, false, false, + RenderType.CompositeState.builder() + .setShaderState(RenderStateShard.POSITION_COLOR_SHADER) + .setTextureState(RenderStateShard.NO_TEXTURE) + .setTransparencyState(RenderStateShard.LIGHTNING_TRANSPARENCY) + .setDepthTestState(RenderStateShard.LEQUAL_DEPTH_TEST) + .setCullState(RenderStateShard.CULL) + .setLightmapState(RenderStateShard.NO_LIGHTMAP) + .setOverlayState(RenderStateShard.NO_OVERLAY) + .setLayeringState(RenderStateShard.NO_LAYERING) + .setOutputState(RenderStateShard.MAIN_TARGET) + .setTexturingState(RenderStateShard.DEFAULT_TEXTURING) + .setWriteMaskState(RenderStateShard.COLOR_DEPTH_WRITE) + .setLineState(RenderStateShard.DEFAULT_LINE) + .createCompositeState(true)); + + public static RenderType gridRenderType = RenderType.create(MOD_ID + ":ic_grid", DefaultVertexFormat.BLOCK, VertexFormat.Mode.QUADS, 256, false, false, + RenderType.CompositeState.builder() + .setShaderState(RenderStateShard.BLOCK_SHADER) + .setTextureState(new RenderStateShard.TextureStateShard(PERFBOARD_TEXTURE, false, false)) // Mipped: Strange artifacts on render. Our normal world rendering is not mipped + .setTransparencyState(RenderStateShard.TRANSLUCENT_TRANSPARENCY) + .setDepthTestState(RenderStateShard.LEQUAL_DEPTH_TEST) + .setCullState(RenderStateShard.CULL) + .setLightmapState(RenderStateShard.NO_LIGHTMAP) + .setOverlayState(RenderStateShard.NO_OVERLAY) + .setLayeringState(RenderStateShard.NO_LAYERING) + .setOutputState(RenderStateShard.MAIN_TARGET) + .setTexturingState(RenderStateShard.DEFAULT_TEXTURING) + .setWriteMaskState(RenderStateShard.COLOR_DEPTH_WRITE) + .setLineState(RenderStateShard.DEFAULT_LINE) + .createCompositeState(true)); + + public static RenderType gridEdgeRenderType = RenderType.create(MOD_ID + ":ic_grid_edge", DefaultVertexFormat.BLOCK, VertexFormat.Mode.QUADS, 256, false, false, + RenderType.CompositeState.builder() + .setShaderState(RenderStateShard.BLOCK_SHADER) + .setTextureState(new RenderStateShard.TextureStateShard(PERFBOARD_EDGE_TEXTURE, false, false)) + .setTransparencyState(RenderStateShard.TRANSLUCENT_TRANSPARENCY) + .setDepthTestState(RenderStateShard.LEQUAL_DEPTH_TEST) + .setCullState(RenderStateShard.CULL) + .setLightmapState(RenderStateShard.NO_LIGHTMAP) + .setOverlayState(RenderStateShard.NO_OVERLAY) + .setLayeringState(RenderStateShard.NO_LAYERING) + .setOutputState(RenderStateShard.MAIN_TARGET) + .setTexturingState(RenderStateShard.DEFAULT_TEXTURING) + .setWriteMaskState(RenderStateShard.COLOR_DEPTH_WRITE) + .setLineState(RenderStateShard.DEFAULT_LINE) + .createCompositeState(true)); + + public static RenderType gridCornerRenderType = RenderType.create(MOD_ID + ":ic_grid_corner", DefaultVertexFormat.BLOCK, VertexFormat.Mode.QUADS, 256, false, false, + RenderType.CompositeState.builder() + .setShaderState(RenderStateShard.BLOCK_SHADER) + .setTextureState(new RenderStateShard.TextureStateShard(PERFBOARD_CORNER_TEXTURE, false, false)) + .setTransparencyState(RenderStateShard.TRANSLUCENT_TRANSPARENCY) + .setDepthTestState(RenderStateShard.LEQUAL_DEPTH_TEST) + .setCullState(RenderStateShard.CULL) + .setLightmapState(RenderStateShard.NO_LIGHTMAP) + .setOverlayState(RenderStateShard.NO_OVERLAY) + .setLayeringState(RenderStateShard.NO_LAYERING) + .setOutputState(RenderStateShard.MAIN_TARGET) + .setTexturingState(RenderStateShard.DEFAULT_TEXTURING) + .setWriteMaskState(RenderStateShard.COLOR_DEPTH_WRITE) + .setLineState(RenderStateShard.DEFAULT_LINE) + .createCompositeState(true)); + + public static TextureAtlasSprite icSurfaceIcon; + public static TextureAtlasSprite icSurfaceBorderIcon; + public static TextureAtlasSprite icSurfaceCornerIcon; + + public static void renderICGrid(PoseStack renderStack, MultiBufferSource getter, Cuboid6 bounds, CCRenderState ccrs) { + // Main + double ymin = -2/16D; + Cuboid6 box = new Cuboid6(bounds.min.x, ymin, bounds.min.z, bounds.max.x, 0, bounds.max.z); + ccrs.bind(ICRenderTypes.gridRenderType, getter, renderStack); + BlockRenderer.renderCuboid(ccrs, box, 1); + + // Edges + double h = 0.01D; + ccrs.bind(ICRenderTypes.gridEdgeRenderType, getter, renderStack); + // Top + box.set(bounds.min.x, ymin, bounds.min.z, bounds.max.x, h, bounds.min.z + 1); + BlockRenderer.renderCuboid(ccrs, box, 1); + // bottom + box.set(bounds.min.x, ymin, bounds.max.z - 1, bounds.max.x, h, bounds.max.z); + BlockRenderer.renderCuboid(ccrs, box, 1); + // left + box.set(bounds.min.x, ymin, bounds.min.z, bounds.min.x + 1, h, bounds.max.z); + BlockRenderer.renderCuboid(ccrs, box, 1); + // right + box.set(bounds.max.x - 1, ymin, bounds.min.z, bounds.max.x, h, bounds.max.z); + BlockRenderer.renderCuboid(ccrs, box, 1); + + // Corners + h = 0.02D; + ccrs.bind(ICRenderTypes.gridCornerRenderType, getter, renderStack); + // Top left + box.set(bounds.min.x, ymin, bounds.min.z, bounds.min.x + 1, h, bounds.min.z + 1); + BlockRenderer.renderCuboid(ccrs, box, 1); + // Top right + box.set(bounds.max.x - 1, ymin, bounds.min.z, bounds.max.x, h, bounds.min.z + 1); + BlockRenderer.renderCuboid(ccrs, box, 1); + // bottom right + box.set(bounds.max.x - 1, ymin, bounds.max.z - 1, bounds.max.x, h, bounds.max.z); + BlockRenderer.renderCuboid(ccrs, box, 1); + // bottom left + box.set(bounds.min.x, ymin, bounds.max.z - 1, bounds.min.x + 1, h, bounds.max.z); + BlockRenderer.renderCuboid(ccrs, box, 1); + + } + + public static void renderSelection(CCRenderState ccrs, Vector3 a, Vector3 b, double height, double th) { + + Cuboid6 ac = new Cuboid6(a.copy().floor(), a.copy().ceil()); + ac.enclose(b.copy().floor()); + ac.enclose(b.copy().ceil()); + ac.expand(0.002); + + Cuboid6 box = new Cuboid6(); + + //Top + box.min.x = ac.min.x; + box.min.y = ac.min.y; + box.min.z = ac.min.z; + box.max.x = ac.max.x; + box.max.y = ac.min.y + height; + box.max.z = ac.min.z + th; + BlockRenderer.renderCuboid(ccrs, box, 1); + + // Bottom + box.min.x = ac.min.x; + box.min.y = ac.min.y; + box.min.z = ac.max.z - th; + box.max.x = ac.max.x; + box.max.y = ac.min.y + height; + box.max.z = ac.max.z; + BlockRenderer.renderCuboid(ccrs, box, 1); + + // Left + box.min.x = ac.min.x; + box.min.y = ac.min.y; + box.min.z = ac.min.z + th; + box.max.x = ac.min.x + th; + box.max.y = ac.min.y + height; + box.max.z = ac.max.z - th; + BlockRenderer.renderCuboid(ccrs, box, 1 | 1<<2 | 1<<3); + + // Right + box.min.x = ac.max.x - th; + box.min.y = ac.min.y; + box.min.z = ac.min.z + th; + box.max.x = ac.max.x; + box.max.y = ac.min.y + height; + box.max.z = ac.max.z - th; + BlockRenderer.renderCuboid(ccrs, box, 1 | 1<<2 | 1<<3); + } + + public static void renderTextCenteredAt(PoseStack stack, Vector3 pos, String text, int bgColor, int textColor) { + Font fontRenderer = Minecraft.getInstance().font; + + stack.pushPose(); + + stack.translate(pos.x, pos.y, pos.z); + stack.scale(1.0f/fontRenderer.lineHeight, 1, 1.0f/fontRenderer.lineHeight); + stack.mulPose(Vector3f.XP.rotationDegrees(90.0F)); + + fontRenderer.draw(stack, text, (float) (0 - fontRenderer.width(text) / 2), (float) (0 - fontRenderer.lineHeight / 2), textColor); + + stack.popPose(); + } + + public void sortComponents(Cuboid6 c) { + + if (c.min.x > c.max.x) { + double tmp = c.max.x; + c.max.x = c.min.x; + c.min.x = tmp; + } + + if (c.min.y > c.max.y) { + double tmp = c.max.y; + c.max.y = c.min.y; + c.min.y = tmp; + } + + if (c.min.z > c.max.z) { + double tmp = c.max.z; + c.max.z = c.min.z; + c.min.z = tmp; + } + } + + public static void registerIcons(AtlasRegistrar registrar) { + registrar.registerSprite(new ResourceLocation(MOD_ID, "block/perfboard"), i -> icSurfaceIcon = i); + registrar.registerSprite(new ResourceLocation(MOD_ID, "block/perfboard_edge"), i -> icSurfaceBorderIcon = i); + registrar.registerSprite(new ResourceLocation(MOD_ID, "block/perfboard_corner"), i -> icSurfaceCornerIcon = i); + } +} diff --git a/fabrication/src/main/java/mrtjp/projectred/fabrication/gui/ICompileOverlayRenderer.java b/fabrication/src/main/java/mrtjp/projectred/fabrication/gui/ICompileOverlayRenderer.java new file mode 100644 index 000000000..c7c447676 --- /dev/null +++ b/fabrication/src/main/java/mrtjp/projectred/fabrication/gui/ICompileOverlayRenderer.java @@ -0,0 +1,16 @@ +package mrtjp.projectred.fabrication.gui; + +import codechicken.lib.render.CCRenderState; +import codechicken.lib.vec.Vector3; +import com.mojang.blaze3d.vertex.PoseStack; +import net.minecraft.client.renderer.MultiBufferSource; +import net.minecraft.network.chat.Component; + +import java.util.List; + +public interface ICompileOverlayRenderer { + + void renderOverlay(ICRenderNode renderNode, Vector3 mousePosition, boolean isFirstHit, CCRenderState ccrs, MultiBufferSource getter, PoseStack matrixStack); + + void buildTooltip(ICRenderNode renderNode, Vector3 mousePosition, List tooltip); +} diff --git a/fabrication/src/main/java/mrtjp/projectred/fabrication/gui/InteractToolTab.java b/fabrication/src/main/java/mrtjp/projectred/fabrication/gui/InteractToolTab.java new file mode 100644 index 000000000..0400509be --- /dev/null +++ b/fabrication/src/main/java/mrtjp/projectred/fabrication/gui/InteractToolTab.java @@ -0,0 +1,48 @@ +package mrtjp.projectred.fabrication.gui; + +import com.mojang.blaze3d.systems.RenderSystem; +import com.mojang.blaze3d.vertex.PoseStack; +import mrtjp.projectred.fabrication.editor.tools.InteractTool; +import mrtjp.projectred.fabrication.gui.screen.ICWorkbenchScreen; +import mrtjp.projectred.lib.Point; +import net.minecraft.client.gui.GuiComponent; +import net.minecraft.network.chat.Component; +import net.minecraft.network.chat.TextComponent; + +import java.util.List; + +public class InteractToolTab extends ICEditorToolTab { + + private final InteractTool tool; + + public InteractToolTab(ICEditorToolManager manager, InteractTool tool) { + super(manager, tool); + this.tool = tool; + construct(); + } + + private void construct() { + + } + + @Override + public TabButtonNode createButtonNode() { + return new TabButtonNode(this, TabButtonNode.TabSide.LEFT) { + @Override + public void renderIcon(PoseStack stack, Point mouse, float partialFrame) { + RenderSystem.setShaderTexture(0, ICWorkbenchScreen.BACKGROUND); + GuiComponent.blit(stack, getFrame().x() + 3, getFrame().y() + 3, 390, 1, 14, 14, 512, 512); + } + + @Override + public void buildTooltip(List tooltip) { + tooltip.add(new TextComponent("Interact")); //TODO Localize + } + + @Override + public boolean hasBody() { + return false; + } + }; + } +} diff --git a/fabrication/src/main/java/mrtjp/projectred/fabrication/gui/LinearVectorAnimation.java b/fabrication/src/main/java/mrtjp/projectred/fabrication/gui/LinearVectorAnimation.java new file mode 100644 index 000000000..15e226861 --- /dev/null +++ b/fabrication/src/main/java/mrtjp/projectred/fabrication/gui/LinearVectorAnimation.java @@ -0,0 +1,48 @@ +package mrtjp.projectred.fabrication.gui; + +import codechicken.lib.vec.Vector3; + +public class LinearVectorAnimation { + + public final Vector3 vector; + private final Vector3 step = new Vector3(); + + private long lastTime = -1; + private long stepsRemaining = 0; + + public LinearVectorAnimation() { + this(0, 0, 0); + } + + public LinearVectorAnimation(double x, double y, double z) { + vector = new Vector3(x, y, z); + } + + public void addDeltaWithNewDuration(Vector3 delta, long duration) { + if (delta.equals(Vector3.ZERO) || duration == 0) { + return; + } + + // Calculate the new step size to satisfy new delta plus previous delta within new duration + step.multiply(stepsRemaining); + step.add(delta); + stepsRemaining = duration; + step.divide(stepsRemaining); + } + + public void tick(long time) { + + long dt = lastTime == -1 ? 0 : time - lastTime; + lastTime = time; + + if (stepsRemaining > 0) { + long stepsToTake = Math.min(stepsRemaining, dt); + vector.add(step.x * stepsToTake, step.y * stepsToTake, step.z * stepsToTake); + stepsRemaining -= stepsToTake; + } + } + + public void apply(Vector3 target) { + target.add(vector); + } +} diff --git a/fabrication/src/main/java/mrtjp/projectred/fabrication/gui/SelectionGridNode.java b/fabrication/src/main/java/mrtjp/projectred/fabrication/gui/SelectionGridNode.java new file mode 100644 index 000000000..a0f546195 --- /dev/null +++ b/fabrication/src/main/java/mrtjp/projectred/fabrication/gui/SelectionGridNode.java @@ -0,0 +1,117 @@ +package mrtjp.projectred.fabrication.gui; + +import com.mojang.blaze3d.systems.RenderSystem; +import com.mojang.blaze3d.vertex.PoseStack; +import mrtjp.projectred.fabrication.gui.screen.ICWorkbenchScreen; +import mrtjp.projectred.lib.Point; +import mrtjp.projectred.redui.AbstractGuiNode; +import net.minecraft.client.gui.GuiComponent; +import net.minecraft.client.resources.sounds.SimpleSoundInstance; +import net.minecraft.network.chat.Component; +import net.minecraft.sounds.SoundEvents; + +import java.util.LinkedList; +import java.util.List; +import java.util.function.BiConsumer; +import java.util.function.Consumer; +import java.util.function.Predicate; + +public class SelectionGridNode extends AbstractGuiNode { + + private static final int BUTTON_WIDTH = 16; + private static final int BUTTON_HEIGHT = 16; + private static final int BUTTON_U = 495; + private static final int BUTTON_V = 1; + private static final int BUTTON_V_SHIFT = 17; + + private final int gridWidth; + private final int gridHeight; + + private Consumer clickFunction = i -> { }; + private Predicate selectionCheckFunction = i -> false; + private BiConsumer> tooltipBuilder = (i, l) -> { }; + + public SelectionGridNode(int gridWidth, int gridHeight) { + this.gridWidth = gridWidth; + this.gridHeight = gridHeight; + setSize(gridWidth * BUTTON_WIDTH, gridHeight * BUTTON_HEIGHT); + addButtons(); + } + + public void setClickFunction(Consumer clickFunction) { + this.clickFunction = clickFunction; + } + + public void setTooltipBuilder(BiConsumer> tooltipBuilder) { + this.tooltipBuilder = tooltipBuilder; + } + + public void setSelectionCheckFunction(Predicate selectionCheckFunction) { + this.selectionCheckFunction = selectionCheckFunction; + } + + private void addButtons() { + + for (int y = 0; y < gridHeight; y++) { + for (int x = 0; x < gridWidth; x++) { + + SelectionGridButtonNode button = new SelectionGridButtonNode(x + y * gridHeight); + button.setPosition(x * button.getFrame().width(), y * button.getFrame().height()); + addChild(button); + } + } + } + + private class SelectionGridButtonNode extends AbstractGuiNode { + + private final int i; + + public SelectionGridButtonNode(int i) { + this.i = i; + this.setSize(BUTTON_WIDTH, BUTTON_HEIGHT); + } + + @Override + public void drawBack(PoseStack stack, Point mouse, float partialFrame) { + + RenderSystem.setShaderTexture(0, ICWorkbenchScreen.BACKGROUND); + + boolean mouseover = getFrame().contains(mouse) && isFirstHit(mouse); + + int state = SelectionGridNode.this.selectionCheckFunction.test(i) ? 2 : + mouseover ? 1 : 0; + + int x = getPosition().x; + int y = getPosition().y; + int w = getFrame().width(); + int h = getFrame().height(); + int u = BUTTON_U; + int v = BUTTON_V + BUTTON_V_SHIFT * state; + + GuiComponent.blit(stack, x, y, u, v, w, h, 512, 512); + + + } + + @Override + public void drawFront(PoseStack stack, Point mouse, float partialFrame) { + + if (!isFirstHit(mouse)) return; + + List tooltip = new LinkedList<>(); + tooltipBuilder.accept(i, tooltip); + + renderTooltip(stack, mouse, tooltip); + } + + @Override + public boolean mouseClicked(Point p, int glfwMouseButton, boolean consumed) { + if (!consumed && isFirstHit(p)) { + getRoot().getMinecraft().getSoundManager().play(SimpleSoundInstance.forUI(SoundEvents.UI_BUTTON_CLICK, 1)); + clickFunction.accept(i); + return true; + } + return false; + } + } +} diff --git a/fabrication/src/main/java/mrtjp/projectred/fabrication/gui/SimpleUVTab.java b/fabrication/src/main/java/mrtjp/projectred/fabrication/gui/SimpleUVTab.java new file mode 100644 index 000000000..260115f25 --- /dev/null +++ b/fabrication/src/main/java/mrtjp/projectred/fabrication/gui/SimpleUVTab.java @@ -0,0 +1,72 @@ +package mrtjp.projectred.fabrication.gui; + +import com.mojang.blaze3d.systems.RenderSystem; +import com.mojang.blaze3d.vertex.PoseStack; +import mrtjp.projectred.fabrication.gui.screen.ICWorkbenchScreen; +import mrtjp.projectred.lib.Point; +import mrtjp.projectred.redui.AbstractGuiNode; +import net.minecraft.client.gui.GuiComponent; +import net.minecraft.network.chat.Component; +import net.minecraft.network.chat.TextComponent; +import net.minecraft.resources.ResourceLocation; + +import java.util.List; + +public class SimpleUVTab implements TabControllerNode.IToolbarTab { + + private final AbstractGuiNode tabBodyNode; + private final String tabName; + private final TabButtonNode.TabSide tabSide; + + private final int u; + private final int v; + private final ResourceLocation texture; + + public SimpleUVTab(AbstractGuiNode tabBodyNode, String tabName, TabButtonNode.TabSide side, int u, int v, ResourceLocation texture) { //TODO Icon width/height? + this.tabBodyNode = tabBodyNode; + this.tabName = tabName; + this.tabSide = side; + this.u = u; + this.v = v; + this.texture = texture; + } + + public SimpleUVTab(AbstractGuiNode tabBodyNode, String tabName, TabButtonNode.TabSide side, int u, int v) { + this(tabBodyNode, tabName, side, u, v, ICWorkbenchScreen.BACKGROUND); + } + + public AbstractGuiNode getTabBodyNode() { + return tabBodyNode; + } + + @Override + public void onTabClosed() { + tabBodyNode.setHidden(true); + } + + @Override + public void onTabOpened() { + tabBodyNode.setHidden(false); + } + + @Override + public void onTabMinimized() { + tabBodyNode.setHidden(true); + } + + @Override + public TabButtonNode createButtonNode() { + return new TabButtonNode(this, tabSide) { + @Override + public void renderIcon(PoseStack stack, Point mouse, float partialFrame) { + RenderSystem.setShaderTexture(0, texture); + GuiComponent.blit(stack, getFrame().x() + 3, getFrame().y() + 3, u, v, 14, 14, 512, 512); + } + + @Override + public void buildTooltip(List tooltip) { + tooltip.add(new TextComponent(tabName)); + } + }; + } +} diff --git a/fabrication/src/main/java/mrtjp/projectred/fabrication/gui/TabButtonNode.java b/fabrication/src/main/java/mrtjp/projectred/fabrication/gui/TabButtonNode.java new file mode 100644 index 000000000..3e77b56a6 --- /dev/null +++ b/fabrication/src/main/java/mrtjp/projectred/fabrication/gui/TabButtonNode.java @@ -0,0 +1,176 @@ +package mrtjp.projectred.fabrication.gui; + +import com.mojang.blaze3d.systems.RenderSystem; +import com.mojang.blaze3d.vertex.PoseStack; +import mrtjp.projectred.fabrication.gui.screen.ICWorkbenchScreen; +import mrtjp.projectred.lib.Point; +import mrtjp.projectred.redui.AbstractGuiNode; +import net.minecraft.client.gui.GuiComponent; +import net.minecraft.client.resources.sounds.SimpleSoundInstance; +import net.minecraft.network.chat.Component; +import net.minecraft.sounds.SoundEvents; + +import java.util.LinkedList; +import java.util.List; + +public abstract class TabButtonNode extends AbstractGuiNode { + + private TabState renderState; + private final TabSide side; + + protected final TabControllerNode.IToolbarTab tab; + + public TabButtonNode(TabControllerNode.IToolbarTab tab, TabSide side) { + this(tab, side, TabState.ALL_CLOSED); + } + + public TabButtonNode(TabControllerNode.IToolbarTab tab, TabSide side, TabState renderState) { + this.tab = tab; + this.side = side; + this.renderState = renderState; + + setSize(side.w, side.h); + } + + + public TabState getRenderState() { + return renderState; + } + + public void setTabState(TabState renderState) { + + if (renderState != this.renderState) { + TabState prevState = this.renderState; + this.renderState = renderState; + + onTabStateChanged(prevState, renderState); + } + } + + @Override + public void drawBack(PoseStack stack, Point mouse, float partialFrame) { + RenderSystem.setShaderTexture(0, ICWorkbenchScreen.BACKGROUND); + + int x = getPosition().x; + int y = getPosition().y; + int u = side.u; + int v = side.v; + int w = side.w; + int h = side.h; + + int ex = x + side.extOffsetX; + int ey = y + side.extOffsetY; + int eu = side.extU; + int ev = side.extV; + int ew = side.extW; + int eh = side.extH; + + // If inactive, render greyed out version of the sprite + if (renderState == TabState.ALL_CLOSED || renderState == TabState.CLOSED) { + u += side.inactiveOffsetU; + v += side.inactiveOffsetV; + eu += side.inactiveOffsetU; + ev += side.inactiveOffsetV; + } + + GuiComponent.blit(stack, x, y, u, v, w, h, 512, 512); + + // Render extension if needed + if (renderState == TabState.CLOSED || renderState == TabState.OPEN) { + GuiComponent.blit(stack, ex, ey, eu, ev, ew, eh, 512, 512); + } + + renderIcon(stack, mouse, partialFrame); + } + + @Override + public void drawFront(PoseStack stack, Point mouse, float partialFrame) { + + if (!isFirstHit(mouse)) + return; + + List tooltip = new LinkedList<>(); + buildTooltip(tooltip); + + renderTooltip(stack, mouse, tooltip); + } + + @Override + public boolean mouseClicked(Point p, int glfwMouseButton, boolean consumed) { + if (!consumed && isFirstHit(p)) { + getRoot().getMinecraft().getSoundManager().play(SimpleSoundInstance.forUI(SoundEvents.UI_BUTTON_CLICK, 1)); + onClicked(); + return true; + } + return false; + } + + public void onClicked() { + TabControllerNode tabControllerNode = (TabControllerNode) getParent(); + + tabControllerNode.openTab(tab); + if (!hasBody()) tabControllerNode.minimizeTab(tab); // If no body, minimize tab + } + + public void onTabStateChanged(TabState prevState, TabState newState) { + switch (newState) { + case OPEN: + tab.onTabOpened(); + break; + case CLOSED: + case ALL_CLOSED: + tab.onTabClosed(); + break; + case MINIMIZED: + tab.onTabMinimized(); + } + } + + public boolean hasBody() { + return true; + } + + public abstract void renderIcon(PoseStack stack, Point mouse, float partialFrame); + + public abstract void buildTooltip(List tooltip); + + enum TabState { + ALL_CLOSED, // Unselected with no extension + CLOSED, // Unselected with extension + MINIMIZED, // Selected with no extension + OPEN // Selected with extension + } + + public enum TabSide { + LEFT(482, 179, 20, 20, 503, 179, 6, 20, 16, 0, 0, 21), + BOTTOM(466, 234, 20, 20, 466, 227, 20, 6, 0, -2, 21, 0); + + public final int u; + public final int v; + public final int w; + public final int h; + public final int extU; + public final int extV; + public final int extW; + public final int extH; + public final int extOffsetX; + public final int extOffsetY; + public final int inactiveOffsetU; + public final int inactiveOffsetV; + + TabSide(int u, int v, int w, int h, int extU, int extV, int extW, int extH, int extOffsetX, int extOffsetY, int inactiveOffsetU, int inactiveOffsetV) { + this.u = u; + this.v = v; + this.w = w; + this.h = h; + this.extU = extU; + this.extV = extV; + this.extW = extW; + this.extH = extH; + this.extOffsetX = extOffsetX; + this.extOffsetY = extOffsetY; + this.inactiveOffsetU = inactiveOffsetU; + this.inactiveOffsetV = inactiveOffsetV; + } + } +} diff --git a/fabrication/src/main/java/mrtjp/projectred/fabrication/gui/TabControllerNode.java b/fabrication/src/main/java/mrtjp/projectred/fabrication/gui/TabControllerNode.java new file mode 100644 index 000000000..56487f1eb --- /dev/null +++ b/fabrication/src/main/java/mrtjp/projectred/fabrication/gui/TabControllerNode.java @@ -0,0 +1,148 @@ +package mrtjp.projectred.fabrication.gui; + +import mrtjp.projectred.redui.AbstractGuiNode; + +import java.util.LinkedList; +import java.util.List; +import java.util.Optional; + +import static mrtjp.projectred.fabrication.gui.TabButtonNode.TabState.*; + +public class TabControllerNode extends AbstractGuiNode { + + private final List tabButtonList = new LinkedList<>(); + private final List tabs = new LinkedList<>(); + + public void addButtonForTab(IToolbarTab tab) { + + int i = tabs.size(); + + TabButtonNode button = tab.createButtonNode(); + button.setZPosition(0.1); + button.setTabState(TabButtonNode.TabState.ALL_CLOSED); + addChild(button); + + tabs.add(new TabEntry(i, button, tab)); + tabButtonList.add(button); + } + + public Optional getSelectedTab() { + for (TabEntry entry : tabs) { + TabButtonNode.TabState state = entry.buttonNode.getRenderState(); + if (state == OPEN || state == MINIMIZED) { + return Optional.ofNullable(entry.tab); + } + } + return Optional.empty(); + } + + public IToolbarTab getTab(int index) { + return tabs.get(index).tab; + } + + public void spreadButtonsVertically(int padding) { + int y = 0; + for (TabButtonNode button : tabButtonList) { + button.setPosition(0, y); + y += button.getFrame().height() + padding; + } + } + + public void spreadButtonsHorizontally(int padding) { + int x = 0; + for (TabButtonNode button : tabButtonList) { + button.setPosition(x, 0); + x += button.getFrame().width() + padding; + } + } + + public void selectInitialTab(int tabIndex) { + + TabEntry tab = tabs.get(tabIndex); + if (tab.buttonNode.hasBody()) { + for (int i = 0; i < tabs.size(); i++) { + tabs.get(i).buttonNode.setTabState(i == tabIndex ? OPEN : CLOSED); + } + } else { + tab.buttonNode.setTabState(MINIMIZED); + } + } + + public void openTab(IToolbarTab tab) { + for (TabEntry entry : tabs) { + if (entry.tab == tab) { + entry.buttonNode.setTabState(OPEN); + } else { + entry.buttonNode.setTabState(CLOSED); + } + } + } + + public void closeTab(IToolbarTab tab) { + + boolean tabsOpen = false; + + for (TabEntry entry : tabs) { + if (entry.tab == tab) { + entry.buttonNode.setTabState(CLOSED); + } + + if (entry.buttonNode.getRenderState() == OPEN) { + tabsOpen = true; + } + } + + if (!tabsOpen) { + for (TabEntry entry : tabs) entry.buttonNode.setTabState(ALL_CLOSED); + } + } + + public void minimizeTab(IToolbarTab tab) { + boolean tabsOpen = false; + + for (TabEntry entry : tabs) { + if (entry.tab == tab) { + entry.buttonNode.setTabState(MINIMIZED); + } + + if (entry.buttonNode.getRenderState() == OPEN) { + tabsOpen = true; + } + } + + if (!tabsOpen) { + for (TabEntry entry : tabs) { + if (entry.tab != tab) entry.buttonNode.setTabState(ALL_CLOSED); + } + } + } + + public void closeAllTabs() { + for (TabEntry entry : tabs) { + entry.buttonNode.setTabState(ALL_CLOSED); + } + } + + private static class TabEntry { + public final int i; + public final TabButtonNode buttonNode; + public final IToolbarTab tab; + + public TabEntry(int i, TabButtonNode buttonNode, IToolbarTab tab) { + this.i = i; + this.buttonNode = buttonNode; + this.tab = tab; + } + } + + public interface IToolbarTab { + + void onTabClosed(); + + void onTabOpened(); + + void onTabMinimized(); + + TabButtonNode createButtonNode(); + } +} diff --git a/fabrication/src/main/java/mrtjp/projectred/fabrication/gui/WirePlacerToolTab.java b/fabrication/src/main/java/mrtjp/projectred/fabrication/gui/WirePlacerToolTab.java new file mode 100644 index 000000000..f79cd4ae1 --- /dev/null +++ b/fabrication/src/main/java/mrtjp/projectred/fabrication/gui/WirePlacerToolTab.java @@ -0,0 +1,109 @@ +package mrtjp.projectred.fabrication.gui; + +import codechicken.lib.math.MathHelper; +import codechicken.lib.render.CCRenderState; +import codechicken.lib.vec.Rotation; +import codechicken.lib.vec.Scale; +import codechicken.lib.vec.TransformationList; +import codechicken.lib.vec.Translation; +import com.mojang.blaze3d.systems.RenderSystem; +import com.mojang.blaze3d.vertex.PoseStack; +import mrtjp.projectred.fabrication.editor.tools.WirePlacerTool; +import mrtjp.projectred.fabrication.engine.wires.ICWireTileType; +import mrtjp.projectred.fabrication.gui.screen.ICWorkbenchScreen; +import mrtjp.projectred.lib.Point; +import mrtjp.projectred.transmission.client.WireModelRenderer; +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.GuiComponent; +import net.minecraft.client.renderer.MultiBufferSource; +import net.minecraft.client.renderer.RenderType; +import net.minecraft.client.renderer.texture.OverlayTexture; +import net.minecraft.network.chat.Component; +import net.minecraft.network.chat.TextComponent; + +import java.util.List; + +public class WirePlacerToolTab extends ICEditorToolTab { + + private final WirePlacerTool tool; + + public WirePlacerToolTab(ICEditorToolManager manager, WirePlacerTool tool) { + super(manager, tool); + this.tool = tool; + construct(); + } + + private void addWireButton(ICWireTileType type, boolean fullRow) { + ButtonController buttonController = new ButtonController() { + @Override public void getTooltip(List tooltip) { tooltip.add(new TextComponent(type.toString())); } + @Override public void onClick() { tool.setWireType(type); } + @Override public boolean isSelected() { return tool.getWireType() == type; } + + @Override + public void renderIcon(PoseStack stack, Point absPos, float partialFrame) { + MultiBufferSource.BufferSource getter = Minecraft.getInstance().renderBuffers().bufferSource(); + CCRenderState ccrs = CCRenderState.instance(); + ccrs.reset(); + ccrs.bind(RenderType.cutout(), getter, stack); + ccrs.overlay = OverlayTexture.NO_OVERLAY; + ccrs.brightness = 0xF000F0; + + double scale = 10/16D; + TransformationList t = new TransformationList( + new Rotation(90.0F * MathHelper.torad, 1.0F, 0.0F, 0.0F), + new Scale(16.0F * scale, -16.0F * scale, 16.0F * scale), + new Translation(absPos.x + 8 - scale*8, absPos.y + 8 - scale*8, 0.0F) + ); + + WireModelRenderer.renderInventory(ccrs, type.multipartType.getThickness(), type.multipartType.getItemColour() << 8 | 0xFF, type.multipartType.getTextures().get(0), t); + + getter.endBatch(); + } + }; + + if (fullRow) { + addFullRowButton(buttonController); + } else { + addSingleButton(buttonController); + } + } + + private void construct() { + + addGroup("Redwire"); + + // Alloy wire + addWireButton(ICWireTileType.RED_ALLOY, true); + + // Insulated wires + for (ICWireTileType type : ICWireTileType.INSULATED) + addWireButton(type, false); + + addGroup("Bundled"); + + // Bundled neutral wire + addWireButton(ICWireTileType.BUNDLED_NEUTRAL, true); + + // Bundled coloured wires + for (ICWireTileType type : ICWireTileType.BUNDLED_COLOURED) + addWireButton(type, false); + + } + + @Override + public TabButtonNode createButtonNode() { + return new TabButtonNode(this, TabButtonNode.TabSide.LEFT) { + @Override + public void renderIcon(PoseStack stack, Point mouse, float partialFrame) { + + RenderSystem.setShaderTexture(0, ICWorkbenchScreen.BACKGROUND); + GuiComponent.blit(stack, getFrame().x() + 3, getFrame().y() + 3, 390, 46, 14, 14, 512, 512); + } + + @Override + public void buildTooltip(List tooltip) { + tooltip.add(new TextComponent("Wires")); //TODO Localize + } + }; + } +} diff --git a/fabrication/src/main/java/mrtjp/projectred/fabrication/gui/screen/ICWorkbenchCompileTab.java b/fabrication/src/main/java/mrtjp/projectred/fabrication/gui/screen/ICWorkbenchCompileTab.java new file mode 100644 index 000000000..0832b396b --- /dev/null +++ b/fabrication/src/main/java/mrtjp/projectred/fabrication/gui/screen/ICWorkbenchCompileTab.java @@ -0,0 +1,218 @@ +package mrtjp.projectred.fabrication.gui.screen; + +import codechicken.lib.render.CCRenderState; +import codechicken.lib.vec.Vector3; +import com.mojang.blaze3d.systems.RenderSystem; +import com.mojang.blaze3d.vertex.PoseStack; +import mrtjp.fengine.TileCoord; +import mrtjp.projectred.fabrication.ProjectRedFabrication; +import mrtjp.projectred.fabrication.editor.ICWorkbenchEditor; +import mrtjp.projectred.fabrication.editor.tools.IICEditorTool; +import mrtjp.projectred.fabrication.gui.*; +import mrtjp.projectred.lib.Point; +import mrtjp.projectred.redui.AbstractButtonNode; +import mrtjp.projectred.redui.AbstractGuiNode; +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.GuiComponent; +import net.minecraft.client.renderer.MultiBufferSource; +import net.minecraft.network.chat.Component; +import net.minecraft.resources.ResourceLocation; +import org.lwjgl.glfw.GLFW; + +import java.util.List; + +public class ICWorkbenchCompileTab extends AbstractGuiNode implements ICRenderNode.IICRenderNodeEventReceiver { + + public static final ResourceLocation TAB_BACKGROUND = new ResourceLocation(ProjectRedFabrication.MOD_ID, "textures/gui/compile_tab.png"); + + private final ICWorkbenchEditor editor; + + private TabControllerNode tabControllerNode; + + private boolean upPressed = false; + private boolean rightPressed = false; + private boolean downPressed = false; + private boolean leftPressed = false; + + public ICWorkbenchCompileTab(ICWorkbenchEditor editor) { + this.editor = editor; + + setSize(304, 222); + initSubNodes(); + } + + private void initSubNodes() { + + CompileButton compileButton = new CompileButton(); + compileButton.setPosition(208, 16); + compileButton.setSize(18, 18); + addChild(compileButton); + + ICRenderNode icRenderNode = new ICRenderNode(editor, this); + icRenderNode.setPosition(7, 18); + icRenderNode.setSize(197, 197); + addChild(icRenderNode); + + // Tab nodes + CompileStackTab compileStackTab = new CompileStackTab(editor); + compileStackTab.setPosition(208, 77); + addChild(compileStackTab); + + CompileTreeTab compileTreeTab = new CompileTreeTab(editor); + compileTreeTab.setPosition(208, 77); + addChild(compileTreeTab); + + CompileProblemsTab compileProblemsTab = new CompileProblemsTab(editor); + compileProblemsTab.setPosition(208, 77); + addChild(compileProblemsTab); + + // Bottom tabs + tabControllerNode = new TabControllerNode(); + tabControllerNode.setPosition(212, 210); + tabControllerNode.setZPosition(0.1); + addChild(tabControllerNode); + + tabControllerNode.addButtonForTab(new SimpleUVTab(compileStackTab, "Stack", TabButtonNode.TabSide.BOTTOM, 350, 11, TAB_BACKGROUND)); + tabControllerNode.addButtonForTab(new SimpleUVTab(compileTreeTab, "Tree", TabButtonNode.TabSide.BOTTOM, 365, 11, TAB_BACKGROUND)); + tabControllerNode.addButtonForTab(new SimpleUVTab(compileProblemsTab, "Problems", TabButtonNode.TabSide.BOTTOM, 380, 11, TAB_BACKGROUND)); + + tabControllerNode.selectInitialTab(0); + tabControllerNode.spreadButtonsHorizontally(1); + } + + @Override + public void drawBack(PoseStack stack, Point mouse, float partialFrame) { + RenderSystem.setShaderTexture(0, TAB_BACKGROUND); + GuiComponent.blit(stack, getFrame().x(), getFrame().y(), 0, 0, getFrame().width(), getFrame().height(), 512, 512); + + // Progress bar + int barWidth = 91; + int progress = editor.getStateMachine().getCompilerLog().getProgressScaled(barWidth); + GuiComponent.blit(stack, getFrame().x() + 208, getFrame().y() + 36, 304, 0, barWidth, 5, 512, 512); + GuiComponent.blit(stack, getFrame().x() + 208, getFrame().y() + 36, 304, 5, progress, 5, 512, 512); + } + + //TODO Reduce this reused code (ICEditorToolManager) + @Override + public boolean onKeyPressed(int glfwKeyCode, int glfwScanCode, int glfwFlags, boolean consumed) { + if (consumed || isHidden()) + return false; + + switch (glfwKeyCode) { + case GLFW.GLFW_KEY_W: + upPressed = true; + break; + case GLFW.GLFW_KEY_A: + leftPressed = true; + break; + case GLFW.GLFW_KEY_S: + downPressed = true; + break; + case GLFW.GLFW_KEY_D: + rightPressed = true; + break; + default: + return false; + } + return true; + } + + @Override + public boolean onKeyReleased(int glfwKeyCode, int glfwScanCode, int glfwFlags, boolean consumed) { + switch (glfwKeyCode) { + case GLFW.GLFW_KEY_W: + upPressed = false; + break; + case GLFW.GLFW_KEY_A: + leftPressed = false; + break; + case GLFW.GLFW_KEY_S: + downPressed = false; + break; + case GLFW.GLFW_KEY_D: + rightPressed = false; + break; + default: + return false; + } + return true; + } + + protected ICompileOverlayRenderer getOverlayRenderer() { + + // Overlay rendering is handled by the currently open tab + SimpleUVTab tab = (SimpleUVTab) tabControllerNode.getSelectedTab().orElse(tabControllerNode.getTab(0)); + return (ICompileOverlayRenderer) tab.getTabBodyNode(); + } + + //region ICRenderNode.IICRenderNodeEventReceiver + + @Override + public void update(ICRenderNode renderNode) { + Vector3 cameraDelta = new Vector3(); + double deltaPerTick = 0.5D; + + cameraDelta.z = (upPressed ? -deltaPerTick : 0) + (downPressed ? deltaPerTick : 0); + cameraDelta.x = (leftPressed ? -deltaPerTick : 0) + (rightPressed ? deltaPerTick : 0); + + renderNode.applyCameraDelta(cameraDelta); + } + + @Override + public void mouseScrolled(ICRenderNode renderNode, Vector3 mousePosition, double scroll) { + renderNode.moveZoomAt(mousePosition, scroll * 0.3D); + } + + @Override + public void buildTooltip(ICRenderNode renderNode, Vector3 mousePosition, boolean isFirstHit, List tooltip) { + if (!isFirstHit) return; + + TileCoord pos = IICEditorTool.toNearestPosition(mousePosition); + editor.getTileMap().getBaseTile(pos).ifPresent(tile -> tile.buildToolTip(tooltip)); + + getOverlayRenderer().buildTooltip(renderNode, mousePosition, tooltip); + } + + @Override + public void onRenderOverlay(ICRenderNode renderNode, Vector3 mousePosition, boolean isFirstHit, CCRenderState ccrs, MultiBufferSource getter, PoseStack matrixStack) { + getOverlayRenderer().renderOverlay(renderNode, mousePosition, isFirstHit, ccrs, getter, matrixStack); + } + + //endregion + + public class CompileButton extends AbstractButtonNode { + + @Override + protected void onButtonClicked() { + editor.getStateMachine().sendCompileButtonClicked(); + } + @Override + protected boolean isButtonDisabled() { + return !editor.getStateMachine().canTriggerCompile(); + } + + @Override + protected void drawButtonBody(PoseStack stack, boolean mouseover) { + RenderSystem.setShaderTexture(0, TAB_BACKGROUND); + + if (editor.getStateMachine().isCompiling()) { + // Spinner + long time = Minecraft.getInstance().level.getGameTime(); + int progress = (int) (time / 2) % 8; + int u = 305 + (15 * progress); + int v = 26; + blitCentered(stack, u, v, 14, 14); + } else { + // Hammer icon + blitCentered(stack, 305, 11, 14, 14); + } + } + + private void blitCentered(PoseStack stack, int u, int v, int width, int height) { + GuiComponent.blit(stack, + getFrame().x() + (getFrame().width() - width) / 2, + getFrame().y() + (getFrame().height() - height) / 2, u, v, + width, height, 512, 512); + } + } +} diff --git a/fabrication/src/main/java/mrtjp/projectred/fabrication/gui/screen/ICWorkbenchEditTab.java b/fabrication/src/main/java/mrtjp/projectred/fabrication/gui/screen/ICWorkbenchEditTab.java new file mode 100644 index 000000000..643e3b725 --- /dev/null +++ b/fabrication/src/main/java/mrtjp/projectred/fabrication/gui/screen/ICWorkbenchEditTab.java @@ -0,0 +1,85 @@ +package mrtjp.projectred.fabrication.gui.screen; + +import com.mojang.blaze3d.systems.RenderSystem; +import com.mojang.blaze3d.vertex.PoseStack; +import mrtjp.projectred.fabrication.editor.ICWorkbenchEditor; +import mrtjp.projectred.fabrication.editor.tools.*; +import mrtjp.projectred.fabrication.gui.*; +import mrtjp.projectred.lib.Point; +import mrtjp.projectred.redui.AbstractGuiNode; +import net.minecraft.client.gui.GuiComponent; + +public class ICWorkbenchEditTab extends AbstractGuiNode { + + private final ICWorkbenchEditor editor; + private final ICEditorToolManager toolManager; + + public ICWorkbenchEditTab(ICWorkbenchEditor editor) { + this.editor = editor; + this.toolManager = new ICEditorToolManager(editor.getToolList()); + + setSize(304, 222); + initSubNodes(); + } + + private void initSubNodes() { + + TabControllerNode toolbarNode = new TabControllerNode(); + toolbarNode.setPosition(286, 24); + toolbarNode.setZPosition(0.1); + addChild(toolbarNode); + + for (IICEditorTool tool : editor.getToolList()) { + + ICEditorToolTab tab = getTabForTool(tool); + tab.setPosition(305, 0); + tab.setHidden(true); + + toolbarNode.addButtonForTab(tab); + addChild(tab); + } + toolbarNode.selectInitialTab(0); + toolbarNode.spreadButtonsVertically(1); + + ICRenderNode icRenderNode = new ICRenderNode(editor, toolManager); + icRenderNode.setPosition(7, 18); + icRenderNode.setSize(290, 197); + addChild(icRenderNode); + } + + private ICEditorToolTab getTabForTool(IICEditorTool tool) { + + if (tool instanceof InteractTool) + return new InteractToolTab(toolManager, (InteractTool) tool); + + if (tool instanceof EraseTool) + return new EraserToolTab(toolManager, (EraseTool) tool); + + if (tool instanceof GatePlacerTool) + return new GatePlacerToolTab(toolManager, (GatePlacerTool) tool); + + if (tool instanceof WirePlacerTool) + return new WirePlacerToolTab(toolManager, (WirePlacerTool) tool); + + return new ICEditorToolTab(toolManager, tool); + } + + @Override + public void drawBack(PoseStack stack, Point mouse, float partialFrame) { + RenderSystem.setShaderTexture(0, ICWorkbenchScreen.BACKGROUND); + GuiComponent.blit(stack, getFrame().x(), getFrame().y(), 0, 0, getFrame().width(), getFrame().height(), 512, 512); + } + + @Override + public boolean onKeyPressed(int glfwKeyCode, int glfwScanCode, int glfwFlags, boolean consumed) { + if (!consumed && !isHidden()) { + return toolManager.keyPressed(glfwKeyCode, glfwFlags); + } + return false; + } + + @Override + public boolean onKeyReleased(int glfwKeyCode, int glfwScanCode, int glfwFlags, boolean consumed) { + return toolManager.keyReleased(glfwKeyCode, glfwFlags); + } +} diff --git a/fabrication/src/main/java/mrtjp/projectred/fabrication/gui/screen/ICWorkbenchScreen.java b/fabrication/src/main/java/mrtjp/projectred/fabrication/gui/screen/ICWorkbenchScreen.java new file mode 100644 index 000000000..54dd43520 --- /dev/null +++ b/fabrication/src/main/java/mrtjp/projectred/fabrication/gui/screen/ICWorkbenchScreen.java @@ -0,0 +1,91 @@ +package mrtjp.projectred.fabrication.gui.screen; + +import com.mojang.blaze3d.vertex.PoseStack; +import mrtjp.projectred.fabrication.ProjectRedFabrication; +import mrtjp.projectred.fabrication.editor.ICWorkbenchEditor; +import mrtjp.projectred.fabrication.gui.SimpleUVTab; +import mrtjp.projectred.fabrication.gui.TabButtonNode; +import mrtjp.projectred.fabrication.gui.TabControllerNode; +import mrtjp.projectred.fabrication.tile.ICWorkbenchTile; +import mrtjp.projectred.lib.Point; +import mrtjp.projectred.lib.Rect; +import mrtjp.projectred.redui.DebugRectNode; +import mrtjp.projectred.redui.RedUIScreen; +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.Font; +import net.minecraft.network.chat.TextComponent; +import net.minecraft.resources.ResourceLocation; + +public class ICWorkbenchScreen extends RedUIScreen { + + public static final ResourceLocation BACKGROUND = new ResourceLocation(ProjectRedFabrication.MOD_ID, "textures/gui/ic_workbench.png"); + + private final ICWorkbenchTile tile; + private final ICWorkbenchEditor editor; + + public ICWorkbenchScreen(ICWorkbenchTile tile) { + super(304, 222, new TextComponent(tile.getType().getRegistryName().toString())); + + this.tile = tile; + this.editor = tile.getEditor(); + + initSubNodes(); + } + + public static void openGuiOnClient(ICWorkbenchTile tile) { + Minecraft.getInstance().setScreen(new ICWorkbenchScreen(tile)); + } + + private void initSubNodes() { + ICWorkbenchEditTab editTab = new ICWorkbenchEditTab(editor); + addChild(editTab); + + ICWorkbenchCompileTab compileTab = new ICWorkbenchCompileTab(editor); + addChild(compileTab); + + TabControllerNode tabControllerNode = new TabControllerNode(); + tabControllerNode.setPosition(-19, 4); + tabControllerNode.setZPosition(0.1); + addChild(tabControllerNode); + + tabControllerNode.addButtonForTab(new SimpleUVTab(new DebugRectNode(), "Info", TabButtonNode.TabSide.LEFT, 420, 1)); + tabControllerNode.addButtonForTab(new SimpleUVTab(editTab, "Edit", TabButtonNode.TabSide.LEFT, 420, 16)); + tabControllerNode.addButtonForTab(new SimpleUVTab(compileTab, "Compile", TabButtonNode.TabSide.LEFT, 420, 31)); + + tabControllerNode.selectInitialTab(1); + tabControllerNode.spreadButtonsVertically(1); + } + + @Override + public void drawBack(PoseStack stack, Point mouse, float partialFrame) { + super.drawBack(stack, mouse, partialFrame); + + if (!editor.isActive()) { //TODO this has to be drawn by a node above viewport node + Rect frame = getFrame(); + fillGradient(stack, frame.x(), frame.y(), frame.width(), frame.height(), -1072689136, -804253680); + + Font fontRenderer = getFontRenderer(); + + String message = "Editor is not active"; + int width = fontRenderer.width(message); + int height = fontRenderer.lineHeight; + + getFontRenderer().draw(stack, message, + frame.x() + frame.width() / 2F - width / 2F, + frame.y() + frame.height() / 2F - height / 2F, 0xFFFFFFFF); + } + } + + @Override + public void removed() { + super.removed(); + tile.closeGuiFromClient(); + ProjectRedFabrication.LOGGER.info("ICWorkbenchScreen REMOVED"); + } + + @Override + public void onClose() { + super.onClose(); + ProjectRedFabrication.LOGGER.info("ICWorkbenchScreen ONCLOSE"); + } +} diff --git a/fabrication/src/main/java/mrtjp/projectred/fabrication/gui/screen/inventory/LithographyTableScreen.java b/fabrication/src/main/java/mrtjp/projectred/fabrication/gui/screen/inventory/LithographyTableScreen.java new file mode 100644 index 000000000..4adde857b --- /dev/null +++ b/fabrication/src/main/java/mrtjp/projectred/fabrication/gui/screen/inventory/LithographyTableScreen.java @@ -0,0 +1,48 @@ +package mrtjp.projectred.fabrication.gui.screen.inventory; + +import com.mojang.blaze3d.systems.RenderSystem; +import com.mojang.blaze3d.vertex.PoseStack; +import mrtjp.projectred.fabrication.ProjectRedFabrication; +import mrtjp.projectred.fabrication.inventory.container.LithographyTableContainer; +import mrtjp.projectred.lib.GuiLib; +import mrtjp.projectred.lib.Point; +import mrtjp.projectred.redui.RedUIContainerScreen; +import net.minecraft.network.chat.Component; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.entity.player.Inventory; + +public class LithographyTableScreen extends RedUIContainerScreen { + + public static final ResourceLocation BACKGROUND = new ResourceLocation(ProjectRedFabrication.MOD_ID, "textures/gui/lithography_table.png"); + + public LithographyTableScreen(LithographyTableContainer container, Inventory playerInventory, Component title) { + super(176, 171, container, playerInventory, title); //TODO size + + inventoryLabelX = 8; + inventoryLabelY = 79; + } + + @Override + public void drawBack(PoseStack stack, Point mouse, float partialFrame) { + super.drawBack(stack, mouse, partialFrame); + + RenderSystem.setShaderTexture(0, BACKGROUND); + int x = getFrame().x(); + int y = getFrame().y(); + + blit(stack, x, y, 0, 0, getFrame().width(), getFrame().height()); + + int s = getMenu().getProgressScaled(24); + blit(stack, x + 80, y + 40, 176, 0, s + 1, 16); + + if (getMenu().canConductorWork()) + blit(stack, x + 16, y + 16, 177, 18, 7, 9); + + GuiLib.drawVerticalTank(stack, this, x + 16, y + 26, 177, 27, 7, 48, getMenu().getChargeScaled(48)); + + if (getMenu().isFlowFull()) + blit(stack, x + 27, y + 16, 185, 18, 7, 9); + + GuiLib.drawVerticalTank(stack, this, x + 27, y + 26, 185, 27, 7, 48, getMenu().getFlowScaled(48)); + } +} diff --git a/fabrication/src/main/java/mrtjp/projectred/fabrication/gui/screen/inventory/PackagingTableScreen.java b/fabrication/src/main/java/mrtjp/projectred/fabrication/gui/screen/inventory/PackagingTableScreen.java new file mode 100644 index 000000000..b61fc0c32 --- /dev/null +++ b/fabrication/src/main/java/mrtjp/projectred/fabrication/gui/screen/inventory/PackagingTableScreen.java @@ -0,0 +1,48 @@ +package mrtjp.projectred.fabrication.gui.screen.inventory; + +import com.mojang.blaze3d.systems.RenderSystem; +import com.mojang.blaze3d.vertex.PoseStack; +import mrtjp.projectred.fabrication.ProjectRedFabrication; +import mrtjp.projectred.fabrication.inventory.container.PackagingTableContainer; +import mrtjp.projectred.lib.GuiLib; +import mrtjp.projectred.lib.Point; +import mrtjp.projectred.redui.RedUIContainerScreen; +import net.minecraft.network.chat.Component; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.entity.player.Inventory; + +public class PackagingTableScreen extends RedUIContainerScreen { + + public static final ResourceLocation BACKGROUND = new ResourceLocation(ProjectRedFabrication.MOD_ID, "textures/gui/packaging_table.png"); + + public PackagingTableScreen(PackagingTableContainer container, Inventory playerInventory, Component title) { + super(176, 171, container, playerInventory, title); //TODO size + + inventoryLabelX = 8; + inventoryLabelY = 79; + } + + @Override + public void drawBack(PoseStack stack, Point mouse, float partialFrame) { + super.drawBack(stack, mouse, partialFrame); + + RenderSystem.setShaderTexture(0, BACKGROUND); + int x = getFrame().x(); + int y = getFrame().y(); + + blit(stack, x, y, 0, 0, getFrame().width(), getFrame().height()); + + int s = getMenu().getProgressScaled(88); + blit(stack, x + 39, y + 25, 0, 171, s + 1, 33); + + if (getMenu().canConductorWork()) + blit(stack, x + 16, y + 16, 177, 18, 7, 9); + + GuiLib.drawVerticalTank(stack, this, x + 16, y + 26, 177, 27, 7, 48, getMenu().getChargeScaled(48)); + + if (getMenu().isFlowFull()) + blit(stack, x + 27, y + 16, 185, 18, 7, 9); + + GuiLib.drawVerticalTank(stack, this, x + 27, y + 26, 185, 27, 7, 48, getMenu().getFlowScaled(48)); + } +} diff --git a/fabrication/src/main/java/mrtjp/projectred/fabrication/gui/screen/inventory/PlottingTableScreen.java b/fabrication/src/main/java/mrtjp/projectred/fabrication/gui/screen/inventory/PlottingTableScreen.java new file mode 100644 index 000000000..db1ca597b --- /dev/null +++ b/fabrication/src/main/java/mrtjp/projectred/fabrication/gui/screen/inventory/PlottingTableScreen.java @@ -0,0 +1,48 @@ +package mrtjp.projectred.fabrication.gui.screen.inventory; + +import com.mojang.blaze3d.systems.RenderSystem; +import com.mojang.blaze3d.vertex.PoseStack; +import mrtjp.projectred.fabrication.ProjectRedFabrication; +import mrtjp.projectred.fabrication.inventory.container.PlottingTableContainer; +import mrtjp.projectred.lib.GuiLib; +import mrtjp.projectred.lib.Point; +import mrtjp.projectred.redui.RedUIContainerScreen; +import net.minecraft.network.chat.Component; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.entity.player.Inventory; + +public class PlottingTableScreen extends RedUIContainerScreen { + + public static final ResourceLocation BACKGROUND = new ResourceLocation(ProjectRedFabrication.MOD_ID, "textures/gui/plotting_table.png"); + + public PlottingTableScreen(PlottingTableContainer container, Inventory playerInventory, Component title) { + super(176, 171, container, playerInventory, title); //TODO size + + inventoryLabelX = 8; + inventoryLabelY = 79; + } + + @Override + public void drawBack(PoseStack stack, Point mouse, float partialFrame) { + super.drawBack(stack, mouse, partialFrame); + + RenderSystem.setShaderTexture(0, BACKGROUND); + int x = getFrame().x(); + int y = getFrame().y(); + + blit(stack, x, y, 0, 0, getFrame().width(), getFrame().height()); + + int s = getMenu().getProgressScaled(24); + blit(stack, x + 80, y + 40, 176, 0, s + 1, 16); + + if (getMenu().canConductorWork()) + blit(stack, x + 16, y + 16, 177, 18, 7, 9); + + GuiLib.drawVerticalTank(stack, this, x + 16, y + 26, 177, 27, 7, 48, getMenu().getChargeScaled(48)); + + if (getMenu().isFlowFull()) + blit(stack, x + 27, y + 16, 185, 18, 7, 9); + + GuiLib.drawVerticalTank(stack, this, x + 27, y + 26, 185, 27, 7, 48, getMenu().getFlowScaled(48)); + } +} diff --git a/fabrication/src/main/java/mrtjp/projectred/fabrication/init/FabricationBlocks.java b/fabrication/src/main/java/mrtjp/projectred/fabrication/init/FabricationBlocks.java new file mode 100644 index 000000000..19980b623 --- /dev/null +++ b/fabrication/src/main/java/mrtjp/projectred/fabrication/init/FabricationBlocks.java @@ -0,0 +1,45 @@ +package mrtjp.projectred.fabrication.init; + +import mrtjp.projectred.fabrication.block.ICWorkbenchBlock; +import mrtjp.projectred.fabrication.block.LithographyTableBlock; +import mrtjp.projectred.fabrication.block.PackagingTableBlock; +import mrtjp.projectred.fabrication.block.PlottingTableBlock; +import mrtjp.projectred.fabrication.tile.ICWorkbenchTile; +import mrtjp.projectred.fabrication.tile.LithographyTableTile; +import mrtjp.projectred.fabrication.tile.PackagingTableTile; +import mrtjp.projectred.fabrication.tile.PlottingTableTile; +import net.minecraft.world.item.BlockItem; +import net.minecraft.world.item.Item; +import net.minecraft.world.level.block.entity.BlockEntityType; + +import static mrtjp.projectred.fabrication.ProjectRedFabrication.*; +import static mrtjp.projectred.fabrication.init.FabricationReferences.*; + +public class FabricationBlocks { + + public static final String ID_IC_WORKBENCH = "ic_workbench"; + public static final String ID_PLOTTING_TABLE = "plotting_table"; + public static final String ID_LITHOGRAPHY_TABLE = "lithography_table"; + public static final String ID_PACKAGING_TABLE = "packaging_table"; + + public static void register() { + + // Blocks + BLOCKS.register(ID_IC_WORKBENCH, ICWorkbenchBlock::new); + BLOCKS.register(ID_PLOTTING_TABLE, PlottingTableBlock::new); + BLOCKS.register(ID_LITHOGRAPHY_TABLE, LithographyTableBlock::new); + BLOCKS.register(ID_PACKAGING_TABLE, PackagingTableBlock::new); + + // Block Items + ITEMS.register(ID_IC_WORKBENCH, () -> new BlockItem(IC_WORKBENCH_BLOCK, new Item.Properties().tab(FABRICATION_GROUP))); + ITEMS.register(ID_PLOTTING_TABLE, () -> new BlockItem(PLOTTING_TABLE_BLOCK, new Item.Properties().tab(FABRICATION_GROUP))); + ITEMS.register(ID_LITHOGRAPHY_TABLE, () -> new BlockItem(LITHOGRAPHY_TABLE_BLOCK, new Item.Properties().tab(FABRICATION_GROUP))); + ITEMS.register(ID_PACKAGING_TABLE, () -> new BlockItem(PACKAGING_TABLE_BLOCK, new Item.Properties().tab(FABRICATION_GROUP))); + + // Tiles + TILE_ENTITIES.register(ID_IC_WORKBENCH, () -> BlockEntityType.Builder.of(ICWorkbenchTile::new, IC_WORKBENCH_BLOCK).build(null)); + TILE_ENTITIES.register(ID_PLOTTING_TABLE, () -> BlockEntityType.Builder.of(PlottingTableTile::new, PLOTTING_TABLE_BLOCK).build(null)); + TILE_ENTITIES.register(ID_LITHOGRAPHY_TABLE, () -> BlockEntityType.Builder.of(LithographyTableTile::new, LITHOGRAPHY_TABLE_BLOCK).build(null)); + TILE_ENTITIES.register(ID_PACKAGING_TABLE, () -> BlockEntityType.Builder.of(PackagingTableTile::new, PACKAGING_TABLE_BLOCK).build(null)); + } +} diff --git a/fabrication/src/main/java/mrtjp/projectred/fabrication/init/FabricationClientInit.java b/fabrication/src/main/java/mrtjp/projectred/fabrication/init/FabricationClientInit.java new file mode 100644 index 000000000..1f1a44c41 --- /dev/null +++ b/fabrication/src/main/java/mrtjp/projectred/fabrication/init/FabricationClientInit.java @@ -0,0 +1,41 @@ +package mrtjp.projectred.fabrication.init; + +import codechicken.lib.model.ModelRegistryHelper; +import codechicken.lib.texture.SpriteRegistryHelper; +import mrtjp.projectred.fabrication.gui.ICRenderTypes; +import mrtjp.projectred.fabrication.gui.screen.inventory.LithographyTableScreen; +import mrtjp.projectred.fabrication.gui.screen.inventory.PackagingTableScreen; +import mrtjp.projectred.fabrication.gui.screen.inventory.PlottingTableScreen; +import mrtjp.projectred.integration.client.GatePartItemRenderer; +import net.minecraft.client.gui.screens.MenuScreens; +import net.minecraft.client.resources.model.ModelResourceLocation; +import net.minecraftforge.eventbus.api.IEventBus; +import net.minecraftforge.fml.event.lifecycle.FMLClientSetupEvent; +import net.minecraftforge.fml.javafmlmod.FMLJavaModLoadingContext; + +import static mrtjp.projectred.fabrication.init.FabricationReferences.*; + +public class FabricationClientInit { + + public static void init() { + final IEventBus modEventBus = FMLJavaModLoadingContext.get().getModEventBus(); + + modEventBus.addListener(FabricationClientInit::clientSetup); + } + + private static void clientSetup(final FMLClientSetupEvent event) { + + // Register sprites + SpriteRegistryHelper iconRegister = new SpriteRegistryHelper(); + iconRegister.addIIconRegister(ICRenderTypes::registerIcons); + + // Register models + ModelRegistryHelper modelRegistryHelper = new ModelRegistryHelper(); + modelRegistryHelper.register(new ModelResourceLocation(FabricationReferences.FABRICATED_GATE_ITEM.getRegistryName(), "inventory"), GatePartItemRenderer.INSTANCE); + + // Register screens + MenuScreens.register(PLOTTING_TABLE_CONTAINER, PlottingTableScreen::new); + MenuScreens.register(LITHOGRAPHY_TABLE_CONTAINER, LithographyTableScreen::new); + MenuScreens.register(PACKAGING_TABLE_CONTAINER, PackagingTableScreen::new); + } +} diff --git a/fabrication/src/main/java/mrtjp/projectred/fabrication/init/FabricationContainers.java b/fabrication/src/main/java/mrtjp/projectred/fabrication/init/FabricationContainers.java new file mode 100644 index 000000000..9a7f1f0d9 --- /dev/null +++ b/fabrication/src/main/java/mrtjp/projectred/fabrication/init/FabricationContainers.java @@ -0,0 +1,19 @@ +package mrtjp.projectred.fabrication.init; + +import codechicken.lib.inventory.container.ICCLContainerType; +import mrtjp.projectred.fabrication.inventory.container.LithographyTableContainer; +import mrtjp.projectred.fabrication.inventory.container.PackagingTableContainer; +import mrtjp.projectred.fabrication.inventory.container.PlottingTableContainer; + +import static mrtjp.projectred.fabrication.ProjectRedFabrication.CONTAINERS; +import static mrtjp.projectred.fabrication.init.FabricationBlocks.*; + +public class FabricationContainers { + + public static void register() { + + CONTAINERS.register(ID_PLOTTING_TABLE, () -> ICCLContainerType.create(PlottingTableContainer.FACTORY)); + CONTAINERS.register(ID_LITHOGRAPHY_TABLE, () -> ICCLContainerType.create(LithographyTableContainer.FACTORY)); + CONTAINERS.register(ID_PACKAGING_TABLE, () -> ICCLContainerType.create(PackagingTableContainer.FACTORY)); + } +} diff --git a/fabrication/src/main/java/mrtjp/projectred/fabrication/init/FabricationItems.java b/fabrication/src/main/java/mrtjp/projectred/fabrication/init/FabricationItems.java new file mode 100644 index 000000000..b7846b863 --- /dev/null +++ b/fabrication/src/main/java/mrtjp/projectred/fabrication/init/FabricationItems.java @@ -0,0 +1,28 @@ +package mrtjp.projectred.fabrication.init; + +import mrtjp.projectred.fabrication.item.*; + +import static mrtjp.projectred.fabrication.ProjectRedFabrication.ITEMS; + +public class FabricationItems { + + public static final String ID_IC_BLUEPRINT = "ic_blueprint"; + public static final String ID_BLANK_PHOTOMASK = "blank_photomask"; + public static final String ID_PHOTOMASK_SET = "photomask_set"; + public static final String ID_ROUGH_SILICON_WAFER = "rough_silicon_wafer"; + public static final String ID_ETCHED_SILICON_WAFER = "etched_silicon_wafer"; + public static final String ID_VALID_DIE = "valid_die"; + public static final String ID_INVALID_DIE = "invalid_die"; + + public static void register() { + + // Items + ITEMS.register(ID_IC_BLUEPRINT, ICBlueprintItem::new); + ITEMS.register(ID_BLANK_PHOTOMASK, BlankPhotomaskItem::new); + ITEMS.register(ID_PHOTOMASK_SET, PhotomaskSetItem::new); + ITEMS.register(ID_ROUGH_SILICON_WAFER, RoughSiliconWaferItem::new); + ITEMS.register(ID_ETCHED_SILICON_WAFER, EtchedSiliconWaferItem::new); + ITEMS.register(ID_VALID_DIE, ValidDieItem::new); + ITEMS.register(ID_INVALID_DIE, InvalidDieItem::new); + } +} \ No newline at end of file diff --git a/fabrication/src/main/java/mrtjp/projectred/fabrication/init/FabricationParts.java b/fabrication/src/main/java/mrtjp/projectred/fabrication/init/FabricationParts.java new file mode 100644 index 000000000..a383477a5 --- /dev/null +++ b/fabrication/src/main/java/mrtjp/projectred/fabrication/init/FabricationParts.java @@ -0,0 +1,30 @@ +package mrtjp.projectred.fabrication.init; + +import codechicken.multipart.api.MultipartType; +import codechicken.multipart.api.SimpleMultipartType; +import mrtjp.projectred.fabrication.part.FabricatedGatePart; +import mrtjp.projectred.integration.GateType; +import mrtjp.projectred.integration.item.GatePartItem; +import mrtjp.projectred.integration.part.GatePart; +import net.minecraft.world.item.Item; +import net.minecraftforge.registries.RegistryObject; + +import static mrtjp.projectred.fabrication.ProjectRedFabrication.ITEMS; +import static mrtjp.projectred.fabrication.ProjectRedFabrication.PARTS; + +public class FabricationParts { + + public static final String ID_FABRICATED_GATE = "fabricated_gate"; + + public static void register() { + + // Items + RegistryObject registeredItem = ITEMS.register(ID_FABRICATED_GATE, () -> new GatePartItem(GateType.FABRICATED_GATE)); + + // Parts + RegistryObject> registeredPartType = PARTS.register(ID_FABRICATED_GATE, () -> new SimpleMultipartType<>(b -> new FabricatedGatePart())); + + // Add to GateType enum + GateType.FABRICATED_GATE.inject(ID_FABRICATED_GATE, isClient -> new FabricatedGatePart(), registeredItem, registeredPartType); + } +} diff --git a/fabrication/src/main/java/mrtjp/projectred/fabrication/init/FabricationReferences.java b/fabrication/src/main/java/mrtjp/projectred/fabrication/init/FabricationReferences.java new file mode 100644 index 000000000..921d99732 --- /dev/null +++ b/fabrication/src/main/java/mrtjp/projectred/fabrication/init/FabricationReferences.java @@ -0,0 +1,78 @@ +package mrtjp.projectred.fabrication.init; + +import codechicken.multipart.api.MultipartType; +import mrtjp.projectred.fabrication.block.ICWorkbenchBlock; +import mrtjp.projectred.fabrication.block.LithographyTableBlock; +import mrtjp.projectred.fabrication.block.PackagingTableBlock; +import mrtjp.projectred.fabrication.block.PlottingTableBlock; +import mrtjp.projectred.fabrication.inventory.container.LithographyTableContainer; +import mrtjp.projectred.fabrication.inventory.container.PackagingTableContainer; +import mrtjp.projectred.fabrication.inventory.container.PlottingTableContainer; +import mrtjp.projectred.fabrication.item.*; +import mrtjp.projectred.fabrication.tile.ICWorkbenchTile; +import mrtjp.projectred.fabrication.tile.LithographyTableTile; +import mrtjp.projectred.fabrication.tile.PackagingTableTile; +import mrtjp.projectred.fabrication.tile.PlottingTableTile; +import mrtjp.projectred.integration.item.GatePartItem; +import net.minecraft.world.inventory.MenuType; +import net.minecraft.world.level.block.entity.BlockEntityType; +import net.minecraftforge.registries.ObjectHolder; + +import static mrtjp.projectred.fabrication.ProjectRedFabrication.MOD_ID; +import static mrtjp.projectred.fabrication.init.FabricationBlocks.*; +import static mrtjp.projectred.fabrication.init.FabricationItems.*; +import static mrtjp.projectred.fabrication.init.FabricationParts.ID_FABRICATED_GATE; + +@ObjectHolder(MOD_ID) +public class FabricationReferences { + + // Blocks + @ObjectHolder(ID_IC_WORKBENCH) + public static ICWorkbenchBlock IC_WORKBENCH_BLOCK = null; + @ObjectHolder(ID_PLOTTING_TABLE) + public static PlottingTableBlock PLOTTING_TABLE_BLOCK = null; + @ObjectHolder(ID_LITHOGRAPHY_TABLE) + public static LithographyTableBlock LITHOGRAPHY_TABLE_BLOCK = null; + @ObjectHolder(ID_PACKAGING_TABLE) + public static PackagingTableBlock PACKAGING_TABLE_BLOCK = null; + + // Tiles + @ObjectHolder(ID_IC_WORKBENCH) + public static BlockEntityType IC_WORKBENCH_TILE = null; + @ObjectHolder(ID_PLOTTING_TABLE) + public static BlockEntityType PLOTTING_TABLE_TILE = null; + @ObjectHolder(ID_LITHOGRAPHY_TABLE) + public static BlockEntityType LITHOGRAPHY_TABLE_TILE = null; + @ObjectHolder(ID_PACKAGING_TABLE) + public static BlockEntityType PACKAGING_TABLE_TILE = null; + + // Containers + @ObjectHolder(ID_PLOTTING_TABLE) + public static MenuType PLOTTING_TABLE_CONTAINER = null; + @ObjectHolder(ID_LITHOGRAPHY_TABLE) + public static MenuType LITHOGRAPHY_TABLE_CONTAINER = null; + @ObjectHolder(ID_PACKAGING_TABLE) + public static MenuType PACKAGING_TABLE_CONTAINER = null; + + // Items + @ObjectHolder(ID_IC_BLUEPRINT) + public static ICBlueprintItem IC_BLUEPRINT_ITEM = null; + @ObjectHolder(ID_BLANK_PHOTOMASK) + public static BlankPhotomaskItem BLANK_PHOTOMASK_ITEM = null; + @ObjectHolder(ID_PHOTOMASK_SET) + public static PhotomaskSetItem PHOTOMASK_SET_ITEM = null; + @ObjectHolder(ID_ROUGH_SILICON_WAFER) + public static RoughSiliconWaferItem ROUGH_SILICON_WAFER_ITEM = null; + @ObjectHolder(ID_ETCHED_SILICON_WAFER) + public static EtchedSiliconWaferItem ETCHED_SILICON_WAFER_ITEM = null; + @ObjectHolder(ID_VALID_DIE) + public static ValidDieItem VALID_DIE_ITEM = null; + @ObjectHolder(ID_INVALID_DIE) + public static InvalidDieItem INVALID_DIE_ITEM = null; + + // Parts + @ObjectHolder(ID_FABRICATED_GATE) + public static GatePartItem FABRICATED_GATE_ITEM = null; + @ObjectHolder(ID_FABRICATED_GATE) + public static MultipartType FABRICATED_GATE_PART = null; +} diff --git a/fabrication/src/main/java/mrtjp/projectred/fabrication/inventory/container/FabricationMachineContainer.java b/fabrication/src/main/java/mrtjp/projectred/fabrication/inventory/container/FabricationMachineContainer.java new file mode 100644 index 000000000..4117d64cc --- /dev/null +++ b/fabrication/src/main/java/mrtjp/projectred/fabrication/inventory/container/FabricationMachineContainer.java @@ -0,0 +1,28 @@ +package mrtjp.projectred.fabrication.inventory.container; + +import mrtjp.projectred.core.inventory.container.BasePoweredTileContainer; +import mrtjp.projectred.core.inventory.container.SimpleDataSlot; +import mrtjp.projectred.fabrication.tile.FabricationMachineTile; +import net.minecraft.world.inventory.MenuType; + +import javax.annotation.Nullable; + +public class FabricationMachineContainer extends BasePoweredTileContainer { + + private final FabricationMachineTile tile; + + private int remainingWork; + private int totalWork; + + public FabricationMachineContainer(@Nullable MenuType containerType, int windowId, FabricationMachineTile tile) { + super(containerType, windowId, tile); + this.tile = tile; + + addDataSlot(new SimpleDataSlot(tile::getRemainingWork, value -> remainingWork = value)); + addDataSlot(new SimpleDataSlot(tile::getTotalWork, value -> totalWork = value)); + } + + public int getProgressScaled(int scale) { + return totalWork == 0 ? 0 : scale * (totalWork - remainingWork) / totalWork; + } +} diff --git a/fabrication/src/main/java/mrtjp/projectred/fabrication/inventory/container/LithographyTableContainer.java b/fabrication/src/main/java/mrtjp/projectred/fabrication/inventory/container/LithographyTableContainer.java new file mode 100644 index 000000000..0e93ed0c1 --- /dev/null +++ b/fabrication/src/main/java/mrtjp/projectred/fabrication/inventory/container/LithographyTableContainer.java @@ -0,0 +1,126 @@ +package mrtjp.projectred.fabrication.inventory.container; + +import codechicken.lib.inventory.container.ICCLContainerFactory; +import mrtjp.projectred.core.inventory.container.TakeOnlySlot; +import mrtjp.projectred.fabrication.init.FabricationReferences; +import mrtjp.projectred.fabrication.item.PhotomaskSetItem; +import mrtjp.projectred.fabrication.item.RoughSiliconWaferItem; +import mrtjp.projectred.fabrication.tile.LithographyTableTile; +import mrtjp.projectred.lib.InventoryLib; +import net.minecraft.world.entity.player.Inventory; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.inventory.Slot; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.level.block.entity.BlockEntity; + +public class LithographyTableContainer extends FabricationMachineContainer { + + public static ICCLContainerFactory FACTORY = (windowId, inventory, packet) -> { + BlockEntity tile = inventory.player.level.getBlockEntity(packet.readPos()); + if (!(tile instanceof LithographyTableTile)) return null; + + return new LithographyTableContainer(inventory, (LithographyTableTile) tile, windowId); + }; + + private final Inventory playerInventory; + private final LithographyTableTile tile; + + public LithographyTableContainer(Inventory playerInventory, LithographyTableTile tile, int windowId) { + super(FabricationReferences.LITHOGRAPHY_TABLE_CONTAINER, windowId, tile); + this.playerInventory = playerInventory; + this.tile = tile; + + InventoryLib.addPlayerInventory(playerInventory, 8, 89, this::addSlot); + addLithographyTableInventory(); + } + + private void addLithographyTableInventory() { + addSlot(new Slot(tile.getInventory(), 0, 56, 31)); // photomask set input + addSlot(new Slot(tile.getInventory(), 1, 56, 49)); // wafer input + addSlot(new TakeOnlySlot(tile.getInventory(), 2, 110, 31)); // valid die output + addSlot(new TakeOnlySlot(tile.getInventory(), 3, 110, 49)); // invalid die output + } + + public ItemStack quickMoveStack(Player player, int slotIndex) { + + Slot slot = slots.get(slotIndex); + if (slot == null || !slot.hasItem()) return ItemStack.EMPTY; + + ItemStack stack = slot.getItem(); + ItemStack originalStack = stack.copy(); + + if (isOutputs(slotIndex)) { + if (!moveToEntireInventory(stack, true)) return ItemStack.EMPTY; + + } else if (isHotbar(slotIndex) || isPlayerInventory(slotIndex)) { + if (isPhotomaskSet(stack)) { + if (!moveToPhotomaskInput(stack, false)) return ItemStack.EMPTY; + + } else if (isSiliconWafer(stack)) { + if (!moveToWaferInput(stack, false)) return ItemStack.EMPTY; + + } else if (isPlayerInventory(slotIndex)) { + if (!moveToHotbar(stack, false)) return ItemStack.EMPTY; + + } else { // Hot bar + if (!moveToPlayerInventory(stack, false)) return ItemStack.EMPTY; + } + + } else if (isInputs(slotIndex)) { + if (!moveToEntireInventory(stack, true)) return ItemStack.EMPTY; + } + + if (stack.isEmpty()) { + slot.set(ItemStack.EMPTY); + } else { + slot.setChanged(); + } + + if (stack.getCount() == originalStack.getCount()) { + return ItemStack.EMPTY; + } + + slot.onTake(player, stack); + + return originalStack; + } + + //@formatter:off + private boolean isHotbar(int slotIndex) { + return slotIndex >= 27 && slotIndex < 36; + } + private boolean isPlayerInventory(int slotIndex) { + return slotIndex >= 0 && slotIndex < 27; + } + private boolean isInputs(int slotIndex) { + return slotIndex >= 36 && slotIndex < 38; + } + private boolean isOutputs(int slotIndex) { + return slotIndex >= 38 && slotIndex < 40; + } + + private boolean moveToHotbar(ItemStack stack, boolean reverse) { + return moveItemStackTo(stack, 27, 36, reverse); + } + private boolean moveToPlayerInventory(ItemStack stack, boolean reverse) { + return moveItemStackTo(stack, 0, 27, reverse); + } + private boolean moveToEntireInventory(ItemStack stack, boolean reverse) { + return moveItemStackTo(stack, 0, 36, reverse); + } + private boolean moveToPhotomaskInput(ItemStack stack, boolean reverse) { + return moveItemStackTo(stack, 36, 37, reverse); + } + private boolean moveToWaferInput(ItemStack stack, boolean reverse) { + return moveItemStackTo(stack, 37, 38, reverse); + } + //@formatter:on + + private boolean isPhotomaskSet(ItemStack stack) { + return stack.getItem() instanceof PhotomaskSetItem; //TODO check tag + } + + private boolean isSiliconWafer(ItemStack stack) { + return stack.getItem() instanceof RoughSiliconWaferItem; + } +} diff --git a/fabrication/src/main/java/mrtjp/projectred/fabrication/inventory/container/PackagingTableContainer.java b/fabrication/src/main/java/mrtjp/projectred/fabrication/inventory/container/PackagingTableContainer.java new file mode 100644 index 000000000..33872cf95 --- /dev/null +++ b/fabrication/src/main/java/mrtjp/projectred/fabrication/inventory/container/PackagingTableContainer.java @@ -0,0 +1,116 @@ +package mrtjp.projectred.fabrication.inventory.container; + +import codechicken.lib.inventory.container.ICCLContainerFactory; +import mrtjp.projectred.core.inventory.container.TakeOnlySlot; +import mrtjp.projectred.fabrication.init.FabricationReferences; +import mrtjp.projectred.fabrication.item.ValidDieItem; +import mrtjp.projectred.fabrication.tile.PackagingTableTile; +import mrtjp.projectred.lib.InventoryLib; +import net.minecraft.world.entity.player.Inventory; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.inventory.Slot; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.level.block.entity.BlockEntity; + +public class PackagingTableContainer extends FabricationMachineContainer { + + public static ICCLContainerFactory FACTORY = (windowId, inventory, packet) -> { + BlockEntity tile = inventory.player.level.getBlockEntity(packet.readPos()); + if (!(tile instanceof PackagingTableTile)) return null; + + return new PackagingTableContainer(inventory, (PackagingTableTile) tile, windowId); + }; + + private final Inventory playerInventory; + private final PackagingTableTile tile; + + public PackagingTableContainer(Inventory playerInventory, PackagingTableTile tile, int windowId) { + super(FabricationReferences.PACKAGING_TABLE_CONTAINER, windowId, tile); + this.playerInventory = playerInventory; + this.tile = tile; + + InventoryLib.addPlayerInventory(playerInventory, 8, 89, this::addSlot); + addPackagingTableInventory(); + } + + private void addPackagingTableInventory() { + addSlot(new Slot(tile.getInventory(), 0, 64, 32)); // die input + addSlot(new Slot(tile.getInventory(), 1, 46, 57)); // A + addSlot(new Slot(tile.getInventory(), 2, 64, 57)); // B + addSlot(new Slot(tile.getInventory(), 3, 82, 57)); // C + addSlot(new TakeOnlySlot(tile.getInventory(), 4, 135, 40)); // output + } + + public ItemStack quickMoveStack(Player player, int slotIndex) { + + Slot slot = slots.get(slotIndex); + if (slot == null || !slot.hasItem()) return ItemStack.EMPTY; + + ItemStack stack = slot.getItem(); + ItemStack originalStack = stack.copy(); + + if (isOutput(slotIndex)) { + if (!moveToEntireInventory(stack, true)) return ItemStack.EMPTY; + + } else if (isHotbar(slotIndex) || isPlayerInventory(slotIndex)) { + if (isValidDie(stack)) { + if (!moveToDieInput(stack, false)) return ItemStack.EMPTY; + //TODO A, B, C inputs transfer + + } else if (isPlayerInventory(slotIndex)) { + if (!moveToHotbar(stack, false)) return ItemStack.EMPTY; + + } else { // Hot bar + if (!moveToPlayerInventory(stack, false)) return ItemStack.EMPTY; + } + + } else if (isInputs(slotIndex)) { + if (!moveToEntireInventory(stack, false)) return ItemStack.EMPTY; + } + + if (stack.isEmpty()) { + slot.set(ItemStack.EMPTY); + } else { + slot.setChanged(); + } + + if (stack.getCount() == originalStack.getCount()) { + return ItemStack.EMPTY; + } + + slot.onTake(player, stack); + return originalStack; + } + + //@formatter:off + private boolean isHotbar(int slotIndex) { + return slotIndex >= 27 && slotIndex < 36; + } + private boolean isPlayerInventory(int slotIndex) { + return slotIndex >= 0 && slotIndex < 27; + } + private boolean isInputs(int slotIndex) { + return slotIndex >= 36 && slotIndex < 40; + } + private boolean isOutput(int slotIndex) { + return slotIndex == 40; + } + + private boolean moveToHotbar(ItemStack stack, boolean reverse) { + return moveItemStackTo(stack, 27, 36, reverse); + } + private boolean moveToPlayerInventory(ItemStack stack, boolean reverse) { + return moveItemStackTo(stack, 0, 27, reverse); + } + private boolean moveToEntireInventory(ItemStack stack, boolean reverse) { + return moveItemStackTo(stack, 0, 36, reverse); + } + private boolean moveToDieInput(ItemStack stack, boolean reverse) { + return moveItemStackTo(stack, 36, 37, reverse); + } + //@formatter:on + + private boolean isValidDie(ItemStack stack) { + return stack.getItem() instanceof ValidDieItem; //TODO check tag + } +} diff --git a/fabrication/src/main/java/mrtjp/projectred/fabrication/inventory/container/PlottingTableContainer.java b/fabrication/src/main/java/mrtjp/projectred/fabrication/inventory/container/PlottingTableContainer.java new file mode 100644 index 000000000..0fec1a2c3 --- /dev/null +++ b/fabrication/src/main/java/mrtjp/projectred/fabrication/inventory/container/PlottingTableContainer.java @@ -0,0 +1,125 @@ +package mrtjp.projectred.fabrication.inventory.container; + +import codechicken.lib.inventory.container.ICCLContainerFactory; +import mrtjp.projectred.core.inventory.container.TakeOnlySlot; +import mrtjp.projectred.fabrication.init.FabricationReferences; +import mrtjp.projectred.fabrication.item.BlankPhotomaskItem; +import mrtjp.projectred.fabrication.item.ICBlueprintItem; +import mrtjp.projectred.fabrication.tile.PlottingTableTile; +import mrtjp.projectred.lib.InventoryLib; +import net.minecraft.world.entity.player.Inventory; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.inventory.Slot; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.level.block.entity.BlockEntity; + +public class PlottingTableContainer extends FabricationMachineContainer { + + public static ICCLContainerFactory FACTORY = (windowId, inventory, packet) -> { + BlockEntity tile = inventory.player.level.getBlockEntity(packet.readPos()); + if (!(tile instanceof PlottingTableTile)) return null; + + return new PlottingTableContainer(inventory, (PlottingTableTile) tile, windowId); + }; + + private final Inventory playerInventory; + private final PlottingTableTile tile; + + public PlottingTableContainer(Inventory playerInventory, PlottingTableTile tile, int windowId) { + super(FabricationReferences.PLOTTING_TABLE_CONTAINER, windowId, tile); + this.playerInventory = playerInventory; + this.tile = tile; + + InventoryLib.addPlayerInventory(playerInventory, 8, 89, this::addSlot); + addPlottingTableInventory(); + } + + private void addPlottingTableInventory() { + addSlot(new Slot(tile.getInventory(), 0, 56, 31)); // blueprint input + addSlot(new Slot(tile.getInventory(), 1, 56, 49)); // empty photo mask input + addSlot(new TakeOnlySlot(tile.getInventory(), 2, 116, 40)); // output + } + + @Override + public ItemStack quickMoveStack(Player player, int slotIndex) { + + Slot slot = slots.get(slotIndex); + if (slot == null || !slot.hasItem()) return ItemStack.EMPTY; + + ItemStack stack = slot.getItem(); + ItemStack originalStack = stack.copy(); + + if (isOutput(slotIndex)) { + if (!moveToEntireInventory(stack, true)) return ItemStack.EMPTY; + + } else if (isHotbar(slotIndex) || isPlayerInventory(slotIndex)) { + if (isBlueprint(stack)) { + if (!moveToBlueprintInput(stack, false)) return ItemStack.EMPTY; + + } else if (isBlankPhotomask(stack)) { + if (!moveToPhotomaskInput(stack, false)) return ItemStack.EMPTY; + + } else if (isPlayerInventory(slotIndex)) { + if (!moveToHotbar(stack, false)) return ItemStack.EMPTY; + + } else { // Hot bar + if (!moveToPlayerInventory(stack, false)) return ItemStack.EMPTY; // Move to player inventory + } + + } else if (isInputs(slotIndex)) { + if (!moveToEntireInventory(stack, false)) return ItemStack.EMPTY; + } + + if (stack.isEmpty()) { + slot.set(ItemStack.EMPTY); + } else { + slot.setChanged(); + } + + if (stack.getCount() == originalStack.getCount()) { + return ItemStack.EMPTY; + } + + slot.onTake(player, stack); + return originalStack; + } + + //@formatter:off + private boolean isHotbar(int slotIndex) { + return slotIndex >= 27 && slotIndex < 36; + } + private boolean isPlayerInventory(int slotIndex) { + return slotIndex >= 0 && slotIndex < 27; + } + private boolean isInputs(int slotIndex) { + return slotIndex >= 36 && slotIndex < 38; + } + private boolean isOutput(int slotIndex) { + return slotIndex == 38; + } + + private boolean moveToHotbar(ItemStack stack, boolean reverse) { + return moveItemStackTo(stack, 27, 36, reverse); + } + private boolean moveToPlayerInventory(ItemStack stack, boolean reverse) { + return moveItemStackTo(stack, 0, 27, reverse); + } + private boolean moveToEntireInventory(ItemStack stack, boolean reverse) { + return moveItemStackTo(stack, 0, 36, reverse); + } + private boolean moveToBlueprintInput(ItemStack stack, boolean reverse) { + return moveItemStackTo(stack, 36, 37, reverse); + } + private boolean moveToPhotomaskInput(ItemStack stack, boolean reverse) { + return moveItemStackTo(stack, 37, 38, reverse); + } + //@formatter:on + + private boolean isBlueprint(ItemStack stack) { + return stack.getItem() instanceof ICBlueprintItem; //TODO check tag + } + + private boolean isBlankPhotomask(ItemStack stack) { + return stack.getItem() instanceof BlankPhotomaskItem; + } +} diff --git a/fabrication/src/main/java/mrtjp/projectred/fabrication/item/BaseSiliconWaferItem.java b/fabrication/src/main/java/mrtjp/projectred/fabrication/item/BaseSiliconWaferItem.java new file mode 100644 index 000000000..353c437aa --- /dev/null +++ b/fabrication/src/main/java/mrtjp/projectred/fabrication/item/BaseSiliconWaferItem.java @@ -0,0 +1,38 @@ +package mrtjp.projectred.fabrication.item; + +import mrtjp.projectred.fabrication.ProjectRedFabrication; +import mrtjp.projectred.fabrication.lithography.WaferType; +import net.minecraft.ChatFormatting; +import net.minecraft.network.chat.Component; +import net.minecraft.network.chat.TextComponent; +import net.minecraft.world.item.Item; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.TooltipFlag; +import net.minecraft.world.level.Level; + +import javax.annotation.Nullable; +import java.util.List; + +public class BaseSiliconWaferItem extends Item { + + private final WaferType waferType; + + public BaseSiliconWaferItem(WaferType waferType) { + super(new Item.Properties() + .tab(ProjectRedFabrication.FABRICATION_GROUP)); + this.waferType = waferType; + } + + @Override + public void appendHoverText(ItemStack stack, @Nullable Level world, List tooltipList, TooltipFlag tooltipFlag) { + super.appendHoverText(stack, world, tooltipList, tooltipFlag); + + //TODO localize + tooltipList.add(new TextComponent("Size").append(": " + waferType.getWaferLen() + " nm").withStyle(ChatFormatting.GRAY)); + tooltipList.add(new TextComponent("Defect chance").append(": " + waferType.getDefectChancePerLen()*100 + "% / nm").withStyle(ChatFormatting.GRAY)); + } + + public WaferType getWaferType() { + return waferType; + } +} diff --git a/fabrication/src/main/java/mrtjp/projectred/fabrication/item/BlankPhotomaskItem.java b/fabrication/src/main/java/mrtjp/projectred/fabrication/item/BlankPhotomaskItem.java new file mode 100644 index 000000000..cb85d930c --- /dev/null +++ b/fabrication/src/main/java/mrtjp/projectred/fabrication/item/BlankPhotomaskItem.java @@ -0,0 +1,12 @@ +package mrtjp.projectred.fabrication.item; + +import mrtjp.projectred.fabrication.ProjectRedFabrication; +import net.minecraft.world.item.Item; + +public class BlankPhotomaskItem extends Item { + + public BlankPhotomaskItem() { + super(new Item.Properties() + .tab(ProjectRedFabrication.FABRICATION_GROUP)); + } +} diff --git a/fabrication/src/main/java/mrtjp/projectred/fabrication/item/EtchedSiliconWaferItem.java b/fabrication/src/main/java/mrtjp/projectred/fabrication/item/EtchedSiliconWaferItem.java new file mode 100644 index 000000000..c02494de2 --- /dev/null +++ b/fabrication/src/main/java/mrtjp/projectred/fabrication/item/EtchedSiliconWaferItem.java @@ -0,0 +1,87 @@ +package mrtjp.projectred.fabrication.item; + +import mrtjp.projectred.fabrication.ProjectRedFabrication; +import mrtjp.projectred.fabrication.init.FabricationReferences; +import net.minecraft.ChatFormatting; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.network.chat.Component; +import net.minecraft.network.chat.TextComponent; +import net.minecraft.world.item.Item; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.TooltipFlag; +import net.minecraft.world.level.Level; + +import javax.annotation.Nullable; +import java.util.List; + +public class EtchedSiliconWaferItem extends Item { + + public EtchedSiliconWaferItem() { + super(new Item.Properties() + .tab(ProjectRedFabrication.FABRICATION_GROUP) + .stacksTo(1)); + } + + @Override + public void appendHoverText(ItemStack stack, @Nullable Level world, List tooltipList, TooltipFlag tooltipFlag) { + super.appendHoverText(stack, world, tooltipList, tooltipFlag); + + if (stack.getTag() == null) + return; + + CompoundTag tag = stack.getTag(); + + // Blueprint data + tooltipList.add(new TextComponent("Name: " + tag.getString("ic_name")).withStyle(ChatFormatting.GRAY)); + tooltipList.add(new TextComponent("Tile count: " + tag.getInt("tilecount")).withStyle(ChatFormatting.GRAY)); + byte bmask = tag.getByte("bmask"); + tooltipList.add(new TextComponent("Input mask: " + "0x" + Integer.toHexString(bmask & 0xF)).withStyle(ChatFormatting.GRAY)); + tooltipList.add(new TextComponent("Output mask: " + "0x" + Integer.toHexString((bmask >> 4) & 0xF)).withStyle(ChatFormatting.GRAY)); + + // Wafer etching data + tooltipList.add(new TextComponent("Yield: " + tag.getDouble("yield")*100 + "%").withStyle(ChatFormatting.GRAY)); + tooltipList.add(new TextComponent("Defects: " + tag.getInt("defectCount")).withStyle(ChatFormatting.GRAY)); + byte[] defects = tag.getByteArray("defects"); + int gridLen = tag.getInt("gridLen"); + for (int y = 0; y < gridLen; y++) { + StringBuilder s = new StringBuilder(); + for (int x = 0; x < gridLen; x++) { + int i = y * gridLen + x; + s.append(defects[i] == 0 ? "[-]" : "[X]"); + } + tooltipList.add(new TextComponent(" " + s).withStyle(ChatFormatting.GRAY)); + } + } + + public static ItemStack createFromPhotomaskSet(ItemStack photomaskSet, int waferLen, int dieLen, double defectChancePerLen) { + + // Create copy of photomask tag + CompoundTag tag = photomaskSet.getTag().copy(); + + int gridLen = waferLen / dieLen; + double defectChancePerDie = dieLen * defectChancePerLen; + int totalDesigns = gridLen * gridLen; + int totalDefects = 0; + + byte[] defects = new byte[totalDesigns]; + for (int i = 0; i < totalDesigns; i++) { + if (Math.random() < defectChancePerDie) { + defects[i] = 1; + totalDefects++; + } + } + + double yield = (totalDesigns - totalDefects) / (double) totalDesigns; + + tag.putInt("gridLen", gridLen); + tag.putInt("designCount", totalDesigns); + tag.putInt("defectCount", totalDefects); + tag.putDouble("yield", yield); + tag.putByteArray("defects", defects); + + // Put NBT on new item stack and return + ItemStack output = new ItemStack(FabricationReferences.ETCHED_SILICON_WAFER_ITEM); + output.setTag(tag); + return output; + } +} diff --git a/fabrication/src/main/java/mrtjp/projectred/fabrication/item/ICBlueprintItem.java b/fabrication/src/main/java/mrtjp/projectred/fabrication/item/ICBlueprintItem.java new file mode 100644 index 000000000..c073ae890 --- /dev/null +++ b/fabrication/src/main/java/mrtjp/projectred/fabrication/item/ICBlueprintItem.java @@ -0,0 +1,62 @@ +package mrtjp.projectred.fabrication.item; + +import mrtjp.projectred.fabrication.ProjectRedFabrication; +import mrtjp.projectred.fabrication.init.FabricationReferences; +import mrtjp.projectred.integration.GateType; +import net.minecraft.ChatFormatting; +import net.minecraft.network.chat.Component; +import net.minecraft.network.chat.TextComponent; +import net.minecraft.world.InteractionResult; +import net.minecraft.world.item.Item; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.TooltipFlag; +import net.minecraft.world.item.context.UseOnContext; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.state.BlockState; + +import javax.annotation.Nullable; +import java.util.List; + +public class ICBlueprintItem extends Item { + + public ICBlueprintItem() { + super(new Item.Properties() + .tab(ProjectRedFabrication.FABRICATION_GROUP) + .stacksTo(1)); + } + + @Override + public void appendHoverText(ItemStack stack, @Nullable Level p_77624_2_, List tooltipList, TooltipFlag tooltipFlag) { + + if (stack.getTag() != null) { + //TODO localize + tooltipList.add(new TextComponent("Name: " + stack.getTag().getString("ic_name")).withStyle(ChatFormatting.GRAY)); + tooltipList.add(new TextComponent("Tile count: " + stack.getTag().getInt("tilecount")).withStyle(ChatFormatting.GRAY)); + + byte bmask = stack.getTag().getByte("bmask"); + tooltipList.add(new TextComponent("Input mask: " + "0x" + Integer.toHexString(bmask & 0xF)).withStyle(ChatFormatting.GRAY)); + tooltipList.add(new TextComponent("Output mask: " + "0x" + Integer.toHexString((bmask >> 4) & 0xF)).withStyle(ChatFormatting.GRAY)); + } + } + + @Override + public InteractionResult onItemUseFirst(ItemStack stack, UseOnContext context) { + + if (!context.getPlayer().isCreative()) return InteractionResult.PASS; + + // Creative mode bypass: Convert blueprint directly to gate block + BlockState blockState = context.getLevel().getBlockState(context.getClickedPos()); + if (blockState.getBlock() == FabricationReferences.IC_WORKBENCH_BLOCK) + return InteractionResult.PASS; + + if (!stack.hasTag() || !stack.getTag().contains("tilecount")) { + return InteractionResult.PASS; + } + + ItemStack gate = GateType.FABRICATED_GATE.makeStack(); + gate.setTag(stack.getTag()); + + context.getPlayer().addItem(gate); + return InteractionResult.SUCCESS; + } +} diff --git a/fabrication/src/main/java/mrtjp/projectred/fabrication/item/InvalidDieItem.java b/fabrication/src/main/java/mrtjp/projectred/fabrication/item/InvalidDieItem.java new file mode 100644 index 000000000..87eba8c31 --- /dev/null +++ b/fabrication/src/main/java/mrtjp/projectred/fabrication/item/InvalidDieItem.java @@ -0,0 +1,12 @@ +package mrtjp.projectred.fabrication.item; + +import mrtjp.projectred.fabrication.ProjectRedFabrication; +import net.minecraft.world.item.Item; + +public class InvalidDieItem extends Item { + + public InvalidDieItem() { + super(new Item.Properties() + .tab(ProjectRedFabrication.FABRICATION_GROUP)); + } +} diff --git a/fabrication/src/main/java/mrtjp/projectred/fabrication/item/PhotomaskSetItem.java b/fabrication/src/main/java/mrtjp/projectred/fabrication/item/PhotomaskSetItem.java new file mode 100644 index 000000000..994448839 --- /dev/null +++ b/fabrication/src/main/java/mrtjp/projectred/fabrication/item/PhotomaskSetItem.java @@ -0,0 +1,56 @@ +package mrtjp.projectred.fabrication.item; + +import mrtjp.projectred.fabrication.ProjectRedFabrication; +import mrtjp.projectred.integration.GateType; +import net.minecraft.ChatFormatting; +import net.minecraft.network.chat.Component; +import net.minecraft.network.chat.TextComponent; +import net.minecraft.world.InteractionResult; +import net.minecraft.world.item.Item; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.TooltipFlag; +import net.minecraft.world.item.context.UseOnContext; +import net.minecraft.world.level.Level; + +import javax.annotation.Nullable; +import java.util.List; + +public class PhotomaskSetItem extends Item { + + public PhotomaskSetItem() { + super(new Item.Properties() + .tab(ProjectRedFabrication.FABRICATION_GROUP)); + } + + @Override + public void appendHoverText(ItemStack stack, @Nullable Level p_77624_2_, List tooltipList, TooltipFlag tooltipFlag) { + + if (stack.getTag() != null) { + //TODO localize + tooltipList.add(new TextComponent("Name: " + stack.getTag().getString("ic_name")).withStyle(ChatFormatting.GRAY)); + tooltipList.add(new TextComponent("Tile count: " + stack.getTag().getInt("tilecount")).withStyle(ChatFormatting.GRAY)); + + byte bmask = stack.getTag().getByte("bmask"); + tooltipList.add(new TextComponent("Input mask: " + "0x" + Integer.toHexString(bmask & 0xF)).withStyle(ChatFormatting.GRAY)); + tooltipList.add(new TextComponent("Output mask: " + "0x" + Integer.toHexString((bmask >> 4) & 0xF)).withStyle(ChatFormatting.GRAY)); + } + } + + @Override + public InteractionResult onItemUseFirst(ItemStack stack, UseOnContext context) { + + if (stack.getTag() != null) { + ItemStack gate = GateType.FABRICATED_GATE.makeStack(); + gate.setTag(stack.getTag()); + + context.getPlayer().addItem(gate); + return InteractionResult.SUCCESS; + } + + return InteractionResult.PASS; + } + + public static void transferNBTToDieItem(ItemStack photomask, ItemStack die) { + die.setTag(photomask.getTag().copy()); + } +} diff --git a/fabrication/src/main/java/mrtjp/projectred/fabrication/item/RoughSiliconWaferItem.java b/fabrication/src/main/java/mrtjp/projectred/fabrication/item/RoughSiliconWaferItem.java new file mode 100644 index 000000000..dcef72bab --- /dev/null +++ b/fabrication/src/main/java/mrtjp/projectred/fabrication/item/RoughSiliconWaferItem.java @@ -0,0 +1,10 @@ +package mrtjp.projectred.fabrication.item; + +import mrtjp.projectred.fabrication.lithography.WaferType; + +public class RoughSiliconWaferItem extends BaseSiliconWaferItem { + + public RoughSiliconWaferItem() { + super(WaferType.ROUGH_WAFER); + } +} diff --git a/fabrication/src/main/java/mrtjp/projectred/fabrication/item/ValidDieItem.java b/fabrication/src/main/java/mrtjp/projectred/fabrication/item/ValidDieItem.java new file mode 100644 index 000000000..6b4d7faa7 --- /dev/null +++ b/fabrication/src/main/java/mrtjp/projectred/fabrication/item/ValidDieItem.java @@ -0,0 +1,46 @@ +package mrtjp.projectred.fabrication.item; + +import mrtjp.projectred.fabrication.ProjectRedFabrication; +import mrtjp.projectred.integration.GateType; +import net.minecraft.ChatFormatting; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.network.chat.Component; +import net.minecraft.network.chat.TextComponent; +import net.minecraft.world.item.Item; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.TooltipFlag; +import net.minecraft.world.level.Level; + +import javax.annotation.Nullable; +import java.util.List; + +public class ValidDieItem extends Item { + + public ValidDieItem() { + super(new Item.Properties() + .tab(ProjectRedFabrication.FABRICATION_GROUP)); + } + + @Override + public void appendHoverText(ItemStack stack, @Nullable Level world, List tooltipList, TooltipFlag tooltipFlag) { + super.appendHoverText(stack, world, tooltipList, tooltipFlag); + + if (stack.getTag() == null) + return; + + CompoundTag tag = stack.getTag(); + + // Blueprint data + tooltipList.add(new TextComponent("Name: " + tag.getString("ic_name")).withStyle(ChatFormatting.GRAY)); + tooltipList.add(new TextComponent("Tile count: " + tag.getInt("tilecount")).withStyle(ChatFormatting.GRAY)); + byte bmask = tag.getByte("bmask"); + tooltipList.add(new TextComponent("Input mask: " + "0x" + Integer.toHexString(bmask & 0xF)).withStyle(ChatFormatting.GRAY)); + tooltipList.add(new TextComponent("Output mask: " + "0x" + Integer.toHexString((bmask >> 4) & 0xF)).withStyle(ChatFormatting.GRAY)); + } + + public static ItemStack createGatePart(ItemStack die) { + ItemStack gate = GateType.FABRICATED_GATE.makeStack(); + gate.setTag(die.getTag().copy()); + return gate; + } +} diff --git a/fabrication/src/main/java/mrtjp/projectred/fabrication/lithography/ILithographerNetwork.java b/fabrication/src/main/java/mrtjp/projectred/fabrication/lithography/ILithographerNetwork.java new file mode 100644 index 000000000..f0bb954c2 --- /dev/null +++ b/fabrication/src/main/java/mrtjp/projectred/fabrication/lithography/ILithographerNetwork.java @@ -0,0 +1,12 @@ +package mrtjp.projectred.fabrication.lithography; + +import codechicken.lib.data.MCDataOutput; + +public interface ILithographerNetwork { + + MCDataOutput getBufferedStream(int frameKey); + + boolean isClientSide(); + + void markSave(); +} diff --git a/fabrication/src/main/java/mrtjp/projectred/fabrication/lithography/Lithographer.java b/fabrication/src/main/java/mrtjp/projectred/fabrication/lithography/Lithographer.java new file mode 100644 index 000000000..f9e19bb5c --- /dev/null +++ b/fabrication/src/main/java/mrtjp/projectred/fabrication/lithography/Lithographer.java @@ -0,0 +1,31 @@ +package mrtjp.projectred.fabrication.lithography; + +import codechicken.lib.data.MCDataInput; + +public class Lithographer { + + // Size of wafer in nanometers + private int waferSize; + // Size of each tile in nanometers + private int tileSize; + // Chance of defect per nanometer + private double defectChance; + + private final ILithographerNetwork network; + + public Lithographer(ILithographerNetwork network) { + this.network = network; + } + + public void clear() { + + } + + public void setup() { + + } + + public void readBufferedStream(MCDataInput in, int frameKey) { + + } +} diff --git a/fabrication/src/main/java/mrtjp/projectred/fabrication/lithography/ProcessNode.java b/fabrication/src/main/java/mrtjp/projectred/fabrication/lithography/ProcessNode.java new file mode 100644 index 000000000..dfe9dfa78 --- /dev/null +++ b/fabrication/src/main/java/mrtjp/projectred/fabrication/lithography/ProcessNode.java @@ -0,0 +1,25 @@ +package mrtjp.projectred.fabrication.lithography; + +public enum ProcessNode { + PROCESS_64NM(64), + PROCESS_32NM(32), + PROCESS_16NM(16), + PROCESS_8NM(8), + ; + + private final int tileLen; + private final int tileArea; + + ProcessNode(int tileLen) { + this.tileLen = tileLen; + this.tileArea = tileLen * tileLen; + } + + public int getTileLen() { + return tileLen; + } + + public int getTileArea() { + return tileArea; + } +} diff --git a/fabrication/src/main/java/mrtjp/projectred/fabrication/lithography/WaferType.java b/fabrication/src/main/java/mrtjp/projectred/fabrication/lithography/WaferType.java new file mode 100644 index 000000000..4529214a4 --- /dev/null +++ b/fabrication/src/main/java/mrtjp/projectred/fabrication/lithography/WaferType.java @@ -0,0 +1,30 @@ +package mrtjp.projectred.fabrication.lithography; + +public enum WaferType { + + ROUGH_WAFER (4096, 0.0005), + PURIFIED_WAFER (4096, 0.0001), + POLISHED_WAFER (4096, 0.00001); + + private final int waferLen; + private final int waferArea; + private final double defectChancePerLen; + + WaferType(int waferLen, double defectChancePerLen) { + this.waferLen = waferLen; + this.waferArea = waferLen * waferLen; + this.defectChancePerLen = defectChancePerLen; + } + + public int getWaferArea() { + return waferArea; + } + + public int getWaferLen() { + return waferLen; + } + + public double getDefectChancePerLen() { + return defectChancePerLen; + } +} diff --git a/fabrication/src/main/java/mrtjp/projectred/fabrication/part/FabricatedGatePart.java b/fabrication/src/main/java/mrtjp/projectred/fabrication/part/FabricatedGatePart.java new file mode 100644 index 000000000..6b465284f --- /dev/null +++ b/fabrication/src/main/java/mrtjp/projectred/fabrication/part/FabricatedGatePart.java @@ -0,0 +1,212 @@ +package mrtjp.projectred.fabrication.part; + +import codechicken.lib.data.MCDataInput; +import codechicken.lib.data.MCDataOutput; +import mrtjp.fengine.api.ICFlatMap; +import mrtjp.projectred.core.BundledSignalsLib; +import mrtjp.projectred.fabrication.engine.ICSimulationContainer; +import mrtjp.projectred.fabrication.engine.PRFabricationEngine; +import mrtjp.projectred.integration.GateType; +import mrtjp.projectred.integration.part.BundledGatePart; +import net.minecraft.core.BlockPos; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.world.InteractionHand; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.item.ItemStack; + +import static mrtjp.projectred.fabrication.ProjectRedFabrication.LOGGER; + +public class FabricatedGatePart extends BundledGatePart { + + private final ICSimulationContainer simulationContainer = new ICSimulationContainer(); + private String icName = "untitled"; + private byte bundledMask = 0; + private byte redstoneMask = 0; + + private long simulationTimeStart = -1L; + + public FabricatedGatePart() { + super(GateType.FABRICATED_GATE); + } + + @Override + public void preparePlacement(Player player, BlockPos pos, int side) { + super.preparePlacement(player, pos, side); + + ItemStack stack = player.getItemInHand(InteractionHand.MAIN_HAND); // TODO handle offhand + if (stack.isEmpty() || !stack.hasTag()) { + LOGGER.warn("Gate placement issue: no NBT on gate item"); + return; + } + + CompoundTag tag = stack.getTag(); + icName = tag.getString("ic_name"); + ICFlatMap flatMap = PRFabricationEngine.instance.deserializeFlatMap(tag.getString("flatMap")); + simulationContainer.setFlatMap(flatMap); + bundledMask = tag.getByte("bmask"); + redstoneMask = tag.getByte("rmask"); + } + + @Override + public void save(CompoundTag tag) { + super.save(tag); + tag.putString("ic_name", icName); + tag.putByte("bmask", bundledMask); + tag.putByte("rmask", redstoneMask); + tag.putLong("sim_time", level().getGameTime() - simulationTimeStart); + simulationContainer.save(tag); + } + + @Override + public void load(CompoundTag tag) { + super.load(tag); + icName = tag.getString("ic_name"); + bundledMask = tag.getByte("bmask"); + redstoneMask = tag.getByte("rmask"); + simulationTimeStart = tag.getLong("sim_time"); + simulationContainer.load(tag); + } + + @Override + public void writeDesc(MCDataOutput packet) { + super.writeDesc(packet); + packet.writeString(icName); + packet.writeByte(bundledMask); + packet.writeByte(redstoneMask); + } + + @Override + public void readDesc(MCDataInput packet) { + super.readDesc(packet); + icName = packet.readString(); + bundledMask = packet.readByte(); + redstoneMask = packet.readByte(); + } + + @Override + public ItemStack getItem() { + return super.getItem(); //TODO set nbt on this item + } + + //region RedstoneGatePart overrides + @Override + protected int outputMask(int shape) { + return (redstoneMask >> 4) & 0xF; + } + + @Override + protected int inputMask(int shape) { + return redstoneMask & 0xF; + } + + @Override + protected int getOutput(int r) { + if ((outputMask(shape()) & 1 << r) != 0) { + return 0; + } + + // TODO interpret analog + return (simulationContainer.getOutput(r) & 1) != 0 ? 15 : 0; + } + + //endregion + + //region BundledGatePart overrides + @Override + protected int bundledInputMask(int shape) { + return bundledMask & 0xF; + } + + @Override + protected int bundledOutputMask(int shape) { + return (bundledMask >> 4) & 0xF; + } + + @Override + protected byte[] getBundledOutput(int r) { + return (bundledOutputMask(shape()) & (1 << r)) != 0 ? + BundledSignalsLib.unpackDigital(null, simulationContainer.getOutput(r)) : null; //TODO reuse an array + } + //endregion + + //region IGateRenderKey overrides + + @Override + public int state2() { + // TODO Temporary: Mask used to render Bundled side conns by FabricatedGateRenderer + return bundledMask; + } + + //endregion + + @Override + protected void gateLogicOnWorldLoad() { + simulationTimeStart = level().getGameTime() - simulationTimeStart; + } + + @Override + protected void gateLogicSetup() { + if (simulationTimeStart == -1L) { + simulationTimeStart = level().getGameTime(); + tile().setChanged(); + } + } + + @Override + protected void gateLogicOnChange() { + + // Latch new input states + short[] newInputs = new short[4]; + for (int r = 0; r < 4; r++) newInputs[r] = getModeBasedInput(r); + int changeMask = simulationContainer.setInputs(newInputs); + + // Schedule update if inputs changed + if (changeMask != 0) { + // TODO set gate state for client rendering here + onInputChange(); + scheduleTick(2); + } + } + + @Override + protected void gateLogicOnScheduledTick() { + + // Push latched inputs into simulation registers + simulationContainer.pushInputs(0xF); + + // Run simulation + simulationContainer.simulate(); + int changeMask = simulationContainer.pullOutputs(); + if (changeMask != 0) { + // TODO set gate state for client rendering here + onOutputChange(changeMask); + } + + // Re-check inputs in case they changed during scheduled tick + gateLogicOnChange(); + } + + @Override + protected void gateLogicOnTick() { + if (!level().isClientSide) { + long simTimeElapsed = level().getGameTime() - simulationTimeStart; + + // Push new simulation time register + simulationContainer.setSystemTime(simTimeElapsed); + simulationContainer.pushTime(); + + // Run simulation + simulationContainer.simulate(); + int changeMask = simulationContainer.pullOutputs(); + if (changeMask != 0) { + // TODO set gate state for client rendering here + onOutputChange(changeMask); + } + } + } + + private short getModeBasedInput(int r) { + if ((bundledInputMask(shape()) & (1 << r)) == 0) return 0; + return (short) BundledSignalsLib.packDigital(getBundledInput(r)); + } +} diff --git a/fabrication/src/main/java/mrtjp/projectred/fabrication/tile/FabricationMachineTile.java b/fabrication/src/main/java/mrtjp/projectred/fabrication/tile/FabricationMachineTile.java new file mode 100644 index 000000000..89beb47c0 --- /dev/null +++ b/fabrication/src/main/java/mrtjp/projectred/fabrication/tile/FabricationMachineTile.java @@ -0,0 +1,135 @@ +package mrtjp.projectred.fabrication.tile; + +import mrtjp.projectred.api.IConnectable; +import mrtjp.projectred.core.power.ILowLoadMachine; +import mrtjp.projectred.core.power.ILowLoadPowerLine; +import mrtjp.projectred.core.power.PowerConductor; +import mrtjp.projectred.core.tile.BasePoweredTile; +import mrtjp.projectred.fabrication.block.FabricationMachineBlock; +import net.minecraft.core.BlockPos; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.world.level.block.entity.BlockEntityType; +import net.minecraft.world.level.block.state.BlockState; + +public abstract class FabricationMachineTile extends BasePoweredTile implements ILowLoadMachine { + + protected final PowerConductor conductor = new PowerConductor(this, 0.01, 160); + + private int chargeFlow = 0; + private boolean isWorking = false; + private boolean isCharged = false; + private int remainingWork = 0; + private int totalWork = 0; + + public FabricationMachineTile(BlockEntityType type, BlockPos pos, BlockState state) { + super(type, pos, state); + } + + @Override + public void saveToNBT(CompoundTag tag) { + super.saveToNBT(tag); + conductor.save(tag); + tag.putBoolean("isWorking", isWorking); + tag.putBoolean("isCharged", isCharged); + } + + @Override + public void loadFromNBT(CompoundTag tag) { + super.loadFromNBT(tag); + conductor.load(tag); + isWorking = tag.getBoolean("isWorking"); + isCharged = tag.getBoolean("isCharged"); + } + + @Override + public BlockState storeBlockState(BlockState defaultState) { + return super.storeBlockState(defaultState) + .setValue(FabricationMachineBlock.CHARGED, isCharged) + .setValue(FabricationMachineBlock.WORKING, isWorking); + } + + @Override + public void tick() { + if (getLevel().isClientSide) return; + + boolean wasCharged = isCharged; + boolean wasWorking = isWorking; + + conductor.tick(); + + chargeFlow <<= 1; + if (canConductorWork()) chargeFlow |= 1; + isCharged = canConductorWork(); + + if (!isWorking) { + if (canStartWork()) { + isWorking = true; + remainingWork = totalWork = startWork(); + } + + } else { + int workDone = tickWork(remainingWork); + remainingWork -= workDone; + if (remainingWork <= 0) { + isWorking = false; + remainingWork = 0; + totalWork = 0; + finishWork(); + } + } + + if (isCharged != wasCharged || isWorking != wasWorking) { + pushBlockState(); + } + } + + @Override + public boolean canConnectPart(IConnectable part, int s, int edgeRot) { + if (part instanceof ILowLoadMachine) return true; + if (part instanceof ILowLoadPowerLine) return true; + + return false; + } + + @Override + public PowerConductor getConductor(int dir) { + return conductor; + } + + @Override + public int getConductorCharge() { + return (int) (conductor.getVoltage() * 10); + } + + @Override + public int getConductorFlow() { + return chargeFlow; + } + + @Override + public boolean canConductorWork() { + return getConductorCharge() > 600; + } + + protected void cancelWorkIfNeeded() { + if (isWorking && !canStartWork()) { + isWorking = false; + remainingWork = 0; + totalWork = 0; + pushBlockState(); + } + } + + public int getRemainingWork() { + return remainingWork; + } + + public int getTotalWork() { + return totalWork; + } + + protected abstract boolean canStartWork(); + protected abstract int startWork(); + protected abstract int tickWork(int remainingWork); + protected abstract void finishWork(); +} diff --git a/fabrication/src/main/java/mrtjp/projectred/fabrication/tile/ICWorkbenchTile.java b/fabrication/src/main/java/mrtjp/projectred/fabrication/tile/ICWorkbenchTile.java new file mode 100644 index 000000000..b5151d10b --- /dev/null +++ b/fabrication/src/main/java/mrtjp/projectred/fabrication/tile/ICWorkbenchTile.java @@ -0,0 +1,242 @@ +package mrtjp.projectred.fabrication.tile; + +import codechicken.lib.data.MCDataInput; +import codechicken.lib.data.MCDataOutput; +import codechicken.lib.packet.PacketCustom; +import codechicken.lib.vec.Vector3; +import mrtjp.projectred.core.CoreNetwork; +import mrtjp.projectred.core.tile.IPacketReceiverTile; +import mrtjp.projectred.core.tile.ProjectRedTile; +import mrtjp.projectred.fabrication.block.ICWorkbenchBlock; +import mrtjp.projectred.fabrication.editor.ICWorkbenchEditor; +import mrtjp.projectred.fabrication.editor.IICWorkbenchEditorNetwork; +import mrtjp.projectred.fabrication.gui.screen.ICWorkbenchScreen; +import mrtjp.projectred.fabrication.init.FabricationReferences; +import net.minecraft.core.BlockPos; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.world.InteractionHand; +import net.minecraft.world.InteractionResult; +import net.minecraft.world.entity.item.ItemEntity; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.phys.BlockHitResult; + +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; +import java.util.stream.Collectors; + +import static mrtjp.projectred.fabrication.ProjectRedFabrication.LOGGER; + +public class ICWorkbenchTile extends ProjectRedTile implements IPacketReceiverTile, IICWorkbenchEditorNetwork { + + private final ICWorkbenchEditor editor = new ICWorkbenchEditor(this); + + private final Map editorBufferedStreams = new HashMap<>(); + private final Set playersWatchingScreen = new HashSet<>(); + + public ICWorkbenchTile(BlockPos pos, BlockState state) { + super(FabricationReferences.IC_WORKBENCH_TILE, pos, state); + } + + public ICWorkbenchEditor getEditor() { + return editor; + } + + @Override + public void writeDesc(MCDataOutput out) { + editor.writeDesc(out); + } + + @Override + public void readDesc(MCDataInput in) { + editor.readDesc(in); + } + + @Override + public void saveToNBT(CompoundTag tag) { + editor.save(tag); + } + + @Override + public void loadFromNBT(CompoundTag tag) { + editor.load(tag); + } + + private Set filterAndGetWatchers() { + Set toRemove = playersWatchingScreen.stream() + .filter(ServerPlayer::hasDisconnected) + .collect(Collectors.toSet()); + playersWatchingScreen.removeAll(toRemove); + return playersWatchingScreen; + } + + @Override + public void tick() { + + editor.tick(); + + flushEditorStreams(); + } + + @Override + public InteractionResult onBlockActivated(Player player, InteractionHand hand, BlockHitResult hit) { + + if (!getLevel().isClientSide()) { + + ItemStack stackInHand = player.getItemInHand(hand); + + boolean blueprintOnTable = getBlockState().getValue(ICWorkbenchBlock.BLUEPRINT_PROPERTY); + boolean blueprintInHand = !stackInHand.isEmpty() && stackInHand.getItem() == FabricationReferences.IC_BLUEPRINT_ITEM; + + if (!blueprintOnTable && blueprintInHand) { + // load blueprint and activate editor + editor.readBlueprintTagAndActivate(stackInHand.getTag()); + stackInHand.shrink(1); + setBlueprintBlockState(true); + sendEditorDescription(); + + } else if (blueprintOnTable && player.isCrouching()) { + // save/drop blueprint and deactivate editor + ItemStack blueprintToDrop = createBlueprintStack(); + dropBlueprintStack(blueprintToDrop); + setBlueprintBlockState(false); + sendEditorDescription(); + + } else { + // open editor GUI + openGuiFromServer(player); + } + } + + return InteractionResult.SUCCESS; + } + + @Override + public void onBlockRemoved() { + if (getEditor().isActive()) { + ItemStack blueprintToDrop = createBlueprintStack(); + ProjectRedTile.dropItem(blueprintToDrop, getLevel(), Vector3.fromBlockPos(getBlockPos())); + } + } + + private ItemStack createBlueprintStack() { + ItemStack stack = new ItemStack(FabricationReferences.IC_BLUEPRINT_ITEM); + editor.writeBlueprintTagAndDeactivate(stack.getOrCreateTag()); + return stack; + } + + private void dropBlueprintStack(ItemStack blueprintToDrop) { + BlockPos pos = getBlockPos().offset(0, 1, 0); + ItemEntity itemEntity = new ItemEntity(getLevel(), pos.getX() + 0.5D, pos.getY() + 0.5D, pos.getZ() + 0.5D, blueprintToDrop); + itemEntity.setPickUpDelay(10); + itemEntity.setDeltaMovement(0, 0.15D, 0); + getLevel().addFreshEntity(itemEntity); + } + + private void setBlueprintBlockState(boolean blueprintOnTable) { + BlockState newState = getBlockState().setValue(ICWorkbenchBlock.BLUEPRINT_PROPERTY, blueprintOnTable); + getLevel().setBlockAndUpdate(getBlockPos(), newState); + } + + private void openGuiFromServer(Player player) { + if (getLevel().isClientSide || !(player instanceof ServerPlayer)) { throw new RuntimeException("Server only"); } + filterAndGetWatchers().add((ServerPlayer) player); + LOGGER.info("Watcher added. Size: " + playersWatchingScreen.size()); + sendUpdateToPlayer(0, editor::writeDesc, (ServerPlayer) player); + } + + private void sendEditorDescription() { + + sendUpdateToPlayerList(50, editor::writeDesc, playersWatchingScreen); + } + + public void closeGuiFromClient() { + sendUpdateToServer(1, n -> { }); + } + + @Override + public void receiveUpdateFromServer(int key, MCDataInput input) { + switch (key) { + case 0: // Client opened screen + editor.readDesc(input); + ICWorkbenchScreen.openGuiOnClient(this); + break; + case 50: // Editor description update + editor.readDesc(input); + break; + case 100: // Some packet for the editor + receiveBufferedStream(input); + break; + default: + LOGGER.error("Unknown packet key from server: " + key); + } + } + + @Override + public void receiveUpdateFromClient(int key, MCDataInput input, ServerPlayer player) { + switch (key) { + case 1: // Client closed screen + filterAndGetWatchers().remove(player); + LOGGER.info("Watcher removed. Size: " + playersWatchingScreen.size()); + break; + case 100: // Some packet for the editor + receiveBufferedStream(input); + break; + default: + LOGGER.error("Unknown packet key from client: " + key); + } + } + + private void receiveBufferedStream(MCDataInput in) { + int streamKey = in.readUByte(); + int frameKey = in.readUByte(); + while (frameKey != 255) { + editor.readBufferedStream(in, streamKey, frameKey); + frameKey = in.readUByte(); + } + } + + @Override + public MCDataOutput getBufferedStream(int streamKey, int frameKey) { + MCDataOutput out = editorBufferedStreams.computeIfAbsent(streamKey, k -> { + PacketCustom packet = getLevel().isClientSide ? + CoreNetwork.createTileServerPacket(this, (byte) 100) : + CoreNetwork.createTileClientPacket(this, (byte) 100); + packet.writeByte(k); // One-time key that identifies the entire stream + return packet; + }); + + return out.writeByte(frameKey); // Frame byte inserted between chunks of data + } + + private void flushEditorStreams() { + for (PacketCustom packet : editorBufferedStreams.values()) { + packet.writeByte(255); // Terminator frame byte + if (getLevel().isClientSide) { + packet.sendToServer(); + } else { + for (ServerPlayer player : filterAndGetWatchers()) { packet.sendToPlayer(player); } + } + } + editorBufferedStreams.clear(); + } + + @Override + public boolean isClientSide() { + return getLevel().isClientSide(); + } + + @Override + public void markSave() { + this.setChanged(); + } + + @Override + public long getGameTime() { + return getLevel().getGameTime(); + } +} diff --git a/fabrication/src/main/java/mrtjp/projectred/fabrication/tile/LithographyTableTile.java b/fabrication/src/main/java/mrtjp/projectred/fabrication/tile/LithographyTableTile.java new file mode 100644 index 000000000..91c939427 --- /dev/null +++ b/fabrication/src/main/java/mrtjp/projectred/fabrication/tile/LithographyTableTile.java @@ -0,0 +1,162 @@ +package mrtjp.projectred.fabrication.tile; + +import codechicken.lib.data.MCDataInput; +import codechicken.lib.data.MCDataOutput; +import codechicken.lib.util.ServerUtils; +import mrtjp.projectred.core.inventory.BaseInventory; +import mrtjp.projectred.fabrication.init.FabricationReferences; +import mrtjp.projectred.fabrication.inventory.container.LithographyTableContainer; +import mrtjp.projectred.fabrication.item.BaseSiliconWaferItem; +import mrtjp.projectred.fabrication.item.PhotomaskSetItem; +import mrtjp.projectred.fabrication.lithography.ProcessNode; +import mrtjp.projectred.fabrication.lithography.WaferType; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.network.chat.TranslatableComponent; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.world.Container; +import net.minecraft.world.InteractionHand; +import net.minecraft.world.InteractionResult; +import net.minecraft.world.SimpleMenuProvider; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.phys.BlockHitResult; +import net.minecraftforge.common.capabilities.Capability; +import net.minecraftforge.common.util.LazyOptional; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; + +public class LithographyTableTile extends FabricationMachineTile { + + private final BaseInventory inventory = new BaseInventory(4) { + + @Override + public boolean canPlaceItem(int slot, ItemStack stack) { + switch (slot) { + case 0: + return stack.getItem() instanceof PhotomaskSetItem; + case 1: + return stack.getItem() instanceof BaseSiliconWaferItem; + default: + return false; + } + } + + @Override + public void setChanged() { + super.setChanged(); + cancelWorkIfNeeded(); + } + }; + + public LithographyTableTile(BlockPos pos, BlockState state) { + super(FabricationReferences.LITHOGRAPHY_TABLE_TILE, pos, state); + } + + public Container getInventory() { + return inventory; + } + + @Override + public void saveToNBT(CompoundTag tag) { + super.saveToNBT(tag); + tag.put("inventory", inventory.createTag()); + } + + @Override + public void loadFromNBT(CompoundTag tag) { + super.loadFromNBT(tag); + inventory.fromTag(tag.getList("inventory", 10)); + } + + @Override + public void writeDesc(MCDataOutput out) { + } + + @Override + public void readDesc(MCDataInput in) { + } + + @Override + public InteractionResult onBlockActivated(Player player, InteractionHand hand, BlockHitResult hit) { + if (!getLevel().isClientSide) { + ServerUtils.openContainer((ServerPlayer) player, new SimpleMenuProvider((id, inv, p) -> new LithographyTableContainer(inv, this, id), new TranslatableComponent(getBlockState().getBlock().getDescriptionId())), p -> p.writePos(getBlockPos())); + } + + return InteractionResult.SUCCESS; + } + + @Nonnull + @Override + public LazyOptional getCapability(@Nonnull Capability cap, @Nullable Direction side) { + return super.getCapability(cap, side); //TODO add capabilities + } + + @Override + protected boolean canStartWork() { + + ItemStack slot0 = inventory.getItem(0); + ItemStack slot1 = inventory.getItem(1); + + if (slot0.isEmpty() || slot1.isEmpty()) { + return false; + } + + if (!(slot0.getItem() instanceof PhotomaskSetItem)) return false; + if (!(slot1.getItem() instanceof BaseSiliconWaferItem)) return false; + + return inventory.getItem(2).isEmpty() && inventory.getItem(3).isEmpty(); + } + + @Override + protected int startWork() { + return 20 * 60; // 60 seconds worth of work + } + + @Override + protected int tickWork(int remainingWork) { + if (canConductorWork()) { + conductor.applyPower(-1100); // draw at rate of 1.1kW + return 1; + } + return 0; + } + + @Override + protected void finishWork() { + BaseSiliconWaferItem wafer = (BaseSiliconWaferItem) inventory.getItem(1).getItem(); + + WaferType waferType = wafer.getWaferType(); + ProcessNode processNode = ProcessNode.PROCESS_64NM; + int dieLen = processNode.getTileLen() * 16; //TODO Source from photomask itemstack instead of assuming 16x16 + int gridLen = waferType.getWaferLen() / dieLen; + double defectChancePerDie = dieLen * waferType.getDefectChancePerLen(); + + // Calculate number of good and bad dies + int totalDesigns = gridLen * gridLen; + int totalDefectiveDies = 0; + for (int i = 0; i < totalDesigns; i++) { + if (Math.random() < defectChancePerDie) { + totalDefectiveDies++; + } + } + int totalValidDies = totalDesigns - totalDefectiveDies; + + // Set the output stacks + if (totalValidDies > 0) { + ItemStack validDieStack = new ItemStack(FabricationReferences.VALID_DIE_ITEM, totalValidDies); + PhotomaskSetItem.transferNBTToDieItem(inventory.getItem(0), validDieStack); + inventory.setItem(2, validDieStack); + } + if (totalDefectiveDies > 0) { + ItemStack defectiveDieStack = new ItemStack(FabricationReferences.INVALID_DIE_ITEM, totalDefectiveDies); + inventory.setItem(3, defectiveDieStack); + } + + // Consume inputs + inventory.removeItem(1, 1); // Consume wafer + } +} diff --git a/fabrication/src/main/java/mrtjp/projectred/fabrication/tile/PackagingTableTile.java b/fabrication/src/main/java/mrtjp/projectred/fabrication/tile/PackagingTableTile.java new file mode 100644 index 000000000..a040ca24a --- /dev/null +++ b/fabrication/src/main/java/mrtjp/projectred/fabrication/tile/PackagingTableTile.java @@ -0,0 +1,132 @@ +package mrtjp.projectred.fabrication.tile; + +import codechicken.lib.data.MCDataInput; +import codechicken.lib.data.MCDataOutput; +import codechicken.lib.util.ServerUtils; +import mrtjp.projectred.core.inventory.BaseInventory; +import mrtjp.projectred.fabrication.init.FabricationReferences; +import mrtjp.projectred.fabrication.inventory.container.PackagingTableContainer; +import mrtjp.projectred.fabrication.item.ValidDieItem; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.network.chat.TranslatableComponent; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.world.Container; +import net.minecraft.world.InteractionHand; +import net.minecraft.world.InteractionResult; +import net.minecraft.world.SimpleMenuProvider; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.phys.BlockHitResult; +import net.minecraftforge.common.capabilities.Capability; +import net.minecraftforge.common.util.LazyOptional; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; + +public class PackagingTableTile extends FabricationMachineTile { + + private final BaseInventory inventory = new BaseInventory(5) { + + @Override + public boolean canPlaceItem(int slot, ItemStack stack) { + switch (slot) { + case 0: + return stack.getItem() instanceof ValidDieItem; + case 1: + case 2: + case 3: + //TODO + default: + return false; + } + } + + @Override + public void setChanged() { + super.setChanged(); + cancelWorkIfNeeded(); + } + }; + public PackagingTableTile(BlockPos pos, BlockState state) { + super(FabricationReferences.PACKAGING_TABLE_TILE, pos, state); + } + + public Container getInventory() { + return inventory; + } + + @Override + public void saveToNBT(CompoundTag tag) { + super.saveToNBT(tag); + tag.put("inventory", inventory.createTag()); + } + + @Override + public void loadFromNBT(CompoundTag tag) { + super.loadFromNBT(tag); + inventory.fromTag(tag.getList("inventory", 10)); + } + + @Override + public void writeDesc(MCDataOutput out) { + } + + @Override + public void readDesc(MCDataInput in) { + } + + @Override + public InteractionResult onBlockActivated(Player player, InteractionHand hand, BlockHitResult hit) { + if (!getLevel().isClientSide) { + ServerUtils.openContainer((ServerPlayer) player, + new SimpleMenuProvider((id, inv, p) -> new PackagingTableContainer(inv, this, id), new TranslatableComponent(getBlockState().getBlock().getDescriptionId())), + p -> p.writePos(getBlockPos())); + } + + return InteractionResult.SUCCESS; + } + + @Nonnull + @Override + public LazyOptional getCapability(@Nonnull Capability cap, @Nullable Direction side) { + return super.getCapability(cap, side); //TODO add capabilities + } + + @Override + protected boolean canStartWork() { + + ItemStack slot0 = inventory.getItem(0); + + if (slot0.isEmpty()) return false; + + if (!(slot0.getItem() instanceof ValidDieItem)) return false; + + return inventory.getItem(4).isEmpty(); //TODO or output can be stackable (made from same blueprint) + } + + @Override + protected int startWork() { + return 20 * 20; // 20 seconds worth of work + } + + @Override + protected int tickWork(int remainingWork) { + if (canConductorWork()) { + conductor.applyPower(-1100); // draw at rate of 1.1kW + return 1; + } + return 0; + } + + @Override + protected void finishWork() { + ItemStack gatePart = ValidDieItem.createGatePart(inventory.getItem(0)); + inventory.setItem(4, gatePart); //TODO or stack + + // Consume inputs + inventory.removeItem(0, 1); + } +} diff --git a/fabrication/src/main/java/mrtjp/projectred/fabrication/tile/PlottingTableTile.java b/fabrication/src/main/java/mrtjp/projectred/fabrication/tile/PlottingTableTile.java new file mode 100644 index 000000000..6f905e835 --- /dev/null +++ b/fabrication/src/main/java/mrtjp/projectred/fabrication/tile/PlottingTableTile.java @@ -0,0 +1,137 @@ +package mrtjp.projectred.fabrication.tile; + +import codechicken.lib.data.MCDataInput; +import codechicken.lib.data.MCDataOutput; +import codechicken.lib.util.ServerUtils; +import mrtjp.projectred.core.inventory.BaseInventory; +import mrtjp.projectred.fabrication.init.FabricationReferences; +import mrtjp.projectred.fabrication.inventory.container.PlottingTableContainer; +import mrtjp.projectred.fabrication.item.BlankPhotomaskItem; +import mrtjp.projectred.fabrication.item.ICBlueprintItem; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.network.chat.TranslatableComponent; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.world.Container; +import net.minecraft.world.InteractionHand; +import net.minecraft.world.InteractionResult; +import net.minecraft.world.SimpleMenuProvider; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.phys.BlockHitResult; +import net.minecraftforge.common.capabilities.Capability; +import net.minecraftforge.common.util.LazyOptional; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; + +public class PlottingTableTile extends FabricationMachineTile { + + private final BaseInventory inventory = new BaseInventory(3) { + + @Override + public boolean canPlaceItem(int slot, ItemStack stack) { + switch (slot) { + case 0: + return stack.getItem() instanceof ICBlueprintItem; + case 1: + return stack.getItem() instanceof BlankPhotomaskItem; + default: + return false; + } + } + + @Override + public void setChanged() { + super.setChanged(); + cancelWorkIfNeeded(); + } + }; + + public PlottingTableTile(BlockPos pos, BlockState state) { + super(FabricationReferences.PLOTTING_TABLE_TILE, pos, state); + } + + public Container getInventory() { + return inventory; + } + + @Override + public void saveToNBT(CompoundTag tag) { + super.saveToNBT(tag); + tag.put("inventory", inventory.createTag()); + } + + @Override + public void loadFromNBT(CompoundTag tag) { + super.loadFromNBT(tag); + inventory.fromTag(tag.getList("inventory", 10)); + } + + @Override + public void writeDesc(MCDataOutput out) { + } + + @Override + public void readDesc(MCDataInput in) { + } + + + @Override + public InteractionResult onBlockActivated(Player player, InteractionHand hand, BlockHitResult hit) { + if (!getLevel().isClientSide) { + ServerUtils.openContainer((ServerPlayer) player, + new SimpleMenuProvider((id, inv, p) -> new PlottingTableContainer(inv, this, id), new TranslatableComponent(getBlockState().getBlock().getDescriptionId())), + p -> p.writePos(getBlockPos())); + } + + return InteractionResult.SUCCESS; + } + + @Nonnull + @Override + public LazyOptional getCapability(@Nonnull Capability cap, @Nullable Direction side) { + return super.getCapability(cap, side); //TODO add capabilities + } + + @Override + protected boolean canStartWork() { + + ItemStack slot0 = inventory.getItem(0); + ItemStack slot1 = inventory.getItem(1); + + if (slot0.isEmpty() || slot1.isEmpty()) { + return false; + } + + if (!(slot0.getItem() instanceof ICBlueprintItem)) return false; + + if (!(slot1.getItem() instanceof BlankPhotomaskItem)) return false; + + return inventory.getItem(2).isEmpty(); + } + + @Override + protected int startWork() { + return 20 * 10; // 10 seconds worth of work + } + + @Override + protected int tickWork(int remainingWork) { + if (canConductorWork()) { + conductor.applyPower(-1100); // draw at rate of 1.1kW + return 1; + } + return 0; + } + + @Override + protected void finishWork() { + ItemStack output = new ItemStack(FabricationReferences.PHOTOMASK_SET_ITEM); + output.setTag(inventory.getItem(0).getTag().copy()); // copy the blueprint tag + inventory.setItem(2, output); + inventory.removeItem(1, 1); // delete 1 blank photomask + } +} diff --git a/fabrication/src/main/resources/META-INF/mods.toml b/fabrication/src/main/resources/META-INF/mods.toml new file mode 100644 index 000000000..78528e2f9 --- /dev/null +++ b/fabrication/src/main/resources/META-INF/mods.toml @@ -0,0 +1,58 @@ +modLoader="javafml" +loaderVersion="[${lang_version},)" +issueTrackerURL="https://github.com/MrTJP/ProjectRed" +license="MIT" + +[[mods]] + modId="projectred_fabrication" + displayName="ProjectRed Fabrication" + version="${file.jarVersion}" + + updateJSONURL="https://version-check.covers1624.net/check/?mod=ProjectRed&mc=${mc_version}" + displayURL="https://github.com/MrTJP/ProjectRed" + authors="MrTJP, Chicken Bones, covers1624" + description=''' +Redstone. The way it was meant to be. + ''' +[[dependencies.projectred_fabrication]] + modId="forge" + mandatory=true + versionRange="[${forge_version},)" + ordering="NONE" + side="BOTH" +[[dependencies.projectred_fabrication]] + modId="minecraft" + mandatory=true + versionRange="[1.18.2]" + ordering="NONE" + side="BOTH" +[[dependencies.projectred_fabrication]] + modId="codechickenlib" + mandatory=true + versionRange="[${ccl_version},)" + ordering="AFTER" + side="BOTH" +[[dependencies.projectred_fabrication]] + modId="cb_multipart" + mandatory=true + versionRange="[${cbm_version},)" + ordering="AFTER" + side="BOTH" +[[dependencies.projectred_fabrication]] + modId="projectred_core" + mandatory=true + versionRange="[${file.jarVersion},)" + ordering="AFTER" + side="BOTH" +[[dependencies.projectred_fabrication]] + modId="projectred_integration" + mandatory=true + versionRange="[${file.jarVersion},)" + ordering="AFTER" + side="BOTH" +[[dependencies.projectred_fabrication]] + modId="projectred_transmission" + mandatory=true + versionRange="[${file.jarVersion},)" + ordering="AFTER" + side="BOTH" diff --git a/fabrication/src/main/resources/assets/projectred_fabrication/lang/en_us.json b/fabrication/src/main/resources/assets/projectred_fabrication/lang/en_us.json new file mode 100644 index 000000000..cc20307a6 --- /dev/null +++ b/fabrication/src/main/resources/assets/projectred_fabrication/lang/en_us.json @@ -0,0 +1,11 @@ +{ + "itemGroup.projectred-fabrication": "Project Red: Fabrication", + + "item.projectred-fabrication.ic_blueprint": "IC Blueprint", + "item.projectred-fabrication.ic_chip": "IC Chip", + "item.projectred-fabrication.creative_mode_ic_chip": "Creative Mode IC Chip", + "block.projectred-fabrication.ic_workbench": "IC Workbench", + "block.projectred-fabrication.ic_printer": "IC Printer", + + "block.projectred-relocation.frame": "Frame" +} \ No newline at end of file diff --git a/fabrication/src/main/resources/assets/projectred_fabrication/models/block/domed_machine.json b/fabrication/src/main/resources/assets/projectred_fabrication/models/block/domed_machine.json new file mode 100644 index 000000000..b6b609955 --- /dev/null +++ b/fabrication/src/main/resources/assets/projectred_fabrication/models/block/domed_machine.json @@ -0,0 +1,18 @@ +{ "parent": "block/block", + "textures": { + "particle": "#south" + }, + "elements": [ + { "from": [ 0, 0, 0 ], + "to": [ 16, 10, 16 ], + "faces": { + "down": { "uv": [ 0, 0, 16, 16 ], "texture": "#down", "cullface": "down" }, + "up": { "uv": [ 0, 0, 16, 16 ], "texture": "#up" }, + "north": { "uv": [ 0, 6, 16, 16 ], "texture": "#north", "cullface": "north" }, + "south": { "uv": [ 0, 6, 16, 16 ], "texture": "#south", "cullface": "south" }, + "west": { "uv": [ 0, 6, 16, 16 ], "texture": "#west", "cullface": "west" }, + "east": { "uv": [ 0, 6, 16, 16 ], "texture": "#east", "cullface": "east" } + } + } + ] +} diff --git a/fabrication/src/main/resources/assets/projectred_fabrication/textures/block/ic_workbench_bottom.png b/fabrication/src/main/resources/assets/projectred_fabrication/textures/block/ic_workbench_bottom.png new file mode 100644 index 0000000000000000000000000000000000000000..d57893eb3e464042cf48213aba0f088364c3733d GIT binary patch literal 18835 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 literal 0 HcmV?d00001 diff --git a/fabrication/src/main/resources/assets/projectred_fabrication/textures/block/ic_workbench_front.png b/fabrication/src/main/resources/assets/projectred_fabrication/textures/block/ic_workbench_front.png new file mode 100644 index 0000000000000000000000000000000000000000..d9d37a872c8aa3d5ac4df432ad731fa1e41bf756 GIT binary patch literal 16562 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 DFkQ;& literal 0 HcmV?d00001 diff --git a/fabrication/src/main/resources/assets/projectred_fabrication/textures/block/ic_workbench_front_bp.png b/fabrication/src/main/resources/assets/projectred_fabrication/textures/block/ic_workbench_front_bp.png new file mode 100644 index 0000000000000000000000000000000000000000..a9ebf9b22c1e4f63ef377bd6fcc3fa885aafe590 GIT binary patch literal 16758 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 AQ2+n{ literal 0 HcmV?d00001 diff --git a/fabrication/src/main/resources/assets/projectred_fabrication/textures/block/ic_workbench_top.png b/fabrication/src/main/resources/assets/projectred_fabrication/textures/block/ic_workbench_top.png new file mode 100644 index 0000000000000000000000000000000000000000..8ffbdb9a8783ec2d219df02d84983fa3742217d6 GIT binary patch literal 16401 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 UX7!jd=R^A`$@4UgiMf^k0b6;DSO5S3 literal 0 HcmV?d00001 diff --git a/fabrication/src/main/resources/assets/projectred_fabrication/textures/block/ic_workbench_top_bp.png b/fabrication/src/main/resources/assets/projectred_fabrication/textures/block/ic_workbench_top_bp.png new file mode 100644 index 0000000000000000000000000000000000000000..d6696a84b629a111d0d665d5e2b7e05a4e5af604 GIT binary patch literal 17034 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 literal 0 HcmV?d00001 diff --git a/fabrication/src/main/resources/assets/projectred_fabrication/textures/block/lithography_table_front_0.png b/fabrication/src/main/resources/assets/projectred_fabrication/textures/block/lithography_table_front_0.png new file mode 100644 index 0000000000000000000000000000000000000000..6a543ea738299a3d6120c9410c9f97551c391e82 GIT binary patch literal 2394 zcmah~2~-o;8lDiKEGHBx)G8KZ)D*;ICV_~gAqa%EhBX`#a3R0|LCAzG5~@XTL7^(U z2N4tnUd0U;KnhqFDyT(*JaIt@YO5%5L7+v;T1g|nWP6L7Xu7(En21JDszgmx*8u9YoOxp1cl(4XQSMQ5x^J5U{nwp?MfNQ`Oh0DunB=}gF(NpmEkBg28|-~a&nx%$&S z)aAIDSj+XM{h62JXJphLYKg{RLNq4iNJLFC9GP?os8*@5+>9kY0vQ09{fc#5k-eEU z0N~q2JieUIUCoR}lBhx~P^vOXf>{DsN+v2M!Ezx{nUpA&F_kVPErN;4m>MJzwGjCR z7ZRTvNc2FYFmVMHqCzCL36V%-Nn>J}!5ptCI{M~9ikHhJOb|>-Nuj1VP!VYyNON{} z1|d2~r&CY_MV2a-3zZbHZ1JR#4|X`PELtj($VG^lh}jiJAqu$*iG(?tZc}k4Nv0i% zWm8$9`GHEI1f)?R@M9!cDVhoIA1rL;lQg*~_7gO0Ws;`djL8^T=#DZyq_9wqNO=g7 z$o_w|!2)M9W)jvK<03Jl*i?>C4zsZ;qCn0Rnj`N+6;0B0Ftga&P~a&xjX{BE6v&bH zp>ik?T1${l2$M)18`$1314T+Wkh82tMUTXF-RE9Rf2LmLZ7>ta3udA~~DR0zamn&En6{*v@E1T8^%AHbL+)g06Bl zAwVjE(PGB}!}8ZU(A7=hSs+&LI`uz!xwKmJcCk&+1Nv}N*(N&|l84Z5hn+9Sjpsvn z#Y^&uh_g(4eUq`?YtP#XL5adYe8W|yT|{1of+`Q@oUlyxXneHYDsN7VOtt&W-(#sfXGy&G%82Ug`N;jMFt`v?SxLEFfL-a%l~R75aVt$i(K`7?For`x2U`}KK~{DZ07s# zp6N%HefhB7G~Gq``q~R%Mc?XfFGJgl-xT*X-Tm#JX4}=fe}&=grSg}fUc{aPzM$8$ z;+XW+!<6(YUW2#>r*wVeM8Vb18+I4F4Elwr-{-@mG~S7{JI0lne_T1~M+!V%R5@0i zyY!1gjL!;Jnr^ll=5*$rFfvFV*&1x$n6>JcgBPBQ;C4%=B4eH)D9-=KQS;EAZ`5Wr zz~0Wxu{og!t11i?mJs1{zl^U79-4cP-6}}@>L+7cpe!#~<5p^bD}E5U1J74P{A+E0 zdUJN^m9JgrTn@T^vD;6P70!QV*H_@Zg_YWPqnLcmG}}t~W@kw>VG}@GelyYLaQ5ee z)WgMSC6;p5JZZLO={{&g0*DR9okLQP`%#)MewvyDZ7wm2=Ib&crX7fB0aJBFBI3#<7jvNU*1;S==?XM^}Hz zx7@-`$IERoCglSqH@EQ?fxE$i5o4FoR^7-QM(x+KKMEDvQqT>sof@ zKFxO~$%AkY>W4(isN-9WHY?wbKe=#jchQ!S@R}dLKM>BXsTL0Ge`XXe#{V$3#fH0} zgHx2DcXU(Z-*t~+x7Q3-h@!-5DDIwdi>BGX#jD@+MMb)*>D>K4@amEid|8NnW$uF8 z&()3KI_myv1HaXEnkC$Uf|34XZAK64o$l# zVS(b$27lG?&+}T^;+9Q}zMptC;Y7V}H-6OO?bFMFNu@*oCG5#j5fT$7YO!Cwuctrf JlzZgX{{d}jbmIU3 literal 0 HcmV?d00001 diff --git a/fabrication/src/main/resources/assets/projectred_fabrication/textures/block/lithography_table_front_1.png b/fabrication/src/main/resources/assets/projectred_fabrication/textures/block/lithography_table_front_1.png new file mode 100644 index 0000000000000000000000000000000000000000..11b592a535ebc6b5e647599fb80f7af44a18def9 GIT binary patch literal 2397 zcmah~2~-nF8t!l?hbW`$6Ty)XM2R6uClF!+1k^Zk1uz698+I{-js$Z+(gOiT4q0FT zZ&4P-CxfD*0>dD%9_x-Ao=n^!a>xw0tEdo;VHwmF2HEa_km2du>Q_~N|Mh+UQT11M zUTE+(D+@ad006A~{n%V&wnn@4B4i8^IpL5AqvCGc3{+`W4;O}}3;@v>`#Cud<1&jeLNF8n839M6D=}2PY=g*!xe~x+mU|JI(Y6ce zh}D^SQ;Z@S!iL5wV1+7H5s#(1k=(E@9HB@eM>Ti=pn_B?6J#(c?pS1`xiQ^n0AO<1 zWX?x#DP}&_QlmM4)}_YtGU5-hM4>T33KMk4A|`3>OezR4%V0E5^LRhL3ILWiqaAac zu+$y^j9VqV2snZh#1tuHBq16oNiB;p=oZAdY2$#bUjbF=8f{{lzRDdGp4_!f-s3OioHlA|<(z6w2LX z3WLEQgH$q=N<e}aat%+U0kF%zQ~vZKr`N=OJR zlstt(%KCq`;YD7^m`_-5jH8H=h?Chu7-FGSLG^ zM9`i0p>l{IQcIvg2s20n8|dCJLnUfR8o`#xAh`-T9u~#Ji~P}rg~TlisX`eRFBCy6 z$}Gh|wGgd$!~c{Ug9QU3dI(G|q*6$~L@Os;E`eE8FY?FK3t18KG!_HNNY61;E+p_j zMle(^B!nm>5K`=DU}*k&2Zp*?ycZd*cZ2$$xmgs%zE z5`1v?cJ>#mM1;n3Fa$dn)~g_U+j6x!Ccjk=P7jB(-72%8~C8JFH ztTSiht`e4N_=b+i`jZRFQxS5NzidLG9}9UK!|x?b{V%KmsJ8_mUx4WMpr!ZUkyb8 z9p~E~oLsfMBc?gtbup;(!@6d zuMS?u_k36JQ$27lmwN0!VXpV3$;GEKM;1Hv-k9=*Lv(Q$i!hUq@u3(;(s;%%%js07 z?ewXle1VjnF=$1P5~z#V8&)VAP5YaK__f&)VYSbA|NWQgqk7}d#5}0Rw6&@5Rx5Z> z2>6DSoXIC;GP0ndu z<1H8X`=SQ~1G{^R@Tzw{e&g*gI_kTV!z&#UnODTV2QCq@8L8W*Hn*EtPd>EyPG{~_ zsnYS?v`79z=iay5Y5ON}2e0j}o!i;gKJIU|u}3q&7>>|L?%m~3N5P!4UlBI$DS-cs z{ibm&-KOLq?Z@iG^SY`QKsw#~LCWGrxWgyy@OEbt2&ec=+{;)QbMH zE*IBhz9iREe+W31LRLj4#vMFVqzl#Hx79t(th4g4zY$HNoaIY8#SP*nab7e3g;PSn zqsgqiW$uJjC2vvwRnKPicF~fGWpyfUigeB1%TX08Yy6C|Yo#u)?$-_s`5fOXYFjNY zKkjljE_ST*z_FM$0|75<*Dj|^$6454D+7}Gzm<$ST=2T~uuvU!i#WCPQC4wc<(r`~ zMz(X{nR48wU~SSm&-GbZLc4#0#<}H3OrBd-N5(S#9mxy7Ti7FL^eMGC^}0Tx%(s9R z-q%p5S)W?@t~oH|P4?upC;6u9&+8Xy|8YMxv#!QBwJ>4Y^yT0^X+!_tV$r|8|JGo3 J)#hFM{s*4FbWH#N literal 0 HcmV?d00001 diff --git a/fabrication/src/main/resources/assets/projectred_fabrication/textures/block/lithography_table_front_2.png b/fabrication/src/main/resources/assets/projectred_fabrication/textures/block/lithography_table_front_2.png new file mode 100644 index 0000000000000000000000000000000000000000..345b83c63dad4f70e4a3ebfdfa19bac53a6eab9d GIT binary patch literal 2394 zcmah~2~-nT7oG?LV!;R~D1u3#r=c{-By46NX&^xf8d-!RL8^ujAVM;b3?xdCV)1Wq z#a}>FmO$|rMA4Q?tyr{5sVy}Mf~bfT3q`cJAWA8Voe2mjN6$Yw@4Y+se&1c*yKj;m zympm^`BHNL04(?cyijz-V*_u3&Ou@)61w1&p{x9WYTdGa^kq;I!H*RPfDcjG3^2u6 z0Y(@E{Q zUME-I7&ux&2#$vlSQ!r|5g2Y%Hv(B85=-Tn#svTvAcFycOo;AIKxYp($juV~jB|{q zW8Bx`W^&cenU06o8qLUPJk%520|My~=uSXgdbmRj5K!8bVy1aX0YW7JST} z7AZmyOyI%_3Bi*JQb7{ioIoJ>C}LuvP~OTZI{L;U#Un@(M5C!xDyqtj3M=AhbS9HY z0~s_1gMuO`%B^xlq^8J~PLodF_~A*EVudsbk-~BU=2sLArywj62@5p+Oywy{nhqpa zPF020M^lTEXmlz_dmBljmd>R2FBWEbCk>ItzJrEYCTaT3n9R`!-BF0Ekcbdi5eCDF z?ElvrKD614nS%As1aOQrb}LVWNZ42xQ9vez?jH80izev?m|1LnDv~KS-Gc(sDWH4U zo6eztXfJ^VDNG^_d|-P61xwYE#0Z{LCXp-A<6+Z1eQ0kr%qDW-L|CydNhFrA=~EN~ z)oiprjPPAy3=9TD>=2+(i4sms!8#{gE=AZ3AKKg0vsn={G&U2hNY61;&L#-oMle*) zCIl&@613T|#IXAH0St9hcpnzYdH?$vdjwHW>8`gn_1 zPT&3E@B2o^i@RQU?_)&`HRKOu6F)ZD9{5}3oWiFCaSwN7>zl z8yf2a8oJ}$G{xTG^!^1_@3U{_mr;1JuF3*Y*?+(M(Q^Hc3S`Y#>RvV z*|;~n?2nqCt6wIUG43ri(;Uia4M3jFA(@T+r&?%Kd?>lZIdZ$>XyAp6xoHREqpTA? zxxM>I%Ze4U!rSq$vpJ?Z zqkBS2C-U=oPC7@MqL$yKULpSJ!pEL?e%3lwdmjh|dFF899?=prafJ4!&YttyOaAGh z4!F$z2aCN1tJ^!b$(}plE5j_>RyF+eyJF40%#&A!j(BNO-DRu`BgEYJ;WV5 z+l$6QLmdzkS^b5tx$l|h6Dy#w+G8IW7tRmsx&8H`uZs3}m;}=f0!TF`a}?LV!ej_lYn$MXrubG+d=pCoGuHNMms1o*RhsZu-akjT@D4Cq@k8E!q9lXXXe)>y&?#ZmY zJ%=0m+PzMtA3s2pbcRuq-JNN1R zhN}$gU}y8LPo1`AS?6bzTh4b=L`_8ar$70vmsPUukX@DIFmh41A>mu9xuJ@{n4lm!!z_ChsJ@@QqjU)LJB{b|WpYOkx JSM9fX$3LmAca#7C literal 0 HcmV?d00001 diff --git a/fabrication/src/main/resources/assets/projectred_fabrication/textures/block/lithography_table_side.png b/fabrication/src/main/resources/assets/projectred_fabrication/textures/block/lithography_table_side.png new file mode 100644 index 0000000000000000000000000000000000000000..8f2151ef324c7416de79abe4f1f26657aba1c16e GIT binary patch literal 2297 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 literal 0 HcmV?d00001 diff --git a/fabrication/src/main/resources/assets/projectred_fabrication/textures/block/packaging_table_front_0.png b/fabrication/src/main/resources/assets/projectred_fabrication/textures/block/packaging_table_front_0.png new file mode 100644 index 0000000000000000000000000000000000000000..b1c449a1cd1abd13cef83e20e10115ad9320c88c GIT binary patch literal 2345 zcmeAS@N?(olHy`uVBq!ia0vp^0w65F1|X?_wfUqO7?{swhD4M^`1)8S=jZArf*h(>ky`*V ziNU7A3dqb&ElE_U$j!+swyLmI0;{kBvO&W7N(x{lCE2!05xxNm&iO^D3TAo+dIm~% zTnY*bHbp6ERzWUqQ0+jTtx`rwNr9EVetCJhUb(Seeo?xG?W zUP)qwZeFo6#1NP{E~&-IMVSR9nfZANAafIw@=Hr>m6Sjh!2#5rxdm{G@`|Cp0{TzC zBC$Z|H&b!RIIn((1A(th(lI()%oAyXN z@;Y;>ji*p3NzlpYnnaS3%P~clYkG&e4Id@vK5M<1dD3yo8IL1ZQqFF8TsUv8ebqku z{qu@nou2)!eDn81=fD5myZ?FZz2~*{GM-C#`p-OZ5BqulP(PC=|}cCZoL zFR(gg-tC^5r#)pBC}ZC|(O-y{K@JrnmN z?8%%W5m}w@%)8n(%d|21*_z63@w^AyOdOjwU4H$7VT#*Qe_6&g9a}SeKi5rQ5tuGK2Ir7JqrZ^r}i?;GxekzuMjSf5)FuWW4>WFz^dw>-DZ*Hs%!@ zKhE#2Qg58E^qFaA&`RaTRQG+&N1phoUhOPB`exItMweKo-Nj}%?v;Oh@%ddE5#>NH98Q06Nt>6Dm_`%OM@xJOC3qNpduSnzf=v^V_ z&dXh{!Tibem}#M~O4gAc&193MN18lU=gbmb7bK=Jc~6k-2k)onGmB+rerqfH@y%Z* zvg}I7uA2!OTO{v1IkT2W`?}KSJEy+188B{hn-*SgaoW!~WdEbYgPJQv8$|@US&Bro z%byA~S_$*Iu{W-o>bA4xb)H|gy6 zjIUbzCu8mIUT=%FekXKVv@Z7PGrs@6Ugt@@18Y?)e|hACO^>Fx2eSm#U#ijbeYh$2 zY}@*GMIzhYYM;(3?=`j)mh(GydHpVvQqCX0{*?UonmyO`PE8?~ompCYpKE{2schC$ zHSJf@*E7p=?H7B^y6wD6d)ax$yC2_YEuQk_VO5QRAxDh;|H${-&+ywAUb6WsYW-Wy zMsm56Y`U7(HuGaOvf%zsPx`=ovMbS~aMaVP33cVmy^O0KOACY4J*PCXM@-zD*X`dO21 zE;p-3&(COox$nCD61$B=#frB955Htxk4h63y|6-C^pAg|OMrc1RpS}`OVj6=H*8N-Cz`+DWwo~vaE76| literal 0 HcmV?d00001 diff --git a/fabrication/src/main/resources/assets/projectred_fabrication/textures/block/packaging_table_front_1.png b/fabrication/src/main/resources/assets/projectred_fabrication/textures/block/packaging_table_front_1.png new file mode 100644 index 0000000000000000000000000000000000000000..b968968c494fa50614687bdbea38e3a3ee396ee2 GIT binary patch literal 2379 zcmai02~-o;8lE5`f*=a0>_ebJ>B%-BEF+05VM#SCA=GF%YJfxrNG2wM#EMkVYOvZ$ z0T(DjY5Sg7MKBgz09y;?*&+(!QXU6<2+}qP`oxD8ls6L)QjVU^oICfQ|Np*!x%a$07Qi#m>LMv=pZcsX3$}JAOM&i zHl2;pTS1u1wZddJo=wGqIT?$Gd7?33Dh;Okf|yH&FAPxuxX@IAnHI~VHYx$Yx)~pY z;`gkb0AN8I!WXCn-1TrWDkY2XM9CVd9QOnSX<$s0id7;|Bh8R0VGWaLK){%ct0_d# z08yngi2`mc7=|jupdXn^rV?2eAP5F2QY0{s9Wg`4-k8Kxl}Zj%C~CEutfrGu#Wo5p zFffopg(wh2!Vo0o4w*`%A<2{;(@tLdVT+Z?3Pi3#P#K8(6(ymWDkhPL2b#TR@|4PF z1Id&#Rbll}G$J{LMy68UL=tO|x%B?R!Yyy5sSwFqXt-sXW>}2r9D}eGg~JqLkqTAt zQ8a_~cfAorna`Lj*x-zdrXZ3XY>`UL!n=q>4J6U%{MTJHO*g{KV;fQt&#-9>5|u`x z`to0Q4vC8O64fY$X{3=4d~M)ZL?g}+uo0vwSfXb(S|S^-xkKmU_`_>0p^L7XhtU9ISDdE#e#w;Z&J@^3Fc_5K&&DI$5=U^u<=a< zW9588i~i_A(Wzb@$i)Ddr(Cd@RvRE}ltHr(@jvRIf zKg#M+LR^$^n;mQXia+hr{Y~j*%^+`6X_ZbD^)PXJne8%e%VJ$fit^mWPc!el7&uVK zu=C$%>yW&}fe77u>^|nMt_+_wX z>Wk6rDRt8?#m~Xtsy^1F6;3%#9{irZ@M~WB3spF*>qH(qn#lK+PY!!QJq*FYaCZM* zZ@Xf42}gLRfnCrMCA@IpU#axE=4ZAXWoPC2(DP2cjjleyWeJwZCvnad&$UHQ_pKO= z>^j7W?{q%FLWI2B^c8*upEaDnUa;kfJ>6`g(kkst$ycjgbDVxY@_AJe5b!k@S&%Bf zRpGlN@2Vgp)${YRbL)P0@2r2eaF@x;>&td}=4*8Ud*b8zC=tze+AiaD_`(JGruO*Ku;G)1h{+Lj|h=H^S2;ap0QZtsRGD08MmcsjTv& zZyEYgn~z;Y-R1eYF07T^Lu+2`RZP05w=XhZs%QRr7nF~lof!YX4N7;BDpQm#E90u}#|7k8UiEdTZ0w8u^BW%lc0laAT{4Ahoxx?+9p z7POpS;%U)!`lE{@%?<2b>%+*6vb92qboXMfB2jM0pFs&6YUC@vC}$+0@q5xaqdeje*o9da55hEO$*0Sh2c$jpJi8_rSs9k!}9@ zIr=LMx}|eR^tBI}MckqHLzyk+*-xIoY~Qe_&Fwf#MymhbHmPK)cUxB0W|uQ(KY3W+ zC%oL!BiJc^an)SM3@=&vPTQcglGh`yE|pP>{UY^}{U5l}uQ2bWGz2(YZ_Q~^S_S-Z z`B}^Dwha;F6WPDEPfB??{rTt@Kiq{mDMKUcZ4G z_l4IFu8v;W)t%{mLv@0mwtJ}Wgr>nAPy3w9pdVFgzr2uBE$ulUrj8T5zwy7m!#QSZ zP(1Eq*4Pg}TGwuJrYTbT@55P)n&Y-P!FE%6%kb9L+EWY?x^yTvrSV1pP+85WKU@CW zp)Y&B>GG`nlHU8r#5GVJz4lgd*5auF$^W39l6z%0rF+*TFLT(Pf78bD*l9SeNzmLr sHM;9GIjiZeb8Xta#v@;Gp@t`v#7%=}>0LAIR{#Jw;nD2s(5-p@2ZPsUzW@LL literal 0 HcmV?d00001 diff --git a/fabrication/src/main/resources/assets/projectred_fabrication/textures/block/packaging_table_front_2.png b/fabrication/src/main/resources/assets/projectred_fabrication/textures/block/packaging_table_front_2.png new file mode 100644 index 0000000000000000000000000000000000000000..f2877413ebe61e1e81523cb053174c7da6c5925d GIT binary patch literal 2375 zcmah~30MVYDqC?Z%-bc?ct(B{swotjGD8-!#2w5I|cINr#|K|JN_dEXo`)3Y@ z1o>GI?T7#XSOoYBCD=^D2gwwB21h$lu!*3P`1t}w4G#U-%P=et*di7KZkTKim=P8O z#yAAK0fHT{KraJ86v2L0jwiUzV2m&f6TqH;BQ~@ImR`2ODea+iGs-?aR`d&;t&m)#ip~#u3|;BQjKe<0KfuSEC}?1m~1lB6XLKTHV6PFM@(j8 zwB`}!a?LZEjYrBeo|Cb7m?tI&0+|r#LB?EiJRlYbEbpX3nCU%@f0zycEUWQBIPsyS zJpdTjE2VN&E*3%2h>EVj6Q!rBG`J^#mkME`3Pu&=R8@jn2c>#b^au!(aW#WN)tyZ6nYAqj%Z^UOfN4l z2FPNtSTqbl)1|3VMJi3LbDDPY#*YxzMQfEBREem`xL-vSl7xCwD0raRYbH;XW;T#o zH&Yc>A0t(vVKC_+<8353RXLa5|FCe&J87tL%R6YeWtyg6jOiSC*or~|Ev!HhtrS5L z`2Vjrc#Qdsxq|i1#7K;COPWxD!hF1oXrLF3$(Fw9qG`GTW*%Fg3OvJRa%dov26{-} zbPf%~dI>a0VH#=R178~`M41XF$c0K3tkz-M!)J1NjJF!*69q^DqFtv^M8kaM48=e- zAFU4)_O37n1_L6#36KQVAqh!%=g8Dbl+WTZ-lm?ZGg~6>TfY1 z+w32nV#6QL%87IK{P5yJrU|tfZZ1UqHATfw+}2z1erZyG#X#pxIIEKX!Dz5b^$<0#+y9sU*RvR)rPgZ7oV?!5+D z-I+0mF@CJ+P81DYnL=9fVoA~?vwMA0|71QkYIgt`r0!BX((_+b+ep@HpSHUEm=%Bd zg-d9@i%(gx^76pQd?q4#+=~)^AL}@GZgs~U(IV%lnqB{D@44+V7;(4B-R@NQ9jjXDs&&r)`{&j- znJeqZ`*%A0Ob&ffQ@58?(0Db2cD}%J+jrtJ8M*WO^X^?*!RdPs0&P|=8{Hd0j)?yf zY;}COy?yXk2aRxL_6--;tv?q(*gfL0voX1~f4gJ#q)(6EK&<=oJ+~UG23Tcf3^A8; ze%K7T)&@@%R3&yucTD80i2OFJXRp&Ts5<@ZU6prO=A|6_@F$Ax(Kl)|YUsqr2qS`! zF}!{qynLkQpl)yDs_fwIlg*DT*$WFplj06PYJd9F5;iAhCaw?=@~cXxCO>nPTE|;O z3-WK4wk^1~?RC(m@?(AdqPqR!tXGMswf)jz&Jb^~f?!>0@?zmzRbCublta@(#SCyWg(R=!BOMD&UcT~3(LB_zHk*+eUj&C?O zwOcJDmFN?0?mDxLmvdU2E`$%&4A`046YFXF`5&-~E*B0(jpp3oe`g+A5d8@V{8rBD zk#l<&A6`E4@an0*w(m*)b?sEz{MS|E p{iUO6#)$TxD=e*qBfVE+IB literal 0 HcmV?d00001 diff --git a/fabrication/src/main/resources/assets/projectred_fabrication/textures/block/packaging_table_side.png b/fabrication/src/main/resources/assets/projectred_fabrication/textures/block/packaging_table_side.png new file mode 100644 index 0000000000000000000000000000000000000000..ec1a168dd5b897b9a8fc59d05069089a0107f410 GIT binary patch literal 2249 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 QhtXjx)6<_m)V+S&|C$~%-v9sr literal 0 HcmV?d00001 diff --git a/fabrication/src/main/resources/assets/projectred_fabrication/textures/block/perfboard_corner.png b/fabrication/src/main/resources/assets/projectred_fabrication/textures/block/perfboard_corner.png new file mode 100644 index 0000000000000000000000000000000000000000..2599f25a74b901977bcb7b6803f4d0354e52e4dd GIT binary patch literal 15627 zcmeI3eTWog9LLAV)FZ7(6D?|55zTXU-u89eTVHn1?!Y~-yG>7s^x2tb_eOVTww<}V zy)#2o1ECizLIWXDN>a4&kN!x(7YsrD!&2z-j|f4cgCi&^g3_MZ*SY8R9xgMYcm{TM zf6w>%{eJU&p6B_^>>snIv*X#BP4k-=hMC#k7Vkpe4?Caf51{i?KivW7Yev3pgT*kj zE;yel?>5hRoMDz7)RR4SPhyRtnmI4f%oOw%b9vO8VIs?md7y5AHk*PO-DvUraO#YQ z)wLGSdVfMlO2} zu%#~cmKM)SCn4LD=wxGN0kVFtpHl@%WP@R^==TSM(o$9uL?17RyeM;GSn>H3L0~I~ zC)$L5MG9J4>58weq(fGVr`NXg3eOJ=40s1*uUW|OVmKV;1&Nm=4)x%yLBj?`&af7g zgH+?hp`{k|yseuC>%;{qv(Ikvc$`GFqcW~szLvAy{)I~lQSlgqfB`1u&7Vq<|t*i(o!hTPy~%ti4`EQ%|g;N zv(fS@>#QPVW3kezVizZXsv8d1XCgfARG;yBJQxQyjG`6k=LDIPgrw+KBuSA3PH@(x zD@eH~79(M5dU|k73|UM{f+B_#S#-y6^~7VK9i#ypOe%`IuPctGDrvKj19nu;fehsH zMkd178(lqX>q?24S+jsH3r6J#->BK;Ra$FGyJ6YDP+@yKiW@)rrPK1mr7_2g_cvQKL}F+P6BB^=L4Y- z2SNdv13_5~q*6i22h-KiF86Vv*A{eC>p<4k$GQ5ynxa9NajDvL3$4&W*UClfw^Yr# z;Y(v%t3p;URi!*ASkT#XEuQM8tCg`@m2!MadshLfQ_rHRvn8Mw;m5SrFRSKRanr|7 z;N&QmGQ_K?bQH2!rZG-^E0TNl{RQpdyE=Rq5ZHi26!a zdx4RGT9mJjt=jNkn!CwW!Moi=4eluai@7WB#<7*LTF}Q=(ungwp`a>^Dgr1~KQY3O zYpbuCa{nHunr8b-{lftP9lYqAE3R%CciljCb<4PG-Sc@vx1&-e8`kXda-Mq1H{@>g zfDWSpzhCx8c)S_+=+uia+Y{H(ozrse2V$V&g9{BEH%#Q{5-N`6sd7C^mnvwv6+Nh< z{|J2TPr|t3TDuF~%OCX--OH$0ESdxZLN+NbG9OH(xG*4Olj0)t!BmP1141?_E;1iX zrMNI4WRv0|^TAY#3j;znDK0V}Or^LmAY_x`BJ;siiVFimHYqMLA55jVFd$@;;v)0G zREi4&LN+NbG9OH(xG*4Olj0)t!BmP1141?_E;1iXrMNI4WRv0|^TAY#3j;znDK0V} zOr^LmAY_x`BJ;siiVFimHYqMLA55jVFd$@;;v)0GREi4&LN+NbG9OH(xG*4Olj0)t z!BmP1141?_E;1iXrMNI4WRr-iss7q6G|;=Y1L&pNt=yCm^g=GHwsj>KW@sV9Y~RT+ zzuiIK-!n{~z%V157)II8FmuhfH-5ev^}W>|Uzsf4xN_~Xu~T?>H@JV{)g@D(euVuv z+daMi#l|L~PyY$<1?{KiT|HcdP9=GAF$4y&r$x`{ktr>t;U)&mY>hO!#PfM|$|?Hy7qz zdt&tLp;beJH>Mrcrd@sV!#9twXl`2bhcPYPcd&VM#%EII^sfH1FL;cbr%#<9KK=EM zt=7xT?AMnJFFSOxv(=Uk?_2cRl5^L^_oWZ^&5O-hK5}mDbB}G?^hNa8FRxsFR2bQw lIF()h)}q_H&s_PH>6-tQzjyB&E6{+M_STO0iB+3k{S#@C2d@AC literal 0 HcmV?d00001 diff --git a/fabrication/src/main/resources/assets/projectred_fabrication/textures/block/perfboard_edge.png b/fabrication/src/main/resources/assets/projectred_fabrication/textures/block/perfboard_edge.png new file mode 100644 index 0000000000000000000000000000000000000000..2baefe17ce50172f670a79a0a69cbc80cfbfc745 GIT binary patch literal 15571 zcmeI3Ux*t;9LKl*se0IAp;~AWmmG?w0cdKIyq>`pFAlihW9 zugM)%OZBA|A1qcy+agjQ`q0xNSX-qky(%K&gI2_XC<;=cRrIM3a?a-O-Xs~$S`lRy zvdM3L^Zos1KQr^&&BN{+*}QQ{-^xCQVU`RHW=7HXZT{!x#prz3?{ffs-C_@Ja~Wpo ztp8bbaLv+H4D-ONMsD02&u&sRs~iTpm51SK*+#t?Cb_n118pbt*gTvt%z@A^@4g>m z4SgW=kdhU$b{ZCq!D$DMO>fR=(>t|<9$K5~OIB4BpbS00R?8*RRjUJ`T3i+V_M7<- zTkGQO90;xR6SCvk5jJf(kX6D8rwNkC#u8ysQDQOaepV912rr1dD05;$jYL#IU>ip$ z)rWp19lfBAW;Qg^A!{I1^gLVT`AVe{uE=4_nc&4lBEbt1FG(Eg!MRhW2dbRu_Sb_n z<7A+#Ifm^SmdW~YLEf7520|e}QR`@2SJ`eQGTjC{M3Juon-{|Z-%X@zEsZ_tlxjoM zH6E5=8JeDpbYfSXU9>#QEm}QNw%k1vqdCcDTe-WAw_NU;+V$4&LI@g2yDHt>lnwb& z=vtGG2G{RGm(t(u>OG^-o}77+d{57@!>Z9k=6mY0+ES>`P!e6Mnsy-YEGK7KrBr>D zjWiLm>2z&XvG-o^Is;xD3$aFnmYH%o%LJeWV&{ZL##|l7EI5`iaTqLFm zTt1%HIFOJG(!jE9ifLE1JycE3iR*VYz#g&zqRQo z8MUfp1ILB_o*M`?H(jfYwW^e_sqI}AXns9QY5tagdXk^l+8$O**^n8X6Sy$S_4omK z?;MpPG)Wt(9;()>cM#VqcopElbrWb!ENr*eAcK4iBtUbbuVNy^oG7S5OqE+z>EE1)_Da@@z?^`3if>+9 zv*EuqcMGe6SGS3}-ckM+b64Mu^DASspm$c%r2jynqAH9k0;p9#G0AtdwO38O|F~aG zOOv(!iKu`MUi8lmY0!;Jw~?hmH!f`}x0r^Pk{a2t=77q7>Z#w5$It^hOhpw%R+2p4 zj4MWrDlCm>40Pvo{riC!ZD?>uSK+o^!hoY8tWQ#gWP9sNh(TYnNdifijG zbS;0hujpDv#bVJU7!a~aagq68UWy9?LN+NbG9S!KabZBnCdEbOgLx?~3<%kzxX64k zFU5rcA)6EznGfcrxG*4Olj0)t!Mqd~283)JkWGq<%m?#QTo@3tNpX?+ zU|xy~141?_E;1j?OL1X9$R@=_=7V`DE({3Sq`1g@FfYZ00U?_d7nu*{rMNI4WRv0| z^TE6n7Y2lEQe0#{n3v+hfRIg!i_8b}Qd}4ivPp4~`Cwj(3j;znDK0V}%u8`$K*%P= zMdpKfDJ~2M*(BoXYrl32P4up91-(?edfCMv&ITy)c5#MW?ioO&CxGDUAk9T{`B`Vn@XoLAAYxH?u~Qj-ahl? zJB#{HDA(*d{N_a1vrA6;?cneiL@UjJ?1{^`??e?3-w?W@eekC(kNd;Rgn4_`U8 zyZ_9wpJt9+K0NpAi>r*SSME7gDk@CzHbm|2Y5An0|Kq_D3%( ZjIrnQ^X%;KQ8aL7X#M8Q%!51j{t2B(@WcQB literal 0 HcmV?d00001 diff --git a/fabrication/src/main/resources/assets/projectred_fabrication/textures/block/plotting_table_bottom.png b/fabrication/src/main/resources/assets/projectred_fabrication/textures/block/plotting_table_bottom.png new file mode 100644 index 0000000000000000000000000000000000000000..d57893eb3e464042cf48213aba0f088364c3733d GIT binary patch literal 18835 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 literal 0 HcmV?d00001 diff --git a/fabrication/src/main/resources/assets/projectred_fabrication/textures/block/plotting_table_front_0.png b/fabrication/src/main/resources/assets/projectred_fabrication/textures/block/plotting_table_front_0.png new file mode 100644 index 0000000000000000000000000000000000000000..43886808528b3f6d09abd9f3a6524a1c38967e2f GIT binary patch literal 2946 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 ww?02UdT&-*Z_@9wUfbAgE&uM*=FXC z03$GV&_Pp5OK;g4no$0-F_J;UT9!481scGFth5U>6bLXNv{|=On$ecrKKU;4PK@mC<{tP(Da5T&5DKvIqFq&UN zgs!hd4#-N0Jc8?lct`*Ut=*o8F>Ed#Pa=d8$SH?q!~hvqTX9tQfUW>2a+zNMIpr|T z8S!cYl4}soA=av7NM0Z$ji9PZ5~@DV;s<;HSm9~LC;~Q>AaR0rP!wmNIf}pu14j^Q z0zS?zi;}A%t_picm~fJCkR(S#C1^ie(-%kYTFi~f&%Q2e}Cg6LBi zs?Jjs@CA^aAh1S*L2rny=Sv~rF0@Jz4<(w2@m@*MPzj`u!5+rT&w{N`0#5yNs?i369bzpm{^u^lE6qAoM}3hSD=e1WsT@d zbh50G)|0ph*)QsgWn2vO#jqwLPq+jY{I4%{Zq&Y06fhZ`tbj8F4R9Lh0nQp(5vNTC z-YF0ypbYfL)}xu4d#ocBMd8s6f-xM95!T{zB^B3-7y=8x@&p!Wgs3=Phz^Rvmje-t zElR^|kI^I=w-1&8IFJddF*pbUk_QL5Bt|vS*oy251bIKmDuz=$N?M3o3MIU^7{Irp z4%2<-ibl8LqXFX;jmU_js)&LVG?e9rEhp0CXs>kt-NuOQo>wQVKC%Sg$Lek3LjXP` zJ|%z`BISo43iov#2M97IY_n!La^LTJ^@ZF8^QXKoo7d@T3ePPv{Gr>|_cC*<_290W zMZa!7k}XspEKO&~2AV09SX+wT0(QcC~)i=9~IXTHU) z9q-=iYOXo`-oL*|TY0DU*6h}c{o7VFBK~nl7B>*`(hG;*nB0EyI#Of*-c_W)5!PJZ zoRoXKyn6r374=h2e0^<9^#}5+FD13jN}i~BxT&r%HK#ANntCL;ZhCn6v`_!lVy~{5 ziDx}3wv1O44u?aA5&jn z79QA~Z@Y1$aH_s@{u$|=+HqGe^lW>gUx(Oi$mR$+k?G# z&P_Ufs+!mO{FEcNc$vZE`>R_57IbPl0s{&c>>~Hz<($Z_$bt|TI=X~;T z9Xr!dc2l$4uSq`mLSrNItE%nZjn8D%-hF5f`sLVd=Cw^|%W8f4n4W?3tbvNV1CwTL zO+juQJGLR^$fYyE#)`YUAGr7=y14$UqP=9My!dwwOPU`mS$49%^uT>jb%3#3p7_Vr zaKnjN&5NEsZ*cUS*mq?t*Ik*^(sNYl(puiBpH8*+epvGMA|$*-OLu<%ksDWTulnTl zo0(^O%99VQ%=~@p#m~!UmcF~D{d_A^)zNggJp7xF&Q@{#&wtzDT-bM~=%d$Gk1z2Y znYy)RNg3$;_)yxox3&ClZD-p4w)2a9SC`k#zJ0;=>EpAnf7N#F+0Q2ZA_R&-}cwm&uN_drse1=8&xyVmE5`}W98YJR5q_$tA0J( Ma`LSEvX`#?54xc)AOHXW literal 0 HcmV?d00001 diff --git a/fabrication/src/main/resources/assets/projectred_fabrication/textures/block/plotting_table_printhead.png b/fabrication/src/main/resources/assets/projectred_fabrication/textures/block/plotting_table_printhead.png new file mode 100644 index 0000000000000000000000000000000000000000..7062e2ddbe62b9bc463f91113b23de5ce5566f8a GIT binary patch literal 19026 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 Ybn#W)h{81_{;xjSTRU16Sop;J4-5Y!)c^nh literal 0 HcmV?d00001 diff --git a/fabrication/src/main/resources/assets/projectred_fabrication/textures/block/plotting_table_side.png b/fabrication/src/main/resources/assets/projectred_fabrication/textures/block/plotting_table_side.png new file mode 100644 index 0000000000000000000000000000000000000000..7f46458aa9de803841eb6569dbcd095a550f248e GIT binary patch literal 2672 zcmbVOd2AF_7+(UZEmA0l$PvOg1rK0$j@_M|9l8{{Tic2YYguF~P<%V{c6Y+=%yef; zw*(F4ECeMSA_UQ3_`^VL6EHCxwFZ!?gwlv$gmQSqf&>skf*gu(_A1p98(wyHX5M$a z@ArM*`@LD?ol%n8e^h^y$&_1G>Mlq3JmbpCLjN;`d>q|!)Y1ygWEyzXxca;|ao}i^ zDVvpie%%n&VLwX`4(1g>e-K3!#n$U`Udk_>F@tI3|fse2&dSc~ln+ zOQnlraMt1(K4I}f!6D*>Q?P=-HSiaV(*tFLdJ5j0G{j z$BVg?7{pjJMFIkgQW(JR*Q*2zTEwCYAy8U z#KXF-@+4VPQ)8~Nn3Y(Fq#X_iNiihD5J-d2YGob730ccedvHTdh)Jq0DKchw1OcU5 zcj740B!sA%aVu-7G@*o%aiEg4nKB?H6h$GUr&h-ziN!^Mgb^5pvaTUrI-{$G6GRY;aYO{tCvuy_#)Ge3<+mx5jC z>}G99y2SrB=th?lXDC!uiY6$lk70P5m1ih|vhfsU1fcRBMU;ZI zX;oA^%0bYSkEVIr!qawS)}@O2N(4ISm2x5kCFWCncImY*k(x*`5?=%K^rR&w2ie8R;v{dzz%3a3^I_Wxj;Z* zVA|fT2-QY+rR_yz4=h1D%K$sUQXEHEIbb1x1y~6S%RmkU0}RJm)AloC658D$^5lMu zZs3s{6a+A~kP}DX5|e(Tu_D#UNe4@zf%Y;QDS5^J$h*X|WeH`U!7-zsk_n%M*a;<; zwb?AT)Vx=U!-(H4p?qk`K-fnm72PF>KDug{hCdCJLerI)mLiuT5K28oq$x=v6BPmF zxXYBYTJ2D@h=j?1Ix%CK9~Emr6!vYEu|y!Kw@zEI~Cq z5R#?Vz#=H(sY$7a2Jc;iCY{!VA!?}%S=f9O#Tzu?NRvfUO;dt;4T!;MA=HPx+}KG= zAq?aYMCTfblTVDOcU!hQqQ`PtuMjbaM7r}-k8l!2PS%S2cNr71M-D%PJ~4$(RO2yo zl%to-#{iU3ref%*2My#klc~?8GWRrJY3sF3$0xe0hPB=}R_PDdSG_Y*3w4Oz3+qZo z21?4d-3k}1EoYAfULWpX7ik!GYtpcdJDN+jEI+Vs^Tvml^apLW)-iVueDm$GyOX~7 ztIg4J@$Q9-&2x&JZE|1AglhssCYK=i3)9ezN*>sfT!OK>U@QehY@zT^cm> zOzx-A6?A*S)~i8b$aaU`AKzRxRn5xT z(DFjwyis-Dj*=0z*UA2avscdPx2*HssquA%m4);1aP!%sy|YJfTc_L}^GyB+Cq4`< zXvp9E{{07gC*3~1Y1_oCtgJ(?m3-|TUotS%^y9=E`@+9>>^N|K-SQzTemS@4?y05J zmn)}^-?RI`yzFyxH_fWOTR(dAhWb;|?8b+?I!DD^!;5 zs9IjJU%tNYcvHiG_4O^s%h!Lk>hRyUN2>>61vmYE)|Ah7-@7_luyvle@893Jd+n|B ejt9Ai`kMCbyx02lmbZ*=!m{ES?#7}wm;D3R0G5sb literal 0 HcmV?d00001 diff --git a/fabrication/src/main/resources/assets/projectred_fabrication/textures/block/plotting_table_top.png b/fabrication/src/main/resources/assets/projectred_fabrication/textures/block/plotting_table_top.png new file mode 100644 index 0000000000000000000000000000000000000000..b212bf3b08b762cdc310311540a0d644f90b9d7b GIT binary patch literal 16827 zcmeI4dsq|47Qj~wC?JTh>jSMZsMX?<2YDL;fvBJj55Z5kR&9c zsP&1Uwt7Xh6t#*dD7K1JYqe_Ct5$8rM?tJ#wW1<&CkcI?GiS~@ zGru`Av-x9L8W}#t!)=%w1VJ8Qq0;H#)5~&sxq$Zwg%1sUxavdWj1c5`(sK1!=j-VW zK@&gM#Kf9nWgiL^nAQ(bVsg~atkr|o5F`pT>k&mFYNE}3lzJF%tGKmi<%IsS(~IY3e5pDt6w4bZmFizsMaQ? z!~mMa5|A1zi=>8N29(P20Ai%I1P{FodLkH?xoWigm+I)h1P`om0tkj)k{7}T~G zP3#7~i401WaJqDITR0#E&=O20y^u~%O-=Pn_4mUJYC2OO5YQPcI*SE^7O*i*XF|-d z&gf%v((Xr!8WjeO-lV~FREu9kjwPD{Xf#Wpj#t~bwEB)fI%69-0cCtxPbn1FQ?vP0c%U@#{#Sx0P#{nct6hBlfe zr2qtNNF7=lW76~}eL8Byk_`%UQVJM~kE79>G^)Eg+v>9+5vS<{V~MPoCwrh;vT zL}0AK5Ce*sP${^?AcHtCg9$U(F)Wsl!xpj_FoOf~NJPiA?3`t*4;iM^sM73waA1~y z43i}Ue;h9G*WtsiCEf?fcqL*&-pPx7Tbv*3crZf@h9!w@t0uBNC8!}G)>T3sCqon( zoh47k+YPPF$j+ZqAyi=oEn*UDw1^s|>vd`oy|dD;Wk+5KL$D;w0EUT*{Y7*~)efzs zm?GJd*bsfD!p@+4wnD+;%l%;`pT~fi zOdbyw@VH!9A>i|Qawf`UapWSpW%&XZo&9Rdj<$Nou9b2=pUd`V!b%Q{XLHTxsd&IO zk1yaN43&b9{#(}|tNfIp$B4g*$7LZrn9JbvVKyJ}hY^2-4f}IhC?8SDS$sa*u`^q3 zS2Fh4iMU!)S0)pN>5L`>U=NduE&b7e{;(7XmyfWyFjvLm!fcd*!U6^lg;glRM8K#S z{w$?6ak`p!5^Qtb9v!%LO!3_&$ktCgXKw|HFlfNRgCyCt`OnzeLO5{qR;W;oB|p=; zri(Q{qtTDM)^_Hn^@z|T1|w?O00U_4J7C9|VoSNU#ItUsLPTLXT*O8s1qHCX)OB{M z!%k#tpm}>T-z~Y`GVeY{Y67b3+$%XT42ICMOA6ZeN}DTdtL~i`F_kG5F`yDPSoQC= zQQ7=&zNk`&i2oPD-}67jPNiMQ2*x+f41%c+)syQ+qYuw9|5i zPGb_Y+M?mA?W`>KJ+>n`8r-6zVlIc{&k@n_)p(0YjTudfm1@9|Y_x1bOm3SEUg6L% zt~*0JMVp~*s_bs2tvjf#7Tl_XUkUV%p9ybmt{t1-U-_kTM1Q4MoG&s64hXSG;v(jQ z(~`JwK!`;W7cn24mc)evLM)QFi22~OBrY5fVv)o}%m=3>ap8avizF^$J~%Cj3kQT) zBykb*!D&fcI3UC#iHn#IPD|p#0U;JiT*Q2ES`rry2(d`wBIbkBlDKd{h(!_?F&~_k z#DxPwERwj0`QWr9E*ubIk;FyJ2d5=*;eZf}Brak;I4y|_2ZUH8aS`*uX-Ql-AjBex zi;3KM zey(fIeAMTZEc&R2B=_hb@7&O9%SSEJ=2z`!*Rkq?CxrI)d*tR_`S2e!jkok8U-_5) ze9u1KyXi=yRQ-DGhvMVLaQemXD1XFPJ*aLLpBJ2;|ASBerBd4JvMW(54Fj>o%$gxR z=dZ4+ji*#funXRlic!2emuqno6V(#g9u3DMUApRFKRzo(`KUIwB7W-lof-4tY1J!D zJA5SLcYc-|(sUufgf#v7_|(tK=Wb}+Kl_tuyZ^kL?pFWe$;ls^y{ZbPme<`mUES0; zqJjF}^3%UEA1PB<6F2=Knc6b7dZ)Q?-WMylcaD@c96@Pv>8E-9hGY({cl|Ty-f?kl zMt;t{8}wT(>OmO`jES!z&ToIQX@1j-tWl}0OS}Ucpj|b)Kb{vf4L(T8svh~I*DdHx zV85s}LF2YBavHUGVE@Q*1Fwy}p)9x)*LvWMx`isIjgi~^mRKGyf2dSpwf6t(DzMz)>p>|e=uO((lZoFbMAr@;@$_B zTn}mVs_&h=NJwQ5-t2x(LLCv>>tbZSb6h^-b-{%X6I`URizW?8c|R2t$)@6^o5#H_ zNk>uC`R4tZ!3-dUqH!IFvS@zRqbJhq{=6piW7~W^0@kT}CO_w#J!<;r$e2?Z2u5(W7VUkWUQQ}?ZfUjI(*BFHlv%Brdwc!;XhCUmY0k<6FJ3OGhI;marcKyKNh&+x@+7;L zXxxDPcT;Yz4B0&=Y#4L=*i)k^5gBRs`erS{t=rNocG2h`RR((*6EaeW3QYXmgnE7zJC7eS+mTsp!7DxdY(m!OLl{j zvujpFd66!sbqgrNYdIBTuV#<>WQY^fM|HA~*ZbkaYuAi%PnXaiIu}P=-PLd@Kca5H zOG;jL?>y-8{lupS)66Z+Q)sJ0M>`2i?+QJy94Pv8TNI~cvU9WQ_9Jh-?@hOIr|+Np zdi?gqDskDRlgJ~*ne4#LBNwmAe7U1B%=_^B@q^wxUUFM^7QPc5?X!N{!RD{7>Q0{N z|F_MaH!IL$@vH@hUQH-IylfBuaG`G34cE-Oyv&{#hb8XqaeF;>wtR+*-{QuDRfh)G z9MhfqS{0PlG%xUZSxSA~n1>q!pGP%+@Ooll#m2LSA7(b#ke(#pCyf s`)40=pC?QN<@V#~sZ&+Yj`x5XPL;&aMi%Y2{CkD4N#WAc;JLZ~0x&&Ms{jB1 literal 0 HcmV?d00001 diff --git a/fabrication/src/main/resources/assets/projectred_fabrication/textures/gui/compile_tab.png b/fabrication/src/main/resources/assets/projectred_fabrication/textures/gui/compile_tab.png new file mode 100644 index 0000000000000000000000000000000000000000..ed92ef537e4d9fbd73c022d05a4dc562f10f32bf GIT binary patch literal 12535 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 literal 0 HcmV?d00001 diff --git a/fabrication/src/main/resources/assets/projectred_fabrication/textures/gui/ic_workbench.png b/fabrication/src/main/resources/assets/projectred_fabrication/textures/gui/ic_workbench.png new file mode 100644 index 0000000000000000000000000000000000000000..0cc012a4e069991bfabd95e5b72b487559321da1 GIT binary patch literal 29122 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 literal 0 HcmV?d00001 diff --git a/fabrication/src/main/resources/assets/projectred_fabrication/textures/gui/lithography_table.png b/fabrication/src/main/resources/assets/projectred_fabrication/textures/gui/lithography_table.png new file mode 100755 index 0000000000000000000000000000000000000000..ba9a9b67018ec09b27a3d84ae110c775fc049416 GIT binary patch literal 4313 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 Z)cN=1X1Dtt2>kB>M1)02cZV!__kR_F(+U6p literal 0 HcmV?d00001 diff --git a/fabrication/src/main/resources/assets/projectred_fabrication/textures/gui/packaging_table.png b/fabrication/src/main/resources/assets/projectred_fabrication/textures/gui/packaging_table.png new file mode 100755 index 0000000000000000000000000000000000000000..5fd023f17a33bfe8f2eefe0e1e34ec2127418d3a GIT binary patch literal 5045 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

$KzKy@<XiG&L=u|1; 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 wCw=gfFZN${oP*YQ|N8Ykf2`h3Eg;)jWXas`#�yboYBK5^fC*2fAMUA8mwE^8f$< literal 0 HcmV?d00001 diff --git a/fabrication/src/main/resources/assets/projectred_fabrication/textures/item/etched_silicon_wafer.png b/fabrication/src/main/resources/assets/projectred_fabrication/textures/item/etched_silicon_wafer.png new file mode 100755 index 0000000000000000000000000000000000000000..d159e9fb0c6fc72f6feb417e493288df3dbc2143 GIT binary patch literal 2577 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 KQ!iAt4g5b7<23L9 literal 0 HcmV?d00001 diff --git a/fabrication/src/main/resources/assets/projectred_fabrication/textures/item/ic_active.png.mcmeta b/fabrication/src/main/resources/assets/projectred_fabrication/textures/item/ic_active.png.mcmeta new file mode 100755 index 000000000..24f9c2fae --- /dev/null +++ b/fabrication/src/main/resources/assets/projectred_fabrication/textures/item/ic_active.png.mcmeta @@ -0,0 +1,5 @@ +{ + "animation": { + "frametime": 1 + } +} diff --git a/src/fabrication/resources/assets/projectred-fabrication/textures/gui/ic_workbench.png b/fabrication/src/main/resources/assets/projectred_fabrication/textures/item/ic_blueprint.png old mode 100644 new mode 100755 similarity index 68% rename from src/fabrication/resources/assets/projectred-fabrication/textures/gui/ic_workbench.png rename to fabrication/src/main/resources/assets/projectred_fabrication/textures/item/ic_blueprint.png index c87f13a1c077817d0902d972907519e8e98e4922..b55df3437118cb16f6b72ea62f1ecbce6005fc99 GIT binary patch delta 5464 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 R-ybQ+K-XBOT-zz`e*g}kBx(Qv delta 6462 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 KDgQf%pZ*GeAOFk% diff --git a/fabrication/src/main/resources/assets/projectred_fabrication/textures/item/ic_inert.png b/fabrication/src/main/resources/assets/projectred_fabrication/textures/item/ic_inert.png new file mode 100644 index 0000000000000000000000000000000000000000..58a798c994f50c88e728406514c2a46a1f7df884 GIT binary patch literal 25927 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 aFS2<3$_v`*PZyaVs3k?E?vI_%FZmyJa`*B8 literal 0 HcmV?d00001 diff --git a/fabrication/src/main/resources/assets/projectred_fabrication/textures/item/rough_silicon_wafer copy.png b/fabrication/src/main/resources/assets/projectred_fabrication/textures/item/rough_silicon_wafer copy.png new file mode 100755 index 0000000000000000000000000000000000000000..4ae83653b7503dcb6b5b2e993e9491ff7573c1d1 GIT binary patch literal 2391 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 literal 0 HcmV?d00001 diff --git a/fabrication/src/main/resources/assets/projectred_fabrication/textures/item/valid_die.png.mcmeta b/fabrication/src/main/resources/assets/projectred_fabrication/textures/item/valid_die.png.mcmeta new file mode 100755 index 000000000..24f9c2fae --- /dev/null +++ b/fabrication/src/main/resources/assets/projectred_fabrication/textures/item/valid_die.png.mcmeta @@ -0,0 +1,5 @@ +{ + "animation": { + "frametime": 1 + } +} diff --git a/fabrication/src/main/resources/assets/projectred_fabrication/textures/item/valid_die_template.png b/fabrication/src/main/resources/assets/projectred_fabrication/textures/item/valid_die_template.png new file mode 100755 index 0000000000000000000000000000000000000000..6554fd3f689faa41dc45c7b5f908a1623b673239 GIT binary patch literal 3129 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 C1gm%e literal 0 HcmV?d00001 diff --git a/fabrication/src/main/resources/pack.mcmeta b/fabrication/src/main/resources/pack.mcmeta new file mode 100644 index 000000000..a4e32f532 --- /dev/null +++ b/fabrication/src/main/resources/pack.mcmeta @@ -0,0 +1,6 @@ +{ + "pack": { + "pack_format": 4, + "description": "Project Red resource pack" + } +} diff --git a/integration/src/main/java/mrtjp/projectred/integration/GateType.java b/integration/src/main/java/mrtjp/projectred/integration/GateType.java index 62957f126..c008a03ec 100644 --- a/integration/src/main/java/mrtjp/projectred/integration/GateType.java +++ b/integration/src/main/java/mrtjp/projectred/integration/GateType.java @@ -49,10 +49,11 @@ public enum GateType TRANSPARENT_LATCH_CELL(ID_STACKING_LATCH, ArrayGatePart.TransparentLatchCell::new), SEGMENT_DISPLAY (ID_SEGMENT_DISPLAY, BundledGatePart.SegmentDisplay::new), DEC_RANDOMIZER (ID_DEC_RANDOMIZER, SimpleGatePart.DecodingRandomizer::new), + FABRICATED_GATE (null, null), // Will be injected if applicable ; - private final String unlocalName; - private final Function partFactory; + private String unlocalName; + private Function partFactory; private RegistryObject itemSupplier; private RegistryObject> partSupplier; @@ -62,6 +63,10 @@ public enum GateType this.partFactory = partFactory; } + public boolean isEnabled() { + return partFactory != null; + } + public String getUnlocalizedName() { return unlocalName; } @@ -86,4 +91,15 @@ public void registerParts(DeferredRegister> partRegistry, Defer itemSupplier = itemRegistry.register(unlocalName, () -> new GatePartItem(this)); partSupplier = partRegistry.register(unlocalName, () -> new SimpleMultipartType<>(isClient -> partFactory.apply(this))); } + + // TODO: Add proper gate registering mechanism + public void inject(String unlocalName, Function partFactory, RegistryObject itemSupplier, RegistryObject> partSupplier) { + if (this.itemSupplier != null || this.partSupplier != null) { + throw new RuntimeException("GateType " + name() + " already registered!"); + } + this.unlocalName = unlocalName; + this.partFactory = partFactory; + this.itemSupplier = itemSupplier; + this.partSupplier = partSupplier; + } } diff --git a/integration/src/main/java/mrtjp/projectred/integration/client/GateComponentModels.java b/integration/src/main/java/mrtjp/projectred/integration/client/GateComponentModels.java index fb4e22f2e..fa71c3043 100644 --- a/integration/src/main/java/mrtjp/projectred/integration/client/GateComponentModels.java +++ b/integration/src/main/java/mrtjp/projectred/integration/client/GateComponentModels.java @@ -56,9 +56,9 @@ public class GateComponentModels { public static Map sixteenSeg = loadModels("array/16seg"); public static CCModel segbus = loadModel("array/segbus"); - public static CCModel icChip = loadModel("icchip").apply(new Translation(8 / 16D, 2 / 16D, 8 / 16D)); - public static CCModel icGlass = loadModel("icglass").apply(new Translation(8 / 16D, 0, 8 / 16D)); - public static CCModel icHousing = loadModel("ichousing").apply(new Translation(8 / 16D, 0, 8 / 16D)); + public static Map fabIC = loadModels("fab_ic", (k, v) -> v.apply(new Translation(0.5, 0, 0.5))); + public static Map ioCrimp = loadModels("io_crimp"); + public static Map ioColourBox = loadModels("io_colour_box"); public static IconTransformation baseIcon; public static IconTransformation wireBorderIcon; @@ -93,6 +93,8 @@ public class GateComponentModels { public static IconTransformation icChipIcon; public static IconTransformation icChipIconOff; public static IconTransformation icHousingIcon; + public static IconTransformation ioCrimpConnectorIcon; + public static IconTransformation ioColourBoxIcon; public static void registerIcons(AtlasRegistrar registrar) { //@formatter:off @@ -133,6 +135,8 @@ public static void registerIcons(AtlasRegistrar registrar) { registrar.registerSprite(new ResourceLocation(MOD_ID, "block/ic_active"), i -> icChipIcon = new IconTransformation(i)); registrar.registerSprite(new ResourceLocation(MOD_ID, "block/ic_inert"), i -> icChipIconOff = new IconTransformation(i)); registrar.registerSprite(new ResourceLocation(MOD_ID, "block/ic_housing"), i -> icHousingIcon = new IconTransformation(i)); + registrar.registerSprite(new ResourceLocation(MOD_ID, "block/io_crimp"), i -> ioCrimpConnectorIcon = new IconTransformation(i)); + registrar.registerSprite(new ResourceLocation(MOD_ID, "block/io_colour_box"), i -> ioColourBoxIcon = new IconTransformation(i)); //@formatter:on } @@ -1428,6 +1432,136 @@ protected UVTransformation getUVT() { } } + public static class SidedICBundledCableModel extends BundledCableModel { + + public int sidemask = 0; + + public SidedICBundledCableModel() { + super(icBundled, new Vector3(8, 0, 8), 7 / 32D, 12 / 32D); + } + + @Override + protected UVTransformation getUVT() { + return busConvIcon; + } + + @Override + public void renderModel(Transformation t, int orient, CCRenderState ccrs) { + for (int r = 0; r < 4; r++) { + if ((sidemask & 1 << r) != 0) { + super.renderModel(t, orient & 0xFC | ((orient & 3) + r) % 4, ccrs); + } + } + } + } + + public static class SidedWireModel extends ComponentModel { + + public int sidemask = 0; + + public final WireModel[] wires; + + public SidedWireModel(WireModel[] wires) { + this.wires = wires; + } + + @Override + public void renderModel(Transformation t, int orient, CCRenderState ccrs) { + for (int r = 0; r < 4; r++) { + if ((sidemask & 1 << r) != 0) { + wires[r].renderModel(t, orient, ccrs); + } + } + } + } + + public static class FabricatedICModel extends ComponentModel { + + public static final FabricatedICModel INSTANCE = new FabricatedICModel(); + + private static final CCModel[] platformModel = bakeOrients(fabIC.get("platform")); + private static final CCModel[] icChipModel = bakeOrients(fabIC.get("ic")); + + @Override + public void renderModel(Transformation t, int orient, CCRenderState ccrs) { + platformModel[orient].render(ccrs, t, icHousingIcon); + icChipModel[orient].render(ccrs, t, icChipIcon); + } + + public void renderDynamic(Transformation t, CCRenderState ccrs) { + fabIC.get("glass").render(ccrs, t, icHousingIcon); + } + } + + public static class IOCrimpConnectorModel extends StaticComponentModel { + + public static final IOCrimpConnectorModel INSTANCE = new IOCrimpConnectorModel(); + + private IOCrimpConnectorModel() { + super(ioCrimp.get("crimp") + .copy() + .apply(new Translation(0.5, 2/16D, 0.5))); + } + + @Override + protected UVTransformation getUVT() { + return ioCrimpConnectorIcon; + } + } + + public static class IOCrimpWireModel extends CellWireModel { + + private static final CCModel[] models = bakeOrients(ioCrimp.get("redalloy").copy().apply(new Translation(0.5, 2/16D, 0.5))); + + private IconTransformation getUVT() { + return ioCrimpConnectorIcon; + } + + @Override + public void renderModel(Transformation t, int orient, CCRenderState ccrs) { + models[orient].render(ccrs, t, getUVT(), colourMult()); + } + } + + public static class IOCrimpColourBoxModel extends ComponentModel { + + public int colour = EnumColour.WHITE.ordinal(); + public boolean isInput = true; + + private final CCModel[] boxModels; + private final CCModel[] inputArrowModels; + private final CCModel[] outputArrowModels; + + public IOCrimpColourBoxModel(double x, double z) { + + CCModel m = ioColourBox.get("box").copy().apply(new Translation(x/16D, 2/16D, z/16D)); + boxModels = bakeOrients(m); + + m = ioColourBox.get("arrow").copy().apply(new Translation(x/16D, 2/16D, z/16D)); + inputArrowModels = bakeOrients(m); + + m = ioColourBox.get("arrow").copy() + .apply(new Rotation(180 * MathHelper.torad, 0, 1, 0)) + .apply(new Translation(x/16D, 2/16D, z/16D)); + outputArrowModels = bakeOrients(m); + } + + private UVTransformation getColourUVT() { + return new UVTranslation((colour%2) * 4 / 32D, (colour/2) * 4 / 32D).with(ioColourBoxIcon); + } + + private UVTransformation getBoxUVT() { + return ioColourBoxIcon; + } + + @Override + public void renderModel(Transformation t, int orient, CCRenderState ccrs) { + boxModels[orient].render(ccrs, t, getBoxUVT()); + (isInput ? inputArrowModels : outputArrowModels)[orient].render(ccrs, t, getColourUVT()); + } + } + + private static class RedundantUVTransformation extends UVTransformation { public static final RedundantUVTransformation INSTANCE = new RedundantUVTransformation(); @@ -1469,5 +1603,4 @@ public UVTransformation copy() { return this; } } - } diff --git a/integration/src/main/java/mrtjp/projectred/integration/client/GateModelRenderer.java b/integration/src/main/java/mrtjp/projectred/integration/client/GateModelRenderer.java index 672a50764..e19a5f07f 100644 --- a/integration/src/main/java/mrtjp/projectred/integration/client/GateModelRenderer.java +++ b/integration/src/main/java/mrtjp/projectred/integration/client/GateModelRenderer.java @@ -66,6 +66,11 @@ public static GateModelRenderer instance() { new RenderTransparentLatchCell(), new RenderSegmentDisplay(), new RenderDecodingRandomizer(), + new RenderFabricatedGate(), + }; + + private final GateRenderer[] nonPartRenderers = new GateRenderer[] { + new RenderIOGate(), }; //region Static rendering @@ -132,10 +137,17 @@ public void spawnParticles(GatePart part, Random random) { r.spawnParticles(part, random); } + public static int getRenderIndex(GateType type) { + return type.ordinal(); + } + + public static int getNonPartRenderIndex(int i) { + return 0x100 | i; + } + private GateRenderer getRenderer(int renderIndex) { if ((renderIndex & 0x100) != 0) { - //TODO return non-gate renders - return null; + return nonPartRenderers[renderIndex & 0xFF]; } else { return renderers[renderIndex]; } @@ -1505,14 +1517,14 @@ protected void prepareInventory() { @Override protected void prepare(IGateRenderData gate) { - boolean on = (gate.state()&0x10) != 0; + boolean on = (gate.state() & 0x10) != 0; topWire.signal = gate.topSignal(); topWire.conn = gate.topSignalConnMask() & ~0x2; // Always render left side wires[0].on = !on; wires[1].on = gate.topSignal() != 0; wires[2].on = gate.topSignal() == 0; wires[3].on = on; - wires[4].on = (gate.state()&4) != 0; + wires[4].on = (gate.state() & 4) != 0; torches[0].on = wires[2].on; torches[1].on = !wires[2].on && !wires[4].on; torches[2].on = !wires[1].on && !wires[3].on; @@ -1831,4 +1843,108 @@ protected void prepare(IGateRenderData gate) { chips[2].on = true; } } + + public static class RenderFabricatedGate extends GateRenderer { + + private final List models = new LinkedList<>(); + + private final SidedWireModel simpleWires = new SidedWireModel(generateWireModels("ic1", 4)); + private final SidedWireModel analogWires = new SidedWireModel(generateWireModels("ic2", 4)); + private final SidedICBundledCableModel bundledWires = new SidedICBundledCableModel(); + private final FabricatedICModel icHousing = FabricatedICModel.INSTANCE; + + private String name = "untitled"; + + public RenderFabricatedGate() { + models.add(BaseComponentModel.INSTANCE); + models.add(simpleWires); + models.add(analogWires); + models.add(bundledWires); + models.add(icHousing); + } + + @Override + protected List getModels() { + return models; + } + + @Override + protected void prepareInventory() { + //TODO load from stack + name = "ERROR!"; + simpleWires.sidemask = 0; + analogWires.sidemask = 0; + bundledWires.sidemask = 0; + } + + @Override + protected void prepare(IGateRenderData gate) { + + //TODO + simpleWires.sidemask = 0; + analogWires.sidemask = 0; + bundledWires.sidemask = gate.state2() & 0xF | (gate.state2() >> 4) & 0xF; + + simpleWires.wires[0].on = (gate.state() & 0x11) != 0; + simpleWires.wires[1].on = (gate.state() & 0x22) != 0; + simpleWires.wires[2].on = (gate.state() & 0x44) != 0; + simpleWires.wires[3].on = (gate.state() & 0x88) != 0; + + analogWires.wires[0].on = simpleWires.wires[0].on; + analogWires.wires[1].on = simpleWires.wires[1].on; + analogWires.wires[2].on = simpleWires.wires[2].on; + analogWires.wires[3].on = simpleWires.wires[3].on; + } + + @Override + public boolean hasSpecials() { + return true; + } + + @Override + protected void prepareDynamic(IGateRenderData gate, float partialFrame) { + // TODO set name string + } + + @Override + public void renderDynamic(CCRenderState ccrs, Transformation t) { + icHousing.renderDynamic(t, ccrs); + } + } + + public static class RenderIOGate extends GateRenderer { + + private final List models = new LinkedList<>(); + + private final WireModel[] wires = generateWireModels("fabio", 1); + private final IOCrimpWireModel crimpWire = new IOCrimpWireModel(); + private final IOCrimpColourBoxModel colourBox = new IOCrimpColourBoxModel(3, 10.5); + + public RenderIOGate() { + models.add(BaseComponentModel.INSTANCE); + models.addAll(Arrays.asList(wires)); + models.add(IOCrimpConnectorModel.INSTANCE); + models.add(crimpWire); + models.add(colourBox); + } + + @Override + protected List getModels() { + return models; + } + + @Override + protected void prepareInventory() { + crimpWire.signal = 0; + colourBox.colour = 0; + } + + @Override + protected void prepare(IGateRenderData gate) { + wires[0].on = (gate.state() & 0x44) != 0; + crimpWire.signal = (byte) (wires[0].on ? 255 : 0); + colourBox.colour = gate.state2() & 0xF; + colourBox.isInput = gate.shape() == 0; + } + } } diff --git a/integration/src/main/java/mrtjp/projectred/integration/data/IntegrationItemModelProvider.java b/integration/src/main/java/mrtjp/projectred/integration/data/IntegrationItemModelProvider.java index 27fe3d2b5..a78c6b28f 100644 --- a/integration/src/main/java/mrtjp/projectred/integration/data/IntegrationItemModelProvider.java +++ b/integration/src/main/java/mrtjp/projectred/integration/data/IntegrationItemModelProvider.java @@ -28,6 +28,7 @@ protected void registerModels() { ModelFile.ExistingModelFile gate = getExistingFile(new ResourceLocation(MOD_ID, "item/gate")); for (GateType type : GateType.values()) { + if (!type.isEnabled()) continue; getSimple(type.getItem()).noTexture().parent(gate); } } diff --git a/integration/src/main/java/mrtjp/projectred/integration/init/IntegrationClientInit.java b/integration/src/main/java/mrtjp/projectred/integration/init/IntegrationClientInit.java index 8eb0ac12d..ce8428ea8 100644 --- a/integration/src/main/java/mrtjp/projectred/integration/init/IntegrationClientInit.java +++ b/integration/src/main/java/mrtjp/projectred/integration/init/IntegrationClientInit.java @@ -49,6 +49,7 @@ private static void clientSetup(final FMLClientSetupEvent event) { // Register part item renderers for (GateType type : GateType.values()) { + if (!type.isEnabled()) continue; MultipartClientRegistry.register(type.getPartType(), GatePartRenderer.INSTANCE); } diff --git a/integration/src/main/java/mrtjp/projectred/integration/init/IntegrationParts.java b/integration/src/main/java/mrtjp/projectred/integration/init/IntegrationParts.java index ac25e86ce..fd8878c35 100644 --- a/integration/src/main/java/mrtjp/projectred/integration/init/IntegrationParts.java +++ b/integration/src/main/java/mrtjp/projectred/integration/init/IntegrationParts.java @@ -44,6 +44,7 @@ public class IntegrationParts { public static void register() { for (GateType type : GateType.values()) { + if (!type.isEnabled()) continue; type.registerParts(PARTS, ITEMS); } } diff --git a/integration/src/main/java/mrtjp/projectred/integration/part/BundledGatePart.java b/integration/src/main/java/mrtjp/projectred/integration/part/BundledGatePart.java index e2b68d207..c483bb681 100644 --- a/integration/src/main/java/mrtjp/projectred/integration/part/BundledGatePart.java +++ b/integration/src/main/java/mrtjp/projectred/integration/part/BundledGatePart.java @@ -606,7 +606,7 @@ protected int inputMask(int shape) { } @Override - int getOutput(int r) { + protected int getOutput(int r) { return shape() != 0 && r == 2 ? rsOut : (state() & 0x10 << r) != 0 ? 0xF : 0; } @@ -805,7 +805,7 @@ protected int inputMask(int shape) { } @Override - int getOutput(int r) { + protected int getOutput(int r) { //TODO same as super. Dont override? return (state() & 0x10 << r) != 0 ? 15 : 0; } @@ -953,7 +953,7 @@ protected int bundledInputMask(int shape) { } @Override - int getOutput(int r) { + protected int getOutput(int r) { return 0; // Super derives output from state, but we store colour in that } diff --git a/integration/src/main/java/mrtjp/projectred/integration/part/ComplexGatePart.java b/integration/src/main/java/mrtjp/projectred/integration/part/ComplexGatePart.java index f47f961fb..1a2671917 100644 --- a/integration/src/main/java/mrtjp/projectred/integration/part/ComplexGatePart.java +++ b/integration/src/main/java/mrtjp/projectred/integration/part/ComplexGatePart.java @@ -1054,7 +1054,7 @@ protected boolean gateLogicCanConnect(int r) { } @Override - int getOutput(int r) { + protected int getOutput(int r) { return r == 0 ? state2() & 0xF : 0; } //endregion diff --git a/integration/src/main/java/mrtjp/projectred/integration/part/GatePart.java b/integration/src/main/java/mrtjp/projectred/integration/part/GatePart.java index fa0fae968..6b7909421 100644 --- a/integration/src/main/java/mrtjp/projectred/integration/part/GatePart.java +++ b/integration/src/main/java/mrtjp/projectred/integration/part/GatePart.java @@ -9,7 +9,6 @@ import codechicken.lib.vec.Vector3; import codechicken.microblock.part.face.FaceMicroblockPart; import codechicken.multipart.api.MultipartType; -import codechicken.multipart.api.NormalOcclusionTest; import codechicken.multipart.api.part.*; import codechicken.multipart.block.TileMultipart; import codechicken.multipart.util.PartRayTraceResult; @@ -21,7 +20,6 @@ import mrtjp.projectred.core.part.IConnectableFacePart; import mrtjp.projectred.integration.GateType; import mrtjp.projectred.integration.client.GateComponentModels; -import net.minecraft.client.particle.ParticleEngine; import net.minecraft.client.renderer.texture.TextureAtlasSprite; import net.minecraft.core.BlockPos; import net.minecraft.core.Direction; @@ -31,7 +29,6 @@ import net.minecraft.world.entity.player.Player; import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.context.UseOnContext; -import net.minecraft.world.level.Level; import net.minecraft.world.level.block.SoundType; import net.minecraft.world.level.chunk.LevelChunk; import net.minecraft.world.phys.shapes.CollisionContext; @@ -357,12 +354,16 @@ public MultipartType getType() { //region Items and drops @Override public ItemStack getCloneStack(PartRayTraceResult hit) { - return getGateType().makeStack(); + return getItem(); } @Override public Iterable getDrops() { - return Collections.singleton(getGateType().makeStack()); + return Collections.singleton(getItem()); + } + + protected ItemStack getItem() { + return getGateType().makeStack(); } //endregion diff --git a/integration/src/main/java/mrtjp/projectred/integration/part/RedstoneGatePart.java b/integration/src/main/java/mrtjp/projectred/integration/part/RedstoneGatePart.java index 3d91951fa..9aeec01b4 100644 --- a/integration/src/main/java/mrtjp/projectred/integration/part/RedstoneGatePart.java +++ b/integration/src/main/java/mrtjp/projectred/integration/part/RedstoneGatePart.java @@ -239,11 +239,11 @@ protected int inputMask(int shape) { return 0; } - int getOutput(int r) { + protected int getOutput(int r) { return (getState() & 0x10 << r) != 0 ? 15 : 0; } - int getInput(int mask) { + protected int getInput(int mask) { int input = 0; for (int r = 0; r < 4; r++) { if ((mask & 1 << r) != 0 && getRedstoneInput(r) > 0) { diff --git a/integration/src/main/java/mrtjp/projectred/integration/part/SimpleGatePart.java b/integration/src/main/java/mrtjp/projectred/integration/part/SimpleGatePart.java index 0fce8fce4..a72c6c9bb 100644 --- a/integration/src/main/java/mrtjp/projectred/integration/part/SimpleGatePart.java +++ b/integration/src/main/java/mrtjp/projectred/integration/part/SimpleGatePart.java @@ -548,7 +548,7 @@ protected int cycleShape(int shape) { } @Override - int getOutput(int r) { + protected int getOutput(int r) { return r == 2 ? state() >> 4 : 0; } diff --git a/integration/src/main/resources/assets/projectred_integration/obj/array/icbundled.blend b/integration/src/main/resources/assets/projectred_integration/obj/array/icbundled.blend index e6d6533b7aa89c90e2f6df2fecfa718e39d38ce3..56b9b4273dcdd9a466db5f3315a060f3d848459b 100644 GIT binary patch literal 632108 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

W_T~VPwDi1zZYU<4hXw3>@r1T!;g4>Hnd|g?PF8 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 STglH_{z|nfmgnZZzyAjb|Dvq` literal 0 HcmV?d00001 diff --git a/integration/src/main/resources/assets/projectred_integration/obj/io_colour_box.obj b/integration/src/main/resources/assets/projectred_integration/obj/io_colour_box.obj new file mode 100644 index 000000000..794e94787 --- /dev/null +++ b/integration/src/main/resources/assets/projectred_integration/obj/io_colour_box.obj @@ -0,0 +1,54 @@ +# Blender v3.1.2 OBJ File: 'io_colour_box.blend' +# www.blender.org +g box +v -0.125000 0.125000 -0.125000 +v -0.125000 0.000000 -0.125000 +v 0.125000 0.125000 -0.125000 +v 0.125000 0.000000 -0.125000 +v -0.125000 0.125000 0.125000 +v -0.125000 -0.000000 0.125000 +v 0.125000 0.125000 0.125000 +v 0.125000 -0.000000 0.125000 +vt 0.437500 0.875000 +vt 0.437500 1.000000 +vt 0.125000 1.000000 +vt 0.125000 0.875000 +vt 0.437500 0.562500 +vt 0.125000 0.562500 +vt 0.125000 0.437500 +vt 0.437500 0.437500 +vt 0.562500 0.562500 +vt 0.562500 0.875000 +vt 0.000000 0.875000 +vt 0.000000 0.562500 +s off +f 3/1 4/2 2/3 1/4 +f 7/5 5/6 6/7 8/8 +f 3/1 7/5 8/9 4/10 +f 2/11 6/12 5/6 1/4 +f 1/4 5/6 7/5 3/1 +g arrow +v -0.100000 0.165063 -0.100000 +v -0.100000 0.124000 -0.100000 +v 0.100000 0.165063 -0.100000 +v 0.100000 0.124000 -0.100000 +v 0.000000 0.165062 0.100000 +v 0.000000 0.124000 0.100000 +vt 0.875000 0.968750 +vt 0.875000 1.000000 +vt 0.750000 1.000000 +vt 0.750000 0.968750 +vt 0.843750 1.000000 +vt 0.843750 0.875000 +vt 0.875000 0.875000 +vt 0.750000 0.875000 +vt 0.781250 0.875000 +vt 0.781250 1.000000 +vt 0.750000 1.000000 +vt 0.812500 0.875000 +vt 0.875000 1.000000 +s off +f 11/13 12/14 10/15 9/16 +f 11/17 13/18 14/19 12/14 +f 10/15 14/20 13/21 9/22 +f 9/23 13/24 11/25 diff --git a/integration/src/main/resources/assets/projectred_integration/obj/io_crimp.blend b/integration/src/main/resources/assets/projectred_integration/obj/io_crimp.blend new file mode 100644 index 0000000000000000000000000000000000000000..0a8a16ee22bbb382e04010bdf17fb792f9e7df9c GIT binary patch literal 626072 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�o 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 literal 0 HcmV?d00001 diff --git a/integration/src/main/resources/assets/projectred_integration/obj/io_crimp.obj b/integration/src/main/resources/assets/projectred_integration/obj/io_crimp.obj new file mode 100644 index 000000000..bcd58d242 --- /dev/null +++ b/integration/src/main/resources/assets/projectred_integration/obj/io_crimp.obj @@ -0,0 +1,233 @@ +# Blender v3.1.2 OBJ File: 'io_crimp.blend' +# www.blender.org +g crimp +v 0.437500 0.031250 -0.187510 +v 0.437500 -0.031250 -0.187510 +v 0.000000 0.031250 -0.187510 +v 0.000000 -0.031250 -0.187510 +v 0.437500 0.031250 0.000010 +v 0.437500 -0.031250 0.000010 +v 0.000000 0.031250 0.000010 +v 0.000000 -0.031250 0.000010 +v 0.000010 -0.031250 -0.062500 +v 0.000010 0.156250 -0.062500 +v 0.125010 -0.031250 -0.062500 +v 0.125010 0.156250 -0.062500 +v 0.000010 -0.031250 0.000000 +v 0.000010 0.156250 0.000000 +v 0.125010 -0.031250 0.000000 +v 0.125010 0.156250 -0.000000 +v 0.000010 -0.031250 -0.187500 +v 0.000010 0.156250 -0.187500 +v 0.125010 -0.031250 -0.187500 +v 0.125010 0.156250 -0.187500 +v 0.000010 -0.031250 -0.125000 +v 0.000010 0.156250 -0.125000 +v 0.125010 -0.031250 -0.125000 +v 0.125010 0.156250 -0.125000 +v -0.406250 0.062500 -0.468750 +v -0.406250 -0.031250 -0.468750 +v 0.406250 0.062500 -0.468750 +v 0.406250 -0.031250 -0.468750 +v -0.406250 0.062500 -0.218750 +v -0.406250 -0.031250 -0.218750 +v 0.406250 0.062500 -0.218750 +v 0.406250 -0.031250 -0.218750 +v 0.212500 0.062500 -0.218750 +v 0.212500 -0.031250 -0.218750 +v 0.406250 0.062500 -0.218750 +v 0.406250 -0.031250 -0.218750 +v 0.212500 0.062500 0.031250 +v 0.212500 -0.031250 0.031250 +v 0.406250 0.062500 0.031250 +v 0.406250 -0.031250 0.031250 +v 0.281250 0.093750 -0.125000 +v 0.281250 -0.031250 -0.125000 +v 0.343750 0.093750 -0.125000 +v 0.343750 -0.031250 -0.125000 +v 0.281250 0.093750 -0.062500 +v 0.281250 -0.031250 -0.062500 +v 0.343750 0.093750 -0.062500 +v 0.343750 -0.031250 -0.062500 +vt 0.000000 0.968750 +vt 0.031250 0.968750 +vt 0.031250 0.750000 +vt 0.000000 0.750000 +vt 0.031250 0.750000 +vt 0.031250 0.718750 +vt 0.125000 0.718750 +vt 0.125000 0.750000 +vt 0.156250 0.750000 +vt 0.156250 0.968750 +vt 0.125000 0.968750 +vt 0.031250 0.968750 +vt 0.281250 0.531250 +vt 0.375000 0.531250 +vt 0.375000 0.593750 +vt 0.281250 0.593750 +vt 0.375000 0.625000 +vt 0.281250 0.625000 +vt 0.531250 0.593750 +vt 0.437500 0.593750 +vt 0.437500 0.531250 +vt 0.531250 0.531250 +vt 0.281250 0.500000 +vt 0.375000 0.500000 +vt 0.000000 0.531250 +vt 0.093750 0.531250 +vt 0.093750 0.593750 +vt 0.000000 0.593750 +vt 0.250000 0.625000 +vt 0.156250 0.625000 +vt 0.156250 0.593750 +vt 0.250000 0.593750 +vt 0.156250 0.531250 +vt 0.250000 0.531250 +vt 0.156250 0.500000 +vt 0.250000 0.500000 +vt 0.093750 0.531250 +vt 0.156250 0.531250 +vt 0.156250 0.593750 +vt 0.093750 0.593750 +vt 0.593750 0.968750 +vt 0.593750 1.000000 +vt 0.187500 1.000000 +vt 0.187500 0.968750 +vt 0.593750 0.843750 +vt 0.187500 0.843750 +vt 0.187500 0.812500 +vt 0.593750 0.812500 +vt 0.625000 0.843750 +vt 0.625000 0.968750 +vt 0.156250 0.968750 +vt 0.156250 0.843750 +vt 0.125000 1.000000 +vt 0.031250 1.000000 +vt 0.593750 0.656250 +vt 0.500000 0.656250 +vt 0.500000 0.625000 +vt 0.593750 0.625000 +vt 0.593750 0.781250 +vt 0.625000 0.656250 +vt 0.625000 0.781250 +vt 0.468750 0.781250 +vt 0.468750 0.656250 +vt 0.500000 0.781250 +vt 0.406250 0.750000 +vt 0.406250 0.781250 +vt 0.375000 0.781250 +vt 0.375000 0.750000 +vt 0.406250 0.718750 +vt 0.375000 0.718750 +vt 0.375000 0.687500 +vt 0.406250 0.687500 +vt 0.437500 0.718750 +vt 0.437500 0.750000 +vt 0.343750 0.750000 +vt 0.343750 0.718750 +s off +f 1/1 2/2 4/3 3/4 +f 3/5 4/6 8/7 7/8 +f 7/8 8/9 6/10 5/11 +f 3/5 7/8 5/11 1/12 +f 9/13 10/14 12/15 11/16 +f 11/16 12/15 16/17 15/18 +f 15/19 16/20 14/21 13/22 +f 13/23 14/24 10/14 9/13 +f 16/20 12/15 10/14 14/21 +f 17/25 18/26 20/27 19/28 +f 19/29 20/30 24/31 23/32 +f 23/32 24/31 22/33 21/34 +f 21/34 22/33 18/35 17/36 +f 24/37 20/38 18/39 22/40 +f 27/41 28/42 26/43 25/44 +f 31/45 29/46 30/47 32/48 +f 27/41 31/45 32/49 28/50 +f 26/51 30/52 29/46 25/44 +f 25/44 29/46 31/45 27/41 +f 1/12 5/11 6/53 2/54 +f 39/55 37/56 38/57 40/58 +f 35/59 39/55 40/60 36/61 +f 34/62 38/63 37/56 33/64 +f 33/64 37/56 39/55 35/59 +f 43/65 44/66 42/67 41/68 +f 47/69 45/70 46/71 48/72 +f 43/65 47/69 48/73 44/74 +f 42/75 46/76 45/70 41/68 +f 41/68 45/70 47/69 43/65 +g redalloy +v -0.125000 -0.062500 -0.156250 +v -0.125000 0.125000 -0.156250 +v 0.187500 -0.062500 -0.156250 +v 0.187500 0.125000 -0.156250 +v -0.125000 -0.062500 -0.031250 +v -0.125000 0.125000 -0.031250 +v 0.187500 -0.062500 -0.031250 +v 0.187500 0.125000 -0.031250 +v -0.375100 -0.109375 -0.156250 +v -0.375100 0.015625 -0.156250 +v -0.125000 -0.109375 -0.156250 +v -0.125000 0.015625 -0.156250 +v -0.375100 -0.109375 -0.031250 +v -0.375100 0.015625 -0.031250 +v -0.125000 -0.109375 -0.031250 +v -0.125000 0.015625 -0.031250 +v 0.336056 -0.000000 0.180101 +v -0.375000 -0.109375 0.093750 +v -0.375000 0.015625 0.093750 +v -0.375000 -0.109375 -0.031250 +v -0.375000 0.015625 -0.031250 +v -0.250000 -0.109375 0.093750 +v -0.250000 0.015625 0.093750 +v -0.250000 -0.109375 -0.031250 +v -0.250000 0.015625 -0.031250 +vt 0.281250 0.468750 +vt 0.281250 0.375000 +vt 0.437500 0.375000 +vt 0.437500 0.468750 +vt 0.531250 0.375000 +vt 0.437500 0.312500 +vt 0.531250 0.312500 +vt 0.437500 0.218750 +vt 0.281250 0.312500 +vt 0.281250 0.218750 +vt 0.187500 0.312500 +vt 0.187500 0.375000 +vt 0.062500 0.437500 +vt 0.062500 0.375000 +vt 0.187500 0.375000 +vt 0.187500 0.437500 +vt 0.187500 0.250000 +vt 0.187500 0.312500 +vt 0.062500 0.312500 +vt 0.062500 0.250000 +vt 0.000000 0.312500 +vt 0.000000 0.375000 +vt 0.000000 0.125000 +vt 0.062500 0.125000 +vt 0.062500 0.187500 +vt 0.000000 0.187500 +vt 0.187500 0.187500 +vt 0.125000 0.187500 +vt 0.125000 0.125000 +vt 0.187500 0.125000 +vt 0.125000 0.062500 +vt 0.062500 0.062500 +vt 0.125000 0.250000 +vt 0.062500 0.250000 +vt 0.062500 0.187500 +vt 0.125000 0.187500 +s off +f 49/77 50/78 52/79 51/80 +f 51/81 52/79 56/82 55/83 +f 55/84 56/82 54/85 53/86 +f 53/87 54/85 50/78 49/88 +f 57/89 58/90 60/91 59/92 +f 56/82 52/79 50/78 54/85 +f 63/93 64/94 62/95 61/96 +f 61/97 62/95 58/90 57/98 +f 64/94 60/91 58/90 62/95 +f 66/99 67/100 69/101 68/102 +f 72/103 73/104 71/105 70/106 +f 70/107 71/105 67/100 66/108 +f 73/109 69/110 67/111 71/112 diff --git a/integration/src/main/resources/assets/projectred_integration/textures/block/io_colour_box.png b/integration/src/main/resources/assets/projectred_integration/textures/block/io_colour_box.png new file mode 100644 index 0000000000000000000000000000000000000000..f309202de2bc7526ca019706d486119270ccd089 GIT binary patch literal 3158 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 G-~AsIfTH&R literal 0 HcmV?d00001 diff --git a/integration/src/main/resources/assets/projectred_integration/textures/block/io_crimp.png b/integration/src/main/resources/assets/projectred_integration/textures/block/io_crimp.png new file mode 100644 index 0000000000000000000000000000000000000000..dae560584335f3e446a878d6d6eee67095eab96c GIT binary patch literal 3472 zcmb_f3se)=77YXu5Q<9W0gA=}L@JZaO#UO`W1@f%p%O(3S|^hUi6NPggl~}|S`8Mp z+FE^7pV$^uYFi&j{go1{6{}dNRbD|rs;vkp)F0vp?SxP2>#}`au9ua`+_`t3bM`s+ z?71sN@e3l|Tzp(;G@4s@R$&YLlB$67cyZUhl}uo83=?xESUOoL70zn1SlI}jC=qpnn9sN7fR-h z#G;-=fXZajqbycdRu(gh%_I$}ELbQMvLJ+oARvVRjX63KmJRBRexn{Fgb_EW^(Hl` zV^}?6ax%jt0w|`#DQNXJw>slUnW%!XvN1giWPe+8gQE0x+}JeP}BYYSmC&CR6J7%9ke(MDO0o?tB`jAVuZ zC+22SH2tjE=uxqOz)Yk;Mv`fx8x=oFnSmfom@!j|;cA^ViJ)gp2nl8)L;$sKFbHu$ zNFYOClq*Cz5D0Nl2pWb;NrhUOV}l}AD9n>V5DIfqtJyP9s%aFM3HzU51&%67gBGJw zR%@|Tf~D7`0t{OrQ8AfD8mPb&JNC2l(PDADfmEu~s0HJ~$T^JYxndqH1VG2k-YA+%2 z3~LjN+AFN~909_Is5m@=OHlSye`0c~Y`72?U;;T`jhGpXIV|AeN*sjv6mt%rgM)G|2L@rKoGpNH zC7Z*Mhp?yPR8IU{ish;$nR#*i3L47ZA01mM>0CKSNPwEB6w`?q#y*lm`I zpq&0i&kw_lq|%gy8Hk8fsuTW(s#t$U--u=YHF+gl!9j!w4&pe1fgB;505L?#2XR6U z!59oHIXqkPHuA$NL}W06Qtw);euq`~V&q3ki>okQDnXqZEa1h{`Fl$H!(RN^OXdHW z&QOC6_ZjPtEjYCH%+W$^=Fk*%URj5>gOYl%9kqmxs+55`NR>aA+@aCNd>Ac>kg3{# z*}gLNLdKN3u5as`&6O!Ds+F&Gw@xhixYTk>Z(o;Q;_kKH$8O>PZEw=N?@|_@&)XrL z?2-JSAjH|lpm%RVG}jNN36nqAH#YD*M|pOuaaTKeYMU`EvyEt9b*5+2{m1!z`L%tW zgM)dYm;1c+c|2#Q(|McBidwPcwxP&evaQFTQA%td{IUKC0Al?+gI1R&^$&C%Z=BR$ zw@13>{g#(%5#JW&+q@b#-_&ujsKd_G2j>eKX4h7|eDY#ZO7^wo38t{(PG6_>(H`n$ zHMNVMGEHh}QD};!CJud)x5uvPKjSx-{lnS5FH+)pE)XEo7)$oLw7zS146}R^zXxnT zNcUMW8B4L>souc*%87orY3tfpl>vWem1F(hY1_>Yu5D@2I-{!0j8|{GdcEow_qZLi zt{CY`Uj~!za-yi`a?iRAv(!Ua4Jc83SyT8-+Xw}>H5l^mAAt5 zshEve>*Inz*^}n+LO9JWmwta`xmjhbV6ZsJ_gZcYTH`_h#g7 z*MZo!i_SBrr+&~pb@rC4Zj*`{A|knK19m&?5KrFd{irf%LEf*WYz&M?Vx$&3j}g3YasTgmE& zLGhac-pMhWgQFONF};C67yR=zxA?W0HHVF@SbMs^!zpy}B=@NsmR&g=FNyoYj3adaL^E!G}}mn@(Iq@vjedYv@SR#3`$N-#k3v8YpmkI5EY1+qriv-RYXv zVON|VlaBZ}xt8$qtFt;GHb?Ll)op*n1z;1?L zQWwtZiZArl0zhqZ(X{!NK1bDx-W$p>vY+Ajpkz8%FFT~Z*Z4h_ ir5a0Hc~*_xQ(ErZkCgp_@M`OSrs%l~B%jS$UicfXn=8`* literal 0 HcmV?d00001 diff --git a/integration/src/main/resources/assets/projectred_integration/textures/block/io_crimp_old.png b/integration/src/main/resources/assets/projectred_integration/textures/block/io_crimp_old.png new file mode 100644 index 0000000000000000000000000000000000000000..073b4b9447d2ea7a80da02d76862d531f4e9dc54 GIT binary patch literal 3218 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 RO2fYffA3()KfU4>{}-HqzeWH6 literal 0 HcmV?d00001 diff --git a/integration/src/main/resources/assets/projectred_integration/textures/block/surface/fabio-0.png b/integration/src/main/resources/assets/projectred_integration/textures/block/surface/fabio-0.png new file mode 100644 index 0000000000000000000000000000000000000000..49144934868f3a9d28464f6730ccf352ca1271a0 GIT binary patch literal 1793 zcmb_d-D=!M6qX5?G{HCN%~A*q%0*k~NTXS4cQr&!-CZYMh+N|=)S)*SjYhk|D~&42 z-nB1t7YOve}+o&&W?m1n~%On59bUB zGFfvp&!&0B=7G83WiZy$wuu&y`Y15BwL^3m?xVgcCF)oN3qsnc>swC8^=S7yL7r%(iEi zKF4|WV9hX)l_=AqPF0RHBahT^9hea5QbJZVw0X5k6C})@^TKv4q9rYWv1o9`aXDQ$ zkA*F#GLv~-0oG}-#YEMrny4$No6i>YWpiu}a9L=xTIYNc%um z>bMkg=LEuhpw$$tUrJu9a-`IBU8wza$cR$QLEnU2q`4OH?Ku-U;I#})sGEa{he>Zl z9p?GWC78I3kR>!!ahjYqP^zJhJAx7ely)ybp=n}X^Us1~!4g$w93-b1A4|K)$0lkL z$@*%lN^lI(Eu#oSHq5J<=Ryt#feEUuG>w^bc!zpziaqJM*cFuEh(@84?L?IH z7AnAgpv1AR?b<#D`y{5_j-L<=Bo21lF2xa-E{-DCYj-H^Mv1ew|EWx2ZSm=idGw0Y zO~H243d(i5S`*LYudC5CMThqufharILEa zOSwIUY+a+F?5o1B_{nF2r=7$Ru8+NL)W)ut^e`7u54$w+iPMYxIEM0n68yOaY!gPB z2E1ADD|RvA`B=h+X`45fbG>f7TF!;_^nc2+^-j6$GyBsPTzosXt3ojsQ?OO*VRJ^n zOLNM|95PkH8FK%<`~l9N)^M;rx_w`~XrVthzixf}>-Oe9o2`voM*r_yTlb`Vtq-Z; M&fehdk1t;S3n7Ie`v3p{ literal 0 HcmV?d00001 diff --git a/runtime/build.gradle b/runtime/build.gradle index 44746bc31..a7380ca6f 100644 --- a/runtime/build.gradle +++ b/runtime/build.gradle @@ -18,6 +18,7 @@ minecraft { 'projectred_core' { source project(":core").sourceSets.main } 'projectred_expansion' { source project(":expansion").sourceSets.main } 'projectred_exploration' { source project(":exploration").sourceSets.main } + 'projectred_fabrication' { source project(":fabrication").sourceSets.main } 'projectred_illumination' { source project(":illumination").sourceSets.main } 'projectred_integration' { source project(":integration").sourceSets.main } 'projectred_transmission' { source project(":transmission").sourceSets.main } @@ -40,6 +41,7 @@ dependencies { runtimeOnly project(":core") runtimeOnly project(":expansion") runtimeOnly project(":exploration") + runtimeOnly project(":fabrication") runtimeOnly project(":illumination") runtimeOnly project(":integration") runtimeOnly project(":transmission") diff --git a/settings.gradle b/settings.gradle index 62215fe71..7e20c0c7a 100644 --- a/settings.gradle +++ b/settings.gradle @@ -12,13 +12,13 @@ pluginManagement { id 'com.matthewprenger.cursegradle' version '1.4.0' apply false id 'net.minecraftforge.gradle' version '5.1.+' apply false id 'org.spongepowered.mixin' version '0.7.+' apply false + id 'com.github.johnrengelman.shadow' version '7.1.+' apply false } } rootProject.name = 'ProjectRed' -// Mod modules -include 'core', 'expansion', 'exploration', 'illumination', 'integration', 'transmission' +include 'core', 'expansion', 'exploration', 'fabrication', 'illumination', 'integration', 'transmission' // Empty module for client/server run configurations include 'runtime' From 6248c5bbd386653f6d083bf3a115ee66dfdaeec1 Mon Sep 17 00:00:00 2001 From: MrTJP Date: Sun, 16 Oct 2022 01:32:12 -0400 Subject: [PATCH 02/23] internal: cleanup editor nbt data --- .../fabrication/editor/EditorDataUtils.java | 58 +++++++++++++++++ .../editor/ICEditorStateMachine.java | 27 ++++++-- .../fabrication/editor/ICWorkbenchEditor.java | 51 ++++++++------- .../fabrication/engine/BaseTileMap.java | 9 +-- .../fabrication/engine/ICCompilerLog.java | 21 ++++--- .../engine/ICSimulationContainer.java | 4 -- .../fabrication/item/ICBlueprintItem.java | 63 ++++++++++++++----- .../fabrication/item/PhotomaskSetItem.java | 19 ++---- .../fabrication/item/ValidDieItem.java | 17 +---- .../fabrication/part/FabricatedGatePart.java | 9 +-- .../tile/LithographyTableTile.java | 3 +- .../fabrication/tile/PlottingTableTile.java | 3 +- 12 files changed, 188 insertions(+), 96 deletions(-) create mode 100644 fabrication/src/main/java/mrtjp/projectred/fabrication/editor/EditorDataUtils.java diff --git a/fabrication/src/main/java/mrtjp/projectred/fabrication/editor/EditorDataUtils.java b/fabrication/src/main/java/mrtjp/projectred/fabrication/editor/EditorDataUtils.java new file mode 100644 index 000000000..2166aad7e --- /dev/null +++ b/fabrication/src/main/java/mrtjp/projectred/fabrication/editor/EditorDataUtils.java @@ -0,0 +1,58 @@ +package mrtjp.projectred.fabrication.editor; + +import net.minecraft.nbt.CompoundTag; + +public class EditorDataUtils { + + // ICEditor + public static final String KEY_FORMAT = "format"; // int + public static final String KEY_ACTIVE = "active"; // boolean + public static final String KEY_IC_NAME = "ic_name"; // String + public static final String KEY_TILE_MAP = "tile_map"; // CompoundTag + public static final String KEY_TILE_COUNT = "tile_count"; // int + public static final String KEY_IS_BUILT = "is_built"; // boolean + public static final String KEY_IO_RS = "rsmask"; // CompoundTag + public static final String KEY_IO_BUNDLED = "bmask"; // CompoundTag + + // ICEditorStateMachine + public static final String KEY_COMP_STATE = "state"; // byte + public static final String KEY_FLAT_MAP = "flat_map"; // String + public static final String KEY_SIMULATION = "sim_cont"; // CompoundTag + public static final String KEY_COMPILER_LOG = "compiler_log"; // CompoundTag + + public static int getFormat(CompoundTag tag) { + return tag.getInt(KEY_FORMAT); + } + + public static boolean hasEditorData(CompoundTag tag) { + return tag != null && + tag.contains(KEY_FORMAT) && + tag.contains(KEY_ACTIVE) && + tag.contains(KEY_TILE_MAP); + } + + // Minimum subset of data required to fabricate gate (i.e. create photomask) + public static boolean hasFabricationTarget(CompoundTag tag) { + return tag != null && + tag.contains(KEY_IS_BUILT) && + tag.contains(KEY_FLAT_MAP); + } + + public static boolean canFabricate(CompoundTag tag) { + return hasFabricationTarget(tag) && tag.getBoolean(KEY_IS_BUILT); + + //TODO check errors + } + + // Creates copy of editor tag with only the data required to fabricate a gate + public static CompoundTag createFabricationCopy(CompoundTag editorTag) { + CompoundTag copy = new CompoundTag(); + copy.putBoolean(KEY_IS_BUILT, editorTag.getBoolean(KEY_IS_BUILT)); + copy.putString(KEY_IC_NAME, editorTag.getString(KEY_IC_NAME)); + copy.putInt(KEY_TILE_COUNT, editorTag.getInt(KEY_TILE_COUNT)); + //TODO handle other types of IO + copy.putByte(KEY_IO_BUNDLED, editorTag.getByte(KEY_IO_BUNDLED)); + copy.putString(KEY_FLAT_MAP, editorTag.getString(KEY_FLAT_MAP)); + return copy; + } +} diff --git a/fabrication/src/main/java/mrtjp/projectred/fabrication/editor/ICEditorStateMachine.java b/fabrication/src/main/java/mrtjp/projectred/fabrication/editor/ICEditorStateMachine.java index c1796bcdd..424b85dfb 100644 --- a/fabrication/src/main/java/mrtjp/projectred/fabrication/editor/ICEditorStateMachine.java +++ b/fabrication/src/main/java/mrtjp/projectred/fabrication/editor/ICEditorStateMachine.java @@ -13,6 +13,7 @@ import java.util.function.Function; import static mrtjp.projectred.fabrication.ProjectRedFabrication.LOGGER; +import static mrtjp.projectred.fabrication.editor.EditorDataUtils.*; public class ICEditorStateMachine { @@ -43,6 +44,8 @@ public class ICEditorStateMachine { private final ICSimulationContainer simulationContainer = new ICSimulationContainer(); private final ICCompilerLog compilerLog = new ICCompilerLog(this); + private String lastCompiledFlatMap = PRFabricationEngine.EMPTY_FLAT_MAP_SERIALIZED; + private boolean autoCompileOnChange = false; //TODO client-side toggle public ICEditorStateMachine(ICWorkbenchEditor editor, StateMachineCallback callback) { @@ -55,15 +58,23 @@ public ICCompilerLog getCompilerLog() { } public void save(CompoundTag tag) { - tag.putByte("comp_state", (byte) currentState); - simulationContainer.save(tag); - compilerLog.save(tag); + tag.putByte(KEY_COMP_STATE, (byte) currentState); + tag.putString(KEY_FLAT_MAP, lastCompiledFlatMap); + + CompoundTag simTag = new CompoundTag(); + simulationContainer.save(simTag); + tag.put(KEY_SIMULATION, simTag); + + CompoundTag logTag = new CompoundTag(); + compilerLog.save(logTag); + tag.put(KEY_COMPILER_LOG, logTag); } public void load(CompoundTag tag) { - currentState = tag.getByte("comp_state") & 0xFF; - simulationContainer.load(tag); - compilerLog.load(tag); + currentState = tag.getByte(KEY_COMP_STATE) & 0xFF; + lastCompiledFlatMap = tag.getString(KEY_FLAT_MAP); + simulationContainer.load(tag.getCompound(KEY_SIMULATION)); + compilerLog.load(tag.getCompound(KEY_COMPILER_LOG)); } public void writeDesc(MCDataOutput out) { @@ -132,6 +143,9 @@ public boolean canTriggerCompile() { public boolean isCompiling() { return currentState == STATE_COMPILING; } + public boolean isSimulating() { + return currentState == STATE_SIMULATING; + } //endregion private void enterState(int id, boolean force) { @@ -263,6 +277,7 @@ public void onTick(long time) { if (assembler.isDone()) { ICFlatMap map = assembler.result(); assembler = null; //TODO make assemblers clearable + lastCompiledFlatMap = PRFabricationEngine.instance.serializeFlatMap(map); simulationContainer.setFlatMap(map); enterStateAndSend(STATE_SIMULATING); if (callback != null) callback.onCompileComplete(); diff --git a/fabrication/src/main/java/mrtjp/projectred/fabrication/editor/ICWorkbenchEditor.java b/fabrication/src/main/java/mrtjp/projectred/fabrication/editor/ICWorkbenchEditor.java index ac9397199..9f2a3c1b6 100644 --- a/fabrication/src/main/java/mrtjp/projectred/fabrication/editor/ICWorkbenchEditor.java +++ b/fabrication/src/main/java/mrtjp/projectred/fabrication/editor/ICWorkbenchEditor.java @@ -14,9 +14,12 @@ import java.util.*; import static mrtjp.projectred.fabrication.ProjectRedFabrication.LOGGER; +import static mrtjp.projectred.fabrication.editor.EditorDataUtils.*; public class ICWorkbenchEditor implements ICEditorStateMachine.StateMachineCallback { + public static final int EDITOR_FORMAT = 1; + private static final int STREAM_ID_GENERAL = 0; private static final int STREAM_ID_TILE_UPDATES = 1; private static final int STREAM_ID_FSM = 2; @@ -59,17 +62,22 @@ public boolean isActive() { //region ICWorkbenchTile utilities public void save(CompoundTag tag) { LOGGER.info("ICWorkbenchEditor: saving to NBT"); - tag.putBoolean("active", isActive); - tag.putString("ic_name", icName); - tileMap.save(tag); + tag.putInt(KEY_FORMAT, EDITOR_FORMAT); + tag.putBoolean(KEY_ACTIVE, isActive); + tag.putString(KEY_IC_NAME, icName); + + CompoundTag tileMapTag = new CompoundTag(); + tileMap.save(tileMapTag); + tag.put(KEY_TILE_MAP, tileMapTag); + stateMachine.save(tag); } public void load(CompoundTag tag) { LOGGER.info("ICWorkbenchEditor: reading form NBT"); - isActive = tag.getBoolean("active"); - icName = tag.getString("ic_name"); - tileMap.load(tag); + isActive = tag.getBoolean(KEY_ACTIVE); + icName = tag.getString(KEY_IC_NAME); + tileMap.load(tag.getCompound(KEY_TILE_MAP)); stateMachine.load(tag); } @@ -96,27 +104,28 @@ private void clear() { } public void readBlueprintTagAndActivate(@Nullable CompoundTag tag) { - + // Clear the session clear(); - isActive = true; - if (tag == null) { - LOGGER.info("ICWorkbenchEditor: No blueprint tag found. Activating fresh session"); - return; - } - LOGGER.info("ICWorkbenchEditor: Reading blueprint tag"); - icName = tag.getString("ic_name"); - tileMap.load(tag); - stateMachine.load(tag); + // Save editor contents + if (tag != null) load(tag); + + // Activate editor + isActive = true; } public void writeBlueprintTagAndDeactivate(CompoundTag tag) { - LOGGER.info("ICWorkbenchEditor: Writing blueprint tag"); + // Save all editor contents + save(tag); + + // Save additional metadata for blueprints + tag.putByte(KEY_IO_RS, tileMap.calcRedstoneIOMask()); + tag.putByte(KEY_IO_BUNDLED, tileMap.calcBundledIOMask()); + tag.putInt(KEY_TILE_COUNT, tileMap.getTileCount()); + tag.putBoolean(KEY_IS_BUILT, stateMachine.isSimulating()); + + // Deactivate editor isActive = false; - tag.putString("ic_name", icName); - tileMap.save(tag); - stateMachine.save(tag); - tag.putInt("tilecount", tileMap.getTileCount()); //TODO better tooltips clear(); } //endregion diff --git a/fabrication/src/main/java/mrtjp/projectred/fabrication/engine/BaseTileMap.java b/fabrication/src/main/java/mrtjp/projectred/fabrication/engine/BaseTileMap.java index 7c3d0368d..42a0e216f 100644 --- a/fabrication/src/main/java/mrtjp/projectred/fabrication/engine/BaseTileMap.java +++ b/fabrication/src/main/java/mrtjp/projectred/fabrication/engine/BaseTileMap.java @@ -106,7 +106,7 @@ private void uncacheType(BaseTile tile) { if (tile instanceof IIOConnectionTile) ioTiles.remove(tile); } - private byte calcBundledIOMask() { + public byte calcBundledIOMask() { // OOOO IIII int bmask = 0; @@ -120,6 +120,10 @@ private byte calcBundledIOMask() { return (byte) bmask; } + public byte calcRedstoneIOMask() { + return 0; //TODO + } + public void save(CompoundTag tag) { ListTag tileList = new ListTag(); @@ -133,9 +137,6 @@ public void save(CompoundTag tag) { tileList.add(tileTag); } tag.put("tiles", tileList); - - tag.putByte("rsmask", (byte) 0); //TODO - tag.putByte("bmask", calcBundledIOMask()); } public void load(CompoundTag tag) { diff --git a/fabrication/src/main/java/mrtjp/projectred/fabrication/engine/ICCompilerLog.java b/fabrication/src/main/java/mrtjp/projectred/fabrication/engine/ICCompilerLog.java index 9da0bd50a..44a415daf 100644 --- a/fabrication/src/main/java/mrtjp/projectred/fabrication/engine/ICCompilerLog.java +++ b/fabrication/src/main/java/mrtjp/projectred/fabrication/engine/ICCompilerLog.java @@ -29,18 +29,16 @@ public ICCompilerLog(ICEditorStateMachine stateMachine) { } public void save(CompoundTag tag) { - CompoundTag treeTag = new CompoundTag(); - compileTree.save(treeTag); - tag.put("compile_tree", treeTag); tag.putInt("completed_steps", completedSteps); tag.putIntArray("current_path", currentPath); + compileTree.save(tag); } public void load(CompoundTag tag) { - compileTree.load(tag.getCompound("compile_tree")); completedSteps = tag.getInt("completed_steps"); currentPath.clear(); currentPath.addAll(Arrays.stream(tag.getIntArray("current_path")).boxed().collect(Collectors.toList())); + compileTree.load(tag); } public void writeDesc(MCDataOutput out) { @@ -175,9 +173,9 @@ public void save(CompoundTag tag) { ListTag tileCoordsTag = new ListTag(); for (TileCoord coord : tileCoords) { CompoundTag coordTag = new CompoundTag(); - coordTag.putInt("x", coord.x); - coordTag.putInt("y", coord.y); - coordTag.putInt("z", coord.z); + coordTag.putByte("x", (byte) coord.x); + coordTag.putByte("y", (byte) coord.y); + coordTag.putByte("z", (byte) coord.z); tileCoordsTag.add(coordTag); } tag.put("tileCoords", tileCoordsTag); @@ -206,13 +204,15 @@ public void save(CompoundTag tag) { public void load(CompoundTag tag) { step = ICStepThroughAssembler.AssemblerStepType.values()[tag.getByte("step")]; + // Note: this is only called on fresh instance. No need to clear lists + ListTag tileCoordsTag = tag.getList("tileCoords", Tag.TAG_COMPOUND); for (Tag coordTag : tileCoordsTag) { CompoundTag coordTagCompound = (CompoundTag) coordTag; tileCoords.add(new TileCoord( - coordTagCompound.getInt("x"), - coordTagCompound.getInt("y"), - coordTagCompound.getInt("z") + coordTagCompound.getByte("x"), + coordTagCompound.getByte("y"), + coordTagCompound.getByte("z") )); } @@ -379,6 +379,7 @@ public void save(CompoundTag tag) { public void load(CompoundTag tag) { size = tag.getInt("size"); + rootNodes.clear(); ListTag rootNodesTag = tag.getList("rootNodes", Tag.TAG_COMPOUND); for (Tag rootNodeTag : rootNodesTag) { CompileTreeNode rootNode = new CompileTreeNode(); diff --git a/fabrication/src/main/java/mrtjp/projectred/fabrication/engine/ICSimulationContainer.java b/fabrication/src/main/java/mrtjp/projectred/fabrication/engine/ICSimulationContainer.java index 5cbc1362d..ac6699f4f 100644 --- a/fabrication/src/main/java/mrtjp/projectred/fabrication/engine/ICSimulationContainer.java +++ b/fabrication/src/main/java/mrtjp/projectred/fabrication/engine/ICSimulationContainer.java @@ -8,7 +8,6 @@ public class ICSimulationContainer { - private String flatMap = PRFabricationEngine.EMPTY_FLAT_MAP_SERIALIZED; //TODO this does not really belong here private ICSimulation simulation = PRFabricationEngine.EMPTY_SIMULATION; /** @@ -60,7 +59,6 @@ public short getOutput(int rotation) { } public void setFlatMap(ICFlatMap flatMap) { - this.flatMap = PRFabricationEngine.instance.serializeFlatMap(flatMap); this.simulation = new ICSimulation(flatMap); pushInputs(0xF); @@ -70,7 +68,6 @@ public void setFlatMap(ICFlatMap flatMap) { } public void save(CompoundTag tag) { - tag.putString("flatMap", flatMap); tag.putString("simulation", PRFabricationEngine.instance.serializeSimulation(simulation)); for (int i = 0; i < 4; i++) { tag.putShort("in" + i, inputs[i]); @@ -80,7 +77,6 @@ public void save(CompoundTag tag) { } public void load(CompoundTag tag) { - this.flatMap = tag.getString("flatMap"); ICSimulation simulation = PRFabricationEngine.instance.deserializeSimulation(tag.getString("simulation")); if (simulation != null) { this.simulation = simulation; diff --git a/fabrication/src/main/java/mrtjp/projectred/fabrication/item/ICBlueprintItem.java b/fabrication/src/main/java/mrtjp/projectred/fabrication/item/ICBlueprintItem.java index c073ae890..4143c178a 100644 --- a/fabrication/src/main/java/mrtjp/projectred/fabrication/item/ICBlueprintItem.java +++ b/fabrication/src/main/java/mrtjp/projectred/fabrication/item/ICBlueprintItem.java @@ -4,6 +4,7 @@ import mrtjp.projectred.fabrication.init.FabricationReferences; import mrtjp.projectred.integration.GateType; import net.minecraft.ChatFormatting; +import net.minecraft.nbt.CompoundTag; import net.minecraft.network.chat.Component; import net.minecraft.network.chat.TextComponent; import net.minecraft.world.InteractionResult; @@ -17,6 +18,8 @@ import javax.annotation.Nullable; import java.util.List; +import static mrtjp.projectred.fabrication.editor.EditorDataUtils.*; + public class ICBlueprintItem extends Item { public ICBlueprintItem() { @@ -27,16 +30,7 @@ public ICBlueprintItem() { @Override public void appendHoverText(ItemStack stack, @Nullable Level p_77624_2_, List tooltipList, TooltipFlag tooltipFlag) { - - if (stack.getTag() != null) { - //TODO localize - tooltipList.add(new TextComponent("Name: " + stack.getTag().getString("ic_name")).withStyle(ChatFormatting.GRAY)); - tooltipList.add(new TextComponent("Tile count: " + stack.getTag().getInt("tilecount")).withStyle(ChatFormatting.GRAY)); - - byte bmask = stack.getTag().getByte("bmask"); - tooltipList.add(new TextComponent("Input mask: " + "0x" + Integer.toHexString(bmask & 0xF)).withStyle(ChatFormatting.GRAY)); - tooltipList.add(new TextComponent("Output mask: " + "0x" + Integer.toHexString((bmask >> 4) & 0xF)).withStyle(ChatFormatting.GRAY)); - } + buildTooltip(stack.getTag(), tooltipList); } @Override @@ -46,17 +40,58 @@ public InteractionResult onItemUseFirst(ItemStack stack, UseOnContext context) { // Creative mode bypass: Convert blueprint directly to gate block BlockState blockState = context.getLevel().getBlockState(context.getClickedPos()); - if (blockState.getBlock() == FabricationReferences.IC_WORKBENCH_BLOCK) - return InteractionResult.PASS; + if (blockState.getBlock() == FabricationReferences.IC_WORKBENCH_BLOCK) { return InteractionResult.PASS; } - if (!stack.hasTag() || !stack.getTag().contains("tilecount")) { + if (!canFabricate(stack.getTag())) { return InteractionResult.PASS; } ItemStack gate = GateType.FABRICATED_GATE.makeStack(); - gate.setTag(stack.getTag()); + gate.setTag(createFabricationCopy(stack.getTag())); context.getPlayer().addItem(gate); return InteractionResult.SUCCESS; } + + public static void buildTooltip(CompoundTag blueprintTag, List tooltipList) { + + if (!hasFabricationTarget(blueprintTag)) { + tooltipList.add(new TextComponent(" ").withStyle(ChatFormatting.RED) + .append(new TextComponent("Corrupted NBT data, please discard").withStyle(ChatFormatting.GRAY))); + return; + } + + //TODO localize + tooltipList.add(new TextComponent("Name: " + blueprintTag.getString(KEY_IC_NAME)).withStyle(ChatFormatting.GRAY)); + tooltipList.add(new TextComponent("Tile count: " + blueprintTag.getInt(KEY_TILE_COUNT)).withStyle(ChatFormatting.GRAY)); + tooltipList.add(new TextComponent("IO Types: ").withStyle(ChatFormatting.GRAY)); + + //TODO handle other types of IO + byte bmask = blueprintTag.getByte(KEY_IO_BUNDLED); + tooltipList.add(new TextComponent(" Top: " + getBundledIOString(bmask, 0)).withStyle(ChatFormatting.GRAY)); + tooltipList.add(new TextComponent(" Right: " + getBundledIOString(bmask, 1)).withStyle(ChatFormatting.GRAY)); + tooltipList.add(new TextComponent(" Bottom: " + getBundledIOString(bmask, 2)).withStyle(ChatFormatting.GRAY)); + tooltipList.add(new TextComponent(" Left: " + getBundledIOString(bmask, 3)).withStyle(ChatFormatting.GRAY)); + + //TODO errors + } + + private static String getBundledIOString(byte bmask, int r) { + int i = 0x01 << r; + int o = 0x10 << r; + return ((bmask & i) != 0 ? "Bundled input" : (bmask & o) != 0 ? "Bundled output" : "None"); + } + + public static ItemStack createPhotomaskStack(ItemStack blueprintStack) { + + ItemStack photomaskStack = new ItemStack(FabricationReferences.PHOTOMASK_SET_ITEM); + CompoundTag blueprintTag = blueprintStack.getTag(); + + if (!hasFabricationTarget(blueprintTag)) return photomaskStack; + + CompoundTag photomaskTag = createFabricationCopy(blueprintTag); + photomaskStack.setTag(photomaskTag); + + return photomaskStack; + } } diff --git a/fabrication/src/main/java/mrtjp/projectred/fabrication/item/PhotomaskSetItem.java b/fabrication/src/main/java/mrtjp/projectred/fabrication/item/PhotomaskSetItem.java index 994448839..8c3e8d8cc 100644 --- a/fabrication/src/main/java/mrtjp/projectred/fabrication/item/PhotomaskSetItem.java +++ b/fabrication/src/main/java/mrtjp/projectred/fabrication/item/PhotomaskSetItem.java @@ -1,10 +1,9 @@ package mrtjp.projectred.fabrication.item; import mrtjp.projectred.fabrication.ProjectRedFabrication; +import mrtjp.projectred.fabrication.init.FabricationReferences; import mrtjp.projectred.integration.GateType; -import net.minecraft.ChatFormatting; import net.minecraft.network.chat.Component; -import net.minecraft.network.chat.TextComponent; import net.minecraft.world.InteractionResult; import net.minecraft.world.item.Item; import net.minecraft.world.item.ItemStack; @@ -25,15 +24,7 @@ public PhotomaskSetItem() { @Override public void appendHoverText(ItemStack stack, @Nullable Level p_77624_2_, List tooltipList, TooltipFlag tooltipFlag) { - if (stack.getTag() != null) { - //TODO localize - tooltipList.add(new TextComponent("Name: " + stack.getTag().getString("ic_name")).withStyle(ChatFormatting.GRAY)); - tooltipList.add(new TextComponent("Tile count: " + stack.getTag().getInt("tilecount")).withStyle(ChatFormatting.GRAY)); - - byte bmask = stack.getTag().getByte("bmask"); - tooltipList.add(new TextComponent("Input mask: " + "0x" + Integer.toHexString(bmask & 0xF)).withStyle(ChatFormatting.GRAY)); - tooltipList.add(new TextComponent("Output mask: " + "0x" + Integer.toHexString((bmask >> 4) & 0xF)).withStyle(ChatFormatting.GRAY)); - } + ICBlueprintItem.buildTooltip(stack.getTag(), tooltipList); } @Override @@ -50,7 +41,9 @@ public InteractionResult onItemUseFirst(ItemStack stack, UseOnContext context) { return InteractionResult.PASS; } - public static void transferNBTToDieItem(ItemStack photomask, ItemStack die) { - die.setTag(photomask.getTag().copy()); + public static ItemStack createDieStack(ItemStack photomask, int count) { + ItemStack validDieStack = new ItemStack(FabricationReferences.VALID_DIE_ITEM, count); + validDieStack.setTag(photomask.getTag().copy()); //Nothing additional to add yet + return validDieStack; } } diff --git a/fabrication/src/main/java/mrtjp/projectred/fabrication/item/ValidDieItem.java b/fabrication/src/main/java/mrtjp/projectred/fabrication/item/ValidDieItem.java index 6b4d7faa7..bf9fe7ab2 100644 --- a/fabrication/src/main/java/mrtjp/projectred/fabrication/item/ValidDieItem.java +++ b/fabrication/src/main/java/mrtjp/projectred/fabrication/item/ValidDieItem.java @@ -2,10 +2,7 @@ import mrtjp.projectred.fabrication.ProjectRedFabrication; import mrtjp.projectred.integration.GateType; -import net.minecraft.ChatFormatting; -import net.minecraft.nbt.CompoundTag; import net.minecraft.network.chat.Component; -import net.minecraft.network.chat.TextComponent; import net.minecraft.world.item.Item; import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.TooltipFlag; @@ -23,19 +20,7 @@ public ValidDieItem() { @Override public void appendHoverText(ItemStack stack, @Nullable Level world, List tooltipList, TooltipFlag tooltipFlag) { - super.appendHoverText(stack, world, tooltipList, tooltipFlag); - - if (stack.getTag() == null) - return; - - CompoundTag tag = stack.getTag(); - - // Blueprint data - tooltipList.add(new TextComponent("Name: " + tag.getString("ic_name")).withStyle(ChatFormatting.GRAY)); - tooltipList.add(new TextComponent("Tile count: " + tag.getInt("tilecount")).withStyle(ChatFormatting.GRAY)); - byte bmask = tag.getByte("bmask"); - tooltipList.add(new TextComponent("Input mask: " + "0x" + Integer.toHexString(bmask & 0xF)).withStyle(ChatFormatting.GRAY)); - tooltipList.add(new TextComponent("Output mask: " + "0x" + Integer.toHexString((bmask >> 4) & 0xF)).withStyle(ChatFormatting.GRAY)); + ICBlueprintItem.buildTooltip(stack.getTag(), tooltipList); } public static ItemStack createGatePart(ItemStack die) { diff --git a/fabrication/src/main/java/mrtjp/projectred/fabrication/part/FabricatedGatePart.java b/fabrication/src/main/java/mrtjp/projectred/fabrication/part/FabricatedGatePart.java index 6b465284f..e3ee79be5 100644 --- a/fabrication/src/main/java/mrtjp/projectred/fabrication/part/FabricatedGatePart.java +++ b/fabrication/src/main/java/mrtjp/projectred/fabrication/part/FabricatedGatePart.java @@ -15,6 +15,7 @@ import net.minecraft.world.item.ItemStack; import static mrtjp.projectred.fabrication.ProjectRedFabrication.LOGGER; +import static mrtjp.projectred.fabrication.editor.EditorDataUtils.*; public class FabricatedGatePart extends BundledGatePart { @@ -40,11 +41,11 @@ public void preparePlacement(Player player, BlockPos pos, int side) { } CompoundTag tag = stack.getTag(); - icName = tag.getString("ic_name"); - ICFlatMap flatMap = PRFabricationEngine.instance.deserializeFlatMap(tag.getString("flatMap")); + icName = tag.getString(KEY_IC_NAME); + ICFlatMap flatMap = PRFabricationEngine.instance.deserializeFlatMap(tag.getString(KEY_FLAT_MAP)); simulationContainer.setFlatMap(flatMap); - bundledMask = tag.getByte("bmask"); - redstoneMask = tag.getByte("rmask"); + bundledMask = tag.getByte(KEY_IO_BUNDLED); + redstoneMask = tag.getByte(KEY_IO_RS); } @Override diff --git a/fabrication/src/main/java/mrtjp/projectred/fabrication/tile/LithographyTableTile.java b/fabrication/src/main/java/mrtjp/projectred/fabrication/tile/LithographyTableTile.java index 91c939427..999abafb7 100644 --- a/fabrication/src/main/java/mrtjp/projectred/fabrication/tile/LithographyTableTile.java +++ b/fabrication/src/main/java/mrtjp/projectred/fabrication/tile/LithographyTableTile.java @@ -147,8 +147,7 @@ protected void finishWork() { // Set the output stacks if (totalValidDies > 0) { - ItemStack validDieStack = new ItemStack(FabricationReferences.VALID_DIE_ITEM, totalValidDies); - PhotomaskSetItem.transferNBTToDieItem(inventory.getItem(0), validDieStack); + ItemStack validDieStack = PhotomaskSetItem.createDieStack(inventory.getItem(0), totalValidDies); inventory.setItem(2, validDieStack); } if (totalDefectiveDies > 0) { diff --git a/fabrication/src/main/java/mrtjp/projectred/fabrication/tile/PlottingTableTile.java b/fabrication/src/main/java/mrtjp/projectred/fabrication/tile/PlottingTableTile.java index 6f905e835..3822e8945 100644 --- a/fabrication/src/main/java/mrtjp/projectred/fabrication/tile/PlottingTableTile.java +++ b/fabrication/src/main/java/mrtjp/projectred/fabrication/tile/PlottingTableTile.java @@ -129,8 +129,7 @@ protected int tickWork(int remainingWork) { @Override protected void finishWork() { - ItemStack output = new ItemStack(FabricationReferences.PHOTOMASK_SET_ITEM); - output.setTag(inventory.getItem(0).getTag().copy()); // copy the blueprint tag + ItemStack output = ICBlueprintItem.createPhotomaskStack(inventory.getItem(0)); inventory.setItem(2, output); inventory.removeItem(1, 1); // delete 1 blank photomask } From 9c46616edf1593714e2ee36aa34f38a28a1b2f6e Mon Sep 17 00:00:00 2001 From: MrTJP Date: Fri, 11 Nov 2022 10:33:17 -0500 Subject: [PATCH 03/23] internal: dont require root to run accumulated frame calc - add TextBoxNode - Rect utility method to expand a rect from its center --- .../mrtjp/projectred/redui/ButtonNode.java | 20 +- .../mrtjp/projectred/redui/RedUINode.java | 39 ++-- .../mrtjp/projectred/redui/TextBoxNode.java | 194 ++++++++++++++++++ 3 files changed, 240 insertions(+), 13 deletions(-) create mode 100644 core/src/main/java/mrtjp/projectred/redui/TextBoxNode.java diff --git a/core/src/main/java/mrtjp/projectred/redui/ButtonNode.java b/core/src/main/java/mrtjp/projectred/redui/ButtonNode.java index ca2f92ff6..99ec3c686 100644 --- a/core/src/main/java/mrtjp/projectred/redui/ButtonNode.java +++ b/core/src/main/java/mrtjp/projectred/redui/ButtonNode.java @@ -5,6 +5,7 @@ import java.util.List; import java.util.function.Consumer; +import java.util.function.Supplier; import static net.minecraft.client.gui.GuiComponent.drawCenteredString; @@ -15,6 +16,8 @@ public class ButtonNode extends AbstractButtonNode { private Runnable clickFunction = () -> { }; private Consumer> tooltipBuilder = c -> { }; + private Supplier isSelectedFunction = () -> false; + private Supplier isEnabledFunction = () -> true; private String buttonText = ""; @@ -26,6 +29,14 @@ public void setTooltipBuilder(Consumer> tooltipBuilder) { this.tooltipBuilder = tooltipBuilder; } + public void setIsSelectedFunction(Supplier isSelectedFunction) { + this.isSelectedFunction = isSelectedFunction; + } + + public void setIsEnabledFunction(Supplier isEnabledFunction) { + this.isEnabledFunction = isEnabledFunction; + } + public void setButtonText(String buttonText) { this.buttonText = buttonText; } @@ -37,7 +48,14 @@ protected void onButtonClicked() { @Override protected boolean isButtonDisabled() { - return false; + return !isEnabledFunction.get(); + } + + @Override + protected int getButtonState(boolean mouseover) { + if (isSelectedFunction.get()) + return BUTTON_STATE_HIGHLIGHT; + return super.getButtonState(mouseover); } @Override diff --git a/core/src/main/java/mrtjp/projectred/redui/RedUINode.java b/core/src/main/java/mrtjp/projectred/redui/RedUINode.java index 638849289..2f7310e1d 100644 --- a/core/src/main/java/mrtjp/projectred/redui/RedUINode.java +++ b/core/src/main/java/mrtjp/projectred/redui/RedUINode.java @@ -222,6 +222,14 @@ default Point convertPointTo(Point p, RedUINode to) { return p.add(difference); } + default Point convertPointToParent(Point p) { + return p.add(getPosition()); + } + + default Point convertPointFromParent(Point p) { + return p.subtract(getPosition()); + } + /** * Convert a given point p in this node's coordinate system to screen space * @@ -270,6 +278,14 @@ default Point getScreenOffset() { */ default Rect convertRectTo(Rect r, RedUINode to) { return new Rect(convertPointTo(r.origin, to), r.size); } + default Rect convertRectToParent(Rect r) { + return new Rect(convertPointToParent(r.origin), r.size); + } + + default Rect convertRectFromParent(Rect r) { + return new Rect(convertPointFromParent(r.origin), r.size); + } + /** * Converts a rectangle from this node's coordinate system to screen space * @@ -361,26 +377,25 @@ default Rect calculateGL11Frame() { } /** - * Calculate a frame encompassing all frames in the entire subtree. Hidden nodes and all its - * descendants are excluded. + * Combines frame encompassing all children with frame of this node. * * @return Rect in the coordinate system of this node's parent */ default Rect calculateAccumulatedFrame() { - Rect screenSpaceFrame = getSubTree(n -> !n.isHidden()).stream() - .map(n -> n.convertParentRectToScreen(n.getFrame())) - .reduce(Rect.ZERO, Rect::union); - return convertScreenRectToParent(screenSpaceFrame); + return getFrame().union(calculateChildrenFrame()); } + /** + * Calculate a frame encompassing all visible children and their subtrees. + * + * @return Rect in the coordinate system of this node's parent + */ default Rect calculateChildrenFrame() { - List subTree = getSubTree(n -> !n.isHidden()); - subTree.remove(0); // drop this node - - Rect screenSpaceFrame = subTree.stream() - .map(n -> n.convertParentRectToScreen(n.getFrame())) + Rect childrenFrame = getOurChildren().stream() + .filter(n -> !n.isHidden()) + .map(RedUINode::calculateAccumulatedFrame) .reduce(Rect.ZERO, Rect::union); - return convertScreenRectToParent(screenSpaceFrame); + return convertRectToParent(childrenFrame); } /** diff --git a/core/src/main/java/mrtjp/projectred/redui/TextBoxNode.java b/core/src/main/java/mrtjp/projectred/redui/TextBoxNode.java new file mode 100644 index 000000000..beb4ea2df --- /dev/null +++ b/core/src/main/java/mrtjp/projectred/redui/TextBoxNode.java @@ -0,0 +1,194 @@ +package mrtjp.projectred.redui; + +import com.mojang.blaze3d.vertex.PoseStack; +import mrtjp.projectred.lib.Point; +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.Font; +import net.minecraft.client.gui.screens.Screen; + +import static net.minecraft.client.gui.GuiComponent.fill; +import static org.lwjgl.glfw.GLFW.*; + +public abstract class TextBoxNode extends AbstractGuiNode { + + private static final int BORDER_COLOR = 0xFFA0A0A0; + private static final int BACKGROUND_COLOR = 0xFF000000; + private static final int SUGGESTION_COLOR = 0xFFA0A0A0; + private static final int ENABLED_COLOR = 0xE0E0E0; + private static final int DISABLED_COLOR = 0x707070; + + protected String currentText = ""; + + protected int characterLimit = -1; // by default, width based limit + protected boolean focused = false; + protected boolean enabled = true; + + public TextBoxNode(String initialText) { + this.currentText = initialText; + } + + public String getText() { + return currentText; + } + + public void setText(String text) { + this.currentText = text; + } + + public boolean isEditing() { + return enabled && focused; + } + + public void setCharacterLimit(int limit) { + this.characterLimit = limit; + } + + @Override + public void drawBack(PoseStack stack, Point mouse, float partialFrame) { + // Border + int x = getPosition().x; + int y = getPosition().y; + int width = getFrame().width(); + int height = getFrame().height(); + + fill(stack, x, y, x + width, y + height, BORDER_COLOR); + fill(stack, x + 1, y + 1, x + width - 1, y + height - 1, BACKGROUND_COLOR); + + Font fontRenderer = getRoot().getFontRenderer(); + String suggestion = getSuggestionString(); + int lineHeight = fontRenderer.lineHeight; + int leftPad = 4; + + int textX = x + leftPad; + int textY = y + height/2 - lineHeight/2; + + if (currentText.isEmpty() && !suggestion.isEmpty()) { + fontRenderer.draw(stack, suggestion, textX, textY, SUGGESTION_COLOR); + } + + if (!currentText.isEmpty()) { + String s = currentText; + if (enabled && focused && System.currentTimeMillis() % 1000 > 1000/2) { + s += "_"; + } + + fontRenderer.drawShadow(stack, s, textX, textY, enabled ? ENABLED_COLOR : DISABLED_COLOR); + } + } + + @Override + public boolean mouseClicked(Point p, int glfwMouseButton, boolean consumed) { + if (enabled && !consumed && isFirstHit(p)) { + setFocused(true); + if (glfwMouseButton == GLFW_MOUSE_BUTTON_RIGHT) { + currentText = ""; + } + return true; + } + + setFocused(false); + return false; + } + + @Override + public boolean onKeyPressed(int glfwKeyCode, int glfwScanCode, int glfwFlags, boolean consumed) { + + if (!focused || !enabled) return false; + + boolean changed = false; + + if (Screen.isPaste(glfwKeyCode)) { + String clipboard = Minecraft.getInstance().keyboardHandler.getClipboard(); + changed = appendText(clipboard); + } else { + switch (glfwKeyCode) { + case GLFW_KEY_BACKSPACE: + changed = backspaceText(); + break; + case GLFW_KEY_ESCAPE: + setFocused(false); + break; + case GLFW_KEY_ENTER: + setFocused(false); + onReturnPressed(); + break; + } + } + + if (changed) { + onTextChanged(); + return true; + } + return false; + } + + @Override + public boolean onCharTyped(char ch, int glfwFlags, boolean consumed) { + if (!focused || !enabled) return false; + + if (appendChar(ch)) { + onTextChanged(); + return true; + } + return false; + } + + private void setFocused(boolean focused) { + this.focused = focused; + } + + private boolean appendText(String text) { + StringBuilder builder = new StringBuilder(currentText); + + char[] chars = text.toCharArray(); + int i = 0; + + while (builder.length() < getCharacterLimit() && i < chars.length) { + char next = chars[i++]; + if (isCharAllowed(next)) { + builder.append(next); + } + } + + String newText = builder.toString(); + + if (!newText.equals(currentText)) { + currentText = newText; + return true; + } + return false; + } + + private boolean appendChar(char c) { + if (currentText.length() < getCharacterLimit() && isCharAllowed(c)) { + currentText += c; + return true; + } + return false; + } + + private boolean backspaceText() { + if (currentText.length() > 0) { + currentText = currentText.substring(0, currentText.length() - 1); + return true; + } + return false; + } + + private boolean isCharAllowed(char c) { + return true; + } + + private int getCharacterLimit() { + if (characterLimit == -1) { + return getFrame().width() / 6; + } + return characterLimit; + } + + protected abstract String getSuggestionString(); + + protected abstract void onTextChanged(); + + protected abstract void onReturnPressed(); +} From 46187796f8c242242e6b3e817dcf11a8733b9757 Mon Sep 17 00:00:00 2001 From: MrTJP Date: Sat, 12 Nov 2022 03:06:08 -0500 Subject: [PATCH 04/23] internal: add ItemStackNode --- .../main/java/mrtjp/projectred/lib/Rect.java | 6 + .../mrtjp/projectred/redui/ItemStackNode.java | 59 ++++ .../mrtjp/projectred/redui/RedUIRootNode.java | 1 - .../resources/META-INF/accesstransformer.cfg | 2 + .../fabrication/editor/EditorDataUtils.java | 25 ++ .../fabrication/editor/ICWorkbenchEditor.java | 27 ++ .../editor/tools/BaseICEditorTool.java | 2 +- .../fabrication/engine/BaseTileMap.java | 29 +- .../fabrication/gui/ButtonArrayNode.java | 86 ++++++ .../fabrication/gui/PipelineDiagramNode.java | 105 +++++++ .../fabrication/gui/VerticalListNode.java | 257 ++++++++++++++++++ .../gui/screen/ICWorkbenchCompileTab.java | 6 + .../gui/screen/ICWorkbenchEditTab.java | 13 +- .../gui/screen/ICWorkbenchInfoTab.java | 241 ++++++++++++++++ .../gui/screen/ICWorkbenchScreen.java | 6 +- .../item/BaseSiliconWaferItem.java | 4 +- .../lithography/LithographyPipeline.java | 36 +++ .../fabrication/lithography/ProcessNode.java | 10 +- .../fabrication/lithography/WaferType.java | 36 ++- .../lithography/YieldCalculator.java | 91 +++++++ .../tile/LithographyTableTile.java | 10 +- .../textures/gui/info_tab.png | Bin 0 -> 7672 bytes 22 files changed, 1028 insertions(+), 24 deletions(-) create mode 100644 core/src/main/java/mrtjp/projectred/redui/ItemStackNode.java create mode 100644 fabrication/src/main/java/mrtjp/projectred/fabrication/gui/ButtonArrayNode.java create mode 100644 fabrication/src/main/java/mrtjp/projectred/fabrication/gui/PipelineDiagramNode.java create mode 100644 fabrication/src/main/java/mrtjp/projectred/fabrication/gui/VerticalListNode.java create mode 100644 fabrication/src/main/java/mrtjp/projectred/fabrication/gui/screen/ICWorkbenchInfoTab.java create mode 100644 fabrication/src/main/java/mrtjp/projectred/fabrication/lithography/LithographyPipeline.java create mode 100644 fabrication/src/main/java/mrtjp/projectred/fabrication/lithography/YieldCalculator.java create mode 100644 fabrication/src/main/resources/assets/projectred_fabrication/textures/gui/info_tab.png diff --git a/core/src/main/java/mrtjp/projectred/lib/Rect.java b/core/src/main/java/mrtjp/projectred/lib/Rect.java index e12e5e79e..00aa2575b 100644 --- a/core/src/main/java/mrtjp/projectred/lib/Rect.java +++ b/core/src/main/java/mrtjp/projectred/lib/Rect.java @@ -91,6 +91,12 @@ public Rect union(Rect rect) { return new Rect(x, y, w, h); } + public Rect expand(int x, int y) { + int dw = width() + x < 0 ? -width() : x; + int dh = height() + y < 0 ? -height() : y; + return new Rect(origin.subtract(dw / 2, dh / 2), new Size(width() + dw, height() + dh)); + } + public Rect trap(Rect rect) { int dx = (rect.x() < x() ? x() - rect.x() : 0) + (rect.maxX() > maxX() ? rect.maxX() - maxX() : 0); int dy = (rect.y() < y() ? y() - rect.y() : 0) + (rect.maxY() > maxY() ? rect.maxY() - maxY() : 0); diff --git a/core/src/main/java/mrtjp/projectred/redui/ItemStackNode.java b/core/src/main/java/mrtjp/projectred/redui/ItemStackNode.java new file mode 100644 index 000000000..6a988f32e --- /dev/null +++ b/core/src/main/java/mrtjp/projectred/redui/ItemStackNode.java @@ -0,0 +1,59 @@ +package mrtjp.projectred.redui; + +import com.mojang.blaze3d.systems.RenderSystem; +import com.mojang.blaze3d.vertex.PoseStack; +import mrtjp.projectred.lib.Point; +import mrtjp.projectred.lib.Rect; +import net.minecraft.client.Minecraft; +import net.minecraft.network.chat.Component; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.TooltipFlag; + +import java.util.List; + +import static net.minecraft.client.gui.GuiComponent.fillGradient; + +public class ItemStackNode extends AbstractGuiNode { + + private ItemStack itemStack; + + public ItemStackNode(ItemStack itemStack) { + this.itemStack = itemStack; + setSize(16, 16); + } + + public ItemStackNode() { + this(ItemStack.EMPTY); + } + + public void setItemStack(ItemStack itemStack) { + this.itemStack = itemStack; + } + + @Override + public void drawBack(PoseStack stack, Point mouse, float partialFrame) { + + // Would be nice if renderGuiItem can take the matrix stack... + Point screenPos = convertParentPointToScreen(getPosition()); + getRoot().getItemRenderer().renderGuiItem(itemStack, screenPos.x, screenPos.y); + + if (isFirstHit(mouse)) { + int slotColor = -2130706433; + RenderSystem.disableDepthTest(); + RenderSystem.colorMask(true, true, true, false); + Rect frame = getFrame(); + fillGradient(stack, frame.x(), frame.y(), frame.x() + frame.width(), frame.y() + frame.height(), slotColor, slotColor, 0); + RenderSystem.colorMask(true, true, true, true); + RenderSystem.enableDepthTest(); + } + } + + @Override + public void drawFront(PoseStack stack, Point mouse, float partialFrame) { + if (isFirstHit(mouse)) { + Minecraft minecraft = getRoot().getMinecraft(); + List tooltip = itemStack.getTooltipLines(minecraft.player, minecraft.options.advancedItemTooltips ? TooltipFlag.Default.ADVANCED : TooltipFlag.Default.NORMAL); + renderTooltip(stack, mouse, tooltip); + } + } +} diff --git a/core/src/main/java/mrtjp/projectred/redui/RedUIRootNode.java b/core/src/main/java/mrtjp/projectred/redui/RedUIRootNode.java index e80b6fc9b..560eff9f1 100644 --- a/core/src/main/java/mrtjp/projectred/redui/RedUIRootNode.java +++ b/core/src/main/java/mrtjp/projectred/redui/RedUIRootNode.java @@ -7,7 +7,6 @@ import net.minecraft.client.gui.Font; import net.minecraft.client.renderer.entity.ItemRenderer; import net.minecraft.network.chat.Component; -import net.minecraft.util.FormattedCharSequence; import javax.annotation.Nullable; import java.util.List; diff --git a/core/src/main/resources/META-INF/accesstransformer.cfg b/core/src/main/resources/META-INF/accesstransformer.cfg index aac0cabee..127413484 100644 --- a/core/src/main/resources/META-INF/accesstransformer.cfg +++ b/core/src/main/resources/META-INF/accesstransformer.cfg @@ -5,6 +5,8 @@ public net.minecraft.client.renderer.PostChain * # All fields public net.minecraft.client.renderer.LevelRenderer m_109501_(IIIZ)V # setSectionDirty +public net.minecraft.client.gui.GuiComponent m_168740_(Lcom/mojang/blaze3d/vertex/PoseStack;IIIIIII)V # fillGradient + public net.minecraft.world.level.lighting.LevelLightEngine f_75802_ # blockEngine public net.minecraft.world.level.lighting.LevelLightEngine f_75803_ # skyEngine diff --git a/fabrication/src/main/java/mrtjp/projectred/fabrication/editor/EditorDataUtils.java b/fabrication/src/main/java/mrtjp/projectred/fabrication/editor/EditorDataUtils.java index 2166aad7e..754d8ff33 100644 --- a/fabrication/src/main/java/mrtjp/projectred/fabrication/editor/EditorDataUtils.java +++ b/fabrication/src/main/java/mrtjp/projectred/fabrication/editor/EditorDataUtils.java @@ -1,5 +1,6 @@ package mrtjp.projectred.fabrication.editor; +import mrtjp.fengine.TileCoord; import net.minecraft.nbt.CompoundTag; public class EditorDataUtils { @@ -55,4 +56,28 @@ public static CompoundTag createFabricationCopy(CompoundTag editorTag) { copy.putString(KEY_FLAT_MAP, editorTag.getString(KEY_FLAT_MAP)); return copy; } + + public static void saveTileCoord(CompoundTag tag, String key, TileCoord coord) { + tag.putByte(key + "_x", (byte) coord.x); + tag.putByte(key + "_y", (byte) coord.y); + tag.putByte(key + "_z", (byte) coord.z); + } + + public static TileCoord loadTileCoord(CompoundTag tag, String key) { + return new TileCoord( + tag.getByte(key + "_x"), + tag.getByte(key + "_y"), + tag.getByte(key + "_z") + ); + } + + public static CompoundTag tileCoordToNBT(TileCoord coord) { + CompoundTag tag = new CompoundTag(); + saveTileCoord(tag, "", coord); + return tag; + } + + public static TileCoord tileCoordFromNBT(CompoundTag tag) { + return loadTileCoord(tag, ""); + } } diff --git a/fabrication/src/main/java/mrtjp/projectred/fabrication/editor/ICWorkbenchEditor.java b/fabrication/src/main/java/mrtjp/projectred/fabrication/editor/ICWorkbenchEditor.java index 9f2a3c1b6..c164bb136 100644 --- a/fabrication/src/main/java/mrtjp/projectred/fabrication/editor/ICWorkbenchEditor.java +++ b/fabrication/src/main/java/mrtjp/projectred/fabrication/editor/ICWorkbenchEditor.java @@ -24,9 +24,14 @@ public class ICWorkbenchEditor implements ICEditorStateMachine.StateMachineCallb private static final int STREAM_ID_TILE_UPDATES = 1; private static final int STREAM_ID_FSM = 2; + // Server to client keys private static final int KEY_ADD_TILE = 1; private static final int KEY_REMOVE_TILE = 2; + private static final int KEY_SET_IC_NAME = 3; + + // Client to server keys private static final int KEY_TOOL = 10; + private static final int KEY_CLIENT_SEND_IC_NAME = 11; private final IICWorkbenchEditorNetwork network; private final BaseTileMap tileMap = new BaseTileMap(this); @@ -43,6 +48,10 @@ public ICWorkbenchEditor(IICWorkbenchEditorNetwork network) { for (IICEditorTool t : toolList) t.bindEditor(this); } + public String getIcName() { + return icName; + } + public ArrayList getToolList() { return toolList; } @@ -101,6 +110,7 @@ private void clear() { LOGGER.info("ICWorkbenchEditor: Preparing load of initial data (Should be server only)"); tileMap.removeAll(); stateMachine.reset(); + icName = "untitled"; } public void readBlueprintTagAndActivate(@Nullable CompoundTag tag) { @@ -174,9 +184,17 @@ private void readGeneralStream(MCDataInput in, int frameKey) { case KEY_REMOVE_TILE: tileMap.removeTile(new TileCoord(in.readByte(), in.readByte(), in.readByte())); //TODO check if removed? break; + case KEY_SET_IC_NAME: + icName = in.readString(); + break; case KEY_TOOL: toolList.get(in.readUByte()).readPacket(in); break; + case KEY_CLIENT_SEND_IC_NAME: + //TODO validate name + icName = in.readString(); + network.getBufferedStream(STREAM_ID_GENERAL, KEY_SET_IC_NAME).writeString(icName); + break; default: LOGGER.error("Unknown key " + frameKey + " in general stream"); } @@ -223,6 +241,7 @@ public MCDataOutput getStateMachineStream(int key) { return network.getBufferedStream(STREAM_ID_FSM, key); } + //region Server Utils public void addTile(BaseTile tile, TileCoord pos) { if (network.isClientSide()) throw new RuntimeException("Tiles can only be added server-side"); @@ -267,6 +286,14 @@ public void markTileChange() { network.markSave(); stateMachine.onTileMapChanged(); } + //endregion + + //region Client Utils + public void sendNewICName(String name) { + // Notifies server to set a new IC name + network.getBufferedStream(STREAM_ID_GENERAL, KEY_CLIENT_SEND_IC_NAME).writeString(name); + } + //endregion //region State Machine callbacks @Override diff --git a/fabrication/src/main/java/mrtjp/projectred/fabrication/editor/tools/BaseICEditorTool.java b/fabrication/src/main/java/mrtjp/projectred/fabrication/editor/tools/BaseICEditorTool.java index 660c09c05..b29a9bb9f 100644 --- a/fabrication/src/main/java/mrtjp/projectred/fabrication/editor/tools/BaseICEditorTool.java +++ b/fabrication/src/main/java/mrtjp/projectred/fabrication/editor/tools/BaseICEditorTool.java @@ -33,7 +33,7 @@ protected boolean isInBody(TileCoord coord) { TileCoord maxBounds = editor.getTileMap().getMaxBounds(); return coord.x > minBounds.x && coord.x < maxBounds.x && - coord.y > minBounds.y && coord.y < maxBounds.y && + coord.y >= minBounds.y && coord.y <= maxBounds.y && coord.z > minBounds.z && coord.z < maxBounds.z; } diff --git a/fabrication/src/main/java/mrtjp/projectred/fabrication/engine/BaseTileMap.java b/fabrication/src/main/java/mrtjp/projectred/fabrication/engine/BaseTileMap.java index 42a0e216f..876acb197 100644 --- a/fabrication/src/main/java/mrtjp/projectred/fabrication/engine/BaseTileMap.java +++ b/fabrication/src/main/java/mrtjp/projectred/fabrication/engine/BaseTileMap.java @@ -12,15 +12,21 @@ import java.util.*; import java.util.stream.Collectors; +import static mrtjp.projectred.fabrication.editor.EditorDataUtils.loadTileCoord; +import static mrtjp.projectred.fabrication.editor.EditorDataUtils.saveTileCoord; + public class BaseTileMap implements FETileMap { + private static final TileCoord defaultMinBounds = new TileCoord(-8, 0, -8); + private static final TileCoord defaultMaxBounds = new TileCoord(7, 0, 7); + private final Map tileMap = new HashMap<>(); private final ICWorkbenchEditor editor; private final Set ioTiles = new HashSet<>(); - private TileCoord minBounds = new TileCoord(-8, -8, -8); - private TileCoord maxBounds = new TileCoord(7, 7, 7); + private TileCoord minBounds = defaultMinBounds; + private TileCoord maxBounds = defaultMaxBounds; public BaseTileMap(ICWorkbenchEditor editor) { this.editor = editor; @@ -38,6 +44,10 @@ public TileCoord getMaxBounds() { return maxBounds; } + public TileCoord getDimensions() { + return maxBounds.subtract(minBounds).add(1, 1, 1); + } + public void setBounds(TileCoord minBounds, TileCoord maxBounds) { this.minBounds = minBounds; this.maxBounds = maxBounds; @@ -96,6 +106,9 @@ public void removeAll() { for (BaseTile t : tileMap.values()) t.unbindMap(); tileMap.clear(); + + minBounds = defaultMinBounds; + maxBounds = defaultMaxBounds; } private void cacheType(BaseTile tile) { @@ -137,6 +150,9 @@ public void save(CompoundTag tag) { tileList.add(tileTag); } tag.put("tiles", tileList); + + saveTileCoord(tag, "maxBounds", maxBounds); + saveTileCoord(tag, "minBounds", minBounds); } public void load(CompoundTag tag) { @@ -153,10 +169,16 @@ public void load(CompoundTag tag) { addTile(new TileCoord(x, y, z), tile); tile.load(tileTag); } + + maxBounds = loadTileCoord(tag, "maxBounds"); + minBounds = loadTileCoord(tag, "minBounds"); } public void writeDesc(MCDataOutput out) { + out.writeByte(minBounds.x).writeByte(minBounds.y).writeByte(minBounds.z); + out.writeByte(maxBounds.x).writeByte(maxBounds.y).writeByte(maxBounds.z); + for (Map.Entry entry : tileMap.entrySet()) { out.writeByte(entry.getValue().getTileType().getID()); out.writeByte(entry.getKey().x); @@ -170,6 +192,9 @@ public void writeDesc(MCDataOutput out) { public void readDesc(MCDataInput in) { removeAll(); + minBounds = new TileCoord(in.readByte(), in.readByte(), in.readByte()); + maxBounds = new TileCoord(in.readByte(), in.readByte(), in.readByte()); + int id = in.readUByte(); while (id != 255) { BaseTile tile = ICTileType.createFromId(id); diff --git a/fabrication/src/main/java/mrtjp/projectred/fabrication/gui/ButtonArrayNode.java b/fabrication/src/main/java/mrtjp/projectred/fabrication/gui/ButtonArrayNode.java new file mode 100644 index 000000000..34b30e619 --- /dev/null +++ b/fabrication/src/main/java/mrtjp/projectred/fabrication/gui/ButtonArrayNode.java @@ -0,0 +1,86 @@ +package mrtjp.projectred.fabrication.gui; + +import mrtjp.projectred.redui.AbstractButtonNode; +import mrtjp.projectred.redui.AbstractGuiNode; +import mrtjp.projectred.redui.ButtonNode; + +import java.util.ArrayList; + +public class ButtonArrayNode extends AbstractGuiNode { + + private final Listener listener; + + private final int rows; + private final int columns; + private final int spacing; + + private final ArrayList buttons = new ArrayList<>(); + + public ButtonArrayNode(Listener listener, int rows, int columns, int spacing) { + this.listener = listener; + this.rows = rows; + this.columns = columns; + this.spacing = spacing; + + initButtons(); + } + + private void initButtons() { + for (int i = 0; i < rows; i++) { + for (int j = 0; j < columns; j++) { + AbstractButtonNode button = createButton(i * columns + j); + addChild(button); + buttons.add(button); + } + } + } + + private void resizeButtons(int bw, int bh, int spacing) { + + for (int i = 0; i < rows; i++) { + for (int j = 0; j < columns; j++) { + AbstractButtonNode button = buttons.get(i * columns + j); + button.setSize(bw, bh); + button.setPosition(j * (bw + spacing), i * (bh + spacing)); + } + } + + setSize(columns * (bw + spacing) - spacing, rows * (bh + spacing) - spacing); + } + + @Override + public void setSize(int width, int height) { + super.setSize(width, height); + } + + public void setGridSize(int width, int height) { + int bw = (width + spacing) / columns - spacing; // width = columns * (bw + spacing) - spacing + int bh = (height + spacing) / rows - spacing; // height = rows * (bh + spacing) - spacing + resizeButtons(bw, bh, spacing); + } + + public void setButtonSize(int buttonWidth, int buttonHeight) { + resizeButtons(buttonWidth, buttonHeight, spacing); + } + + protected AbstractButtonNode createButton(int index) { + + ButtonNode button = new ButtonNode(); + button.setButtonText(listener.getButtonText(index)); + button.setClickFunction(() -> listener.onButtonClicked(index)); + button.setIsSelectedFunction(() -> listener.isButtonSelected(index)); + button.setIsEnabledFunction(() -> listener.isButtonEnabled(index)); + + return button; + } + + public interface Listener { + String getButtonText(int index); + + void onButtonClicked(int index); + + boolean isButtonEnabled(int index); + + boolean isButtonSelected(int index); + } +} diff --git a/fabrication/src/main/java/mrtjp/projectred/fabrication/gui/PipelineDiagramNode.java b/fabrication/src/main/java/mrtjp/projectred/fabrication/gui/PipelineDiagramNode.java new file mode 100644 index 000000000..3904aed62 --- /dev/null +++ b/fabrication/src/main/java/mrtjp/projectred/fabrication/gui/PipelineDiagramNode.java @@ -0,0 +1,105 @@ +package mrtjp.projectred.fabrication.gui; + +import com.mojang.blaze3d.systems.RenderSystem; +import com.mojang.blaze3d.vertex.PoseStack; +import mrtjp.projectred.fabrication.gui.screen.ICWorkbenchInfoTab; +import mrtjp.projectred.fabrication.init.FabricationReferences; +import mrtjp.projectred.fabrication.lithography.LithographyPipeline; +import mrtjp.projectred.fabrication.lithography.YieldCalculator; +import mrtjp.projectred.lib.Point; +import mrtjp.projectred.redui.AbstractGuiNode; +import mrtjp.projectred.redui.ItemStackNode; +import net.minecraft.client.gui.GuiComponent; +import net.minecraft.world.item.ItemStack; + +import java.util.ArrayList; + +public class PipelineDiagramNode extends AbstractGuiNode { + + private final YieldCalculator yieldCalculator; + + private BasicPipelineItems basicPipelineItems; + private AbstractGuiNode advancedPipelineItems; + + public PipelineDiagramNode(YieldCalculator yieldCalculator) { + this.yieldCalculator = yieldCalculator; + setSize(280, 56); + initSubNodes(); + } + + private void initSubNodes() { + + basicPipelineItems = new BasicPipelineItems(); + addChild(basicPipelineItems); + + advancedPipelineItems = new AbstractGuiNode() { }; //TODO + addChild(advancedPipelineItems); + + updatePipelines(); + } + + @Override + public void drawBack(PoseStack stack, Point mouse, float partialFrame) { + + } + + @Override + public void update() { + updatePipelines(); + } + + private void updatePipelines() { + boolean isBasic = yieldCalculator.getPipeline() == LithographyPipeline.BASIC; + basicPipelineItems.setHidden(!isBasic); + advancedPipelineItems.setHidden(isBasic); + } + + private class BasicPipelineItems extends AbstractGuiNode { + + private final ArrayList items = new ArrayList<>(); + + public BasicPipelineItems() { + addItem(new ItemStack(FabricationReferences.IC_BLUEPRINT_ITEM), 30, 5); + addItem(new ItemStack(FabricationReferences.PLOTTING_TABLE_BLOCK), 64, 5); + addItem(new ItemStack(FabricationReferences.BLANK_PHOTOMASK_ITEM), 64, 39); + addItem(new ItemStack(FabricationReferences.PHOTOMASK_SET_ITEM), 98, 5); + addItem(new ItemStack(FabricationReferences.LITHOGRAPHY_TABLE_BLOCK), 132, 5); + addItem(new ItemStack(FabricationReferences.ROUGH_SILICON_WAFER_ITEM), 132, 39); + addItem(new ItemStack(FabricationReferences.VALID_DIE_ITEM), 166, 5); + addItem(new ItemStack(FabricationReferences.PACKAGING_TABLE_BLOCK), 200, 5); + addItem(new ItemStack(FabricationReferences.FABRICATED_GATE_ITEM), 234, 5); + } + + private void addItem(ItemStack stack, int x, int y) { + ItemStackNode stackNode = new ItemStackNode(stack); + stackNode.setPosition(x, y); + items.add(stackNode); + addChild(stackNode); + } + + @Override + public void drawBack(PoseStack stack, Point mouse, float partialFrame) { + RenderSystem.setShaderTexture(0, ICWorkbenchInfoTab.TAB_BACKGROUND); + + // Draw the diagram centered in this node + GuiComponent.blit(stack, getFrame().x(), getFrame().y(), 1, 223, 280, 56, 512, 512); + } + + @Override + public void update() { + // Update the wafer input slot to the Lithography table + ItemStackNode node = items.get(5); //Wafer slot + switch (yieldCalculator.getWaferType()) { + case ROUGH_WAFER: + node.setItemStack(new ItemStack(FabricationReferences.ROUGH_SILICON_WAFER_ITEM)); + break; + case POLISHED_WAFER: + case PURIFIED_WAFER: + node.setItemStack(ItemStack.EMPTY); //TODO + break; + } + } + + //TODO update final Gate stack to reflect proper IO + } +} diff --git a/fabrication/src/main/java/mrtjp/projectred/fabrication/gui/VerticalListNode.java b/fabrication/src/main/java/mrtjp/projectred/fabrication/gui/VerticalListNode.java new file mode 100644 index 000000000..3ee60a5e0 --- /dev/null +++ b/fabrication/src/main/java/mrtjp/projectred/fabrication/gui/VerticalListNode.java @@ -0,0 +1,257 @@ +package mrtjp.projectred.fabrication.gui; + +import com.mojang.blaze3d.systems.RenderSystem; +import com.mojang.blaze3d.vertex.PoseStack; +import mrtjp.projectred.lib.Point; +import mrtjp.projectred.lib.Rect; +import mrtjp.projectred.redui.AbstractGuiNode; +import mrtjp.projectred.redui.RedUINode; +import net.minecraft.client.gui.Font; +import net.minecraft.client.gui.GuiComponent; +import net.minecraft.network.chat.Component; + +import java.util.function.Supplier; + +public class VerticalListNode extends AbstractGuiNode { + + private static final int TITLE_LINE_HEIGHT = 16; + private static final int TEXT_LINE_HEIGHT = 12; + private static final int TEXT_LEFT_PAD = 5; + private static final int NODE_ROW_VERTICAL_PAD = 2; + + private int listHeight = 0; + + @Override + public void onSubTreePreDrawBack() { + // This node's frame converted to GL11 window coordinates + Rect gl11Rect = calculateGL11Frame(); + + // Enable scissor using the calculated rect + RenderSystem.enableScissor(gl11Rect.x(), gl11Rect.y(), gl11Rect.width(), gl11Rect.height()); + } + + @Override + public void onSubTreePostDrawBack() { + // Disable scissor + RenderSystem.disableScissor(); + } + + @Override + public void drawBack(PoseStack stack, Point mouse, float partialFrame) { + //Background + GuiComponent.fill(stack, getFrame().x(), getFrame().y(), getFrame().x() + getFrame().width(), getFrame().y() + getFrame().height(), 0x7F000000); + + //TODO render top/bottom gradients + } + + public void sortElementsVertically() { + positionElementsAt(0); + } + + public boolean canScroll() { + Rect subFrame = calculateChildrenFrame(); + return subFrame.height() <= calculateAccumulatedFrame().height(); + } + + public double getScrollPercentage() { + Rect subFrame = calculateChildrenFrame(); + if (subFrame.height() <= calculateAccumulatedFrame().height()) { + return 0; + } + + int totalScroll = subFrame.height() - getFrame().height(); // How much scroll is possible + int dist = subFrame.maxY() - getFrame().maxY(); // How close to the bottom we are + + return (double) (totalScroll - dist) / totalScroll; + } + + public void setScrollPercentage(double scrollPercentage) { + Rect subFrame = calculateChildrenFrame(); + if (subFrame.height() <= getFrame().height()) return; + + int totalScroll = subFrame.height() - getFrame().height(); // How much scroll is possible + int dist = (int) (totalScroll * scrollPercentage); // How much we want to scroll + + positionElementsAt(-dist); + } + + protected void positionChildNode(RedUINode node, int x, int y) { + if (node instanceof AbstractGuiNode) { + ((AbstractGuiNode) node).setPosition(x, y); + } + } + + private void positionElementsAt(int y) { + for (RedUINode node : getOurChildren()) { + positionChildNode(node, 0, y); + y += node.calculateAccumulatedFrame().height(); + } + } + + private void positionAndAddChildListElement(RedUINode node) { + positionChildNode(node, 0, listHeight); + listHeight += node.calculateAccumulatedFrame().height(); + addChild(node); + } + + public void addTitleRow(Component title) { + TitleRow titleNode = new TitleRow(title); + titleNode.setSize(getFrame().width(), TITLE_LINE_HEIGHT); + positionAndAddChildListElement(new RowNode(0, titleNode)); + } + + public void addKeyValueRow(Component key, Supplier valueSupplier) { + + TextNode keyNode = new TextNode(key); + keyNode.setSize(getFrame().width() / 2, TEXT_LINE_HEIGHT); + keyNode.setPadding(TEXT_LEFT_PAD); + + TextNode valueNode = new TextNode(valueSupplier); + valueNode.setSize(getFrame().width() / 2, TEXT_LINE_HEIGHT); + valueNode.setPadding(TEXT_LEFT_PAD); + + positionAndAddChildListElement(new RowNode(0, keyNode, valueNode)); + } + + public void addTextWithNodeRow(Component key, RedUINode node) { + TextNode textNode = new TextNode(key); + textNode.setSize(getFrame().width() / 2, Math.max(TEXT_LINE_HEIGHT, node.calculateAccumulatedFrame().height())); + textNode.setPadding(TEXT_LEFT_PAD); + + positionAndAddChildListElement(new RowNode(NODE_ROW_VERTICAL_PAD, textNode, node)); + } + + public void addSingleNodeRow(RedUINode node) { + positionAndAddChildListElement(new RowNode(NODE_ROW_VERTICAL_PAD, node)); + } + + private class RowNode extends AbstractGuiNode { + + public RowNode(int verticalPadding, RedUINode... rowElements) { + int x = 0; + int maxH = 0; + for (RedUINode node : rowElements) { + VerticalListNode.this.positionChildNode(node, x, verticalPadding); + Rect childFrame = node.calculateAccumulatedFrame(); + maxH = Math.max(maxH, childFrame.height()); + x += childFrame.width(); + addChild(node); + } + + setSize(x, maxH + verticalPadding * 2); + } + } + + // TODO move to redui lib + private static class TextNode extends AbstractGuiNode { + + private final Supplier textSupplier; + + private HorizontalAlignment horizontalAlignment = HorizontalAlignment.LEFT; + private VerticalAlignment verticalAlignment = VerticalAlignment.CENTER; + + private int padding = 4; + private int textColor = 0xFFFFFFFF; + + public TextNode(Supplier textSupplier) { + this.textSupplier = textSupplier; + } + + public TextNode(Component text) { + this(() -> text); + } + + public void setTextColor(int textColor) { + this.textColor = textColor; + } + + public void setPadding(int padding) { + this.padding = padding; + } + + public void setHorizontalAlignment(HorizontalAlignment horizontalAlignment) { + this.horizontalAlignment = horizontalAlignment; + } + + public void setVerticalAlignment(VerticalAlignment verticalAlignment) { + this.verticalAlignment = verticalAlignment; + } + + @Override + public void drawBack(PoseStack stack, Point mouse, float partialFrame) { + Font fontRenderer = getRoot().getFontRenderer(); + Component text = textSupplier.get(); + + int x = getXForAlignment(fontRenderer, text); + int y = getYForAlignment(fontRenderer); + fontRenderer.drawShadow(stack, text, x, y, textColor); + } + + private Rect getPaddedFrame() { + return getFrame().expand(-padding, -padding); + } + + private int getXForAlignment(Font fontRenderer, Component text) { + switch (horizontalAlignment) { + case LEFT: + return getPaddedFrame().x(); + case CENTER: + return getPaddedFrame().midX() - fontRenderer.width(text) / 2; + case RIGHT: + return getPaddedFrame().maxX() - fontRenderer.width(text); + default: + return getPaddedFrame().x(); + } + } + + private int getYForAlignment(Font fontRenderer) { + switch (verticalAlignment) { + case TOP: + return getPaddedFrame().y(); + case CENTER: + return getPaddedFrame().midY() - fontRenderer.lineHeight / 2; + case BOTTOM: + return getPaddedFrame().maxY() - fontRenderer.lineHeight; + default: + return getPaddedFrame().y(); + } + } + + public enum HorizontalAlignment { + LEFT, + CENTER, + RIGHT + } + + public enum VerticalAlignment { + TOP, + CENTER, + BOTTOM + } + } + + private static class TitleRow extends AbstractGuiNode { + + private static final int TITLE_COLOR = 0xFFFFFFFF; + private final Component title; + + public TitleRow(Component title) { + this.title = title; + } + + @Override + public void drawBack(PoseStack stack, Point mouse, float partialFrame) { + //Line + GuiComponent.fill(stack, getFrame().x(), getFrame().y(), getFrame().x() + getFrame().width(), getFrame().y() + 1, 0xFF000000); + + Font fontRenderer = getRoot().getFontRenderer(); + + int x = getFrame().midX() - fontRenderer.width(title) / 2; + int y = getFrame().midY() - fontRenderer.lineHeight / 2; + fontRenderer.drawShadow(stack, title, x, y, TITLE_COLOR); + + //Line + GuiComponent.fill(stack, getFrame().x(), getFrame().y() + getFrame().height() - 1, getFrame().x() + getFrame().width(), getFrame().y() + getFrame().height(), 0xFF000000); + } + } +} diff --git a/fabrication/src/main/java/mrtjp/projectred/fabrication/gui/screen/ICWorkbenchCompileTab.java b/fabrication/src/main/java/mrtjp/projectred/fabrication/gui/screen/ICWorkbenchCompileTab.java index 0832b396b..ceafd3a55 100644 --- a/fabrication/src/main/java/mrtjp/projectred/fabrication/gui/screen/ICWorkbenchCompileTab.java +++ b/fabrication/src/main/java/mrtjp/projectred/fabrication/gui/screen/ICWorkbenchCompileTab.java @@ -1,5 +1,6 @@ package mrtjp.projectred.fabrication.gui.screen; +import codechicken.lib.colour.EnumColour; import codechicken.lib.render.CCRenderState; import codechicken.lib.vec.Vector3; import com.mojang.blaze3d.systems.RenderSystem; @@ -85,7 +86,12 @@ public void drawBack(PoseStack stack, Point mouse, float partialFrame) { RenderSystem.setShaderTexture(0, TAB_BACKGROUND); GuiComponent.blit(stack, getFrame().x(), getFrame().y(), 0, 0, getFrame().width(), getFrame().height(), 512, 512); + if (editor.isActive()) { + getRoot().getFontRenderer().draw(stack, editor.getIcName(), getFrame().x() + 8, getFrame().y() + 6, EnumColour.GRAY.argb()); + } + // Progress bar + RenderSystem.setShaderTexture(0, TAB_BACKGROUND); int barWidth = 91; int progress = editor.getStateMachine().getCompilerLog().getProgressScaled(barWidth); GuiComponent.blit(stack, getFrame().x() + 208, getFrame().y() + 36, 304, 0, barWidth, 5, 512, 512); diff --git a/fabrication/src/main/java/mrtjp/projectred/fabrication/gui/screen/ICWorkbenchEditTab.java b/fabrication/src/main/java/mrtjp/projectred/fabrication/gui/screen/ICWorkbenchEditTab.java index 643e3b725..ca89029f9 100644 --- a/fabrication/src/main/java/mrtjp/projectred/fabrication/gui/screen/ICWorkbenchEditTab.java +++ b/fabrication/src/main/java/mrtjp/projectred/fabrication/gui/screen/ICWorkbenchEditTab.java @@ -1,12 +1,15 @@ package mrtjp.projectred.fabrication.gui.screen; +import codechicken.lib.colour.EnumColour; import com.mojang.blaze3d.systems.RenderSystem; import com.mojang.blaze3d.vertex.PoseStack; import mrtjp.projectred.fabrication.editor.ICWorkbenchEditor; import mrtjp.projectred.fabrication.editor.tools.*; import mrtjp.projectred.fabrication.gui.*; import mrtjp.projectred.lib.Point; +import mrtjp.projectred.lib.Rect; import mrtjp.projectred.redui.AbstractGuiNode; +import net.minecraft.client.gui.Font; import net.minecraft.client.gui.GuiComponent; public class ICWorkbenchEditTab extends AbstractGuiNode { @@ -67,7 +70,15 @@ private ICEditorToolTab getTabForTool(IICEditorTool tool) { @Override public void drawBack(PoseStack stack, Point mouse, float partialFrame) { RenderSystem.setShaderTexture(0, ICWorkbenchScreen.BACKGROUND); - GuiComponent.blit(stack, getFrame().x(), getFrame().y(), 0, 0, getFrame().width(), getFrame().height(), 512, 512); + + Rect frame = getFrame(); + Font fontRenderer = getRoot().getFontRenderer(); + + GuiComponent.blit(stack, frame.x(), frame.y(), 0, 0, frame.width(), frame.height(), 512, 512); + + if (editor.isActive()) { + fontRenderer.draw(stack, editor.getIcName(), frame.x() + 8, frame.y() + 6, EnumColour.GRAY.argb()); + } } @Override diff --git a/fabrication/src/main/java/mrtjp/projectred/fabrication/gui/screen/ICWorkbenchInfoTab.java b/fabrication/src/main/java/mrtjp/projectred/fabrication/gui/screen/ICWorkbenchInfoTab.java new file mode 100644 index 000000000..89b104df8 --- /dev/null +++ b/fabrication/src/main/java/mrtjp/projectred/fabrication/gui/screen/ICWorkbenchInfoTab.java @@ -0,0 +1,241 @@ +package mrtjp.projectred.fabrication.gui.screen; + +import codechicken.lib.colour.EnumColour; +import codechicken.lib.texture.TextureUtils; +import com.mojang.blaze3d.systems.RenderSystem; +import com.mojang.blaze3d.vertex.PoseStack; +import mrtjp.fengine.TileCoord; +import mrtjp.projectred.fabrication.ProjectRedFabrication; +import mrtjp.projectred.fabrication.editor.ICWorkbenchEditor; +import mrtjp.projectred.fabrication.gui.ButtonArrayNode; +import mrtjp.projectred.fabrication.gui.PipelineDiagramNode; +import mrtjp.projectred.fabrication.gui.VerticalListNode; +import mrtjp.projectred.fabrication.lithography.LithographyPipeline; +import mrtjp.projectred.fabrication.lithography.ProcessNode; +import mrtjp.projectred.fabrication.lithography.WaferType; +import mrtjp.projectred.fabrication.lithography.YieldCalculator; +import mrtjp.projectred.lib.Point; +import mrtjp.projectred.lib.Rect; +import mrtjp.projectred.redui.AbstractGuiNode; +import mrtjp.projectred.redui.ScrollBarNode; +import mrtjp.projectred.redui.TextBoxNode; +import net.minecraft.client.gui.GuiComponent; +import net.minecraft.network.chat.Component; +import net.minecraft.network.chat.TextComponent; +import net.minecraft.network.chat.TranslatableComponent; +import net.minecraft.resources.ResourceLocation; + +public class ICWorkbenchInfoTab extends AbstractGuiNode { + + public static final ResourceLocation TAB_BACKGROUND = new ResourceLocation(ProjectRedFabrication.MOD_ID, "textures/gui/info_tab.png"); + + private final ICWorkbenchEditor editor; + + private final YieldCalculator yieldCalculator = new YieldCalculator(); + + private VerticalListNode listNode; + + public ICWorkbenchInfoTab(ICWorkbenchEditor editor) { + this.editor = editor; + + setSize(304, 222); + initSubNodes(); + } + + private void initSubNodes() { + + listNode = new VerticalListNode(); + listNode.setPosition(6, 17); + listNode.setSize(280, 198); + addChild(listNode); + + NameTextBox nameTextBox = new NameTextBox(); + nameTextBox.setSize(80, 18); + + //TODO localize + listNode.addTitleRow(new TranslatableComponent("Info")); + listNode.addTextWithNodeRow(new TranslatableComponent("Name"), nameTextBox); + listNode.addKeyValueRow(new TranslatableComponent("Owner"), () -> new TranslatableComponent("//TODO")); + + listNode.addKeyValueRow(new TranslatableComponent("Dimensions"), () -> { + TileCoord dimensions = editor.getTileMap().getDimensions(); + Component tilesWord = new TranslatableComponent("tiles"); + Component byWord = new TranslatableComponent("by"); + return new TextComponent("" + dimensions.x).append(" ").append(tilesWord).append(" ").append(byWord).append(" ").append("" + dimensions.z).append(" ").append(tilesWord); + }); + + listNode.addKeyValueRow(new TranslatableComponent("Layers"), () -> { + TileCoord dimensions = editor.getTileMap().getDimensions(); + return new TextComponent("" + dimensions.y); + }); + + listNode.addTitleRow(new TranslatableComponent("Yield Calculator")); + + ButtonArrayNode pipelineButtonGrid = createPipelineButtons(); + pipelineButtonGrid.setGridSize(128, 18); + listNode.addTextWithNodeRow(new TranslatableComponent("Lithography Pipeline"), pipelineButtonGrid); + + ButtonArrayNode processNodeButtonGrid = createProcessNodeButtons(); + processNodeButtonGrid.setGridSize(128, 18); + listNode.addTextWithNodeRow(new TranslatableComponent("Process Node"), processNodeButtonGrid); + + ButtonArrayNode waferTypeButtonGrid = createWaferTypeButtons(); + waferTypeButtonGrid.setGridSize(128, 18); + listNode.addTextWithNodeRow(new TranslatableComponent("Wafer Type"), waferTypeButtonGrid); + + PipelineDiagramNode diagramNode = new PipelineDiagramNode(yieldCalculator); + listNode.addSingleNodeRow(diagramNode); + + ScrollBarNode scrollBarNode = new ScrollBarNode(ScrollBarNode.ScrollAxis.VERTICAL) { + @Override + protected void drawSlider(PoseStack stack, Rect sliderFrame) { + RenderSystem.setShaderTexture(0, TAB_BACKGROUND); + GuiComponent.blit(stack, sliderFrame.x(), sliderFrame.y(), 305, 58, sliderFrame.width(), sliderFrame.height(), 512, 512); + } + + @Override + protected void adjustContent(double scrollPercentage) { + listNode.setScrollPercentage(scrollPercentage); + } + }; + + listNode.addKeyValueRow(new TranslatableComponent("Die size"), () -> new TextComponent(yieldCalculator.getDieSizeString())); + listNode.addKeyValueRow(new TranslatableComponent("Wafer size"), () -> new TextComponent(yieldCalculator.getWaferSizeString())); + listNode.addKeyValueRow(new TranslatableComponent("Dies per wafer"), () -> new TextComponent(yieldCalculator.getDiesPerWaferString())); + listNode.addKeyValueRow(new TranslatableComponent("Single layer yield"), () -> new TextComponent(yieldCalculator.getSingleLayerYieldString())); + listNode.addKeyValueRow(new TranslatableComponent("Yield"), () -> new TextComponent(yieldCalculator.getYieldString())); + + scrollBarNode.setPosition(290, 17); + scrollBarNode.setSize(8, 198); + scrollBarNode.setSliderSize(8, 16); + addChild(scrollBarNode); + } + + @Override + public void update() { + super.update(); + TileCoord dimensions = editor.getTileMap().getDimensions(); + yieldCalculator.setTileMapSize(dimensions.x, dimensions.z, dimensions.y); + } + + @Override + public void drawBack(PoseStack stack, Point mouse, float partialFrame) { + RenderSystem.setShaderTexture(0, TAB_BACKGROUND); + GuiComponent.blit(stack, getFrame().x(), getFrame().y(), 0, 0, getFrame().width(), getFrame().height(), 512, 512); + + if (editor.isActive()) { + getRoot().getFontRenderer().draw(stack, editor.getIcName(), getFrame().x() + 8, getFrame().y() + 6, EnumColour.GRAY.argb()); + } + } + + private ButtonArrayNode createPipelineButtons() { + ButtonArrayNode.Listener listener = new ButtonArrayNode.Listener() { + @Override + public String getButtonText(int index) { + return LithographyPipeline.values()[index].getUnlocalizedName(); + } + + @Override + public void onButtonClicked(int index) { + LithographyPipeline pipeline = LithographyPipeline.values()[index]; + yieldCalculator.setPipeline(pipeline); + if (!pipeline.isProcessNodeValid(yieldCalculator.getProcessNode())) { + yieldCalculator.setProcessNode(ProcessNode.PROCESS_64NM); + } + if (!pipeline.isWaferTypeValid(yieldCalculator.getWaferType())) { + yieldCalculator.setWaferType(WaferType.ROUGH_WAFER); + } + } + + @Override + public boolean isButtonEnabled(int index) { + return true; + } + + @Override + public boolean isButtonSelected(int index) { + return yieldCalculator.getPipeline().ordinal() == index; + } + }; + return new ButtonArrayNode(listener, 1, LithographyPipeline.values().length, 2); + } + + private ButtonArrayNode createProcessNodeButtons() { + ButtonArrayNode.Listener listener = new ButtonArrayNode.Listener() { + @Override + public String getButtonText(int index) { + return ProcessNode.values()[index].getDisplayName(); + } + + @Override + public void onButtonClicked(int index) { + yieldCalculator.setProcessNode(ProcessNode.values()[index]); + } + + @Override + public boolean isButtonEnabled(int index) { + return yieldCalculator.getPipeline().isProcessNodeValid(ProcessNode.values()[index]); + } + + @Override + public boolean isButtonSelected(int index) { + return yieldCalculator.getProcessNode().ordinal() == index; + } + }; + return new ButtonArrayNode(listener, 1, ProcessNode.values().length, 2); + } + + private ButtonArrayNode createWaferTypeButtons() { + ButtonArrayNode.Listener listener = new ButtonArrayNode.Listener() { + @Override + public String getButtonText(int index) { + return WaferType.values()[index].getUnlocalizedName(); + } + + @Override + public void onButtonClicked(int index) { + yieldCalculator.setWaferType(WaferType.values()[index]); + } + + @Override + public boolean isButtonEnabled(int index) { + return yieldCalculator.getPipeline().isWaferTypeValid(WaferType.values()[index]); + } + + @Override + public boolean isButtonSelected(int index) { + return yieldCalculator.getWaferType().ordinal() == index; + } + }; + return new ButtonArrayNode(listener, 1, WaferType.values().length, 2); + } + + private class NameTextBox extends TextBoxNode { + + public NameTextBox() { + super(editor.getIcName()); + } + + @Override + public void update() { + super.update(); + if (!getText().equals(editor.getIcName()) && !isEditing()) { + setText(editor.getIcName()); + } + } + + @Override + protected String getSuggestionString() { + return editor.getIcName(); + } + + @Override + protected void onTextChanged() { + } + + @Override + protected void onReturnPressed() { + editor.sendNewICName(getText()); + } + } +} diff --git a/fabrication/src/main/java/mrtjp/projectred/fabrication/gui/screen/ICWorkbenchScreen.java b/fabrication/src/main/java/mrtjp/projectred/fabrication/gui/screen/ICWorkbenchScreen.java index 54dd43520..35c7bd9ee 100644 --- a/fabrication/src/main/java/mrtjp/projectred/fabrication/gui/screen/ICWorkbenchScreen.java +++ b/fabrication/src/main/java/mrtjp/projectred/fabrication/gui/screen/ICWorkbenchScreen.java @@ -9,7 +9,6 @@ import mrtjp.projectred.fabrication.tile.ICWorkbenchTile; import mrtjp.projectred.lib.Point; import mrtjp.projectred.lib.Rect; -import mrtjp.projectred.redui.DebugRectNode; import mrtjp.projectred.redui.RedUIScreen; import net.minecraft.client.Minecraft; import net.minecraft.client.gui.Font; @@ -37,6 +36,9 @@ public static void openGuiOnClient(ICWorkbenchTile tile) { } private void initSubNodes() { + ICWorkbenchInfoTab infoTab = new ICWorkbenchInfoTab(editor); + addChild(infoTab); + ICWorkbenchEditTab editTab = new ICWorkbenchEditTab(editor); addChild(editTab); @@ -48,7 +50,7 @@ private void initSubNodes() { tabControllerNode.setZPosition(0.1); addChild(tabControllerNode); - tabControllerNode.addButtonForTab(new SimpleUVTab(new DebugRectNode(), "Info", TabButtonNode.TabSide.LEFT, 420, 1)); + tabControllerNode.addButtonForTab(new SimpleUVTab(infoTab, "Info", TabButtonNode.TabSide.LEFT, 420, 1)); tabControllerNode.addButtonForTab(new SimpleUVTab(editTab, "Edit", TabButtonNode.TabSide.LEFT, 420, 16)); tabControllerNode.addButtonForTab(new SimpleUVTab(compileTab, "Compile", TabButtonNode.TabSide.LEFT, 420, 31)); diff --git a/fabrication/src/main/java/mrtjp/projectred/fabrication/item/BaseSiliconWaferItem.java b/fabrication/src/main/java/mrtjp/projectred/fabrication/item/BaseSiliconWaferItem.java index 353c437aa..9185bb1c5 100644 --- a/fabrication/src/main/java/mrtjp/projectred/fabrication/item/BaseSiliconWaferItem.java +++ b/fabrication/src/main/java/mrtjp/projectred/fabrication/item/BaseSiliconWaferItem.java @@ -28,8 +28,8 @@ public void appendHoverText(ItemStack stack, @Nullable Level world, List compatibleProcesses; + private final Set compatibleWafers; + private final String unlocalizedName; + + LithographyPipeline(ProcessNode[] compatibleProcesses, WaferType[] compatibleWafers, String unlocalizedName) { + this.compatibleProcesses = Arrays.stream(compatibleProcesses).collect(Collectors.toSet()); + this.compatibleWafers = Arrays.stream(compatibleWafers).collect(Collectors.toSet()); + this.unlocalizedName = unlocalizedName; + } + + public boolean isProcessNodeValid(ProcessNode process) { + return compatibleProcesses.contains(process); + } + + public boolean isWaferTypeValid(WaferType wafer) { + return compatibleWafers.contains(wafer); + } + + public String getUnlocalizedName() { + return unlocalizedName; + } +} diff --git a/fabrication/src/main/java/mrtjp/projectred/fabrication/lithography/ProcessNode.java b/fabrication/src/main/java/mrtjp/projectred/fabrication/lithography/ProcessNode.java index dfe9dfa78..eca41ba5b 100644 --- a/fabrication/src/main/java/mrtjp/projectred/fabrication/lithography/ProcessNode.java +++ b/fabrication/src/main/java/mrtjp/projectred/fabrication/lithography/ProcessNode.java @@ -15,11 +15,19 @@ public enum ProcessNode { this.tileArea = tileLen * tileLen; } - public int getTileLen() { + public int getTileWidth() { + return tileLen; + } + + public int getTileHeight() { return tileLen; } public int getTileArea() { return tileArea; } + + public String getDisplayName() { + return "" + tileLen + "nm"; + } } diff --git a/fabrication/src/main/java/mrtjp/projectred/fabrication/lithography/WaferType.java b/fabrication/src/main/java/mrtjp/projectred/fabrication/lithography/WaferType.java index 4529214a4..0093e84a3 100644 --- a/fabrication/src/main/java/mrtjp/projectred/fabrication/lithography/WaferType.java +++ b/fabrication/src/main/java/mrtjp/projectred/fabrication/lithography/WaferType.java @@ -2,29 +2,45 @@ public enum WaferType { - ROUGH_WAFER (4096, 0.0005), - PURIFIED_WAFER (4096, 0.0001), - POLISHED_WAFER (4096, 0.00001); + //@formatter:off + ROUGH_WAFER (4096, 0.5, "roughWafer"), + PURIFIED_WAFER (4096, 0.1, "purifiedWafer"), + POLISHED_WAFER (4096, 0.01, "polishedWafer"); + //@formatter:on + private final String unlocalizedName; private final int waferLen; private final int waferArea; - private final double defectChancePerLen; + private final double defectRatePerUnitArea; - WaferType(int waferLen, double defectChancePerLen) { + // Note: standard die defect rate is rate of defect of 16x16 design in 64nm process + WaferType(int waferLen, double standardDieDefectRate, String unlocalizedName) { this.waferLen = waferLen; - this.waferArea = waferLen * waferLen; - this.defectChancePerLen = defectChancePerLen; + this.waferArea = waferLen * waferLen; // square wafers only atm + + // back-calculate standard die defect rate to defect per unit area + this.defectRatePerUnitArea = standardDieDefectRate / (Math.pow(64 * 16, 2)); + + this.unlocalizedName = unlocalizedName; } public int getWaferArea() { return waferArea; } - public int getWaferLen() { + public int getWaferWidth() { return waferLen; } - public double getDefectChancePerLen() { - return defectChancePerLen; + public int getWaferHeight() { + return waferLen; + } + + public double getDefectRatePerUnitArea() { + return defectRatePerUnitArea; + } + + public String getUnlocalizedName() { + return unlocalizedName; } } diff --git a/fabrication/src/main/java/mrtjp/projectred/fabrication/lithography/YieldCalculator.java b/fabrication/src/main/java/mrtjp/projectred/fabrication/lithography/YieldCalculator.java new file mode 100644 index 000000000..8dc7c63f1 --- /dev/null +++ b/fabrication/src/main/java/mrtjp/projectred/fabrication/lithography/YieldCalculator.java @@ -0,0 +1,91 @@ +package mrtjp.projectred.fabrication.lithography; + +import mrtjp.projectred.lib.Size; + +public class YieldCalculator { + + private int tileMapWidth; + private int tileMapHeight; + private int tileMapLayers; + + private LithographyPipeline pipeline = LithographyPipeline.BASIC; + private ProcessNode processNode = ProcessNode.PROCESS_64NM; + private WaferType waferType = WaferType.ROUGH_WAFER; + + public LithographyPipeline getPipeline() { + return pipeline; + } + + public void setPipeline(LithographyPipeline pipeline) { + this.pipeline = pipeline; + } + + public ProcessNode getProcessNode() { + return processNode; + } + + public void setProcessNode(ProcessNode processNode) { + this.processNode = processNode; + } + + public WaferType getWaferType() { + return waferType; + } + + public void setWaferType(WaferType waferType) { + this.waferType = waferType; + } + + public void setTileMapSize(int width, int height, int layers) { + this.tileMapWidth = width; + this.tileMapHeight = height; + this.tileMapLayers = layers; + } + + public Size getTileMapSize() { + return new Size(tileMapWidth, tileMapHeight); + } + + public Size getDieSize() { + return new Size(tileMapWidth * processNode.getTileWidth(), tileMapHeight * processNode.getTileHeight()); + } + + public Size getWaferSize() { + return new Size(waferType.getWaferWidth(), waferType.getWaferHeight()); + } + + public Size getDieCount() { + return getWaferSize().divide(getDieSize()); + } + + public double getSingleLayerYield() { + Size dieSize = getDieSize(); + return 1.0 - waferType.getDefectRatePerUnitArea() * dieSize.width * dieSize.height; + } + + public double getMultiLayerYield() { + return Math.pow(getSingleLayerYield(), tileMapLayers); + } + + public String getDieSizeString() { + Size dieSize = getDieSize(); + return String.format("%d nm x %d nm", dieSize.width, dieSize.height); + } + + public String getWaferSizeString() { + return String.format("%d nm x %d nm", waferType.getWaferWidth(), waferType.getWaferHeight()); + } + + public String getDiesPerWaferString() { + Size dieCount = getDieCount(); + return String.format("%d dies x %d dies (%d total)", dieCount.width, dieCount.height, dieCount.width * dieCount.height); + } + + public String getSingleLayerYieldString() { + return String.format("%.2f%%", getSingleLayerYield() * 100); + } + + public String getYieldString() { + return String.format("%.2f%%", getMultiLayerYield() * 100); + } +} diff --git a/fabrication/src/main/java/mrtjp/projectred/fabrication/tile/LithographyTableTile.java b/fabrication/src/main/java/mrtjp/projectred/fabrication/tile/LithographyTableTile.java index 999abafb7..7830123d0 100644 --- a/fabrication/src/main/java/mrtjp/projectred/fabrication/tile/LithographyTableTile.java +++ b/fabrication/src/main/java/mrtjp/projectred/fabrication/tile/LithographyTableTile.java @@ -131,12 +131,14 @@ protected void finishWork() { WaferType waferType = wafer.getWaferType(); ProcessNode processNode = ProcessNode.PROCESS_64NM; - int dieLen = processNode.getTileLen() * 16; //TODO Source from photomask itemstack instead of assuming 16x16 - int gridLen = waferType.getWaferLen() / dieLen; - double defectChancePerDie = dieLen * waferType.getDefectChancePerLen(); + int dieWidth = processNode.getTileWidth() * 16; //TODO Source from photomask itemstack instead of assuming 16x16 + int dieHeight = processNode.getTileHeight() * 16; + int gridWidth = waferType.getWaferWidth() / dieWidth; + int gridHeight = waferType.getWaferHeight() / dieHeight; + double defectChancePerDie = dieWidth * dieHeight * waferType.getDefectRatePerUnitArea(); // Calculate number of good and bad dies - int totalDesigns = gridLen * gridLen; + int totalDesigns = gridWidth * gridHeight; int totalDefectiveDies = 0; for (int i = 0; i < totalDesigns; i++) { if (Math.random() < defectChancePerDie) { diff --git a/fabrication/src/main/resources/assets/projectred_fabrication/textures/gui/info_tab.png b/fabrication/src/main/resources/assets/projectred_fabrication/textures/gui/info_tab.png new file mode 100644 index 0000000000000000000000000000000000000000..6f38483e1d8dbce62aaf1cd578b07c4825e13f2a GIT binary patch literal 7672 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 literal 0 HcmV?d00001 From 22a21ddc6e4e9ab7d6b45dfa504becdfbceda0d1 Mon Sep 17 00:00:00 2001 From: MrTJP Date: Sat, 12 Nov 2022 03:07:52 -0500 Subject: [PATCH 05/23] feat: workbench ui overlay if no blueprint --- .../gui/screen/ICWorkbenchScreen.java | 92 ++++++++++++++---- .../fabrication/item/ICBlueprintItem.java | 2 + .../textures/gui/ic_workbench.png | Bin 29122 -> 35141 bytes 3 files changed, 74 insertions(+), 20 deletions(-) diff --git a/fabrication/src/main/java/mrtjp/projectred/fabrication/gui/screen/ICWorkbenchScreen.java b/fabrication/src/main/java/mrtjp/projectred/fabrication/gui/screen/ICWorkbenchScreen.java index 35c7bd9ee..ab92a600b 100644 --- a/fabrication/src/main/java/mrtjp/projectred/fabrication/gui/screen/ICWorkbenchScreen.java +++ b/fabrication/src/main/java/mrtjp/projectred/fabrication/gui/screen/ICWorkbenchScreen.java @@ -1,19 +1,26 @@ package mrtjp.projectred.fabrication.gui.screen; +import codechicken.lib.colour.EnumColour; +import com.mojang.blaze3d.systems.RenderSystem; import com.mojang.blaze3d.vertex.PoseStack; import mrtjp.projectred.fabrication.ProjectRedFabrication; import mrtjp.projectred.fabrication.editor.ICWorkbenchEditor; import mrtjp.projectred.fabrication.gui.SimpleUVTab; import mrtjp.projectred.fabrication.gui.TabButtonNode; import mrtjp.projectred.fabrication.gui.TabControllerNode; +import mrtjp.projectred.fabrication.init.FabricationReferences; import mrtjp.projectred.fabrication.tile.ICWorkbenchTile; import mrtjp.projectred.lib.Point; -import mrtjp.projectred.lib.Rect; +import mrtjp.projectred.redui.AbstractGuiNode; +import mrtjp.projectred.redui.ItemStackNode; import mrtjp.projectred.redui.RedUIScreen; import net.minecraft.client.Minecraft; import net.minecraft.client.gui.Font; +import net.minecraft.network.chat.Component; import net.minecraft.network.chat.TextComponent; +import net.minecraft.network.chat.TranslatableComponent; import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.item.ItemStack; public class ICWorkbenchScreen extends RedUIScreen { @@ -22,6 +29,9 @@ public class ICWorkbenchScreen extends RedUIScreen { private final ICWorkbenchTile tile; private final ICWorkbenchEditor editor; + private AbstractGuiNode contentNode; + private InactiveOverlayNode overlayNode; + public ICWorkbenchScreen(ICWorkbenchTile tile) { super(304, 222, new TextComponent(tile.getType().getRegistryName().toString())); @@ -36,19 +46,24 @@ public static void openGuiOnClient(ICWorkbenchTile tile) { } private void initSubNodes() { + + //organizational node to make hiding everything easy + contentNode = new AbstractGuiNode() { }; + addChild(contentNode); + ICWorkbenchInfoTab infoTab = new ICWorkbenchInfoTab(editor); - addChild(infoTab); + contentNode.addChild(infoTab); ICWorkbenchEditTab editTab = new ICWorkbenchEditTab(editor); - addChild(editTab); + contentNode.addChild(editTab); ICWorkbenchCompileTab compileTab = new ICWorkbenchCompileTab(editor); - addChild(compileTab); + contentNode.addChild(compileTab); TabControllerNode tabControllerNode = new TabControllerNode(); tabControllerNode.setPosition(-19, 4); tabControllerNode.setZPosition(0.1); - addChild(tabControllerNode); + contentNode.addChild(tabControllerNode); tabControllerNode.addButtonForTab(new SimpleUVTab(infoTab, "Info", TabButtonNode.TabSide.LEFT, 420, 1)); tabControllerNode.addButtonForTab(new SimpleUVTab(editTab, "Edit", TabButtonNode.TabSide.LEFT, 420, 16)); @@ -56,26 +71,20 @@ private void initSubNodes() { tabControllerNode.selectInitialTab(1); tabControllerNode.spreadButtonsVertically(1); + + // Overlay for no blueprint + overlayNode = new InactiveOverlayNode(); + overlayNode.setPosition( + getFrame().midX() - overlayNode.getFrame().width() / 2, + getFrame().midY() - overlayNode.getFrame().height() / 2); + addChild(overlayNode); + + refreshOverlay(); } @Override public void drawBack(PoseStack stack, Point mouse, float partialFrame) { super.drawBack(stack, mouse, partialFrame); - - if (!editor.isActive()) { //TODO this has to be drawn by a node above viewport node - Rect frame = getFrame(); - fillGradient(stack, frame.x(), frame.y(), frame.width(), frame.height(), -1072689136, -804253680); - - Font fontRenderer = getFontRenderer(); - - String message = "Editor is not active"; - int width = fontRenderer.width(message); - int height = fontRenderer.lineHeight; - - getFontRenderer().draw(stack, message, - frame.x() + frame.width() / 2F - width / 2F, - frame.y() + frame.height() / 2F - height / 2F, 0xFFFFFFFF); - } } @Override @@ -90,4 +99,47 @@ public void onClose() { super.onClose(); ProjectRedFabrication.LOGGER.info("ICWorkbenchScreen ONCLOSE"); } + + @Override + public void update() { + refreshOverlay(); + } + + private void refreshOverlay() { + // If active, hide overlay and show every thing else. Otherwise, do opposite + boolean isActive = editor.isActive(); + overlayNode.setHidden(isActive); + contentNode.setHidden(!isActive); + } + + private static class InactiveOverlayNode extends AbstractGuiNode { + + public InactiveOverlayNode() { + setSize(132, 92); + initSubNodes(); + } + + private void initSubNodes() { + ItemStackNode blueprintNode = new ItemStackNode(new ItemStack(FabricationReferences.IC_BLUEPRINT_ITEM)); + blueprintNode.setPosition(58, 24); + addChild(blueprintNode); + + ItemStackNode workbenchNode = new ItemStackNode(new ItemStack(FabricationReferences.IC_WORKBENCH_BLOCK)); + workbenchNode.setPosition(58, 64); + addChild(workbenchNode); + } + + @Override + public void drawBack(PoseStack stack, Point mouse, float partialFrame) { + RenderSystem.setShaderTexture(0, BACKGROUND); + blit(stack, getFrame().x(), getFrame().y(), 0, 222, getFrame().width(), getFrame().height(), 512, 512); + + Font fontRenderer = getRoot().getFontRenderer(); + Component text = new TranslatableComponent("Place blueprint"); // TODO: localize + + fontRenderer.draw(stack, text, + getFrame().midX() - fontRenderer.width(text) / 2f, + getFrame().y() + 6, EnumColour.GRAY.argb()); + } + } } diff --git a/fabrication/src/main/java/mrtjp/projectred/fabrication/item/ICBlueprintItem.java b/fabrication/src/main/java/mrtjp/projectred/fabrication/item/ICBlueprintItem.java index 4143c178a..db35dff00 100644 --- a/fabrication/src/main/java/mrtjp/projectred/fabrication/item/ICBlueprintItem.java +++ b/fabrication/src/main/java/mrtjp/projectred/fabrication/item/ICBlueprintItem.java @@ -55,6 +55,8 @@ public InteractionResult onItemUseFirst(ItemStack stack, UseOnContext context) { public static void buildTooltip(CompoundTag blueprintTag, List tooltipList) { + if (blueprintTag == null) return; + if (!hasFabricationTarget(blueprintTag)) { tooltipList.add(new TextComponent(" ").withStyle(ChatFormatting.RED) .append(new TextComponent("Corrupted NBT data, please discard").withStyle(ChatFormatting.GRAY))); diff --git a/fabrication/src/main/resources/assets/projectred_fabrication/textures/gui/ic_workbench.png b/fabrication/src/main/resources/assets/projectred_fabrication/textures/gui/ic_workbench.png index 0cc012a4e069991bfabd95e5b72b487559321da1..276a4bf16f96b00b78adf9fec84ffd143a1496aa 100644 GIT binary patch literal 35141 zcmcG$1zc2H_Xd1uRFn`U1q2insTp8~ZV*WYMVf&bLb^Ky6-7ElBm}{rLplZNMj0BE zmhK$*&VYLFec$)~-}t`o{=7QO*=L`%_g;JLXFcmVJX2GVKYNiGh0RUX^ zBQ8Kp2>!F-`ehIN=alVDEe8NNSC9Q4Cz|6N9RQHvnrqy5ysxYzWNc%_g+SUEp}1VF zY{Aw5AR_K+i!io8IWifcOwFxDnU~9}nVHOyqRg87$~?-p(kL_Yo9^}~b$1mFV|NQ< zK_s)d7?X&r5ZHkg$`QfjYGrBdAml2_eB7@P_!;{(H#5_56GsbCW=ZS=neHpAF-hCl zqnKb^yqv~7JUmP=K`udKV`DxfN)UR33Bm(`aPvU9dHFbb`Gk02LJ$bk&;OXg2ihY| zgzm`5{d^qwlPI&9qob`5H@Az63zrL&%f{Z6n^#a!kedg>4S{fiEjS(AtQ`@qoYoF3 zzj}~CIT+iU+d7)tSTkXJL>SpPIf^oa#-5DA%Jz4+)($^s3Y;@;SA;D$FBcDXRL2dG z#=qOyI@wzuKOAYyjj}{pp{yMpz_z@<+uEAhINCUv+5An{zc2sg0pRQ^EB}7RzqG~5 z>h~iY9A%xsVf>tsf7#kW!_5}OeFx=W<797)l63~nWcf83M{|=urt>d%W3T+hE|jbJ z-!#Qu`Q6l3NZKBSaI~@4u(7fH@Cry=Ykme?CznX$8&dbZm3(??#2toOTcm+6l z`2T1MIwTU|i1@dSk;XzMHuhEsa4yZQ5T+<@TWeEhrr#?hByD49V-G$Uv<`Y~g|f1c zg0+Jq!rB<6AS22Q4uQ+u94W-lgEBJW<%4k=!HuDud?qkKPB<^W04EB<%M0h_wjFnYi$lrF*pTS zr#YEbbubEn(+WQ8_&YUoSCr*_8FO%E9FC3P=l#|E_>$H?TmmD+9~1U#@RH!NIDk&* z@H2i$AxwXMvNRWiLj+)gFn&2fDL9lL#w#fY;o*~(=7&qc;XIPkP(BfEY=8h8p2QyT z!~ecI|7l-vK4W7D+z85vgu{41hlas81z`dLoW_E1ILwF_B>>?!`cL~p8o}WLd{ACa zBtHap(ia?N0t5Sk!36~nJSN6))Iaz2%U5_!1bLtkV}4GgAOiGYeiP8=cp-e8FeD6y zW6iV#E*QL2&Yzz>u7LMm&6+aDIN!6dsrnl#dSqH~v@S`1Ne4kug6E zWhB4}L74D!g01142)F>069I$r3K$u|Abcp3zkfC#QUKf&f=F=4d?-#nV<`A+K3*_9 z@WDZ=_#nmtNZ8-s{h#cSzrR~RfX9d*bsUTMOgQ;?Py(C?BPc(o5yFU%7X}rCB25r~ ze>V&&05dX1AUWYia2`%RJ|kmr+{S{OJW!~K0EEX#5N^!#_jkkjkvxJ%0$|MH1&7RM z!jIw<5ROD~@}N*g2xHJ^1W|vU zvEv|LREi zkAm+>w=QNVFzo&x=if;)2OASd7lb`Z(iDuw{icYBOYJ-6N&}b z^Y|+e8e>2HhUMT7zkxl<8k{M65Vlj>s?Py{=bVC!q=xIOMU2NQR!ygw=ZDTRVjn(a zWQ_fY`N~Iq3PEiMDOd}3!Pp^Pb-;OoKYGk_e|~~ zkq1?Kh51IN3-|M!O&at)7C)lzXnscg4?&U-1^sP1n36@_!InbeQ|`1)KSKl@^(qk zSr$tU(oSzrrA1Z!_>eJPX03g(k(a(vk__LLp2&_qb-O*}vi@ZIlr&!&S#s|F!p`K4=UP0OpP6nCE3rJh`THWdM)@C zGDf|&N8;b%U4BH;kX1YyNM~L0+V)GMY5zEKh%&DG=#2LkccFDX;49~F@w6Dgv_=1@ z!~RZo{7wg(w{%4_OKDQ;m~*-Hb*ft)5+!~%N1MU`AbvPKM8-jsN2u=!nu;ktvL6vT zq`yshImDQcRzWinL*hB6dgM$`ber<^i1k|r0I~)6 zK4)~)>*G&ai6K}?y}Q$WJ#lZzr}q7_=ef64>w;#QQ$L*R9A)O+sopFpjvn5=)IhG$ zD@z>QwCJd=Xc{Wrc)I(6Z}exB$PtxTa)HylU!Tz8L0TkQduI4x00K^j8Q-`Y1HeQg zZI+eSfG0tG`4O?AqN3||`B-p)Y3Fpy4A)-XWM~a{rViPQ(xrD^M=Dg>ACny)T^ceS zcjx6gi1i7MhBo3X8jd9jm}v7FT}Ty$LUYA>{o0P6*Itw*kGf+~!LwG?M;k21!cPx$ z0Zfm`dJ>+b+Wz=*&2v_o@srNj-o29RG{J8Zd`JuX9&~-BQB8U}4p$&bBO6~Yt`hWG zmOYw3qRYynWmA>!dfHvH#uS?}fq6;^p>I_wb)?Cs$?36JLJAJq=Dml{}^{pZ?L)=rfA~<3e2e_7l~L zW6x8`?A`!heIFFQewn3Q`c{FJZYQ>R29IfO_G91shhf2_K$j?S7?~6?`70BSu~iN# zHLj(d%B04jbBmvjW_*qW>m~2s7atPbR8%Ljbpl{3!_OO!10fmTN_gpEkJQHw zeS$s2b*^5jpvJYMm$nGzA?daERR`U*3;6i&RtYlpzl5Qc)esiMZlzJQG$}7R3$eXsdoTro=uR4i1vvR+iL6*UyZZes1DPkU~lks+$k;fQNaOcK#P={n5TUHPTNu$ zB~;kJaC%(&VEJgw)Yfu&ekEsFgaExbGN64bzAtNKBoq^IC*2}2*ZC1+Be~}o9@)eY z<9_tq^4uAg?kfr9TNOQvL3{5L^_z~x6_lnO*Q5?a8HE2dw?RxY3(JME7|H7>nbEE_AuSbd1+ zI6~}Bu-FWQ4Vz2K?YEmi&#tvL06@a5&$UPlfF!^<3rG=P7EmBeI&0Z#K}ROLzIty( z8(oHJ%9$7F(w;9|CkjhHAP6G_TD|~bH|V0;ef!$+cM`WNOrc9jWK!;HgXpWxrrG67 zWmWSlG(}=wg>!Opy%8&Hrf^Ct3S>g6fKcGr&7#^5sZl+e23}6tdeL{x1magjxMMd} z2MzoPP^TrXrOn}h+b;q&IfS!4r=SMdZYwW;g$h%34VIp*HKLe0irB7D_F4}W3yQ6n zvD#@f6-!NWo2CJ3T3SwzZWR^3FDpI58Bg?B%Jb*gmm^7cI_vxO>s_Ep_N+->6~q>@6GCX81H|iCmfmj z{H!WF(z9>ub6{VNdf-hbSD^ z!#M}DMct-ouW>v^061vtJW%3{*}s4o6tr594mg*!zb|Azc{4lv&Vw~$AfJ@nji<$5 zl9_f2!yeevPL6D3F~?6Xcx-griz&&#jUxH*OSKZFHHsTA3^BA^Q{@I%VRqm65`YK#eKO)*XJKV7?B>pHn^M$wDsPdAYkULs;CUfBxm1W4mg=mrQ z2_?oF4E?as&9HL^l>uWZNt?!u_*z0BfaB%fDI_ ze|A@{TG+a&&=G0u#-nulOVXaH!F>7=UzcT(?a{Vsj2GScI;O?E`2lgiOHiFIF&?5B zEh@=5>JMKfJce)w&*De=Z9fYgs=M$7=pJ}ukchlb!-rpJXelL#4L?=q@=)JSm-oMVfCR@;2;P6Uf zM)Ecvo3;Qr#dw=vt6OyK4PCNko>>u^hniMlcsde7^OkozB^|vlJSP<+EFO`vFuABA z{Y?-AgB;lWfKnC$81L zn%Nv>kBz#vBF+~ceFX5;k2ZBq@%{NnxFt}l%vauo1;WnXYl#?TGQNJQ^4iY@gLPH* z0BK^Z<4*P&I9D=%80K_)XQ#2V^TpQIR*S0V0%N5!UOO(uM@c)8)w=Wp7-b3y2Ruh_ zm{xxE>xCW(#7JKx<2#L66D{OpN{sE|n{&=;;WJmn3GI~ox$5%4ZOiyB=djmz#)G(S zAm7H=i29A_OW|UcH5T2SH4Ab#hLp6s^|zl|ahKrRQKx);@Or@Vdw*nOZdqC2^DTp@ zKCe29oUs+rhN~rB=yOz(K%`dk`XQ0{jwDdSjp^ZbdS7X`wD)z42+-ZG9iy9bYLpc) z6xa`HNk3?h!AVHgM?0-PLFuMrF#4Qsu^Z3cdyx=Vx5PN$ZyQzXO1t6}yzJds z7bN+UWmC5>d_$x&W0TUiWWAvJ{M9tvs`OzeD>JOXVm$Z)BeWpV%=*?Ut@@Q~=_|G$C+3|Fp!rA-orR>PI)?v#Kve zgPs~pCU@D7r#{H7C+kUbQ-5?q*Tey_y@ds)bbF)h>hGn`+$ZFQ_eP9x@^^tZb)DJNvlgcf@4VZ`PJ>Uf2&OegoCHDn zy=L^1>qdAZ4ggi@v1_ABqwd=6wzE{WlDE^JX>z4tB@a<*ypDrk3F$<=HLGhxZ(Oa@Zv9xCwQ5<`jT?aiUCAeXQ>p&Y(2ugRu8)A)ZM)Ut)};_ zh^@kI+4z#j>^YH^Wi0*it8eCa!^bAsit^t#=E-QWts#38o8B$Z?&kWT8?S)7Xw8_# zU@(~rIz+{H8+XEHyG_N4X=Ve&KJF(%=) znRHRNxcYryS(m&ArSm5!;4Y(1GVx?t+of|cfM0{{a@RB1*udAFS$T<^j-&bN?HR9; z**8oH;=aQT+TX(|Nw0*7bowzh5ujBHiINwHYzNeQevn4Jtxm|x0b|Nam+|xdk6q6w z$G)>}3mKyZBj33T|Ilw)Z1XgFIWV+#(VEEeI%V*1;}wGqJ-!PIThvk165<|w=OT&O zTN6XCCW!Odt~GqTbi_2g)vZ2Xb<{4t#{*~>P1+bStVHK{Uf~pWoFxO#6p_wW<=cUm zSEjgU-lDt@eca;o(ZKA5ib%bCVQK8qX5kiU6h8g?>9H85bPzhxId%Kct{f~~bD6&- zzKEc6Uv@{A7rt>y+-)DL4}FneS}F+CEFT>%XIPGKd#^rs1-F6NO67q4w&zA}OvikE zSi(_&Sef^dzrn$0gL-9d>fr8ttrs1lR08H`(?RZj>hDR~SvYE>~` zRKH83a1#1Z$takau9IzUA?%`b!n9xUK^b$_yq(Dzbi?{YqqhoG9fbRX%kH<-W@L=zlC!Lm8= zvmjL3uBUZGb=i0vj5usP0O02>#%H|AJIfbUR~PQ#+2D+WOEQte2vlwT@YMLH!@iHBOSxI01@62gFHXgy{3+79RdtRM*Q0yv=Vixu z946YGN9o9kn%}uL-{?0mo1W>rLTjKkYUFXQnw>EDo#*fxT^Nb4LTRBq_uwtW+j&En zFZZq(!)|c=DzR^pXQzklTs5Y6r^Y}O=Lp92si!-&@z0CtgH>MTqvbB#BAs>Deb;9?Q{Bb| zUswp()e=w{zMT)sgo>?B3zx?%S7G>@mzzmkUBg#)+Dt?CiLA>{ zv!Uqj(fvd+*Bw5iIzQow-}gD|nlM`|>Rc8wXbvH)0^z-)@BkfJfk4DsrD9iQ0UY!# zNpp6BtjG&^TaJ=?WG-T5nUP8{xS!g#+3bL#T0p6UNaEyZ#v&A-fwh3kK~ngLr!)hm zHM$-hZ3#mTv$8DKl907$>3PxbRZ}+f6a!M$@>*dTB+R`HJq(rXv|qQwPrGKms#xvq zci2ay@dpvyX{}u!?AiE=u_0XRxB8#jhze6GS0XVf<<`6h@^l|G8P`}2 zRES7h+12`XPn}=H`2%I0;0wP#T5I)`@%G9W#-%LJQew?K1(zPzQ#9SA3ue7O7OWZk zYO)03=#rV`+Q?}TClLJtFb`#*bbiOE`!>6e_Bxd4o-;$R`AmG$4ys}!xH#U@*YDQI z{y@G6?bt#65Y7e<5Ez3qu-rx- z-L6`4a$mAJBrIlsd>6<Z2aQqiKPdS{-SGx%nmo%oy!!D(q4l50WfRWWt% zIe+m+LiS2kQszaJo>Vh+o9pz>nu*{|#4Nv=xw4if+9z#scE+G=C&|X0v#Mg7q2$A} z0#%IF(oV7W{;AGtcIst(K;H-^HQ!S=+L^UZ;6=p z$sz+H?jPK`R&V#JDoL+_QucP)f*ux{s?$<>1#(o65E1jcYhInm}U(&!2iO@GQ-upviecv&0NG0ai?^p4uNwv!ENKbF>XJ$NPa05V^Tgjb6_i4xZNPjgz<1zIWSG2qu26;hW70Mj1^Y-55 zoa>q29rG_!Z;gnI{7hLR5TpoZA#KIMMD>O8)t=v$M?-CV_J{U{#tsF5@uR&7 zIsIALe~aD`&34du5_8<`JIK`6rJTW-EKQwdwUmb5m{;X@sgq+R=Y zzc}4tMoKrgL*M>KYlh*>0+#B?td1r3vYg(Tg6nlMYOO6y@HYGW(EXnEu-hPhYc@6^ z+yCg>$~Py@C&J4})3P{{mxkt|vmo)R#F@B!nZ&fUD)<>_*sSTycwIn-_*;E`ITU`T z1@QE-ej!7D$kyToWy_hvnDx(TtPZ{q)B8~tudp_~H8^CCks_2N<_03X7JOrFEm_G? zq``OP$5U(;#m8N?rP^q?n^Lq4#7z@F>%VG>3yvf&p4>9%Zhl%}Wq-g?pf_JK)k(dZ zA!I(J;<3@`BWC;XT)S!UkW<&a(?fbhW4u)E&KVCI56Ir8Qrq~fQO@Wz1T~kyBP_bX zvQXU3Cwd@dq^Y}gLuAFjm!%|r&ai8%_8gYyoRl@Z*$NEqSo>{v zJDz_?fyZMpYH%vE^oY0BU^9Z+m*%`WNHa2gFl4Lo<~j9Xmf#(6+p%f7=u7Tbd^2?E z`_VpKLxoTY50c^i3~ifM9c4mo0z;iijP|T-cZIBA9XOBRA9+dY$M9SiA_lKXJD?`0 zIa)JkcWZCg2u$EV|MxUT2CLHqLpkHX%6wi~IsGuHQ5Y)D!UET|^A=usUL zuWx$!5Y#CHmMPt4$2B*w7FlL0=REkXWiymsa4oQWxk?z#zCG%}?fa%~`JTRPA3qQ{ z{oPWr(yW+!Xsx*OJn|93lp)o#<3nPJ0Nb<)gZ-co8>p5lI5*9{wkW2b4y_*L& ze{`11$#cX#u#}q(q50No?G=7|fPW3~85W{=_(5f|QLd^`UcAZs;y_U78qHo+(jljZ zLE+Hi@RNIYv$=83 zF71gQ897hxTsJL532R>K6&lEGwxf4V3@|B(3(3sTHOLkAe*NQ8b#69}q5RB6t&k#= z4fh!N^D6e!C1%#$9n^BWQL4L};o_(9#$PvH%(Fo7ijMwMs%mcv`9y`J5^tX3X4x!A zm+Efv(p{4slU1*^4rR_yitB6UiWxX}H*EW3pBW$R+&kfNJd+FaXEp$^BzUU-S^&&% zMpN7d!%p)?6lr0R>``M{lp58+KU90KQcTT(R3c|qFK>KtJ<$FcRr}e%R@uxV{ZkU` zps)DsO@%U(Vp-8#8wLjxuS)y%{O5fGXSRrSTdS4E$5~eV@T| zEI@!|t_u#+&YB$cdsiNQnZ=4uD}Z}`$x0@TX(0#9Eu;-_M=3sIniO5kbxDUrvp;rZ zoepQ;Uog{-=^tQta~=Jb2&|u7Z@EI`9Qq~sosfT#e4i|r!z4tzPdn$-O3(z{1@i%& z^O2|~q;Jth&$g(xp#Nf(s1!S`pc-~tVBH+|x! z)%tA_6Y)2KntVoTn&zkQ9yhHBI~$c|Pg}9bBxTbOv1bjjN?uz+p0BaFm!=Ylge5kw zKw}~-az`d0E{Rv>KZmQ_Yx$thn2ep9TL?;r?LWu9)Dc%bATXDC6lB!lG~!;K_@~TX13_vyPxWW z1$m~JTcUnMvU{O>K$8~M+OPXJ73P8IU}2y6%qiBSU{6wHmF{%Mc~M$oKPL3Id!^ob zSj!+Ef6|EksWUBA(a$8nz_dN=(8(e2&G~AKj&*6;JeQB`)ZMfkCEt9mI}oP<2k)&{ z$)ZxZsZSTz>mg_S>i62MM{XW(!YJ{;@cVy?jJ~N93G`TyzDvH7NuetF&@zEhv=ua0 z$GL6E-#&rqmg9pDo*27Um$qGmrI>mzLuJX{kBsWD&4Z?4S2FxL-LlNMPLt6{&1*?T zd*VB_q-A~Ljv()|7E>z3@KzL=`}ONld1S*D%4&3Oq010lHSzasWu@U-54 zho{}c^`vt?>Kl_0gNh2F5s91Ajq|$I*Sq+xf;NsYl=y!?LAv6L-R%+%^rr2m;fu4A z1uco{+k1DDbEtjw_x)Sx6JMFiW58fyq&Il6+Dh>D@zFdL>c<{vYd9uC&sG{B3uQhR zvu-`O>+CJVMYG9TET*wmHhG0*p;Qh6DW2KTZ1eRTZEplhriDz~iAP2++Ul-pYOFnV zK~hPAUeMHmG8Gm4P8-{Kt7USKLPQgMIzkUmf-+pw{AqM_^c(xD@D!a&XPse9leu7X zH8;clR-Z{p-fPDMN>=#PTw(g<+J5fu$e@;TQ`o4kBy!~_|^pf8hf4;2OG?p zd4V&~XBF^S20R|FT@ZPU2{4d>Bgq{ZqQEC|1i@cL3AW&n9o%_mdoNPSfY6tnHPFQ2 z3Z8|(2mWr#z|2IDWC{eB3Gm@0weABi-g4;*@Q0 z0Yng!L@&?!H5n1@Z=AjwfnG=_kucp2D*>!x5m?TO^ou6Q0$@X}i4%@a|tLR{cwhmK5}oV$w7hOy%30atsLevE?4KclxmLhR;_;BfvyS>EX|)OvIX`(C5H%Ddj*8+55^eKx=02?&};jT}oNKSb-+@ z<^@j$*!PnCZ2dc(hcI(+nnBG&Mi3UH7JGN;U^%6Q<&-<8L8%Cgll9W&+&V@I$GxX z&`sJ_EDz02V0LzjFWCt{O&6f`#Z4xcl$89qjS-9VjB})i1 zJo`C3@PS_SbugXkuN9Ovpx+O$>Wm$1y|#d6MjH*RUpuM3`Dp(Hu;Pp1B}JFsB+&CY z(n|_{UlKqGspyVhpQDWKm7sr|UQvY&D<^e?vskvsZLie=q_V#KJybP%*-UH@rgy*^ zTOIVJ^W|w-mTkLcDlaN!f^yM7wZ4O56-^Gxb{m)JdX#rX$7Y6<0WTo1MOwu!=$CM- zu!*1jnK*Jl^>$ac36_s4r-*RMYPYg;@6{$8OB28ouEv-P(hb$GfES@lq}S+5}(MC{^Sgp^Lb$*?$a z^7t}w-`{>sSGz5`Q$=be*Ynzrt5CbSlHj%r_w%4aE99lB%<|$q^tbKnjKv3C3s;y} z?uoDU=+UBCLM*q7o;W^fjwog?zAE9t? zFuv@kPhUTCOguaF`p}k4)+{~apKUQ**$V4WJrwW}fGh1b6;G{)jL)3~^z(;S>K#doo8nq8SNI|vSQ(RZ)93$93HC+M0#4gs*9c6)o<)!_JgdU2&{uwy6m0*LP7?WY93IaN>6Mo83H zWS*OEfE)})rn9+n8 z5|IzgG~-<*j^M6-Bf;sxCxfkT8DQSxXqJMR9S4KQhVDQyg#4z*26GaTxS(@<*1=VH z+_rG`nx(I<*SzLqurBsTSuEmp&OgNB@pqFiL%=$E#R0MBKl0i5&zqh6*t_4qU)yZt z9OIn{$TP=6<(qljK^$dFU9AHKPb+f-cp8w*Pk=hlh(>O)AwZ6 z=zbi4nzUk>%I7i&GxHLDAP%9y=(2S?Fct)MN6yXRJWXLwn1~FBx_=N+Av4-3MmhD6rqRwF6eHiJywFD!aoblkpx?sB)-9~X z&G}27XfgZR0=axK(NAg?Tb(+|{6iv#>r!aQiCTBf_Wr=cN`xg>xM>ib{1M@$qHn8> z2q)LA#RzNo(SjCovs*>J6A{%Z5%Lws#4Hp3Ec86nQKLcxP83T~_ zW$NzqsRZP{(?LIu{!{(x>L6Qh+#)^%+0CGDto5mwfWv|PtL&N3U(&A*%LC&Lbh;=p&N21Lo46dznzm9{v&E#< zxA`Zov)uyAb)qo2Z8$Adh3shfaUv)G57^Q;|KkI;BVyf+td8#GrN=Lz`eCvKRo)%L zAE?;uO(u}_oTV5|M+mb`JpIx2b1>P%pz!JskwuGz@~R&`X0)3P+`MjB?tNu2gaMFh z`eKi*?d3&sfHj7CtU#R@ReuWl<7{6zIOi`j}e%? zkP$SSvM+WMMZc(HxcssCDCzO>u)mjZsgIdp7ku6w2y~V&;M`0Zsj_Sx6H^T%f0E!9 z^ppCg1mRR4ZK6P#+4*9!DW`mwiO5oqYpUpVmiOYzw3qH4lG8TkzgK5gb)J77)RG-e zYT@zNuG!%0vxEMo*exdf7b}atr!H@zG|HLFxGp7V^)tv|59Cyb=Qres@{3(a&;Nf% z|B>FYIrcAB=az55KY^0>p!BuR=6)}`G)a7etyYI-E=*Byzod(5Gss^mMjuXKr&t`b zwy%fEW%$qJAb0;s4)Sv!oo``J2VS;cTsk^zCLeBh>{9jcJg})QRB(}QF~Q=cK(v0N zMd#vxU=6{((3(HDHmTAv*AiU~%G&*x_q$A3FVW7(Wke6_kU7C1e+Vlo&sA&gmP`eh zaN}6rW84XkUFx|>Tqk+zvU)3a>t3lLnr9^&w}rs9x@tIz4O9ycdZ3PjIEtz2e(Pbk4q5 z9K*@nYR|t;?G_zV^d~tr|M(({_f-=S23JCICSGijW{^|H_(iveuPEKimN!arYRod|kZoVuWZ) zNHS{ni^lFASOBoX__8g7z0LuD54r~gBvcL>t%ffGY6CXqfTxAAMsN^gFSoQG^k^3b9sY@J%>36 zlhKFckN~!sf!ozv!-;J)Anhc&Eq}5P#80QNe|qS(Zu@GI;bQw!`27y~-p=B67W?LR zY^9s8BhdfN5sLttNbl-@W;W1LfG8-Cg^Fsj%@hxPuYxGrw2|sDP;adaSbjTPPNJ_JQ6d7@0+sUiH>55b*i#KWK>RLX3j9q0^WTt2j{q-P;QQcts)U1; z$0>{AQ_oFeTm2=nIYqI~7=Q~4slaTVyJfQ)tKJ}%a>W7K06_bC zX)(6}jPvAs<;bmbIeh)tv9P>XX0A zj$}PE*MZu@%iHb}1N|U^&z{v*y-xx_k z6>Ju#uC>NglYe5DA$#(ISGDYG7qTVt#(|w!W9@%YL6jus8NUwfKkQ$|%V&S_mK`trShe(VHmqb?El?9c$C+^Sw%P zJAMn_*-8&kZ@l|7*l9~c6{}{;&93(^O8!tjVLC>|a(>A{oAQ%Vl2hA3Lg~o*i!7Fd zEPp$k#qo39!Th^5@yxMUG(OFT9M#JB=!Bu3ZrgL8nnqD&6;LgZ7X^)9K_5!7h`TVp z==V#%Vya(3n=Zmdy&9^0=*Df{D#+sVwUFp?jW40ZZL-kHphoA#fol@j!`Se}m#ODH?_;o_OD z=W@e-$jS4{#vJNNGIQlI=VYghV{Puy$fO6Sfw{$A8$SCpLDt&=i)$R(gslCNGFxtI zzNh>qTe+{PwRSvK`IR&OW1dfj3(E3-iV?w$6-(j;`qz`c9`R^LurN42B|lzpON4+R zsj_1%GN^=Lw*_vpEm^8Uc14K)Zq;GQl<@QckAT$!5a=g&f{8P!L74H7tQn}{jm5nA z)K04By(4Si;`aw>3fZ(GEFx-#bTjz==D?0$WeQ<2%lam8<@D(AbHNzl2zGa{N;#o_ z^TxxV!tR?XYa^~-n-oIm=JbJG0qSB;)S!kD?iDN&`K=MZ}QM}0EGhxG>Pu76` z|3EF)&k(OT?UK{VhZ}UDJMd>BY2&cun4&$Aj_1CZ#_1pA(I){Jm7of%H@baOXDG64 zi4$-Ozu0`V`mMChw2-E}`B*H^>ePo7hac+BIXzs= z+Z_hq&Mw(sDz}@@D*pb2&bq1eTWbYdGAXt$KS!S=@}~Z~=B>*i6C0QX>Dvr1?C9Ul zSY(mQ-bQ#a(Gc`IJgwX!iY0mv7QHSFIXq|XWUzDeSh)l8@tPPm$*M~RJnSb)09?hM z^tp)){f(K_xtXC|@>1lN$l*P;=J|-&pxhbS=BDAqUISjdH8&U|-uTP;SNtrF9y&E( z;=@}|5wgH+Hs~LvSU#c>40NvF36-dBcsKzE#|%~mv9HqgHBci_$nXxv7c18QshgE^ zD9;U0267BNx<@n^i{wi^*CLZ{c;+-Ik8y8p_$f7KHG-n&`(ta@9qf(lZh|7K-oGOT z{sWQKPmE&yH>^PZZcxEGk-$Y`i4%>-pG8y;7jH9Yp*>pS=VRTcu z@g#_S0nT7eKtOxmdNGY)n~xP7OeiA>M6+Ud&R@Nj~@?*J>2!qM~^ix#74!Bd-09P zB!jZIm)n}S7E3;DYnqjB3X*tv33?ci`C-vKsfJ-ps#x~s{ImHo=^T99=;wI*)EifG zMbnccNqisP!|A{1R(;Vu+#{9U^q5Bh<#(XqfM{!}CN) Pq-9!r!Q>Df{>}ptEf$ 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 literal 29122 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 From 50b7782c82a101ec598ea5caafd6ecb62f0aae20 Mon Sep 17 00:00:00 2001 From: MrTJP Date: Wed, 16 Nov 2022 10:47:34 -0500 Subject: [PATCH 06/23] feat: add fabrication recipes --- .../recipes/blank_photomask.json | 19 ++++ .../recipes/ic_blueprint.json | 22 +++++ .../recipes/ic_workbench.json | 22 +++++ .../recipes/lithography_table.json | 31 +++++++ .../recipes/packaging_table.json | 28 ++++++ .../recipes/plotting_table.json | 31 +++++++ .../recipes/rough_silicon_wafer.json | 11 +++ .../fabrication/ProjectRedFabrication.java | 4 + .../data/FabricationRecipeProvider.java | 88 +++++++++++++++++++ 9 files changed, 256 insertions(+) create mode 100644 fabrication/src/main/generated/data/projectred-fabrication/recipes/blank_photomask.json create mode 100644 fabrication/src/main/generated/data/projectred-fabrication/recipes/ic_blueprint.json create mode 100644 fabrication/src/main/generated/data/projectred-fabrication/recipes/ic_workbench.json create mode 100644 fabrication/src/main/generated/data/projectred-fabrication/recipes/lithography_table.json create mode 100644 fabrication/src/main/generated/data/projectred-fabrication/recipes/packaging_table.json create mode 100644 fabrication/src/main/generated/data/projectred-fabrication/recipes/plotting_table.json create mode 100644 fabrication/src/main/generated/data/projectred-fabrication/recipes/rough_silicon_wafer.json create mode 100644 fabrication/src/main/java/mrtjp/projectred/fabrication/data/FabricationRecipeProvider.java diff --git a/fabrication/src/main/generated/data/projectred-fabrication/recipes/blank_photomask.json b/fabrication/src/main/generated/data/projectred-fabrication/recipes/blank_photomask.json new file mode 100644 index 000000000..8e1865d24 --- /dev/null +++ b/fabrication/src/main/generated/data/projectred-fabrication/recipes/blank_photomask.json @@ -0,0 +1,19 @@ +{ + "type": "minecraft:crafting_shaped", + "result": { + "item": "projectred-fabrication:blank_photomask" + }, + "pattern": [ + "ggg", + "gqg", + "ggg" + ], + "key": { + "g": { + "tag": "forge:glass_panes" + }, + "q": { + "tag": "forge:gems/quartz" + } + } +} \ No newline at end of file diff --git a/fabrication/src/main/generated/data/projectred-fabrication/recipes/ic_blueprint.json b/fabrication/src/main/generated/data/projectred-fabrication/recipes/ic_blueprint.json new file mode 100644 index 000000000..8478fc34b --- /dev/null +++ b/fabrication/src/main/generated/data/projectred-fabrication/recipes/ic_blueprint.json @@ -0,0 +1,22 @@ +{ + "type": "minecraft:crafting_shaped", + "result": { + "item": "projectred-fabrication:ic_blueprint" + }, + "pattern": [ + "pbp", + "brb", + "pbp" + ], + "key": { + "r": { + "tag": "forge:dusts/redstone" + }, + "p": { + "item": "minecraft:paper" + }, + "b": { + "tag": "forge:dyes/blue" + } + } +} \ No newline at end of file diff --git a/fabrication/src/main/generated/data/projectred-fabrication/recipes/ic_workbench.json b/fabrication/src/main/generated/data/projectred-fabrication/recipes/ic_workbench.json new file mode 100644 index 000000000..d3d5790d4 --- /dev/null +++ b/fabrication/src/main/generated/data/projectred-fabrication/recipes/ic_workbench.json @@ -0,0 +1,22 @@ +{ + "type": "minecraft:crafting_shaped", + "result": { + "item": "projectred-fabrication:ic_workbench" + }, + "pattern": [ + "sss", + "wbw", + "www" + ], + "key": { + "w": { + "tag": "minecraft:planks" + }, + "s": { + "item": "minecraft:stone" + }, + "b": { + "item": "projectred-fabrication:ic_blueprint" + } + } +} \ No newline at end of file diff --git a/fabrication/src/main/generated/data/projectred-fabrication/recipes/lithography_table.json b/fabrication/src/main/generated/data/projectred-fabrication/recipes/lithography_table.json new file mode 100644 index 000000000..24981da12 --- /dev/null +++ b/fabrication/src/main/generated/data/projectred-fabrication/recipes/lithography_table.json @@ -0,0 +1,31 @@ +{ + "type": "minecraft:crafting_shaped", + "result": { + "item": "projectred-fabrication:lithography_table" + }, + "pattern": [ + "gtg", + "oio", + "wbw" + ], + "key": { + "g": { + "item": "minecraft:glass" + }, + "o": { + "tag": "forge:obsidian" + }, + "t": { + "tag": "forge:gems/emerald" + }, + "w": { + "tag": "minecraft:planks" + }, + "b": { + "tag": "forge:ingots/electrotine_alloy" + }, + "i": { + "tag": "forge:ingots/iron" + } + } +} \ No newline at end of file diff --git a/fabrication/src/main/generated/data/projectred-fabrication/recipes/packaging_table.json b/fabrication/src/main/generated/data/projectred-fabrication/recipes/packaging_table.json new file mode 100644 index 000000000..5c27a499f --- /dev/null +++ b/fabrication/src/main/generated/data/projectred-fabrication/recipes/packaging_table.json @@ -0,0 +1,28 @@ +{ + "type": "minecraft:crafting_shaped", + "result": { + "item": "projectred-fabrication:packaging_table" + }, + "pattern": [ + "gtg", + "ppp", + "wbw" + ], + "key": { + "g": { + "item": "minecraft:glass" + }, + "t": { + "tag": "forge:dusts/redstone" + }, + "w": { + "tag": "minecraft:planks" + }, + "p": { + "item": "projectred-core:plate" + }, + "b": { + "tag": "forge:ingots/electrotine_alloy" + } + } +} \ No newline at end of file diff --git a/fabrication/src/main/generated/data/projectred-fabrication/recipes/plotting_table.json b/fabrication/src/main/generated/data/projectred-fabrication/recipes/plotting_table.json new file mode 100644 index 000000000..47dde0755 --- /dev/null +++ b/fabrication/src/main/generated/data/projectred-fabrication/recipes/plotting_table.json @@ -0,0 +1,31 @@ +{ + "type": "minecraft:crafting_shaped", + "result": { + "item": "projectred-fabrication:plotting_table" + }, + "pattern": [ + "gtg", + "sps", + "wbw" + ], + "key": { + "g": { + "item": "minecraft:glass" + }, + "t": { + "tag": "forge:gems/sapphire" + }, + "w": { + "tag": "minecraft:planks" + }, + "p": { + "item": "projectred-fabrication:blank_photomask" + }, + "s": { + "item": "minecraft:stone" + }, + "b": { + "tag": "forge:ingots/electrotine_alloy" + } + } +} \ No newline at end of file diff --git a/fabrication/src/main/generated/data/projectred-fabrication/recipes/rough_silicon_wafer.json b/fabrication/src/main/generated/data/projectred-fabrication/recipes/rough_silicon_wafer.json new file mode 100644 index 000000000..58196469d --- /dev/null +++ b/fabrication/src/main/generated/data/projectred-fabrication/recipes/rough_silicon_wafer.json @@ -0,0 +1,11 @@ +{ + "type": "minecraft:smelting", + "result": { + "item": "projectred-fabrication:rough_silicon_wafer" + }, + "ingredient": { + "item": "projectred-core:silicon" + }, + "experience": 0.0, + "cookingtime": 200 +} \ No newline at end of file diff --git a/fabrication/src/main/java/mrtjp/projectred/fabrication/ProjectRedFabrication.java b/fabrication/src/main/java/mrtjp/projectred/fabrication/ProjectRedFabrication.java index 2abf3e74f..e32e76bf2 100644 --- a/fabrication/src/main/java/mrtjp/projectred/fabrication/ProjectRedFabrication.java +++ b/fabrication/src/main/java/mrtjp/projectred/fabrication/ProjectRedFabrication.java @@ -4,6 +4,7 @@ import codechicken.multipart.api.MultipartType; import mrtjp.projectred.fabrication.data.FabricationBlockStateModelProvider; import mrtjp.projectred.fabrication.data.FabricationItemModelProvider; +import mrtjp.projectred.fabrication.data.FabricationRecipeProvider; import mrtjp.projectred.fabrication.init.*; import net.minecraft.data.DataGenerator; import net.minecraft.world.inventory.MenuType; @@ -75,5 +76,8 @@ private void onGatherDataEvent(final GatherDataEvent event) { generator.addProvider(new FabricationBlockStateModelProvider(generator, fileHelper)); generator.addProvider(new FabricationItemModelProvider(generator, fileHelper)); } + if (event.includeServer()) { + generator.addProvider(new FabricationRecipeProvider(generator)); + } } } diff --git a/fabrication/src/main/java/mrtjp/projectred/fabrication/data/FabricationRecipeProvider.java b/fabrication/src/main/java/mrtjp/projectred/fabrication/data/FabricationRecipeProvider.java new file mode 100644 index 000000000..8575328ce --- /dev/null +++ b/fabrication/src/main/java/mrtjp/projectred/fabrication/data/FabricationRecipeProvider.java @@ -0,0 +1,88 @@ +package mrtjp.projectred.fabrication.data; + +import codechicken.lib.datagen.recipe.RecipeProvider; +import net.minecraft.data.DataGenerator; +import net.minecraft.tags.ItemTags; +import net.minecraft.world.item.Items; +import net.minecraft.world.level.block.Blocks; +import net.minecraftforge.common.Tags; + +import static mrtjp.projectred.core.init.CoreReferences.PLATE_ITEM; +import static mrtjp.projectred.core.init.CoreReferences.SILICON_ITEM; +import static mrtjp.projectred.core.init.CoreTags.ELECTROTINE_ALLOY_INGOT_TAG; +import static mrtjp.projectred.core.init.CoreTags.SAPPHIRE_GEM_TAG; +import static mrtjp.projectred.fabrication.init.FabricationReferences.*; + +public class FabricationRecipeProvider extends RecipeProvider { + + public FabricationRecipeProvider(DataGenerator dataGenerator) { + super(dataGenerator); + } + + @Override + public String getName() { + return "ProjectRed-Fabrication Recipes"; + } + + @Override + protected void registerRecipes() { + + shapedRecipe(IC_WORKBENCH_BLOCK) + .key('s', Blocks.STONE) + .key('w', ItemTags.PLANKS) + .key('b', IC_BLUEPRINT_ITEM) + .patternLine("sss") + .patternLine("wbw") + .patternLine("www"); + + shapedRecipe(PLOTTING_TABLE_BLOCK) + .key('g', Blocks.GLASS) + .key('t', SAPPHIRE_GEM_TAG) + .key('s', Blocks.STONE) + .key('p', BLANK_PHOTOMASK_ITEM) + .key('w', ItemTags.PLANKS) + .key('b', ELECTROTINE_ALLOY_INGOT_TAG) + .patternLine("gtg") + .patternLine("sps") + .patternLine("wbw"); + + shapedRecipe(LITHOGRAPHY_TABLE_BLOCK) + .key('g', Blocks.GLASS) + .key('t', Tags.Items.GEMS_EMERALD) + .key('o', Tags.Items.OBSIDIAN) + .key('i', Tags.Items.INGOTS_IRON) + .key('w', ItemTags.PLANKS) + .key('b', ELECTROTINE_ALLOY_INGOT_TAG) + .patternLine("gtg") + .patternLine("oio") + .patternLine("wbw"); + + shapedRecipe(PACKAGING_TABLE_BLOCK) + .key('g', Blocks.GLASS) + .key('t', Tags.Items.DUSTS_REDSTONE) + .key('p', PLATE_ITEM) + .key('w', ItemTags.PLANKS) + .key('b', ELECTROTINE_ALLOY_INGOT_TAG) + .patternLine("gtg") + .patternLine("ppp") + .patternLine("wbw"); + + shapedRecipe(IC_BLUEPRINT_ITEM) + .key('p', Items.PAPER) + .key('b', Tags.Items.DYES_BLUE) + .key('r', Tags.Items.DUSTS_REDSTONE) + .patternLine("pbp") + .patternLine("brb") + .patternLine("pbp"); + + shapedRecipe(BLANK_PHOTOMASK_ITEM) + .key('g', Tags.Items.GLASS_PANES) + .key('q', Tags.Items.GEMS_QUARTZ) + .patternLine("ggg") + .patternLine("gqg") + .patternLine("ggg"); + + smelting(ROUGH_SILICON_WAFER_ITEM) + .ingredient(SILICON_ITEM); + } +} From bd3b2c99514ca666e2fdbe5f2ae1266ea38a6ddb Mon Sep 17 00:00:00 2001 From: MrTJP Date: Wed, 16 Nov 2022 15:38:31 -0500 Subject: [PATCH 07/23] fix: limit ic workbench zoom within frustum --- .../fabrication/gui/ICRenderNode.java | 16 +++++++++++++++- .../gui/LinearVectorAnimation.java | 19 +++++++++++++++++++ 2 files changed, 34 insertions(+), 1 deletion(-) diff --git a/fabrication/src/main/java/mrtjp/projectred/fabrication/gui/ICRenderNode.java b/fabrication/src/main/java/mrtjp/projectred/fabrication/gui/ICRenderNode.java index cee33a659..dbafba979 100644 --- a/fabrication/src/main/java/mrtjp/projectred/fabrication/gui/ICRenderNode.java +++ b/fabrication/src/main/java/mrtjp/projectred/fabrication/gui/ICRenderNode.java @@ -26,6 +26,8 @@ public class ICRenderNode extends ViewportRenderNode { private static final int ZOOM_ANIMATION_TIME_MS = 100; private static final int LAYER_ANIMATION_TIME_MS = 200; private static final int CAMERA_ANIMATION_TIME_MS = 100; + private static final int ZOOM_DIST_MAX = 18; + private static final int ZOOM_DIST_MIN = 3; private final ICWorkbenchEditor editor; private final IICRenderNodeEventReceiver eventReceiver; @@ -33,7 +35,7 @@ public class ICRenderNode extends ViewportRenderNode { private final Vector3 cameraPosition = new Vector3(); private final LinearVectorAnimation cameraLayerAnimator = new LinearVectorAnimation(); - private final LinearVectorAnimation cameraZoomAnimator = new LinearVectorAnimation(0, 3, 0); + private final LinearVectorAnimation cameraZoomAnimator = new LinearVectorAnimation(0, 5, 0); private int currentLayer = 0; @@ -64,6 +66,18 @@ public void applyCameraDelta(Vector3 delta) { @Override public void frameUpdate(Point mouse, float partialFrame) { + + // Set camera location bounds + TileCoord minBounds = editor.getTileMap().getMinBounds(); + TileCoord maxBounds = editor.getTileMap().getMaxBounds(); + cameraZoomAnimator.setBounds( + minBounds.x, + cameraLayerAnimator.vector.y + ZOOM_DIST_MIN, // Y bounds follows zoom + minBounds.z, + maxBounds.x + 1, + cameraLayerAnimator.vector.y + ZOOM_DIST_MAX, + maxBounds.z + 1); + long t = System.currentTimeMillis(); cameraZoomAnimator.tick(t); cameraLayerAnimator.tick(t); diff --git a/fabrication/src/main/java/mrtjp/projectred/fabrication/gui/LinearVectorAnimation.java b/fabrication/src/main/java/mrtjp/projectred/fabrication/gui/LinearVectorAnimation.java index 15e226861..54c353c60 100644 --- a/fabrication/src/main/java/mrtjp/projectred/fabrication/gui/LinearVectorAnimation.java +++ b/fabrication/src/main/java/mrtjp/projectred/fabrication/gui/LinearVectorAnimation.java @@ -1,10 +1,13 @@ package mrtjp.projectred.fabrication.gui; +import codechicken.lib.vec.Cuboid6; import codechicken.lib.vec.Vector3; public class LinearVectorAnimation { public final Vector3 vector; + + private final Cuboid6 bounds = new Cuboid6(Double.NEGATIVE_INFINITY, Double.NEGATIVE_INFINITY, Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY, Double.POSITIVE_INFINITY, Double.POSITIVE_INFINITY); private final Vector3 step = new Vector3(); private long lastTime = -1; @@ -18,6 +21,17 @@ public LinearVectorAnimation(double x, double y, double z) { vector = new Vector3(x, y, z); } + public void setBounds(double xmin, double ymin, double zmin, double xmax, double ymax, double zmax) { + bounds.min.set(xmin, ymin, zmin); + bounds.max.set(xmax, ymax, zmax); + // If now outside, jump into bounds + if (!bounds.contains(vector)) { + vector.x = Math.max(bounds.min.x, Math.min(bounds.max.x, vector.x)); + vector.y = Math.max(bounds.min.y, Math.min(bounds.max.y, vector.y)); + vector.z = Math.max(bounds.min.z, Math.min(bounds.max.z, vector.z)); + } + } + public void addDeltaWithNewDuration(Vector3 delta, long duration) { if (delta.equals(Vector3.ZERO) || duration == 0) { return; @@ -39,6 +53,11 @@ public void tick(long time) { long stepsToTake = Math.min(stepsRemaining, dt); vector.add(step.x * stepsToTake, step.y * stepsToTake, step.z * stepsToTake); stepsRemaining -= stepsToTake; + + // Contain within bounds + vector.x = Math.max(bounds.min.x, Math.min(bounds.max.x, vector.x)); + vector.y = Math.max(bounds.min.y, Math.min(bounds.max.y, vector.y)); + vector.z = Math.max(bounds.min.z, Math.min(bounds.max.z, vector.z)); } } From 4c806b71a2539f0d4cc9f298d72cafeb7c5fb9ac Mon Sep 17 00:00:00 2001 From: MrTJP Date: Wed, 16 Nov 2022 18:21:38 -0500 Subject: [PATCH 08/23] fix: compile tab always consuming layer shift --- .../fabrication/gui/ICEditorToolManager.java | 27 +++++++++++++++++-- .../fabrication/gui/ICRenderNode.java | 20 +++----------- .../gui/screen/ICWorkbenchCompileTab.java | 26 ++++++++++++++++-- 3 files changed, 53 insertions(+), 20 deletions(-) diff --git a/fabrication/src/main/java/mrtjp/projectred/fabrication/gui/ICEditorToolManager.java b/fabrication/src/main/java/mrtjp/projectred/fabrication/gui/ICEditorToolManager.java index 10a3e5e12..42478ed56 100644 --- a/fabrication/src/main/java/mrtjp/projectred/fabrication/gui/ICEditorToolManager.java +++ b/fabrication/src/main/java/mrtjp/projectred/fabrication/gui/ICEditorToolManager.java @@ -27,6 +27,8 @@ public class ICEditorToolManager implements ICRenderNode.IICRenderNodeEventRecei private boolean rightPressed = false; private boolean downPressed = false; private boolean leftPressed = false; + private boolean layerUpPressed = false; + private boolean layerDownPressed = false; public ICEditorToolManager(ArrayList toolList) { this.toolList = toolList; @@ -56,6 +58,12 @@ public boolean keyPressed(int glfwKeyCode, int glfwFlags) { case GLFW.GLFW_KEY_D: rightPressed = true; break; + case GLFW.GLFW_KEY_UP: + layerUpPressed = true; + break; + case GLFW.GLFW_KEY_DOWN: + layerDownPressed = true; + break; default: return false; } @@ -76,20 +84,35 @@ public boolean keyReleased(int glfwKeyCode, int glfwFlags) { case GLFW.GLFW_KEY_D: rightPressed = false; break; + case GLFW.GLFW_KEY_UP: + layerUpPressed = false; + break; + case GLFW.GLFW_KEY_DOWN: + layerDownPressed = false; + break; default: return false; } + return true; } public void update(ICRenderNode renderNode) { + // Move camera Vector3 cameraDelta = new Vector3(); double deltaPerTick = 0.5D; - cameraDelta.z = (upPressed ? -deltaPerTick : 0) + (downPressed ? deltaPerTick : 0); cameraDelta.x = (leftPressed ? -deltaPerTick : 0) + (rightPressed ? deltaPerTick : 0); - renderNode.applyCameraDelta(cameraDelta); + + // Shift Layers + if (layerUpPressed) { + renderNode.setLayer(renderNode.getLayer() + 1); + } else if (layerDownPressed) { + renderNode.setLayer(renderNode.getLayer() - 1); + } + layerUpPressed = false; + layerDownPressed = false; } @Override diff --git a/fabrication/src/main/java/mrtjp/projectred/fabrication/gui/ICRenderNode.java b/fabrication/src/main/java/mrtjp/projectred/fabrication/gui/ICRenderNode.java index dbafba979..8a9d29ae0 100644 --- a/fabrication/src/main/java/mrtjp/projectred/fabrication/gui/ICRenderNode.java +++ b/fabrication/src/main/java/mrtjp/projectred/fabrication/gui/ICRenderNode.java @@ -53,6 +53,10 @@ public void setLayer(int layer) { eventReceiver.layerChanged(this, previousLayer, currentLayer); } + public int getLayer() { + return currentLayer; + } + public void moveZoomAt(Vector3 zoomPos, double zoomDelta) { Vector3 zoomVec = zoomPos.copy().subtract(cameraPosition).normalize(); @@ -173,22 +177,6 @@ protected List getToolTip(Point mousePosition, boolean isFirstHit) { return tooltip; } - @Override - public boolean onKeyPressed(int glfwKeyCode, int glfwScanCode, int glfwFlags, boolean consumed) { - if (!consumed) { - if (glfwKeyCode == GLFW.GLFW_KEY_UP) { - setLayer(currentLayer + 1); - return true; - } - - if (glfwKeyCode == GLFW.GLFW_KEY_DOWN) { - setLayer(currentLayer - 1); - return true; - } - } - return false; - } - @Override public boolean mouseClicked(Point p, int glfwMouseButton, boolean consumed) { lastMousePos = p; diff --git a/fabrication/src/main/java/mrtjp/projectred/fabrication/gui/screen/ICWorkbenchCompileTab.java b/fabrication/src/main/java/mrtjp/projectred/fabrication/gui/screen/ICWorkbenchCompileTab.java index ceafd3a55..52254636a 100644 --- a/fabrication/src/main/java/mrtjp/projectred/fabrication/gui/screen/ICWorkbenchCompileTab.java +++ b/fabrication/src/main/java/mrtjp/projectred/fabrication/gui/screen/ICWorkbenchCompileTab.java @@ -34,6 +34,8 @@ public class ICWorkbenchCompileTab extends AbstractGuiNode implements ICRenderNo private boolean rightPressed = false; private boolean downPressed = false; private boolean leftPressed = false; + private boolean layerUpPressed = false; + private boolean layerDownPressed = false; public ICWorkbenchCompileTab(ICWorkbenchEditor editor) { this.editor = editor; @@ -117,6 +119,12 @@ public boolean onKeyPressed(int glfwKeyCode, int glfwScanCode, int glfwFlags, bo case GLFW.GLFW_KEY_D: rightPressed = true; break; + case GLFW.GLFW_KEY_UP: + layerUpPressed = true; + break; + case GLFW.GLFW_KEY_DOWN: + layerDownPressed = true; + break; default: return false; } @@ -138,6 +146,12 @@ public boolean onKeyReleased(int glfwKeyCode, int glfwScanCode, int glfwFlags, b case GLFW.GLFW_KEY_D: rightPressed = false; break; + case GLFW.GLFW_KEY_UP: + layerUpPressed = false; + break; + case GLFW.GLFW_KEY_DOWN: + layerDownPressed = false; + break; default: return false; } @@ -155,13 +169,21 @@ protected ICompileOverlayRenderer getOverlayRenderer() { @Override public void update(ICRenderNode renderNode) { + // Move camera Vector3 cameraDelta = new Vector3(); double deltaPerTick = 0.5D; - cameraDelta.z = (upPressed ? -deltaPerTick : 0) + (downPressed ? deltaPerTick : 0); cameraDelta.x = (leftPressed ? -deltaPerTick : 0) + (rightPressed ? deltaPerTick : 0); - renderNode.applyCameraDelta(cameraDelta); + + // Shift Layers + if (layerUpPressed) { + renderNode.setLayer(renderNode.getLayer() + 1); + } else if (layerDownPressed) { + renderNode.setLayer(renderNode.getLayer() - 1); + } + layerUpPressed = false; + layerDownPressed = false; } @Override From 1252db363736f6dc074c9a1c3bc40dba54f9df25 Mon Sep 17 00:00:00 2001 From: MrTJP Date: Sat, 19 Nov 2022 19:49:36 -0500 Subject: [PATCH 09/23] fix: fabrication block breaking patricles --- .../blockstates/ic_workbench.json | 4 +- .../blockstates/lithography_table.json | 32 ++++++------ .../blockstates/packaging_table.json | 32 ++++++------ .../blockstates/plotting_table.json | 32 ++++++------ ...ch_no_blueprint.json => ic_workbench.json} | 3 +- .../models/block/ic_workbench_blueprint.json | 11 ---- .../models/block/ic_workbench_empty.json | 12 +++++ ...y_table_c0.json => lithography_table.json} | 0 ..._c1.json => lithography_table_state1.json} | 0 ..._c2.json => lithography_table_state2.json} | 0 ...ing_table_c0.json => packaging_table.json} | 0 ...le_c1.json => packaging_table_state1.json} | 0 ...le_c2.json => packaging_table_state2.json} | 0 ...ting_table_c0.json => plotting_table.json} | 0 ...ble_c1.json => plotting_table_state1.json} | 0 ...ble_c2.json => plotting_table_state2.json} | 0 .../models/item/ic_workbench.json | 2 +- .../models/item/lithography_table.json | 2 +- .../models/item/packaging_table.json | 2 +- .../models/item/plotting_table.json | 2 +- .../recipes/blank_photomask.json | 2 +- .../recipes/ic_blueprint.json | 2 +- .../recipes/ic_workbench.json | 4 +- .../recipes/lithography_table.json | 2 +- .../recipes/packaging_table.json | 4 +- .../recipes/plotting_table.json | 4 +- .../recipes/rough_silicon_wafer.json | 4 +- .../FabricationBlockStateModelProvider.java | 49 ++++++++++-------- .../data/FabricationItemModelProvider.java | 18 ++----- .../textures/block/ic_workbench_front.png | Bin 16562 -> 16758 bytes .../textures/block/ic_workbench_front_bp.png | Bin 16758 -> 16562 bytes .../block/ic_workbench_front_empty.png | Bin 0 -> 16562 bytes .../textures/block/ic_workbench_side.png | Bin 16303 -> 16506 bytes .../textures/block/ic_workbench_side_bp.png | Bin 16506 -> 16303 bytes .../block/ic_workbench_side_empty.png | Bin 0 -> 16303 bytes .../textures/block/ic_workbench_top.png | Bin 16401 -> 17034 bytes .../textures/block/ic_workbench_top_bp.png | Bin 17034 -> 16401 bytes .../textures/block/ic_workbench_top_empty.png | Bin 0 -> 16401 bytes 38 files changed, 110 insertions(+), 113 deletions(-) rename fabrication/src/main/generated/assets/projectred_fabrication/models/block/{ic_workbench_no_blueprint.json => ic_workbench.json} (74%) delete mode 100644 fabrication/src/main/generated/assets/projectred_fabrication/models/block/ic_workbench_blueprint.json create mode 100644 fabrication/src/main/generated/assets/projectred_fabrication/models/block/ic_workbench_empty.json rename fabrication/src/main/generated/assets/projectred_fabrication/models/block/{lithography_table_c0.json => lithography_table.json} (100%) rename fabrication/src/main/generated/assets/projectred_fabrication/models/block/{lithography_table_c1.json => lithography_table_state1.json} (100%) rename fabrication/src/main/generated/assets/projectred_fabrication/models/block/{lithography_table_c2.json => lithography_table_state2.json} (100%) rename fabrication/src/main/generated/assets/projectred_fabrication/models/block/{packaging_table_c0.json => packaging_table.json} (100%) rename fabrication/src/main/generated/assets/projectred_fabrication/models/block/{packaging_table_c1.json => packaging_table_state1.json} (100%) rename fabrication/src/main/generated/assets/projectred_fabrication/models/block/{packaging_table_c2.json => packaging_table_state2.json} (100%) rename fabrication/src/main/generated/assets/projectred_fabrication/models/block/{plotting_table_c0.json => plotting_table.json} (100%) rename fabrication/src/main/generated/assets/projectred_fabrication/models/block/{plotting_table_c1.json => plotting_table_state1.json} (100%) rename fabrication/src/main/generated/assets/projectred_fabrication/models/block/{plotting_table_c2.json => plotting_table_state2.json} (100%) rename fabrication/src/main/generated/data/{projectred-fabrication => projectred_fabrication}/recipes/blank_photomask.json (80%) rename fabrication/src/main/generated/data/{projectred-fabrication => projectred_fabrication}/recipes/ic_blueprint.json (84%) rename fabrication/src/main/generated/data/{projectred-fabrication => projectred_fabrication}/recipes/ic_workbench.json (70%) rename fabrication/src/main/generated/data/{projectred-fabrication => projectred_fabrication}/recipes/lithography_table.json (88%) rename fabrication/src/main/generated/data/{projectred-fabrication => projectred_fabrication}/recipes/packaging_table.json (79%) rename fabrication/src/main/generated/data/{projectred-fabrication => projectred_fabrication}/recipes/plotting_table.json (79%) rename fabrication/src/main/generated/data/{projectred-fabrication => projectred_fabrication}/recipes/rough_silicon_wafer.json (55%) create mode 100644 fabrication/src/main/resources/assets/projectred_fabrication/textures/block/ic_workbench_front_empty.png create mode 100644 fabrication/src/main/resources/assets/projectred_fabrication/textures/block/ic_workbench_side_empty.png create mode 100644 fabrication/src/main/resources/assets/projectred_fabrication/textures/block/ic_workbench_top_empty.png diff --git a/fabrication/src/main/generated/assets/projectred_fabrication/blockstates/ic_workbench.json b/fabrication/src/main/generated/assets/projectred_fabrication/blockstates/ic_workbench.json index 955878173..7f5b01928 100644 --- a/fabrication/src/main/generated/assets/projectred_fabrication/blockstates/ic_workbench.json +++ b/fabrication/src/main/generated/assets/projectred_fabrication/blockstates/ic_workbench.json @@ -1,10 +1,10 @@ { "variants": { "blueprint=false": { - "model": "projectred_fabrication:block/ic_workbench_no_blueprint" + "model": "projectred_fabrication:block/ic_workbench_empty" }, "blueprint=true": { - "model": "projectred_fabrication:block/ic_workbench_blueprint" + "model": "projectred_fabrication:block/ic_workbench" } } } \ No newline at end of file diff --git a/fabrication/src/main/generated/assets/projectred_fabrication/blockstates/lithography_table.json b/fabrication/src/main/generated/assets/projectred_fabrication/blockstates/lithography_table.json index ef4ecdbbf..0efd13726 100644 --- a/fabrication/src/main/generated/assets/projectred_fabrication/blockstates/lithography_table.json +++ b/fabrication/src/main/generated/assets/projectred_fabrication/blockstates/lithography_table.json @@ -1,63 +1,63 @@ { "variants": { "charged=false,rotation=0,working=false": { - "model": "projectred_fabrication:block/lithography_table_c0" + "model": "projectred_fabrication:block/lithography_table" }, "charged=true,rotation=0,working=false": { - "model": "projectred_fabrication:block/lithography_table_c1" + "model": "projectred_fabrication:block/lithography_table_state1" }, "charged=false,rotation=1,working=false": { - "model": "projectred_fabrication:block/lithography_table_c0", + "model": "projectred_fabrication:block/lithography_table", "y": 90 }, "charged=true,rotation=1,working=false": { - "model": "projectred_fabrication:block/lithography_table_c1", + "model": "projectred_fabrication:block/lithography_table_state1", "y": 90 }, "charged=false,rotation=2,working=false": { - "model": "projectred_fabrication:block/lithography_table_c0", + "model": "projectred_fabrication:block/lithography_table", "y": 180 }, "charged=true,rotation=2,working=false": { - "model": "projectred_fabrication:block/lithography_table_c1", + "model": "projectred_fabrication:block/lithography_table_state1", "y": 180 }, "charged=false,rotation=3,working=false": { - "model": "projectred_fabrication:block/lithography_table_c0", + "model": "projectred_fabrication:block/lithography_table", "y": 270 }, "charged=true,rotation=3,working=false": { - "model": "projectred_fabrication:block/lithography_table_c1", + "model": "projectred_fabrication:block/lithography_table_state1", "y": 270 }, "charged=false,rotation=0,working=true": { - "model": "projectred_fabrication:block/lithography_table_c0" + "model": "projectred_fabrication:block/lithography_table" }, "charged=true,rotation=0,working=true": { - "model": "projectred_fabrication:block/lithography_table_c2" + "model": "projectred_fabrication:block/lithography_table_state2" }, "charged=false,rotation=1,working=true": { - "model": "projectred_fabrication:block/lithography_table_c0", + "model": "projectred_fabrication:block/lithography_table", "y": 90 }, "charged=true,rotation=1,working=true": { - "model": "projectred_fabrication:block/lithography_table_c2", + "model": "projectred_fabrication:block/lithography_table_state2", "y": 90 }, "charged=false,rotation=2,working=true": { - "model": "projectred_fabrication:block/lithography_table_c0", + "model": "projectred_fabrication:block/lithography_table", "y": 180 }, "charged=true,rotation=2,working=true": { - "model": "projectred_fabrication:block/lithography_table_c2", + "model": "projectred_fabrication:block/lithography_table_state2", "y": 180 }, "charged=false,rotation=3,working=true": { - "model": "projectred_fabrication:block/lithography_table_c0", + "model": "projectred_fabrication:block/lithography_table", "y": 270 }, "charged=true,rotation=3,working=true": { - "model": "projectred_fabrication:block/lithography_table_c2", + "model": "projectred_fabrication:block/lithography_table_state2", "y": 270 } } diff --git a/fabrication/src/main/generated/assets/projectred_fabrication/blockstates/packaging_table.json b/fabrication/src/main/generated/assets/projectred_fabrication/blockstates/packaging_table.json index 931d6ef18..083843757 100644 --- a/fabrication/src/main/generated/assets/projectred_fabrication/blockstates/packaging_table.json +++ b/fabrication/src/main/generated/assets/projectred_fabrication/blockstates/packaging_table.json @@ -1,63 +1,63 @@ { "variants": { "charged=false,rotation=0,working=false": { - "model": "projectred_fabrication:block/packaging_table_c0" + "model": "projectred_fabrication:block/packaging_table" }, "charged=true,rotation=0,working=false": { - "model": "projectred_fabrication:block/packaging_table_c1" + "model": "projectred_fabrication:block/packaging_table_state1" }, "charged=false,rotation=1,working=false": { - "model": "projectred_fabrication:block/packaging_table_c0", + "model": "projectred_fabrication:block/packaging_table", "y": 90 }, "charged=true,rotation=1,working=false": { - "model": "projectred_fabrication:block/packaging_table_c1", + "model": "projectred_fabrication:block/packaging_table_state1", "y": 90 }, "charged=false,rotation=2,working=false": { - "model": "projectred_fabrication:block/packaging_table_c0", + "model": "projectred_fabrication:block/packaging_table", "y": 180 }, "charged=true,rotation=2,working=false": { - "model": "projectred_fabrication:block/packaging_table_c1", + "model": "projectred_fabrication:block/packaging_table_state1", "y": 180 }, "charged=false,rotation=3,working=false": { - "model": "projectred_fabrication:block/packaging_table_c0", + "model": "projectred_fabrication:block/packaging_table", "y": 270 }, "charged=true,rotation=3,working=false": { - "model": "projectred_fabrication:block/packaging_table_c1", + "model": "projectred_fabrication:block/packaging_table_state1", "y": 270 }, "charged=false,rotation=0,working=true": { - "model": "projectred_fabrication:block/packaging_table_c0" + "model": "projectred_fabrication:block/packaging_table" }, "charged=true,rotation=0,working=true": { - "model": "projectred_fabrication:block/packaging_table_c2" + "model": "projectred_fabrication:block/packaging_table_state2" }, "charged=false,rotation=1,working=true": { - "model": "projectred_fabrication:block/packaging_table_c0", + "model": "projectred_fabrication:block/packaging_table", "y": 90 }, "charged=true,rotation=1,working=true": { - "model": "projectred_fabrication:block/packaging_table_c2", + "model": "projectred_fabrication:block/packaging_table_state2", "y": 90 }, "charged=false,rotation=2,working=true": { - "model": "projectred_fabrication:block/packaging_table_c0", + "model": "projectred_fabrication:block/packaging_table", "y": 180 }, "charged=true,rotation=2,working=true": { - "model": "projectred_fabrication:block/packaging_table_c2", + "model": "projectred_fabrication:block/packaging_table_state2", "y": 180 }, "charged=false,rotation=3,working=true": { - "model": "projectred_fabrication:block/packaging_table_c0", + "model": "projectred_fabrication:block/packaging_table", "y": 270 }, "charged=true,rotation=3,working=true": { - "model": "projectred_fabrication:block/packaging_table_c2", + "model": "projectred_fabrication:block/packaging_table_state2", "y": 270 } } diff --git a/fabrication/src/main/generated/assets/projectred_fabrication/blockstates/plotting_table.json b/fabrication/src/main/generated/assets/projectred_fabrication/blockstates/plotting_table.json index 28816b4d5..06593b8ce 100644 --- a/fabrication/src/main/generated/assets/projectred_fabrication/blockstates/plotting_table.json +++ b/fabrication/src/main/generated/assets/projectred_fabrication/blockstates/plotting_table.json @@ -1,63 +1,63 @@ { "variants": { "charged=false,rotation=0,working=false": { - "model": "projectred_fabrication:block/plotting_table_c0" + "model": "projectred_fabrication:block/plotting_table" }, "charged=true,rotation=0,working=false": { - "model": "projectred_fabrication:block/plotting_table_c1" + "model": "projectred_fabrication:block/plotting_table_state1" }, "charged=false,rotation=1,working=false": { - "model": "projectred_fabrication:block/plotting_table_c0", + "model": "projectred_fabrication:block/plotting_table", "y": 90 }, "charged=true,rotation=1,working=false": { - "model": "projectred_fabrication:block/plotting_table_c1", + "model": "projectred_fabrication:block/plotting_table_state1", "y": 90 }, "charged=false,rotation=2,working=false": { - "model": "projectred_fabrication:block/plotting_table_c0", + "model": "projectred_fabrication:block/plotting_table", "y": 180 }, "charged=true,rotation=2,working=false": { - "model": "projectred_fabrication:block/plotting_table_c1", + "model": "projectred_fabrication:block/plotting_table_state1", "y": 180 }, "charged=false,rotation=3,working=false": { - "model": "projectred_fabrication:block/plotting_table_c0", + "model": "projectred_fabrication:block/plotting_table", "y": 270 }, "charged=true,rotation=3,working=false": { - "model": "projectred_fabrication:block/plotting_table_c1", + "model": "projectred_fabrication:block/plotting_table_state1", "y": 270 }, "charged=false,rotation=0,working=true": { - "model": "projectred_fabrication:block/plotting_table_c0" + "model": "projectred_fabrication:block/plotting_table" }, "charged=true,rotation=0,working=true": { - "model": "projectred_fabrication:block/plotting_table_c2" + "model": "projectred_fabrication:block/plotting_table_state2" }, "charged=false,rotation=1,working=true": { - "model": "projectred_fabrication:block/plotting_table_c0", + "model": "projectred_fabrication:block/plotting_table", "y": 90 }, "charged=true,rotation=1,working=true": { - "model": "projectred_fabrication:block/plotting_table_c2", + "model": "projectred_fabrication:block/plotting_table_state2", "y": 90 }, "charged=false,rotation=2,working=true": { - "model": "projectred_fabrication:block/plotting_table_c0", + "model": "projectred_fabrication:block/plotting_table", "y": 180 }, "charged=true,rotation=2,working=true": { - "model": "projectred_fabrication:block/plotting_table_c2", + "model": "projectred_fabrication:block/plotting_table_state2", "y": 180 }, "charged=false,rotation=3,working=true": { - "model": "projectred_fabrication:block/plotting_table_c0", + "model": "projectred_fabrication:block/plotting_table", "y": 270 }, "charged=true,rotation=3,working=true": { - "model": "projectred_fabrication:block/plotting_table_c2", + "model": "projectred_fabrication:block/plotting_table_state2", "y": 270 } } diff --git a/fabrication/src/main/generated/assets/projectred_fabrication/models/block/ic_workbench_no_blueprint.json b/fabrication/src/main/generated/assets/projectred_fabrication/models/block/ic_workbench.json similarity index 74% rename from fabrication/src/main/generated/assets/projectred_fabrication/models/block/ic_workbench_no_blueprint.json rename to fabrication/src/main/generated/assets/projectred_fabrication/models/block/ic_workbench.json index 9f8161361..ade716fc6 100644 --- a/fabrication/src/main/generated/assets/projectred_fabrication/models/block/ic_workbench_no_blueprint.json +++ b/fabrication/src/main/generated/assets/projectred_fabrication/models/block/ic_workbench.json @@ -6,6 +6,7 @@ "north": "projectred_fabrication:block/ic_workbench_front", "south": "projectred_fabrication:block/ic_workbench_front", "east": "projectred_fabrication:block/ic_workbench_side", - "west": "projectred_fabrication:block/ic_workbench_side" + "west": "projectred_fabrication:block/ic_workbench_side", + "particle": "projectred_fabrication:block/ic_workbench_front" } } \ No newline at end of file diff --git a/fabrication/src/main/generated/assets/projectred_fabrication/models/block/ic_workbench_blueprint.json b/fabrication/src/main/generated/assets/projectred_fabrication/models/block/ic_workbench_blueprint.json deleted file mode 100644 index c0bedfc40..000000000 --- a/fabrication/src/main/generated/assets/projectred_fabrication/models/block/ic_workbench_blueprint.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "parent": "minecraft:block/cube", - "textures": { - "down": "projectred_fabrication:block/ic_workbench_bottom", - "up": "projectred_fabrication:block/ic_workbench_top_bp", - "north": "projectred_fabrication:block/ic_workbench_front_bp", - "south": "projectred_fabrication:block/ic_workbench_front_bp", - "east": "projectred_fabrication:block/ic_workbench_side_bp", - "west": "projectred_fabrication:block/ic_workbench_side_bp" - } -} \ No newline at end of file diff --git a/fabrication/src/main/generated/assets/projectred_fabrication/models/block/ic_workbench_empty.json b/fabrication/src/main/generated/assets/projectred_fabrication/models/block/ic_workbench_empty.json new file mode 100644 index 000000000..f4e51e324 --- /dev/null +++ b/fabrication/src/main/generated/assets/projectred_fabrication/models/block/ic_workbench_empty.json @@ -0,0 +1,12 @@ +{ + "parent": "minecraft:block/cube", + "textures": { + "down": "projectred_fabrication:block/ic_workbench_bottom", + "up": "projectred_fabrication:block/ic_workbench_top_empty", + "north": "projectred_fabrication:block/ic_workbench_front_empty", + "south": "projectred_fabrication:block/ic_workbench_front_empty", + "east": "projectred_fabrication:block/ic_workbench_side_empty", + "west": "projectred_fabrication:block/ic_workbench_side_empty", + "particle": "projectred_fabrication:block/ic_workbench_front_empty" + } +} \ No newline at end of file diff --git a/fabrication/src/main/generated/assets/projectred_fabrication/models/block/lithography_table_c0.json b/fabrication/src/main/generated/assets/projectred_fabrication/models/block/lithography_table.json similarity index 100% rename from fabrication/src/main/generated/assets/projectred_fabrication/models/block/lithography_table_c0.json rename to fabrication/src/main/generated/assets/projectred_fabrication/models/block/lithography_table.json diff --git a/fabrication/src/main/generated/assets/projectred_fabrication/models/block/lithography_table_c1.json b/fabrication/src/main/generated/assets/projectred_fabrication/models/block/lithography_table_state1.json similarity index 100% rename from fabrication/src/main/generated/assets/projectred_fabrication/models/block/lithography_table_c1.json rename to fabrication/src/main/generated/assets/projectred_fabrication/models/block/lithography_table_state1.json diff --git a/fabrication/src/main/generated/assets/projectred_fabrication/models/block/lithography_table_c2.json b/fabrication/src/main/generated/assets/projectred_fabrication/models/block/lithography_table_state2.json similarity index 100% rename from fabrication/src/main/generated/assets/projectred_fabrication/models/block/lithography_table_c2.json rename to fabrication/src/main/generated/assets/projectred_fabrication/models/block/lithography_table_state2.json diff --git a/fabrication/src/main/generated/assets/projectred_fabrication/models/block/packaging_table_c0.json b/fabrication/src/main/generated/assets/projectred_fabrication/models/block/packaging_table.json similarity index 100% rename from fabrication/src/main/generated/assets/projectred_fabrication/models/block/packaging_table_c0.json rename to fabrication/src/main/generated/assets/projectred_fabrication/models/block/packaging_table.json diff --git a/fabrication/src/main/generated/assets/projectred_fabrication/models/block/packaging_table_c1.json b/fabrication/src/main/generated/assets/projectred_fabrication/models/block/packaging_table_state1.json similarity index 100% rename from fabrication/src/main/generated/assets/projectred_fabrication/models/block/packaging_table_c1.json rename to fabrication/src/main/generated/assets/projectred_fabrication/models/block/packaging_table_state1.json diff --git a/fabrication/src/main/generated/assets/projectred_fabrication/models/block/packaging_table_c2.json b/fabrication/src/main/generated/assets/projectred_fabrication/models/block/packaging_table_state2.json similarity index 100% rename from fabrication/src/main/generated/assets/projectred_fabrication/models/block/packaging_table_c2.json rename to fabrication/src/main/generated/assets/projectred_fabrication/models/block/packaging_table_state2.json diff --git a/fabrication/src/main/generated/assets/projectred_fabrication/models/block/plotting_table_c0.json b/fabrication/src/main/generated/assets/projectred_fabrication/models/block/plotting_table.json similarity index 100% rename from fabrication/src/main/generated/assets/projectred_fabrication/models/block/plotting_table_c0.json rename to fabrication/src/main/generated/assets/projectred_fabrication/models/block/plotting_table.json diff --git a/fabrication/src/main/generated/assets/projectred_fabrication/models/block/plotting_table_c1.json b/fabrication/src/main/generated/assets/projectred_fabrication/models/block/plotting_table_state1.json similarity index 100% rename from fabrication/src/main/generated/assets/projectred_fabrication/models/block/plotting_table_c1.json rename to fabrication/src/main/generated/assets/projectred_fabrication/models/block/plotting_table_state1.json diff --git a/fabrication/src/main/generated/assets/projectred_fabrication/models/block/plotting_table_c2.json b/fabrication/src/main/generated/assets/projectred_fabrication/models/block/plotting_table_state2.json similarity index 100% rename from fabrication/src/main/generated/assets/projectred_fabrication/models/block/plotting_table_c2.json rename to fabrication/src/main/generated/assets/projectred_fabrication/models/block/plotting_table_state2.json diff --git a/fabrication/src/main/generated/assets/projectred_fabrication/models/item/ic_workbench.json b/fabrication/src/main/generated/assets/projectred_fabrication/models/item/ic_workbench.json index f5601fe48..01abc7198 100644 --- a/fabrication/src/main/generated/assets/projectred_fabrication/models/item/ic_workbench.json +++ b/fabrication/src/main/generated/assets/projectred_fabrication/models/item/ic_workbench.json @@ -1,3 +1,3 @@ { - "parent": "projectred_fabrication:block/ic_workbench_blueprint" + "parent": "projectred_fabrication:block/ic_workbench" } \ No newline at end of file diff --git a/fabrication/src/main/generated/assets/projectred_fabrication/models/item/lithography_table.json b/fabrication/src/main/generated/assets/projectred_fabrication/models/item/lithography_table.json index e193a4f08..c95bda678 100644 --- a/fabrication/src/main/generated/assets/projectred_fabrication/models/item/lithography_table.json +++ b/fabrication/src/main/generated/assets/projectred_fabrication/models/item/lithography_table.json @@ -1,3 +1,3 @@ { - "parent": "projectred_fabrication:block/lithography_table_c0" + "parent": "projectred_fabrication:block/lithography_table" } \ No newline at end of file diff --git a/fabrication/src/main/generated/assets/projectred_fabrication/models/item/packaging_table.json b/fabrication/src/main/generated/assets/projectred_fabrication/models/item/packaging_table.json index 134d48a3a..e4241aca7 100644 --- a/fabrication/src/main/generated/assets/projectred_fabrication/models/item/packaging_table.json +++ b/fabrication/src/main/generated/assets/projectred_fabrication/models/item/packaging_table.json @@ -1,3 +1,3 @@ { - "parent": "projectred_fabrication:block/packaging_table_c0" + "parent": "projectred_fabrication:block/packaging_table" } \ No newline at end of file diff --git a/fabrication/src/main/generated/assets/projectred_fabrication/models/item/plotting_table.json b/fabrication/src/main/generated/assets/projectred_fabrication/models/item/plotting_table.json index 31c51d729..46a0db2e5 100644 --- a/fabrication/src/main/generated/assets/projectred_fabrication/models/item/plotting_table.json +++ b/fabrication/src/main/generated/assets/projectred_fabrication/models/item/plotting_table.json @@ -1,3 +1,3 @@ { - "parent": "projectred_fabrication:block/plotting_table_c0" + "parent": "projectred_fabrication:block/plotting_table" } \ No newline at end of file diff --git a/fabrication/src/main/generated/data/projectred-fabrication/recipes/blank_photomask.json b/fabrication/src/main/generated/data/projectred_fabrication/recipes/blank_photomask.json similarity index 80% rename from fabrication/src/main/generated/data/projectred-fabrication/recipes/blank_photomask.json rename to fabrication/src/main/generated/data/projectred_fabrication/recipes/blank_photomask.json index 8e1865d24..c19cec02a 100644 --- a/fabrication/src/main/generated/data/projectred-fabrication/recipes/blank_photomask.json +++ b/fabrication/src/main/generated/data/projectred_fabrication/recipes/blank_photomask.json @@ -1,7 +1,7 @@ { "type": "minecraft:crafting_shaped", "result": { - "item": "projectred-fabrication:blank_photomask" + "item": "projectred_fabrication:blank_photomask" }, "pattern": [ "ggg", diff --git a/fabrication/src/main/generated/data/projectred-fabrication/recipes/ic_blueprint.json b/fabrication/src/main/generated/data/projectred_fabrication/recipes/ic_blueprint.json similarity index 84% rename from fabrication/src/main/generated/data/projectred-fabrication/recipes/ic_blueprint.json rename to fabrication/src/main/generated/data/projectred_fabrication/recipes/ic_blueprint.json index 8478fc34b..47b026e6f 100644 --- a/fabrication/src/main/generated/data/projectred-fabrication/recipes/ic_blueprint.json +++ b/fabrication/src/main/generated/data/projectred_fabrication/recipes/ic_blueprint.json @@ -1,7 +1,7 @@ { "type": "minecraft:crafting_shaped", "result": { - "item": "projectred-fabrication:ic_blueprint" + "item": "projectred_fabrication:ic_blueprint" }, "pattern": [ "pbp", diff --git a/fabrication/src/main/generated/data/projectred-fabrication/recipes/ic_workbench.json b/fabrication/src/main/generated/data/projectred_fabrication/recipes/ic_workbench.json similarity index 70% rename from fabrication/src/main/generated/data/projectred-fabrication/recipes/ic_workbench.json rename to fabrication/src/main/generated/data/projectred_fabrication/recipes/ic_workbench.json index d3d5790d4..ed95bc33e 100644 --- a/fabrication/src/main/generated/data/projectred-fabrication/recipes/ic_workbench.json +++ b/fabrication/src/main/generated/data/projectred_fabrication/recipes/ic_workbench.json @@ -1,7 +1,7 @@ { "type": "minecraft:crafting_shaped", "result": { - "item": "projectred-fabrication:ic_workbench" + "item": "projectred_fabrication:ic_workbench" }, "pattern": [ "sss", @@ -16,7 +16,7 @@ "item": "minecraft:stone" }, "b": { - "item": "projectred-fabrication:ic_blueprint" + "item": "projectred_fabrication:ic_blueprint" } } } \ No newline at end of file diff --git a/fabrication/src/main/generated/data/projectred-fabrication/recipes/lithography_table.json b/fabrication/src/main/generated/data/projectred_fabrication/recipes/lithography_table.json similarity index 88% rename from fabrication/src/main/generated/data/projectred-fabrication/recipes/lithography_table.json rename to fabrication/src/main/generated/data/projectred_fabrication/recipes/lithography_table.json index 24981da12..1a1bb51b2 100644 --- a/fabrication/src/main/generated/data/projectred-fabrication/recipes/lithography_table.json +++ b/fabrication/src/main/generated/data/projectred_fabrication/recipes/lithography_table.json @@ -1,7 +1,7 @@ { "type": "minecraft:crafting_shaped", "result": { - "item": "projectred-fabrication:lithography_table" + "item": "projectred_fabrication:lithography_table" }, "pattern": [ "gtg", diff --git a/fabrication/src/main/generated/data/projectred-fabrication/recipes/packaging_table.json b/fabrication/src/main/generated/data/projectred_fabrication/recipes/packaging_table.json similarity index 79% rename from fabrication/src/main/generated/data/projectred-fabrication/recipes/packaging_table.json rename to fabrication/src/main/generated/data/projectred_fabrication/recipes/packaging_table.json index 5c27a499f..3293e192b 100644 --- a/fabrication/src/main/generated/data/projectred-fabrication/recipes/packaging_table.json +++ b/fabrication/src/main/generated/data/projectred_fabrication/recipes/packaging_table.json @@ -1,7 +1,7 @@ { "type": "minecraft:crafting_shaped", "result": { - "item": "projectred-fabrication:packaging_table" + "item": "projectred_fabrication:packaging_table" }, "pattern": [ "gtg", @@ -19,7 +19,7 @@ "tag": "minecraft:planks" }, "p": { - "item": "projectred-core:plate" + "item": "projectred_core:plate" }, "b": { "tag": "forge:ingots/electrotine_alloy" diff --git a/fabrication/src/main/generated/data/projectred-fabrication/recipes/plotting_table.json b/fabrication/src/main/generated/data/projectred_fabrication/recipes/plotting_table.json similarity index 79% rename from fabrication/src/main/generated/data/projectred-fabrication/recipes/plotting_table.json rename to fabrication/src/main/generated/data/projectred_fabrication/recipes/plotting_table.json index 47dde0755..ed8c915cd 100644 --- a/fabrication/src/main/generated/data/projectred-fabrication/recipes/plotting_table.json +++ b/fabrication/src/main/generated/data/projectred_fabrication/recipes/plotting_table.json @@ -1,7 +1,7 @@ { "type": "minecraft:crafting_shaped", "result": { - "item": "projectred-fabrication:plotting_table" + "item": "projectred_fabrication:plotting_table" }, "pattern": [ "gtg", @@ -19,7 +19,7 @@ "tag": "minecraft:planks" }, "p": { - "item": "projectred-fabrication:blank_photomask" + "item": "projectred_fabrication:blank_photomask" }, "s": { "item": "minecraft:stone" diff --git a/fabrication/src/main/generated/data/projectred-fabrication/recipes/rough_silicon_wafer.json b/fabrication/src/main/generated/data/projectred_fabrication/recipes/rough_silicon_wafer.json similarity index 55% rename from fabrication/src/main/generated/data/projectred-fabrication/recipes/rough_silicon_wafer.json rename to fabrication/src/main/generated/data/projectred_fabrication/recipes/rough_silicon_wafer.json index 58196469d..71b434438 100644 --- a/fabrication/src/main/generated/data/projectred-fabrication/recipes/rough_silicon_wafer.json +++ b/fabrication/src/main/generated/data/projectred_fabrication/recipes/rough_silicon_wafer.json @@ -1,10 +1,10 @@ { "type": "minecraft:smelting", "result": { - "item": "projectred-fabrication:rough_silicon_wafer" + "item": "projectred_fabrication:rough_silicon_wafer" }, "ingredient": { - "item": "projectred-core:silicon" + "item": "projectred_core:silicon" }, "experience": 0.0, "cookingtime": 200 diff --git a/fabrication/src/main/java/mrtjp/projectred/fabrication/data/FabricationBlockStateModelProvider.java b/fabrication/src/main/java/mrtjp/projectred/fabrication/data/FabricationBlockStateModelProvider.java index 54c205594..59928e736 100644 --- a/fabrication/src/main/java/mrtjp/projectred/fabrication/data/FabricationBlockStateModelProvider.java +++ b/fabrication/src/main/java/mrtjp/projectred/fabrication/data/FabricationBlockStateModelProvider.java @@ -30,33 +30,23 @@ public String getName() { @Override protected void registerStatesAndModels() { - BlockModelBuilder noBP = models().cube(IC_WORKBENCH_BLOCK.getRegistryName().getPath() + "_no_blueprint", - new ResourceLocation(MOD_ID, "block/ic_workbench_bottom"), - new ResourceLocation(MOD_ID, "block/ic_workbench_top"), - new ResourceLocation(MOD_ID, "block/ic_workbench_front"), - new ResourceLocation(MOD_ID, "block/ic_workbench_front"), - new ResourceLocation(MOD_ID, "block/ic_workbench_side"), - new ResourceLocation(MOD_ID, "block/ic_workbench_side")); - - BlockModelBuilder withBP = models().cube(IC_WORKBENCH_BLOCK.getRegistryName().getPath() + "_blueprint", - new ResourceLocation(MOD_ID, "block/ic_workbench_bottom"), - new ResourceLocation(MOD_ID, "block/ic_workbench_top_bp"), - new ResourceLocation(MOD_ID, "block/ic_workbench_front_bp"), - new ResourceLocation(MOD_ID, "block/ic_workbench_front_bp"), - new ResourceLocation(MOD_ID, "block/ic_workbench_side_bp"), - new ResourceLocation(MOD_ID, "block/ic_workbench_side_bp")); - - getVariantBuilder(IC_WORKBENCH_BLOCK) - .partialState().with(ICWorkbenchBlock.BLUEPRINT_PROPERTY, false).modelForState().modelFile(noBP).addModel(); - - getVariantBuilder(IC_WORKBENCH_BLOCK) - .partialState().with(ICWorkbenchBlock.BLUEPRINT_PROPERTY, true).modelForState().modelFile(withBP).addModel(); + addICWorkbenchVariants(IC_WORKBENCH_BLOCK); addFabricationMachineVariants(PLOTTING_TABLE_BLOCK); addFabricationMachineVariants(LITHOGRAPHY_TABLE_BLOCK); addFabricationMachineVariants(PACKAGING_TABLE_BLOCK); } + private void addICWorkbenchVariants(Block block) { + getVariantBuilder(block) + .partialState().with(ICWorkbenchBlock.BLUEPRINT_PROPERTY, false) + .modelForState().modelFile(createICWorkbenchModel(block, false)).addModel(); + + getVariantBuilder(block) + .partialState().with(ICWorkbenchBlock.BLUEPRINT_PROPERTY, true) + .modelForState().modelFile(createICWorkbenchModel(block, true)).addModel(); + } + private void addFabricationMachineVariants(Block block) { addRotatableDomedMachineVariants(block, createDomedMachineModelFileForBlock(block, 2), @@ -82,8 +72,9 @@ private void addRotatableDomedMachineVariants(Block block, ModelFile workingMode private BlockModelBuilder createDomedMachineModelFileForBlock(Block block, int chargeState) { String textureName = block.getRegistryName().getPath(); + String modelName = textureName + (chargeState > 0 ? "_state" + chargeState : ""); return models() - .withExistingParent(textureName + "_c" + chargeState, modLoc("block/domed_machine")) + .withExistingParent(modelName, modLoc("block/domed_machine")) .texture("down", modLoc("block/" + textureName + "_bottom")) .texture("up", modLoc("block/" + textureName + "_top")) .texture("north", modLoc("block/" + textureName + "_front_" + chargeState)) @@ -91,4 +82,18 @@ private BlockModelBuilder createDomedMachineModelFileForBlock(Block block, int c .texture("west", modLoc("block/" + textureName + "_side")) .texture("east", modLoc("block/" + textureName + "_side")); } + + private BlockModelBuilder createICWorkbenchModel(Block block, boolean hasBlueprint) { + String textureName = block.getRegistryName().getPath(); + String suffix = hasBlueprint ? "" : "_empty"; + String modelName = textureName + suffix; + return models().cube(modelName, + modLoc("block/" + textureName + "_bottom"), + modLoc("block/" + textureName + "_top" + suffix), + modLoc("block/" + textureName + "_front" + suffix), + modLoc("block/" + textureName + "_front" + suffix), + modLoc("block/" + textureName + "_side" + suffix), + modLoc("block/" + textureName + "_side" + suffix)) + .texture("particle", modLoc("block/" + textureName + "_front" + suffix)); + } } diff --git a/fabrication/src/main/java/mrtjp/projectred/fabrication/data/FabricationItemModelProvider.java b/fabrication/src/main/java/mrtjp/projectred/fabrication/data/FabricationItemModelProvider.java index 0626ecf04..3ac91c622 100644 --- a/fabrication/src/main/java/mrtjp/projectred/fabrication/data/FabricationItemModelProvider.java +++ b/fabrication/src/main/java/mrtjp/projectred/fabrication/data/FabricationItemModelProvider.java @@ -2,8 +2,6 @@ import codechicken.lib.datagen.ItemModelProvider; import net.minecraft.data.DataGenerator; -import net.minecraft.world.level.block.Block; -import net.minecraftforge.client.model.generators.ModelFile; import net.minecraftforge.common.data.ExistingFileHelper; import static mrtjp.projectred.fabrication.ProjectRedFabrication.MOD_ID; @@ -23,13 +21,11 @@ public String getName() { @Override protected void registerModels() { - getSimple(IC_WORKBENCH_BLOCK) - .parent(new ModelFile.UncheckedModelFile(modLoc("block/" + name(IC_WORKBENCH_BLOCK) + "_blueprint"))) - .noTexture(); + simpleItemBlock(IC_WORKBENCH_BLOCK); - domedMachine(PLOTTING_TABLE_BLOCK); - domedMachine(LITHOGRAPHY_TABLE_BLOCK); - domedMachine(PACKAGING_TABLE_BLOCK); + simpleItemBlock(PLOTTING_TABLE_BLOCK); + simpleItemBlock(LITHOGRAPHY_TABLE_BLOCK); + simpleItemBlock(PACKAGING_TABLE_BLOCK); generated(IC_BLUEPRINT_ITEM); generated(BLANK_PHOTOMASK_ITEM); @@ -41,10 +37,4 @@ protected void registerModels() { generated(FABRICATED_GATE_ITEM).noTexture(); // Dummy model to suppress warnings (actually rendered runtime via IItemRenderer) } - - private void domedMachine(Block block) { - getSimple(block) - .parent(new ModelFile.UncheckedModelFile(modLoc("block/" + name(block) + "_c0"))) - .noTexture(); - } } diff --git a/fabrication/src/main/resources/assets/projectred_fabrication/textures/block/ic_workbench_front.png b/fabrication/src/main/resources/assets/projectred_fabrication/textures/block/ic_workbench_front.png index d9d37a872c8aa3d5ac4df432ad731fa1e41bf756..a9ebf9b22c1e4f63ef377bd6fcc3fa885aafe590 100644 GIT binary patch delta 1552 zcma*g`9ISQ00;1lv9YAXS+a!}dYXNwIY(HYYI|IfCYIYOl)0YrIOdF=yh!AVrd%ag z!&n;4a^y_8hCO-`lG*d*95T;(o`2x^ynp%p@OiyH^mvK&1c|yEl3=u{nW1S`n56Z8 zt)3|v1ky70H^7*hVEmB&fRQ&6V~jRJdK&<~$de`}0NK|MZ3>_<^>}Hbq~`xvX30QI zv%W(ikbkd`04B>3(vvj^mad>Bb>hqgZ_^n1r{nzHn=zA=@+P2vISmjTv>* z0DCl;@vxu4V05~Qa!YM4{vwA{gk}QSN^;Ik9qjYgib^=hokNJbXJRON2Re$q;7PK> zsTaCKi=4FCrSg?mKc_YrIQio)fUg9a*6apJcfA;!;c~fAk>e)yBI4WH?RmA?BWCp&0Cg+}+yzFt}OYs4ygzgx}oYgMCkJ1#Wvdwr?+m zg3`9WBu^N_vjy=Bu&XGO%-}eSjEWSaeeLUfu@hfP?Z0YWeVnWW&vqi{iLQ?p8(!Uu z`+iHzq~XXp*wk04HG4|L(xT%8b;&KaqA9Ko<#BQh9*rgL4xE3d=P*Y)hf>LB9?6R# z)3`D|q_n#s3gtjDRNKW#8~g+$p8$t|bTNtrvUab{SNcx3<4vG46Swaxk7nG!`-$fI z8ucN`Q6Ga<-=UN`iS_S%%D($(VAg-Ivhx+w?2hH4w*PFCQ=+ib-V4k zdRX=XHS}enzHV|^-Jy#!xhH$`XJNW$O?%?|*<#iJoyFB?-KZO7D<{@U=@f4-2)5fO z8pDQTVu=bkh(t%7iV_F;p0`dsP}NZP#1BmR*1{3gVPRMF9}QjEg)Z-nbZgy17cxK1 zbST5k6n4m~2VbMpLtr_bKU7*#c_mTd`)s;OW`@2YMf)wDoUPpG%tMpY;?>S;29&Dl zTwWk3zp1;0HW1 zjiTMLsXkbbc<@qFHG{LZ*#RC)-e-ux4D(#T6(6upccg+o8!sO|DrJp^orZ9H6mC;? zxQoF9(@EnLemMWIS9my|S@8_NNbqm8ubwgan?+NP{q!!^d(J(0O(amzaYv);KoZm|F-d+~JHoU%-%<%NhBL zVUCf|&KM0|OB3_bVj^q9QXvxvi6wW26bov?&GM7Bwu+uDg;0189=Hd7jBM4A8tI{P znao*j;lyG_w7CV88XXY87zgt*mITcUk_d^TwjLzcZa-=<3whL&l#r!^x_n$3{ z!01hdiY=Kd=7Whhr&&2gwA#?)B&amb3ZoXC$=Hi^4#ASyD0|V|+o51i=s*OKXdP=q z(DRzz9O-?y8T$M_9>Tfrb}8PuLRO@Xzej&nT$)yJlQ6z&%u3jYo}?SSGSDGQs0dG~ xR9D;Ct*yC@b^88#si3EPdzT;oyNd_AO?nTEoxZHj1#0$)ga6syrUvJg@DH%Y@7(|Z delta 1356 zcmV-S1+)70f&sFD0kCcZ1u`%?F*1{L13?8cFgh_Zv$+Fo0wgstF*G$XWH~KjHaKK0 zG%__|EjTq{G%aN?Fl8}eG-hNmGBLAB23G?lH8C+XH8Es4En+q}WGyr@HDN6{HDNR@ zWiT*hF<~@jWHB-^lL!bnll%z?2r@7_F)}SMG?P#W%9GCp2D97>_Amsp>al{8);lhL z1ei%gK~#9!w3SsaThaprneRF-Gt~6fcdHA{IlC5PdMF ziINy12@eo_&}ak|qlv);V;U`*073yDytEM$d?82(mfEzXm+e|gFSD~VXJ>ra9=29} z^n3Z{eCM3+|3BYtv^8tjtX;Dq6X) z+i@FmUe3#T5QbqGh7b`EQC#1!hfx@XAe2GZbzRq?#4IsO%vl6xfHgEU!1sOM_lpG7 zJ>}3a4bw0oFY_`l!Sg)N^NN0y_|liYgc~O1Sc!6+^K*XA2O)$Ivxq1_(=<(g(=48w zOGw>Qb}6NlvWO$*I+{yB0ji5C1;nmStI%RRmW1BQ+y6BQ+2@p%Xfg-ILvu-2>v}-6ywo z+y?$L{tNz3(6pmz)zd2>mWri+VyU771vocCikM1a;0J!-Lq5!h`EZuKHE0c5;aJzP z==h%?wu}8@6NupP;Mw3UFm@WR7!LpkImkg6ZXa$RZZ85x%~5mI48{rLgmGe)y)9~s z+KT&HyVkC?L)aF!g>AD!oe>$40sVk}NZ$osgZGfP8?>(FU59?&5k=O2`FMx58D6?? z%WoStf(mP1&S^{Wce|$ld;3N+d6u&9B}C!m{&zl}_jv%}d-)IYUxT>1Zt&fqqhRl} zhvQ43)JZIH9B^IN^*r#rf-Wm7b>cQuR?aU^B%ps_XfTt3TWV`-7cM9QCzBPGWo0lu zH9a-$g6{`XN{}+}rG)-}-TgldT!Z+5_|f>wpfxlszq76`iqy+Wol?hf;EnfR+qC6* z=x+U`<%=y){#i`-${_cB?#*CD5%BbxzP?4ZuvL5R?e$CGO2fJQSKmP5^X&0q4`Q#| z!%htx|Mv3bWD+i3{Jp!s4^$^;EAL&gB9)4w%`K}|#{`@{)7|ZVIIwU*GFe^@)zwv% zHzgpG85_Gk0j}$LzF&MdE_)op5sdx!#}=nl>(LxaI*89~U~i1_x_u zVCn6N#LzGtK796U;Ddnt%!u^;NP=x!R*4BMdmnCETo38-%fFtz05Vhd;N&`>mmm2A z3=tE7gpN~&NTtAkIY0H-A4zE5Uf-Lq1IA?!oe+e1X$ZJJ?z(}5FtjWwi?t*mHZy`9 zr^JG|H91jY!I8b4$FBAi4lS}FkbbZC9cXB}mMYeO5JF5&z|gs>4q5ZhVysHqwh&;N zh7h8FV_Aj2OwI!xBEk^TqmvU;Q!vl5ZQF)z8(KbkVjnzzwd*hR&+m)CF(8VkO O0000_Amsp>al{8);lhL z1ei%gK~#9!w3SsaThaprneRF-Gt~6fcdHA{IlC5PdMF ziINy12@eo_&}ak|qlv);V;U`*073yDytEM$d?82(mfEzXm+e|gFSD~VXJ>ra9=29} z^n3Z{eCM3+|3BYtv^8tjtX;Dq6X) z+i@FmUe3#T5QbqGh7b`EQC#1!hfx@XAe2GZbzRq?#4IsO%vl6xfHgEU!1sOM_lpG7 zJ>}3a4bw0oFY_`l!Sg)N^NN0y_|liYgc~O1Sc!6+^K*XA2O)$Ivxq1_(=<(g(=48w zOGw>Qb}6NlvWO$*I+{yB0ji5C1;nmStI%RRmW1BQ+y6BQ+2@p%Xfg-ILvu-2>v}-6ywo z+y?$L{tNz3(6pmz)zd2>mWri+VyU771vocCikM1a;0J!-Lq5!h`EZuKHE0c5;aJzP z==h%?wu}8@6NupP;Mw3UFm@WR7!LpkImkg6ZXa$RZZ85x%~5mI48{rLgmGe)y)9~s z+KT&HyVkC?L)aF!g>AD!oe>$40sVk}NZ$osgZGfP8?>(FU59?&5k=O2`FMx58D6?? z%WoStf(mP1&S^{Wce|$ld;3N+d6u&9B}C!m{&zl}_jv%}d-)IYUxT>1Zt&fqqhRl} zhvQ43)JZIH9B^IN^*r#rf-Wm7b>cQuR?aU^B%ps_XfTt3TWV`-7cM9QCzBPGWo0lu zH9a-$g6{`XN{}+}rG)-}-TgldT!Z+5_|f>wpfxlszq76`iqy+Wol?hf;EnfR+qC6* z=x+U`<%=y){#i`-${_cB?#*CD5%BbxzP?4ZuvL5R?e$CGO2fJQSKmP5^X&0q4`Q#| z!%htx|Mv3bWD+i3{Jp!s4^$^;EAL&gB9)4w%`K}|#{`@{)7|ZVIIwU*GFe^@)zwv% zHzgpG85_Gk0j}$LzF&MdE_)op5sdx!#}=nl>(LxaI*89~U~i1_x_u zVCn6N#LzGtK796U;Ddnt%!u^;NP=x!R*4BMdmnCETo38-%fFtz05Vhd;N&`>mmm2A z3=tE7gpN~&NTtAkIY0H-A4zE5Uf-Lq1IA?!oe+e1X$ZJJ?z(}5FtjWwi?t*mHZy`9 zr^JG|H91jY!I8b4$FBAi4lS}FkbbZC9cXB}mMYeO5JF5&z|gs>4q5ZhVysHqwh&;N zh7h8FV_Aj2OwI!xBEk^TqmvU;Q!vl5ZQF)z8(KbkVjnzzwd*hR&+m)CF(8VkO O0000_<^>}Hbq~`xvX30QI zv%W(ikbkd`04B>3(vvj^mad>Bb>hqgZ_^n1r{nzHn=zA=@+P2vISmjTv>* z0DCl;@vxu4V05~Qa!YM4{vwA{gk}QSN^;Ik9qjYgib^=hokNJbXJRON2Re$q;7PK> zsTaCKi=4FCrSg?mKc_YrIQio)fUg9a*6apJcfA;!;c~fAk>e)yBI4WH?RmA?BWCp&0Cg+}+yzFt}OYs4ygzgx}oYgMCkJ1#Wvdwr?+m zg3`9WBu^N_vjy=Bu&XGO%-}eSjEWSaeeLUfu@hfP?Z0YWeVnWW&vqi{iLQ?p8(!Uu z`+iHzq~XXp*wk04HG4|L(xT%8b;&KaqA9Ko<#BQh9*rgL4xE3d=P*Y)hf>LB9?6R# z)3`D|q_n#s3gtjDRNKW#8~g+$p8$t|bTNtrvUab{SNcx3<4vG46Swaxk7nG!`-$fI z8ucN`Q6Ga<-=UN`iS_S%%D($(VAg-Ivhx+w?2hH4w*PFCQ=+ib-V4k zdRX=XHS}enzHV|^-Jy#!xhH$`XJNW$O?%?|*<#iJoyFB?-KZO7D<{@U=@f4-2)5fO z8pDQTVu=bkh(t%7iV_F;p0`dsP}NZP#1BmR*1{3gVPRMF9}QjEg)Z-nbZgy17cxK1 zbST5k6n4m~2VbMpLtr_bKU7*#c_mTd`)s;OW`@2YMf)wDoUPpG%tMpY;?>S;29&Dl zTwWk3zp1;0HW1 zjiTMLsXkbbc<@qFHG{LZ*#RC)-e-ux4D(#T6(6upccg+o8!sO|DrJp^orZ9H6mC;? zxQoF9(@EnLemMWIS9my|S@8_NNbqm8ubwgan?+NP{q!!^d(J(0O(amzaYv);KoZm|F-d+~JHoU%-%<%NhBL zVUCf|&KM0|OB3_bVj^q9QXvxvi6wW26bov?&GM7Bwu+uDg;0189=Hd7jBM4A8tI{P znao*j;lyG_w7CV88XXY87zgt*mITcUk_d^TwjLzcZa-=<3whL&l#r!^x_n$3{ z!01hdiY=Kd=7Whhr&&2gwA#?)B&amb3ZoXC$=Hi^4#ASyD0|V|+o51i=s*OKXdP=q z(DRzz9O-?y8T$M_9>Tfrb}8PuLRO@Xzej&nT$)yJlQ6z&%u3jYo}?SSGSDGQs0dG~ xR9D;Ct*yC@b^88#si3EPdzT;oyNd_AO?nTEoxZHj1#0$)ga6syrUvJg@DH%Y@7(|Z diff --git a/fabrication/src/main/resources/assets/projectred_fabrication/textures/block/ic_workbench_front_empty.png b/fabrication/src/main/resources/assets/projectred_fabrication/textures/block/ic_workbench_front_empty.png new file mode 100644 index 0000000000000000000000000000000000000000..d9d37a872c8aa3d5ac4df432ad731fa1e41bf756 GIT binary patch literal 16562 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 DFkQ;& literal 0 HcmV?d00001 diff --git a/fabrication/src/main/resources/assets/projectred_fabrication/textures/block/ic_workbench_side.png b/fabrication/src/main/resources/assets/projectred_fabrication/textures/block/ic_workbench_side.png index 8b5d991b1f2ebbaf23888670c759e981d24de711..0f4a27086658d8495d8032c0b4267da83d22b032 100644 GIT binary patch delta 1306 zcmV+#1?Bp$fBJv{uxkScGB7$ZGCDMqasxjHGB7$ZGCDM~xC3nhBw{% zW@9a4G&W&nI5s#jGB`Pt2naY3H7zhTR5CC+F)}(dI4v+VlTZlClg|YPv)l^yFa+xH z309NVJ1&0&U`a$lRCwC7luv9FRUF4Z^XAR#bUWRab}7(oOw*LM2qBG#7-NKR=mC;O zv|=DN@zfaO2{bm5aA-UTsRkQEsxg6xho)%=0o@o59Ee0>IFO=7jaC9Hw96XWvh1JP z+4nqb$5{&K$=_vWet+Kg_xt|7^Q`SVw(r=!!x(>-%?z0#GX%K$5`hv^( zDbT(7;mo(N;q5iu<WWVf}{ooCF1Kt2sf=W;cqWpjP zdzAS@2R{5lI8swk-w?4Xk7Gfi@x%ytH1grsg=iS}A>fGqSAh@4jT7rMMIo~%L zlF3!gP0dlfb7U|`RJe!a3#>4Og>+m7uwpjN?8J=Y>36ot;nbtWd1tG_4pfzOf+*``!pru8KAc%f;w^9Qu?Z33K zQX>nCg?ugtV6X*9un+)+=RJ6kqd+MsLt)jq(IBf< z)wzvvaHLYQW(AI8ORFkBibb%xyE{AE+l^_A*T-D9_NM!P?tw@P)#u*>03Q!4S&&&b Q<^TWy07*qoM6N<$f{CqhKL7v# delta 1102 zcmey>z_`ACLpC$Jp{13np_S3(B4&FSd-D$FTqc!dlQh#*0|O&nGh;JTT@zztOWmY2 z!!+GAv!t|C<0O-`Boo8Uo^0XFM5&z2!C@g_s%u~x0=3XW*T7_Q0LQ7x=ULe{-{JaZ zz>+%iUiRc`)_V2KQ$1ZALn>}<331Gbah3R&cF%rue!SVn%u7+H<~<5(@#?%1^)aF7 zQ-ESb?=&$M*AEJlyalb0rZ5}w(J20}ca0sbzB+My1 z)>t9Z|41;PcU7P%lhD)^E{xZrvUMLkcrfAr`=4t!pJRF=JE!=ZWxzzy$ce2iWu1}| z5)5m%UbFH)aJ-6*b1$d|LY*y(5D;NsHiVzY2c zkk`!l+Uidp@3}9L+;g&WMLkc5-vQxY4)ILD6PHGSBjnj5x!s_?GV?Qfy-mkO{nEB=1`SEd6 z@x$|1cRy5puy=F*-%r1!8>X8YFHQIS{kNyy{@>4Ccdew2|0zk$-}CL~b>aI<8vYvn z*7_~B;C}qS$KCe%j2EY_2(Fbn!84Dgf#1IBX^iR_#@%{^@0#Q~cmj z>t_8PH_Q47>N>(-cP$S5IA?qE@g*rT3bQ(vE&If>XVX8`4VTZ)wYr*NQU3DL%;(HZ zY3bQp7rpt%cJJ0(_U5;Yd|Q;=7i)C!-FyGN{cuCWZ1eYby-gh)wplA}Eo0-@Vd(Xg zaidpAVZoU*Y%yLA0S+rGWm*jj741xC3bt})ti87Gg7*{E_4OyB)(Z8hYV)Zq`fL7u zX~uSWo-g|~0z+CdYBomnR;pz^4pQe*IB+m(!R_iD#xhLp{Ka`bal4E7r@Y-?wfK&5 z^VN;JzxDk SrkGg_K;Y@>=d#Wzp$Pz*_56GQ diff --git a/fabrication/src/main/resources/assets/projectred_fabrication/textures/block/ic_workbench_side_bp.png b/fabrication/src/main/resources/assets/projectred_fabrication/textures/block/ic_workbench_side_bp.png index 0f4a27086658d8495d8032c0b4267da83d22b032..8b5d991b1f2ebbaf23888670c759e981d24de711 100644 GIT binary patch delta 1102 zcmey>z_`ACLpC$Jp{13np_S3(B4&FSd-D$FTqc!dlQh#*0|O&nGh;JTT@zztOWmY2 z!!+GAv!t|C<0O-`Boo8Uo^0XFM5&z2!C@g_s%u~x0=3XW*T7_Q0LQ7x=ULe{-{JaZ zz>+%iUiRc`)_V2KQ$1ZALn>}<331Gbah3R&cF%rue!SVn%u7+H<~<5(@#?%1^)aF7 zQ-ESb?=&$M*AEJlyalb0rZ5}w(J20}ca0sbzB+My1 z)>t9Z|41;PcU7P%lhD)^E{xZrvUMLkcrfAr`=4t!pJRF=JE!=ZWxzzy$ce2iWu1}| z5)5m%UbFH)aJ-6*b1$d|LY*y(5D;NsHiVzY2c zkk`!l+Uidp@3}9L+;g&WMLkc5-vQxY4)ILD6PHGSBjnj5x!s_?GV?Qfy-mkO{nEB=1`SEd6 z@x$|1cRy5puy=F*-%r1!8>X8YFHQIS{kNyy{@>4Ccdew2|0zk$-}CL~b>aI<8vYvn z*7_~B;C}qS$KCe%j2EY_2(Fbn!84Dgf#1IBX^iR_#@%{^@0#Q~cmj z>t_8PH_Q47>N>(-cP$S5IA?qE@g*rT3bQ(vE&If>XVX8`4VTZ)wYr*NQU3DL%;(HZ zY3bQp7rpt%cJJ0(_U5;Yd|Q;=7i)C!-FyGN{cuCWZ1eYby-gh)wplA}Eo0-@Vd(Xg zaidpAVZoU*Y%yLA0S+rGWm*jj741xC3bt})ti87Gg7*{E_4OyB)(Z8hYV)Zq`fL7u zX~uSWo-g|~0z+CdYBomnR;pz^4pQe*IB+m(!R_iD#xhLp{Ka`bal4E7r@Y-?wfK&5 z^VN;JzxDk SrkGg_K;Y@>=d#Wzp$Pz*_56GQ delta 1306 zcmV+#1?Bp$fBJv{uxkScGB7$ZGCDMqasxjHGB7$ZGCDM~xC3nhBw{% zW@9a4G&W&nI5s#jGB`Pt2naY3H7zhTR5CC+F)}(dI4v+VlTZlClg|YPv)l^yFa+xH z309NVJ1&0&U`a$lRCwC7luv9FRUF4Z^XAR#bUWRab}7(oOw*LM2qBG#7-NKR=mC;O zv|=DN@zfaO2{bm5aA-UTsRkQEsxg6xho)%=0o@o59Ee0>IFO=7jaC9Hw96XWvh1JP z+4nqb$5{&K$=_vWet+Kg_xt|7^Q`SVw(r=!!x(>-%?z0#GX%K$5`hv^( zDbT(7;mo(N;q5iu<WWVf}{ooCF1Kt2sf=W;cqWpjP zdzAS@2R{5lI8swk-w?4Xk7Gfi@x%ytH1grsg=iS}A>fGqSAh@4jT7rMMIo~%L zlF3!gP0dlfb7U|`RJe!a3#>4Og>+m7uwpjN?8J=Y>36ot;nbtWd1tG_4pfzOf+*``!pru8KAc%f;w^9Qu?Z33K zQX>nCg?ugtV6X*9un+)+=RJ6kqd+MsLt)jq(IBf< z)wzvvaHLYQW(AI8ORFkBibb%xyE{AE+l^_A*T-D9_NM!P?tw@P)#u*>03Q!4S&&&b Q<^TWy07*qoM6N<$f{CqhKL7v# diff --git a/fabrication/src/main/resources/assets/projectred_fabrication/textures/block/ic_workbench_side_empty.png b/fabrication/src/main/resources/assets/projectred_fabrication/textures/block/ic_workbench_side_empty.png new file mode 100644 index 0000000000000000000000000000000000000000..8b5d991b1f2ebbaf23888670c759e981d24de711 GIT binary patch literal 16303 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 JT8B$_{sT_-pRfP` delta 1332 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 JT8B$_{sT_-pRfP` diff --git a/fabrication/src/main/resources/assets/projectred_fabrication/textures/block/ic_workbench_top_empty.png b/fabrication/src/main/resources/assets/projectred_fabrication/textures/block/ic_workbench_top_empty.png new file mode 100644 index 0000000000000000000000000000000000000000..8ffbdb9a8783ec2d219df02d84983fa3742217d6 GIT binary patch literal 16401 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 UX7!jd=R^A`$@4UgiMf^k0b6;DSO5S3 literal 0 HcmV?d00001 From c951d19d4802d809a9a6f6298d86492575816b42 Mon Sep 17 00:00:00 2001 From: MrTJP Date: Tue, 22 Nov 2022 16:33:48 -0500 Subject: [PATCH 10/23] internal: add fabrication localization --- .../projectred_fabrication/lang/en_us.json | 75 ++++++++++ .../fabrication/ProjectRedFabrication.java | 2 + .../data/FabricationLanguageProvider.java | 106 ++++++++++++++ .../fabrication/engine/BaseTile.java | 4 +- .../fabrication/engine/ICTileType.java | 129 ++++++++++-------- .../fabrication/engine/gates/IOGateTile.java | 11 +- .../engine/gates/RepeaterGateTile.java | 8 +- .../engine/gates/SimpleGateTile.java | 7 +- .../fabrication/gui/EraserToolTab.java | 6 +- .../fabrication/gui/GatePlacerToolTab.java | 16 ++- .../fabrication/gui/ICEditorToolTab.java | 11 +- .../fabrication/gui/InteractToolTab.java | 6 +- .../fabrication/gui/SimpleUVTab.java | 10 +- .../fabrication/gui/WirePlacerToolTab.java | 11 +- .../gui/screen/ICWorkbenchCompileTab.java | 8 +- .../gui/screen/ICWorkbenchInfoTab.java | 34 +++-- .../gui/screen/ICWorkbenchScreen.java | 10 +- .../fabrication/init/FabricationUnlocal.java | 83 +++++++++++ .../item/BaseSiliconWaferItem.java | 8 +- .../fabrication/item/ICBlueprintItem.java | 24 ++-- .../lithography/YieldCalculator.java | 25 ++-- .../projectred_fabrication/lang/en_us.json | 11 -- 22 files changed, 452 insertions(+), 153 deletions(-) create mode 100644 fabrication/src/main/generated/assets/projectred_fabrication/lang/en_us.json create mode 100644 fabrication/src/main/java/mrtjp/projectred/fabrication/data/FabricationLanguageProvider.java create mode 100644 fabrication/src/main/java/mrtjp/projectred/fabrication/init/FabricationUnlocal.java delete mode 100644 fabrication/src/main/resources/assets/projectred_fabrication/lang/en_us.json diff --git a/fabrication/src/main/generated/assets/projectred_fabrication/lang/en_us.json b/fabrication/src/main/generated/assets/projectred_fabrication/lang/en_us.json new file mode 100644 index 000000000..152acff88 --- /dev/null +++ b/fabrication/src/main/generated/assets/projectred_fabrication/lang/en_us.json @@ -0,0 +1,75 @@ +{ + "block.projectred_fabrication.ic_workbench": "IC Workbench", + "block.projectred_fabrication.lithography_table": "Lithography Table", + "block.projectred_fabrication.packaging_table": "Packaging Table", + "block.projectred_fabrication.plotting_table": "Plotting Table", + "item.projectred_fabrication.blank_photomask": "Blank Photomask", + "item.projectred_fabrication.etched_silicon_wafer": "Etched Silicon Wafer", + "item.projectred_fabrication.fabricated_gate": "Fabricated Gate", + "item.projectred_fabrication.ic_blueprint": "IC Blueprint", + "item.projectred_fabrication.invalid_die": "Invalid Die", + "item.projectred_fabrication.photomask_set": "Photomask Set", + "item.projectred_fabrication.rough_silicon_wafer": "Rough Silicon Wafer", + "item.projectred_fabrication.valid_die": "Valid Die", + "itemGroup.projectred_fabrication": "Project Red: Fabrication", + "projectred-fabrication.dimensions.dies": "%d dies x %d dies", + "projectred-fabrication.dimensions.dies_total": "%d dies x %d dies (%d dies^2)", + "projectred-fabrication.dimensions.nm": "%d nm x %d nm", + "projectred-fabrication.dimensions.nm_total": "%d nm x %d nm (%d nm^2)", + "projectred-fabrication.dimensions.tiles": "%d tiles x %d tiles", + "projectred-fabrication.dimensions.tiles_total": "%d tiles x %d tiles (%d tiles^2)", + "projectred-fabrication.interact.io_mode.input": "Input", + "projectred-fabrication.interact.io_mode.output": "Output", + "projectred-fabrication.interact.side_disabled": "Side disabled", + "projectred-fabrication.interact.side_enabled": "Side enabled", + "projectred-fabrication.interact.toggle_colour": "Toggle colour", + "projectred-fabrication.interact.toggle_delay": "Toggle delay", + "projectred-fabrication.interact.toggle_io_mode": "Toggle IO mode", + "projectred-fabrication.interact.toggle_state": "Toggle state", + "projectred-fabrication.tab.compile": "Compile", + "projectred-fabrication.tab.edit": "Edit", + "projectred-fabrication.tab.info": "Info", + "projectred-fabrication.tab.problems": "Problems", + "projectred-fabrication.tab.stack": "Stack", + "projectred-fabrication.tab.tree": "Tree", + "projectred-fabrication.tilegroup.basic": "Basic", + "projectred-fabrication.tilegroup.bundled": "Bundled", + "projectred-fabrication.tilegroup.io": "IO", + "projectred-fabrication.tilegroup.memory": "Memory", + "projectred-fabrication.tilegroup.redwire": "Redwire", + "projectred-fabrication.tilegroup.timing": "Timing", + "projectred-fabrication.tiles.io_gate": "IO Gate", + "projectred-fabrication.tool.eraser": "Erase", + "projectred-fabrication.tool.gates": "Gates", + "projectred-fabrication.tool.interact": "Interact", + "projectred-fabrication.tool.wires": "Wires", + "projectred-fabrication.tooltip.bottom": "Bottom", + "projectred-fabrication.tooltip.bundled_input": "Bundled input", + "projectred-fabrication.tooltip.bundled_output": "Bundled output", + "projectred-fabrication.tooltip.corrupted_discard": "Corrupted NBT data, please discard", + "projectred-fabrication.tooltip.defect_chance": "Defect chance", + "projectred-fabrication.tooltip.io_none": "None", + "projectred-fabrication.tooltip.io_types": "IO types", + "projectred-fabrication.tooltip.left": "Left", + "projectred-fabrication.tooltip.name": "Name", + "projectred-fabrication.tooltip.right": "Right", + "projectred-fabrication.tooltip.size": "Size", + "projectred-fabrication.tooltip.tile_count": "Tile count", + "projectred-fabrication.tooltip.top": "Top", + "projectred-fabrication.ui.blueprint_dim": "Dimensions", + "projectred-fabrication.ui.blueprint_info": "Blueprint Info", + "projectred-fabrication.ui.blueprint_layers": "Layers", + "projectred-fabrication.ui.blueprint_name": "Name", + "projectred-fabrication.ui.blueprint_owner": "Owner", + "projectred-fabrication.ui.die_size": "Die size", + "projectred-fabrication.ui.dies_per_wafer": "Dies per wafer", + "projectred-fabrication.ui.lithography_pipeline": "Lithography pipeline", + "projectred-fabrication.ui.place_blueprint": "Place blueprint", + "projectred-fabrication.ui.process_node": "Process node", + "projectred-fabrication.ui.single_layer_yield": "Single layer yield", + "projectred-fabrication.ui.wafer_size": "Wafer size", + "projectred-fabrication.ui.wafer_type": "Wafer type", + "projectred-fabrication.ui.yield": "Yield", + "projectred-fabrication.ui.yield_calculator": "Yield Calculator", + "projectred-fabrication.unit.ticks": "%d ticks" +} \ No newline at end of file diff --git a/fabrication/src/main/java/mrtjp/projectred/fabrication/ProjectRedFabrication.java b/fabrication/src/main/java/mrtjp/projectred/fabrication/ProjectRedFabrication.java index e32e76bf2..7302f7059 100644 --- a/fabrication/src/main/java/mrtjp/projectred/fabrication/ProjectRedFabrication.java +++ b/fabrication/src/main/java/mrtjp/projectred/fabrication/ProjectRedFabrication.java @@ -4,6 +4,7 @@ import codechicken.multipart.api.MultipartType; import mrtjp.projectred.fabrication.data.FabricationBlockStateModelProvider; import mrtjp.projectred.fabrication.data.FabricationItemModelProvider; +import mrtjp.projectred.fabrication.data.FabricationLanguageProvider; import mrtjp.projectred.fabrication.data.FabricationRecipeProvider; import mrtjp.projectred.fabrication.init.*; import net.minecraft.data.DataGenerator; @@ -75,6 +76,7 @@ private void onGatherDataEvent(final GatherDataEvent event) { if (event.includeClient()) { generator.addProvider(new FabricationBlockStateModelProvider(generator, fileHelper)); generator.addProvider(new FabricationItemModelProvider(generator, fileHelper)); + generator.addProvider(new FabricationLanguageProvider(generator)); } if (event.includeServer()) { generator.addProvider(new FabricationRecipeProvider(generator)); diff --git a/fabrication/src/main/java/mrtjp/projectred/fabrication/data/FabricationLanguageProvider.java b/fabrication/src/main/java/mrtjp/projectred/fabrication/data/FabricationLanguageProvider.java new file mode 100644 index 000000000..32c1a2b6a --- /dev/null +++ b/fabrication/src/main/java/mrtjp/projectred/fabrication/data/FabricationLanguageProvider.java @@ -0,0 +1,106 @@ +package mrtjp.projectred.fabrication.data; + +import net.minecraft.data.DataGenerator; +import net.minecraftforge.common.data.LanguageProvider; + +import static mrtjp.projectred.fabrication.ProjectRedFabrication.MOD_ID; +import static mrtjp.projectred.fabrication.init.FabricationReferences.*; +import static mrtjp.projectred.fabrication.init.FabricationUnlocal.*; + +public class FabricationLanguageProvider extends LanguageProvider { + + public FabricationLanguageProvider(DataGenerator gen) { + super(gen, MOD_ID, "en_us"); + } + + @Override + protected void addTranslations() { + + // Creative tab + add("itemGroup." + MOD_ID, "Project Red: Fabrication"); + + add(IC_WORKBENCH_BLOCK, "IC Workbench"); + add(PLOTTING_TABLE_BLOCK, "Plotting Table"); + add(LITHOGRAPHY_TABLE_BLOCK, "Lithography Table"); + add(PACKAGING_TABLE_BLOCK, "Packaging Table"); + + add(IC_BLUEPRINT_ITEM, "IC Blueprint"); + add(BLANK_PHOTOMASK_ITEM, "Blank Photomask"); + add(PHOTOMASK_SET_ITEM, "Photomask Set"); + add(ROUGH_SILICON_WAFER_ITEM, "Rough Silicon Wafer"); + add(ETCHED_SILICON_WAFER_ITEM, "Etched Silicon Wafer"); + add(VALID_DIE_ITEM, "Valid Die"); + add(INVALID_DIE_ITEM, "Invalid Die"); + + add(FABRICATED_GATE_ITEM, "Fabricated Gate"); + + add(UL_TAB_INFO, "Info"); + add(UL_TAB_EDIT, "Edit"); + add(UL_TAB_COMPILE, "Compile"); + add(UL_TAB_STACK, "Stack"); + add(UL_TAB_TREE, "Tree"); + add(UL_TAB_PROBLEMS, "Problems"); + + add(UL_ERASER_TOOL, "Erase"); + add(UL_INTERACT_TOOL, "Interact"); + add(UL_WIRE_TOOL, "Wires"); + add(UL_GATE_TOOL, "Gates"); + + add(UL_TOGGLE_STATE, "Toggle state"); + add(UL_TOGGLE_IO_MODE, "Toggle IO mode"); + add(UL_IO_MODE_INPUT, "Input"); + add(UL_IO_MODE_OUTPUT, "Output"); + add(UL_TOGGLE_COLOUR, "Toggle colour"); + add(UL_TOGGLE_DELAY, "Toggle delay"); + add(UL_SIDE_ENABLED, "Side enabled"); + add(UL_SIDE_DISABLED, "Side disabled"); + add(UL_PLACE_BLUEPRINT, "Place blueprint"); + + add(UL_BLUEPRINT_INFO, "Blueprint Info"); + add(UL_BLUEPRINT_NAME, "Name"); + add(UL_BLUEPRINT_OWNER, "Owner"); + add(UL_BLUEPRINT_DIM, "Dimensions"); + add(UL_BLUEPRINT_LAYERS, "Layers"); + + add(UL_YIELD_CALCULATOR, "Yield Calculator"); + add(UL_LITHOGRAPHY_PIPELINE, "Lithography pipeline"); + add(UL_PROCESS_NODE, "Process node"); + add(UL_WAFER_TYPE, "Wafer type"); + add(UL_DIE_SIZE, "Die size"); + add(UL_WAFER_SIZE, "Wafer size"); + add(UL_DIES_PER_WAFER, "Dies per wafer"); + add(UL_SINGLE_LAYER_YIELD, "Single layer yield"); + add(UL_YIELD, "Yield"); + + add(UL_SIZE, "Size"); + add(UL_DEFECT_CHANCE, "Defect chance"); + add(UL_CORRUPTED_DISCARD, "Corrupted NBT data, please discard"); + add(UL_NAME, "Name"); + add(UL_TILE_COUNT, "Tile count"); + add(UL_IO_TYPES, "IO types"); + add(UL_TOP, "Top"); + add(UL_RIGHT, "Right"); + add(UL_BOTTOM, "Bottom"); + add(UL_LEFT, "Left"); + add(UL_BUNDLED_INPUT, "Bundled input"); + add(UL_BUNDLED_OUTPUT, "Bundled output"); + add(UL_IO_NONE, "None"); + + add(UL_IO_GATE_TILE, "IO Gate"); + + add(UL_TILEGROUP_REDWIRE, "Redwire"); + add(UL_TILEGROUP_BUNDLED, "Bundled"); + add(UL_TILEGROUP_IO, "IO"); + add(UL_TILEGROUP_BASIC, "Basic"); + add(UL_TILEGROUP_TIMING, "Timing"); + add(UL_TILEGROUP_MEMORY, "Memory"); + + add(UL_UNIT_TICKS, "%d ticks"); + add(UL_DIMENSIONS_NM, "%d nm x %d nm"); + add(UL_DIMENSIONS_TILES, "%d tiles x %d tiles"); + add(UL_DIMENSIONS_DIES, "%d dies x %d dies"); + add(UL_DIMENSIONS_NM_TOTAL, "%d nm x %d nm (%d nm^2)"); + add(UL_DIMENSIONS_TILES_TOTAL, "%d tiles x %d tiles (%d tiles^2)"); + add(UL_DIMENSIONS_DIES_TOTAL, "%d dies x %d dies (%d dies^2)"); + } +} diff --git a/fabrication/src/main/java/mrtjp/projectred/fabrication/engine/BaseTile.java b/fabrication/src/main/java/mrtjp/projectred/fabrication/engine/BaseTile.java index 3a0a00172..480be3d9f 100644 --- a/fabrication/src/main/java/mrtjp/projectred/fabrication/engine/BaseTile.java +++ b/fabrication/src/main/java/mrtjp/projectred/fabrication/engine/BaseTile.java @@ -10,7 +10,7 @@ import mrtjp.projectred.fabrication.editor.ICWorkbenchEditor; import net.minecraft.nbt.CompoundTag; import net.minecraft.network.chat.Component; -import net.minecraft.network.chat.TextComponent; +import net.minecraft.network.chat.TranslatableComponent; import net.minecraftforge.api.distmarker.Dist; import net.minecraftforge.api.distmarker.OnlyIn; @@ -95,7 +95,7 @@ public void onInteractionZoneActivated(int i) { } @OnlyIn(Dist.CLIENT) public void buildToolTip(List toolTip) { - toolTip.add(new TextComponent(tileType.getName())); + toolTip.add(new TranslatableComponent(tileType.getUnlocalizedName())); } @OnlyIn(Dist.CLIENT) diff --git a/fabrication/src/main/java/mrtjp/projectred/fabrication/engine/ICTileType.java b/fabrication/src/main/java/mrtjp/projectred/fabrication/engine/ICTileType.java index 31b16c304..391446ac7 100644 --- a/fabrication/src/main/java/mrtjp/projectred/fabrication/engine/ICTileType.java +++ b/fabrication/src/main/java/mrtjp/projectred/fabrication/engine/ICTileType.java @@ -4,67 +4,72 @@ import mrtjp.projectred.fabrication.engine.wires.BundledWireTile; import mrtjp.projectred.fabrication.engine.wires.InsulatedWireTile; import mrtjp.projectred.fabrication.engine.wires.RedAlloyWireTile; +import mrtjp.projectred.integration.GateType; +import mrtjp.projectred.transmission.WireType; import java.util.function.Supplier; import static mrtjp.projectred.fabrication.engine.ICTileTypeOffsets.*; +import static mrtjp.projectred.fabrication.init.FabricationUnlocal.UL_IO_GATE_TILE; +import static mrtjp.projectred.integration.GateType.*; +import static mrtjp.projectred.transmission.WireType.*; public enum ICTileType { //@formatter:off - IO_GATE(ID_OFFSET_IOGATE, "IO Gate", IOGateTile::new), - - OR_GATE (ID_OFFSET_GATE, "OR Gate", ORGateTile::new), - NOR_GATE (ID_OFFSET_GATE + 1, "NOR Gate", NORGateTile::new), - NOT_GATE (ID_OFFSET_GATE + 2, "NOT Gate", NOTGateTile::new), - AND_GATE (ID_OFFSET_GATE + 3, "AND Gate", ANDGateTile::new), - NAND_GATE (ID_OFFSET_GATE + 4, "NAND Gate", NANDGateTile::new), - XOR_GATE (ID_OFFSET_GATE + 5, "XOR Gate", XORGateTile::new), - XNOR_GATE (ID_OFFSET_GATE + 6, "XOR Gate", XNORGateTile::new), - BUFFER_GATE (ID_OFFSET_GATE + 7, "Buffer Gate", BufferGateTile::new), - MULTIPLEXER_GATE (ID_OFFSET_GATE + 8, "Multiplexer Gate", MultiplexerGateTile::new), - PULSE_GATE (ID_OFFSET_GATE + 9, "Pulse Gate", PulseGateTile::new), - REPEATER_GATE (ID_OFFSET_GATE + 10, "Repeater Gate", RepeaterGateTile::new), - RANDOMIZER_GATE (ID_OFFSET_GATE + 11, "Randomizer Gate", RandomizerGateTile::new), - SR_LATCH_GATE (ID_OFFSET_GATE + 12, "SR Latch Gate", SRLatchGateTile::new), - TOGGLE_LATCH_GATE (ID_OFFSET_GATE + 13, "Toggle Latch Gate", ToggleLatchGateTile::new), - TRANSPARENT_LATCH_GATE(ID_OFFSET_GATE + 14, "Transparent Latch Gate", TransparentLatchGateTile::new), - - RED_ALLOY_WIRE (ID_OFFSET_WIRE_RED, "Red Alloy Wire", RedAlloyWireTile::new), - INSULATED_WHITE_WIRE (ID_OFFSET_WIRE_RED + 1, "White Insulated Wire", () -> new InsulatedWireTile(0)), - INSULATED_ORANGE_WIRE (ID_OFFSET_WIRE_RED + 2, "Orange Insulated Wire", () -> new InsulatedWireTile(1)), - INSULATED_MAGENTA_WIRE (ID_OFFSET_WIRE_RED + 3, "Magenta Insulated Wire", () -> new InsulatedWireTile(2)), - INSULATED_LIGHT_BLUE_WIRE(ID_OFFSET_WIRE_RED + 4, "Light Blue Insulated Wire", () -> new InsulatedWireTile(3)), - INSULATED_YELLOW_WIRE (ID_OFFSET_WIRE_RED + 5, "Yellow Insulated Wire", () -> new InsulatedWireTile(4)), - INSULATED_LIME_WIRE (ID_OFFSET_WIRE_RED + 6, "Lime Insulated Wire", () -> new InsulatedWireTile(5)), - INSULATED_PINK_WIRE (ID_OFFSET_WIRE_RED + 7, "Pink Insulated Wire", () -> new InsulatedWireTile(6)), - INSULATED_GRAY_WIRE (ID_OFFSET_WIRE_RED + 8, "Gray Insulated Wire", () -> new InsulatedWireTile(7)), - INSULATED_LIGHT_GRAY_WIRE(ID_OFFSET_WIRE_RED + 9, "Light Gray Insulated Wire", () -> new InsulatedWireTile(8)), - INSULATED_CYAN_WIRE (ID_OFFSET_WIRE_RED + 10, "Cyan Insulated Wire", () -> new InsulatedWireTile(9)), - INSULATED_PURPLE_WIRE (ID_OFFSET_WIRE_RED + 11, "Purple Insulated Wire", () -> new InsulatedWireTile(10)), - INSULATED_BLUE_WIRE (ID_OFFSET_WIRE_RED + 12, "Blue Insulated Wire", () -> new InsulatedWireTile(11)), - INSULATED_BROWN_WIRE (ID_OFFSET_WIRE_RED + 13, "Brown Insulated Wire", () -> new InsulatedWireTile(12)), - INSULATED_GREEN_WIRE (ID_OFFSET_WIRE_RED + 14, "Green Insulated Wire", () -> new InsulatedWireTile(13)), - INSULATED_RED_WIRE (ID_OFFSET_WIRE_RED + 15, "Red Insulated Wire", () -> new InsulatedWireTile(14)), - INSULATED_BLACK_WIRE (ID_OFFSET_WIRE_RED + 16, "Black Insulated Wire", () -> new InsulatedWireTile(15)), - - BUNDLED_NEUTRAL_WIRE (ID_OFFSET_WIRE_BUNDLED, "Bundled Wire", () -> new BundledWireTile(-1)), - BUNDLED_WHITE_WIRE (ID_OFFSET_WIRE_BUNDLED + 1, "White Bundled Wire", () -> new BundledWireTile(0)), - BUNDLED_ORANGE_WIRE (ID_OFFSET_WIRE_BUNDLED + 2, "Orange Bundled Wire", () -> new BundledWireTile(1)), - BUNDLED_MAGENTA_WIRE (ID_OFFSET_WIRE_BUNDLED + 3, "Magenta Bundled Wire", () -> new BundledWireTile(2)), - BUNDLED_LIGHT_BLUE_WIRE(ID_OFFSET_WIRE_BUNDLED + 4, "Light Blue Bundled Wire", () -> new BundledWireTile(3)), - BUNDLED_YELLOW_WIRE (ID_OFFSET_WIRE_BUNDLED + 5, "Yellow Bundled Wire", () -> new BundledWireTile(4)), - BUNDLED_LIME_WIRE (ID_OFFSET_WIRE_BUNDLED + 6, "Lime Bundled Wire", () -> new BundledWireTile(5)), - BUNDLED_PINK_WIRE (ID_OFFSET_WIRE_BUNDLED + 7, "Pink Bundled Wire", () -> new BundledWireTile(6)), - BUNDLED_GRAY_WIRE (ID_OFFSET_WIRE_BUNDLED + 8, "Gray Bundled Wire", () -> new BundledWireTile(7)), - BUNDLED_LIGHT_GRAY_WIRE(ID_OFFSET_WIRE_BUNDLED + 9, "Light Gray Bundled Wire", () -> new BundledWireTile(8)), - BUNDLED_CYAN_WIRE (ID_OFFSET_WIRE_BUNDLED + 10, "Cyan Bundled Wire", () -> new BundledWireTile(9)), - BUNDLED_PURPLE_WIRE (ID_OFFSET_WIRE_BUNDLED + 11, "Purple Bundled Wire", () -> new BundledWireTile(10)), - BUNDLED_BLUE_WIRE (ID_OFFSET_WIRE_BUNDLED + 12, "Blue Bundled Wire", () -> new BundledWireTile(11)), - BUNDLED_BROWN_WIRE (ID_OFFSET_WIRE_BUNDLED + 13, "Brown Bundled Wire", () -> new BundledWireTile(12)), - BUNDLED_GREEN_WIRE (ID_OFFSET_WIRE_BUNDLED + 14, "Green Bundled Wire", () -> new BundledWireTile(13)), - BUNDLED_RED_WIRE (ID_OFFSET_WIRE_BUNDLED + 15, "Red Bundled Wire", () -> new BundledWireTile(14)), - BUNDLED_BLACK_WIRE (ID_OFFSET_WIRE_BUNDLED + 16, "Black Bundled Wire", () -> new BundledWireTile(15)); + IO_GATE(ID_OFFSET_IOGATE, UL_IO_GATE_TILE, IOGateTile::new), + + OR_GATE (ID_OFFSET_GATE, OR, ORGateTile::new), + NOR_GATE (ID_OFFSET_GATE + 1, NOR, NORGateTile::new), + NOT_GATE (ID_OFFSET_GATE + 2, NOT, NOTGateTile::new), + AND_GATE (ID_OFFSET_GATE + 3, AND, ANDGateTile::new), + NAND_GATE (ID_OFFSET_GATE + 4, NAND, NANDGateTile::new), + XOR_GATE (ID_OFFSET_GATE + 5, XOR, XORGateTile::new), + XNOR_GATE (ID_OFFSET_GATE + 6, XNOR, XNORGateTile::new), + BUFFER_GATE (ID_OFFSET_GATE + 7, BUFFER, BufferGateTile::new), + MULTIPLEXER_GATE (ID_OFFSET_GATE + 8, MULTIPLEXER, MultiplexerGateTile::new), + PULSE_GATE (ID_OFFSET_GATE + 9, PULSE, PulseGateTile::new), + REPEATER_GATE (ID_OFFSET_GATE + 10, REPEATER, RepeaterGateTile::new), + RANDOMIZER_GATE (ID_OFFSET_GATE + 11, RANDOMIZER, RandomizerGateTile::new), + SR_LATCH_GATE (ID_OFFSET_GATE + 12, SR_LATCH, SRLatchGateTile::new), + TOGGLE_LATCH_GATE (ID_OFFSET_GATE + 13, TOGGLE_LATCH, ToggleLatchGateTile::new), + TRANSPARENT_LATCH_GATE(ID_OFFSET_GATE + 14, TRANSPARENT_LATCH, TransparentLatchGateTile::new), + + RED_ALLOY_WIRE (ID_OFFSET_WIRE_RED, RED_ALLOY, RedAlloyWireTile::new), + INSULATED_WHITE_WIRE (ID_OFFSET_WIRE_RED + 1, INSULATED_WHITE, () -> new InsulatedWireTile(0)), + INSULATED_ORANGE_WIRE (ID_OFFSET_WIRE_RED + 2, INSULATED_ORANGE, () -> new InsulatedWireTile(1)), + INSULATED_MAGENTA_WIRE (ID_OFFSET_WIRE_RED + 3, INSULATED_MAGENTA, () -> new InsulatedWireTile(2)), + INSULATED_LIGHT_BLUE_WIRE(ID_OFFSET_WIRE_RED + 4, INSULATED_BLUE, () -> new InsulatedWireTile(3)), + INSULATED_YELLOW_WIRE (ID_OFFSET_WIRE_RED + 5, INSULATED_YELLOW, () -> new InsulatedWireTile(4)), + INSULATED_LIME_WIRE (ID_OFFSET_WIRE_RED + 6, INSULATED_LIME, () -> new InsulatedWireTile(5)), + INSULATED_PINK_WIRE (ID_OFFSET_WIRE_RED + 7, INSULATED_PINK, () -> new InsulatedWireTile(6)), + INSULATED_GRAY_WIRE (ID_OFFSET_WIRE_RED + 8, INSULATED_GRAY, () -> new InsulatedWireTile(7)), + INSULATED_LIGHT_GRAY_WIRE(ID_OFFSET_WIRE_RED + 9, INSULATED_LIGHT_GRAY, () -> new InsulatedWireTile(8)), + INSULATED_CYAN_WIRE (ID_OFFSET_WIRE_RED + 10, INSULATED_CYAN, () -> new InsulatedWireTile(9)), + INSULATED_PURPLE_WIRE (ID_OFFSET_WIRE_RED + 11, INSULATED_PURPLE, () -> new InsulatedWireTile(10)), + INSULATED_BLUE_WIRE (ID_OFFSET_WIRE_RED + 12, INSULATED_BLUE, () -> new InsulatedWireTile(11)), + INSULATED_BROWN_WIRE (ID_OFFSET_WIRE_RED + 13, INSULATED_BROWN, () -> new InsulatedWireTile(12)), + INSULATED_GREEN_WIRE (ID_OFFSET_WIRE_RED + 14, INSULATED_GREEN, () -> new InsulatedWireTile(13)), + INSULATED_RED_WIRE (ID_OFFSET_WIRE_RED + 15, INSULATED_RED, () -> new InsulatedWireTile(14)), + INSULATED_BLACK_WIRE (ID_OFFSET_WIRE_RED + 16, INSULATED_BLACK, () -> new InsulatedWireTile(15)), + + BUNDLED_NEUTRAL_WIRE (ID_OFFSET_WIRE_BUNDLED, BUNDLED_NEUTRAL, () -> new BundledWireTile(-1)), + BUNDLED_WHITE_WIRE (ID_OFFSET_WIRE_BUNDLED + 1, BUNDLED_WHITE, () -> new BundledWireTile(0)), + BUNDLED_ORANGE_WIRE (ID_OFFSET_WIRE_BUNDLED + 2, BUNDLED_ORANGE, () -> new BundledWireTile(1)), + BUNDLED_MAGENTA_WIRE (ID_OFFSET_WIRE_BUNDLED + 3, BUNDLED_MAGENTA, () -> new BundledWireTile(2)), + BUNDLED_LIGHT_BLUE_WIRE(ID_OFFSET_WIRE_BUNDLED + 4, BUNDLED_LIGHT_BLUE, () -> new BundledWireTile(3)), + BUNDLED_YELLOW_WIRE (ID_OFFSET_WIRE_BUNDLED + 5, BUNDLED_YELLOW, () -> new BundledWireTile(4)), + BUNDLED_LIME_WIRE (ID_OFFSET_WIRE_BUNDLED + 6, BUNDLED_LIME, () -> new BundledWireTile(5)), + BUNDLED_PINK_WIRE (ID_OFFSET_WIRE_BUNDLED + 7, BUNDLED_PINK, () -> new BundledWireTile(6)), + BUNDLED_GRAY_WIRE (ID_OFFSET_WIRE_BUNDLED + 8, BUNDLED_GRAY, () -> new BundledWireTile(7)), + BUNDLED_LIGHT_GRAY_WIRE(ID_OFFSET_WIRE_BUNDLED + 9, BUNDLED_LIGHT_GRAY, () -> new BundledWireTile(8)), + BUNDLED_CYAN_WIRE (ID_OFFSET_WIRE_BUNDLED + 10, BUNDLED_CYAN, () -> new BundledWireTile(9)), + BUNDLED_PURPLE_WIRE (ID_OFFSET_WIRE_BUNDLED + 11, BUNDLED_PURPLE, () -> new BundledWireTile(10)), + BUNDLED_BLUE_WIRE (ID_OFFSET_WIRE_BUNDLED + 12, BUNDLED_BLUE, () -> new BundledWireTile(11)), + BUNDLED_BROWN_WIRE (ID_OFFSET_WIRE_BUNDLED + 13, BUNDLED_BROWN, () -> new BundledWireTile(12)), + BUNDLED_GREEN_WIRE (ID_OFFSET_WIRE_BUNDLED + 14, BUNDLED_GREEN, () -> new BundledWireTile(13)), + BUNDLED_RED_WIRE (ID_OFFSET_WIRE_BUNDLED + 15, BUNDLED_RED, () -> new BundledWireTile(14)), + BUNDLED_BLACK_WIRE (ID_OFFSET_WIRE_BUNDLED + 16, BUNDLED_BLACK, () -> new BundledWireTile(15)); //@formatter:on private static final ICTileType[] VALUES_BY_ID; @@ -77,17 +82,25 @@ public enum ICTileType { } private final int id; - private final String name; + private final String unlocalizedName; private final Supplier factory; - ICTileType(int id, String name, Supplier factory) { + ICTileType(int id, String unlocalizedName, Supplier factory) { this.id = id; - this.name = name; //TODO localize + this.unlocalizedName = unlocalizedName; this.factory = factory; } - public String getName() { - return name; + ICTileType(int id, GateType gateType, Supplier factory) { + this(id, gateType.getItem().getDescriptionId(), factory); + } + + ICTileType(int id, WireType wireType, Supplier factory) { + this(id, wireType.getItem().getDescriptionId(), factory); + } + + public String getUnlocalizedName() { + return unlocalizedName; } public BaseTile create() { diff --git a/fabrication/src/main/java/mrtjp/projectred/fabrication/engine/gates/IOGateTile.java b/fabrication/src/main/java/mrtjp/projectred/fabrication/engine/gates/IOGateTile.java index 4b78c5375..01ac2a4fd 100644 --- a/fabrication/src/main/java/mrtjp/projectred/fabrication/engine/gates/IOGateTile.java +++ b/fabrication/src/main/java/mrtjp/projectred/fabrication/engine/gates/IOGateTile.java @@ -27,6 +27,7 @@ import static mrtjp.projectred.fabrication.ProjectRedFabrication.LOGGER; import static mrtjp.projectred.fabrication.engine.PRFabricationEngine.*; +import static mrtjp.projectred.fabrication.init.FabricationUnlocal.*; public class IOGateTile extends RedstoneGateTile implements IIOConnectionTile { @@ -132,17 +133,17 @@ public List getInteractionZones() { @OnlyIn(Dist.CLIENT) public void buildInteractionToolTip(List toolTip, int i) { - switch (i) { //TODO localize + switch (i) { case 0: - toolTip.add(new TextComponent("Toggle state")); + toolTip.add(new TranslatableComponent(UL_TOGGLE_STATE)); toolTip.add(new TextComponent(((getState() & 0x44) != 0 ? "0x1" : "0x0")).withStyle(ChatFormatting.GRAY)); break; case 1: - toolTip.add(new TextComponent("Toggle IO mode")); - toolTip.add(new TextComponent((isInputIOMode() ? "input" : "output")).withStyle(ChatFormatting.GRAY)); + toolTip.add(new TranslatableComponent(UL_TOGGLE_IO_MODE)); + toolTip.add(new TranslatableComponent((isInputIOMode() ? UL_IO_MODE_INPUT : UL_IO_MODE_OUTPUT)).withStyle(ChatFormatting.GRAY)); break; case 2: - toolTip.add(new TextComponent("Toggle colour")); + toolTip.add(new TranslatableComponent(UL_TOGGLE_COLOUR)); toolTip.add(new TranslatableComponent(EnumColour.values()[colour & 0xFF].getUnlocalizedName()).withStyle(ChatFormatting.GRAY)); break; default: diff --git a/fabrication/src/main/java/mrtjp/projectred/fabrication/engine/gates/RepeaterGateTile.java b/fabrication/src/main/java/mrtjp/projectred/fabrication/engine/gates/RepeaterGateTile.java index 4064bacf5..9a63c48bb 100644 --- a/fabrication/src/main/java/mrtjp/projectred/fabrication/engine/gates/RepeaterGateTile.java +++ b/fabrication/src/main/java/mrtjp/projectred/fabrication/engine/gates/RepeaterGateTile.java @@ -8,7 +8,7 @@ import mrtjp.fengine.simulate.ICSimulation; import net.minecraft.ChatFormatting; import net.minecraft.network.chat.Component; -import net.minecraft.network.chat.TextComponent; +import net.minecraft.network.chat.TranslatableComponent; import net.minecraftforge.api.distmarker.Dist; import net.minecraftforge.api.distmarker.OnlyIn; @@ -18,6 +18,8 @@ import static mrtjp.projectred.fabrication.ProjectRedFabrication.LOGGER; import static mrtjp.projectred.fabrication.engine.PRFabricationEngine.*; +import static mrtjp.projectred.fabrication.init.FabricationUnlocal.UL_TOGGLE_DELAY; +import static mrtjp.projectred.fabrication.init.FabricationUnlocal.UL_UNIT_TICKS; public class RepeaterGateTile extends TimedStateGateTile { @@ -42,8 +44,8 @@ public List getInteractionZones() { @OnlyIn(Dist.CLIENT) public void buildInteractionToolTip(List toolTip, int i) { - toolTip.add(new TextComponent("Toggle delay")); - toolTip.add(new TextComponent(DELAYS[getShape()] + " ticks").withStyle(ChatFormatting.GRAY)); //TODO localize + toolTip.add(new TranslatableComponent(UL_TOGGLE_DELAY)); + toolTip.add(new TranslatableComponent(UL_UNIT_TICKS, DELAYS[getShape()]).withStyle(ChatFormatting.GRAY)); } @Override diff --git a/fabrication/src/main/java/mrtjp/projectred/fabrication/engine/gates/SimpleGateTile.java b/fabrication/src/main/java/mrtjp/projectred/fabrication/engine/gates/SimpleGateTile.java index 1d2ef294f..66f8d13fc 100644 --- a/fabrication/src/main/java/mrtjp/projectred/fabrication/engine/gates/SimpleGateTile.java +++ b/fabrication/src/main/java/mrtjp/projectred/fabrication/engine/gates/SimpleGateTile.java @@ -4,7 +4,7 @@ import mrtjp.fengine.simulate.ICGate; import net.minecraft.nbt.CompoundTag; import net.minecraft.network.chat.Component; -import net.minecraft.network.chat.TextComponent; +import net.minecraft.network.chat.TranslatableComponent; import net.minecraftforge.api.distmarker.Dist; import net.minecraftforge.api.distmarker.OnlyIn; @@ -12,6 +12,9 @@ import java.util.LinkedList; import java.util.List; +import static mrtjp.projectred.fabrication.init.FabricationUnlocal.UL_SIDE_DISABLED; +import static mrtjp.projectred.fabrication.init.FabricationUnlocal.UL_SIDE_ENABLED; + public abstract class SimpleGateTile extends SidedRedstoneGateTile { public static int[] DEAD_SIDES_MASKS = new int[] { 1, 2, 3, 0, 5, 6, 3 }; @@ -75,7 +78,7 @@ public List getInteractionZones() { public void buildInteractionToolTip(List toolTip, int i) { boolean isEnabled = (getShape() & (1 << (i-1))) == 0; - toolTip.add(new TextComponent("side " + (isEnabled ? "enabled" : "disabled"))); // TODO localize + toolTip.add(new TranslatableComponent(isEnabled ? UL_SIDE_ENABLED : UL_SIDE_DISABLED)); } @Override diff --git a/fabrication/src/main/java/mrtjp/projectred/fabrication/gui/EraserToolTab.java b/fabrication/src/main/java/mrtjp/projectred/fabrication/gui/EraserToolTab.java index 3cace497b..9b2a37389 100644 --- a/fabrication/src/main/java/mrtjp/projectred/fabrication/gui/EraserToolTab.java +++ b/fabrication/src/main/java/mrtjp/projectred/fabrication/gui/EraserToolTab.java @@ -7,10 +7,12 @@ import mrtjp.projectred.lib.Point; import net.minecraft.client.gui.GuiComponent; import net.minecraft.network.chat.Component; -import net.minecraft.network.chat.TextComponent; +import net.minecraft.network.chat.TranslatableComponent; import java.util.List; +import static mrtjp.projectred.fabrication.init.FabricationUnlocal.UL_ERASER_TOOL; + public class EraserToolTab extends ICEditorToolTab { private final EraseTool tool; @@ -36,7 +38,7 @@ public void renderIcon(PoseStack stack, Point mouse, float partialFrame) { @Override public void buildTooltip(List tooltip) { - tooltip.add(new TextComponent("Eraser")); //TODO Localize + tooltip.add(new TranslatableComponent(UL_ERASER_TOOL)); } @Override diff --git a/fabrication/src/main/java/mrtjp/projectred/fabrication/gui/GatePlacerToolTab.java b/fabrication/src/main/java/mrtjp/projectred/fabrication/gui/GatePlacerToolTab.java index 1114ca85f..552f91b65 100644 --- a/fabrication/src/main/java/mrtjp/projectred/fabrication/gui/GatePlacerToolTab.java +++ b/fabrication/src/main/java/mrtjp/projectred/fabrication/gui/GatePlacerToolTab.java @@ -19,10 +19,12 @@ import net.minecraft.client.renderer.RenderType; import net.minecraft.client.renderer.texture.OverlayTexture; import net.minecraft.network.chat.Component; -import net.minecraft.network.chat.TextComponent; +import net.minecraft.network.chat.TranslatableComponent; import java.util.List; +import static mrtjp.projectred.fabrication.init.FabricationUnlocal.*; + public class GatePlacerToolTab extends ICEditorToolTab { private final GatePlacerTool tool; @@ -35,7 +37,7 @@ public GatePlacerToolTab(ICEditorToolManager manager, GatePlacerTool tool) { private void addGateButton(ICGateTileType type) { ButtonController buttonController = new ButtonController() { - @Override public void getTooltip(List tooltip) { tooltip.add(new TextComponent(type.toString())); } + @Override public void getTooltip(List tooltip) { tooltip.add(new TranslatableComponent(type.tileType.getUnlocalizedName())); } @Override public void onClick() { tool.setGateType(type); } @Override public boolean isSelected() { return tool.getGateType() == type; } @@ -67,10 +69,10 @@ public void renderIcon(PoseStack stack, Point absPos, float partialFrame) { private void construct() { - addGroup("IO"); + addGroup(UL_TILEGROUP_IO); addGateButton(ICGateTileType.IO); - addGroup("Basic"); + addGroup(UL_TILEGROUP_BASIC); addGateButton(ICGateTileType.OR); addGateButton(ICGateTileType.NOR); addGateButton(ICGateTileType.NOT); @@ -81,12 +83,12 @@ private void construct() { addGateButton(ICGateTileType.BUFFER); addGateButton(ICGateTileType.MULTIPLEXER); - addGroup("Timing"); + addGroup(UL_TILEGROUP_TIMING); addGateButton(ICGateTileType.PULSE); addGateButton(ICGateTileType.REPEATER); addGateButton(ICGateTileType.RANDOMIZER); - addGroup("Latches"); + addGroup(UL_TILEGROUP_MEMORY); addGateButton(ICGateTileType.SR_LATCH); addGateButton(ICGateTileType.TOGGLE_LATCH); addGateButton(ICGateTileType.TRANSPARENT_LATCH); @@ -103,7 +105,7 @@ public void renderIcon(PoseStack stack, Point mouse, float partialFrame) { @Override public void buildTooltip(List tooltip) { - tooltip.add(new TextComponent("Logic")); //TODO Localize + tooltip.add(new TranslatableComponent(UL_GATE_TOOL)); } }; } diff --git a/fabrication/src/main/java/mrtjp/projectred/fabrication/gui/ICEditorToolTab.java b/fabrication/src/main/java/mrtjp/projectred/fabrication/gui/ICEditorToolTab.java index d884e2413..9d20ebfc4 100644 --- a/fabrication/src/main/java/mrtjp/projectred/fabrication/gui/ICEditorToolTab.java +++ b/fabrication/src/main/java/mrtjp/projectred/fabrication/gui/ICEditorToolTab.java @@ -11,6 +11,7 @@ import net.minecraft.client.resources.sounds.SimpleSoundInstance; import net.minecraft.network.chat.Component; import net.minecraft.network.chat.TextComponent; +import net.minecraft.network.chat.TranslatableComponent; import net.minecraft.sounds.SoundEvents; import java.util.LinkedList; @@ -66,7 +67,11 @@ private void setAndIncrGridPos(AbstractGuiNode node, int cellWidth) { } } - protected void addGroup(String groupName) { + protected void addGroup(String unlocal) { + addGroup(new TranslatableComponent(unlocal)); + } + + protected void addGroup(Component groupName) { GroupHeaderNode header = new GroupHeaderNode(groupName); setAndIncrGridPos(header, 4); @@ -136,9 +141,9 @@ interface ButtonController { private static class GroupHeaderNode extends AbstractGuiNode { - private final String title; + private final Component title; - public GroupHeaderNode(String title) { + public GroupHeaderNode(Component title) { this.title = title; this.setSize(GROUP_WIDTH, GROUP_HEIGHT); } diff --git a/fabrication/src/main/java/mrtjp/projectred/fabrication/gui/InteractToolTab.java b/fabrication/src/main/java/mrtjp/projectred/fabrication/gui/InteractToolTab.java index 0400509be..ea44e4f12 100644 --- a/fabrication/src/main/java/mrtjp/projectred/fabrication/gui/InteractToolTab.java +++ b/fabrication/src/main/java/mrtjp/projectred/fabrication/gui/InteractToolTab.java @@ -7,10 +7,12 @@ import mrtjp.projectred.lib.Point; import net.minecraft.client.gui.GuiComponent; import net.minecraft.network.chat.Component; -import net.minecraft.network.chat.TextComponent; +import net.minecraft.network.chat.TranslatableComponent; import java.util.List; +import static mrtjp.projectred.fabrication.init.FabricationUnlocal.UL_INTERACT_TOOL; + public class InteractToolTab extends ICEditorToolTab { private final InteractTool tool; @@ -36,7 +38,7 @@ public void renderIcon(PoseStack stack, Point mouse, float partialFrame) { @Override public void buildTooltip(List tooltip) { - tooltip.add(new TextComponent("Interact")); //TODO Localize + tooltip.add(new TranslatableComponent(UL_INTERACT_TOOL)); } @Override diff --git a/fabrication/src/main/java/mrtjp/projectred/fabrication/gui/SimpleUVTab.java b/fabrication/src/main/java/mrtjp/projectred/fabrication/gui/SimpleUVTab.java index 260115f25..137dae5c6 100644 --- a/fabrication/src/main/java/mrtjp/projectred/fabrication/gui/SimpleUVTab.java +++ b/fabrication/src/main/java/mrtjp/projectred/fabrication/gui/SimpleUVTab.java @@ -7,7 +7,7 @@ import mrtjp.projectred.redui.AbstractGuiNode; import net.minecraft.client.gui.GuiComponent; import net.minecraft.network.chat.Component; -import net.minecraft.network.chat.TextComponent; +import net.minecraft.network.chat.TranslatableComponent; import net.minecraft.resources.ResourceLocation; import java.util.List; @@ -15,16 +15,16 @@ public class SimpleUVTab implements TabControllerNode.IToolbarTab { private final AbstractGuiNode tabBodyNode; - private final String tabName; + private final Component tabName; private final TabButtonNode.TabSide tabSide; private final int u; private final int v; private final ResourceLocation texture; - public SimpleUVTab(AbstractGuiNode tabBodyNode, String tabName, TabButtonNode.TabSide side, int u, int v, ResourceLocation texture) { //TODO Icon width/height? + public SimpleUVTab(AbstractGuiNode tabBodyNode, String unlocalTabName, TabButtonNode.TabSide side, int u, int v, ResourceLocation texture) { //TODO Icon width/height? this.tabBodyNode = tabBodyNode; - this.tabName = tabName; + this.tabName = new TranslatableComponent(unlocalTabName); this.tabSide = side; this.u = u; this.v = v; @@ -65,7 +65,7 @@ public void renderIcon(PoseStack stack, Point mouse, float partialFrame) { @Override public void buildTooltip(List tooltip) { - tooltip.add(new TextComponent(tabName)); + tooltip.add(tabName); } }; } diff --git a/fabrication/src/main/java/mrtjp/projectred/fabrication/gui/WirePlacerToolTab.java b/fabrication/src/main/java/mrtjp/projectred/fabrication/gui/WirePlacerToolTab.java index f79cd4ae1..b4df61546 100644 --- a/fabrication/src/main/java/mrtjp/projectred/fabrication/gui/WirePlacerToolTab.java +++ b/fabrication/src/main/java/mrtjp/projectred/fabrication/gui/WirePlacerToolTab.java @@ -20,9 +20,12 @@ import net.minecraft.client.renderer.texture.OverlayTexture; import net.minecraft.network.chat.Component; import net.minecraft.network.chat.TextComponent; +import net.minecraft.network.chat.TranslatableComponent; import java.util.List; +import static mrtjp.projectred.fabrication.init.FabricationUnlocal.*; + public class WirePlacerToolTab extends ICEditorToolTab { private final WirePlacerTool tool; @@ -35,7 +38,7 @@ public WirePlacerToolTab(ICEditorToolManager manager, WirePlacerTool tool) { private void addWireButton(ICWireTileType type, boolean fullRow) { ButtonController buttonController = new ButtonController() { - @Override public void getTooltip(List tooltip) { tooltip.add(new TextComponent(type.toString())); } + @Override public void getTooltip(List tooltip) { tooltip.add(new TranslatableComponent(type.tileType.getUnlocalizedName())); } @Override public void onClick() { tool.setWireType(type); } @Override public boolean isSelected() { return tool.getWireType() == type; } @@ -70,7 +73,7 @@ public void renderIcon(PoseStack stack, Point absPos, float partialFrame) { private void construct() { - addGroup("Redwire"); + addGroup(UL_TILEGROUP_REDWIRE); // Alloy wire addWireButton(ICWireTileType.RED_ALLOY, true); @@ -79,7 +82,7 @@ private void construct() { for (ICWireTileType type : ICWireTileType.INSULATED) addWireButton(type, false); - addGroup("Bundled"); + addGroup(UL_TILEGROUP_BUNDLED); // Bundled neutral wire addWireButton(ICWireTileType.BUNDLED_NEUTRAL, true); @@ -102,7 +105,7 @@ public void renderIcon(PoseStack stack, Point mouse, float partialFrame) { @Override public void buildTooltip(List tooltip) { - tooltip.add(new TextComponent("Wires")); //TODO Localize + tooltip.add(new TextComponent(UL_WIRE_TOOL)); } }; } diff --git a/fabrication/src/main/java/mrtjp/projectred/fabrication/gui/screen/ICWorkbenchCompileTab.java b/fabrication/src/main/java/mrtjp/projectred/fabrication/gui/screen/ICWorkbenchCompileTab.java index 52254636a..0b2befa11 100644 --- a/fabrication/src/main/java/mrtjp/projectred/fabrication/gui/screen/ICWorkbenchCompileTab.java +++ b/fabrication/src/main/java/mrtjp/projectred/fabrication/gui/screen/ICWorkbenchCompileTab.java @@ -22,6 +22,8 @@ import java.util.List; +import static mrtjp.projectred.fabrication.init.FabricationUnlocal.*; + public class ICWorkbenchCompileTab extends AbstractGuiNode implements ICRenderNode.IICRenderNodeEventReceiver { public static final ResourceLocation TAB_BACKGROUND = new ResourceLocation(ProjectRedFabrication.MOD_ID, "textures/gui/compile_tab.png"); @@ -75,9 +77,9 @@ private void initSubNodes() { tabControllerNode.setZPosition(0.1); addChild(tabControllerNode); - tabControllerNode.addButtonForTab(new SimpleUVTab(compileStackTab, "Stack", TabButtonNode.TabSide.BOTTOM, 350, 11, TAB_BACKGROUND)); - tabControllerNode.addButtonForTab(new SimpleUVTab(compileTreeTab, "Tree", TabButtonNode.TabSide.BOTTOM, 365, 11, TAB_BACKGROUND)); - tabControllerNode.addButtonForTab(new SimpleUVTab(compileProblemsTab, "Problems", TabButtonNode.TabSide.BOTTOM, 380, 11, TAB_BACKGROUND)); + tabControllerNode.addButtonForTab(new SimpleUVTab(compileStackTab, UL_TAB_STACK, TabButtonNode.TabSide.BOTTOM, 350, 11, TAB_BACKGROUND)); + tabControllerNode.addButtonForTab(new SimpleUVTab(compileTreeTab, UL_TAB_TREE, TabButtonNode.TabSide.BOTTOM, 365, 11, TAB_BACKGROUND)); + tabControllerNode.addButtonForTab(new SimpleUVTab(compileProblemsTab, UL_TAB_PROBLEMS, TabButtonNode.TabSide.BOTTOM, 380, 11, TAB_BACKGROUND)); tabControllerNode.selectInitialTab(0); tabControllerNode.spreadButtonsHorizontally(1); diff --git a/fabrication/src/main/java/mrtjp/projectred/fabrication/gui/screen/ICWorkbenchInfoTab.java b/fabrication/src/main/java/mrtjp/projectred/fabrication/gui/screen/ICWorkbenchInfoTab.java index 89b104df8..825ff4fe9 100644 --- a/fabrication/src/main/java/mrtjp/projectred/fabrication/gui/screen/ICWorkbenchInfoTab.java +++ b/fabrication/src/main/java/mrtjp/projectred/fabrication/gui/screen/ICWorkbenchInfoTab.java @@ -24,6 +24,7 @@ import net.minecraft.network.chat.TextComponent; import net.minecraft.network.chat.TranslatableComponent; import net.minecraft.resources.ResourceLocation; +import static mrtjp.projectred.fabrication.init.FabricationUnlocal.*; public class ICWorkbenchInfoTab extends AbstractGuiNode { @@ -52,36 +53,33 @@ private void initSubNodes() { NameTextBox nameTextBox = new NameTextBox(); nameTextBox.setSize(80, 18); - //TODO localize - listNode.addTitleRow(new TranslatableComponent("Info")); - listNode.addTextWithNodeRow(new TranslatableComponent("Name"), nameTextBox); - listNode.addKeyValueRow(new TranslatableComponent("Owner"), () -> new TranslatableComponent("//TODO")); + listNode.addTitleRow(new TranslatableComponent(UL_BLUEPRINT_INFO)); + listNode.addTextWithNodeRow(new TranslatableComponent(UL_BLUEPRINT_NAME), nameTextBox); + listNode.addKeyValueRow(new TranslatableComponent(UL_BLUEPRINT_OWNER), () -> new TranslatableComponent("//TODO")); - listNode.addKeyValueRow(new TranslatableComponent("Dimensions"), () -> { + listNode.addKeyValueRow(new TranslatableComponent(UL_BLUEPRINT_DIM), () -> { TileCoord dimensions = editor.getTileMap().getDimensions(); - Component tilesWord = new TranslatableComponent("tiles"); - Component byWord = new TranslatableComponent("by"); - return new TextComponent("" + dimensions.x).append(" ").append(tilesWord).append(" ").append(byWord).append(" ").append("" + dimensions.z).append(" ").append(tilesWord); + return new TranslatableComponent(UL_DIMENSIONS_TILES, dimensions.x, dimensions.z); }); - listNode.addKeyValueRow(new TranslatableComponent("Layers"), () -> { + listNode.addKeyValueRow(new TranslatableComponent(UL_BLUEPRINT_LAYERS), () -> { TileCoord dimensions = editor.getTileMap().getDimensions(); return new TextComponent("" + dimensions.y); }); - listNode.addTitleRow(new TranslatableComponent("Yield Calculator")); + listNode.addTitleRow(new TranslatableComponent(UL_YIELD_CALCULATOR)); ButtonArrayNode pipelineButtonGrid = createPipelineButtons(); pipelineButtonGrid.setGridSize(128, 18); - listNode.addTextWithNodeRow(new TranslatableComponent("Lithography Pipeline"), pipelineButtonGrid); + listNode.addTextWithNodeRow(new TranslatableComponent(UL_LITHOGRAPHY_PIPELINE), pipelineButtonGrid); ButtonArrayNode processNodeButtonGrid = createProcessNodeButtons(); processNodeButtonGrid.setGridSize(128, 18); - listNode.addTextWithNodeRow(new TranslatableComponent("Process Node"), processNodeButtonGrid); + listNode.addTextWithNodeRow(new TranslatableComponent(UL_PROCESS_NODE), processNodeButtonGrid); ButtonArrayNode waferTypeButtonGrid = createWaferTypeButtons(); waferTypeButtonGrid.setGridSize(128, 18); - listNode.addTextWithNodeRow(new TranslatableComponent("Wafer Type"), waferTypeButtonGrid); + listNode.addTextWithNodeRow(new TranslatableComponent(UL_WAFER_TYPE), waferTypeButtonGrid); PipelineDiagramNode diagramNode = new PipelineDiagramNode(yieldCalculator); listNode.addSingleNodeRow(diagramNode); @@ -99,11 +97,11 @@ protected void adjustContent(double scrollPercentage) { } }; - listNode.addKeyValueRow(new TranslatableComponent("Die size"), () -> new TextComponent(yieldCalculator.getDieSizeString())); - listNode.addKeyValueRow(new TranslatableComponent("Wafer size"), () -> new TextComponent(yieldCalculator.getWaferSizeString())); - listNode.addKeyValueRow(new TranslatableComponent("Dies per wafer"), () -> new TextComponent(yieldCalculator.getDiesPerWaferString())); - listNode.addKeyValueRow(new TranslatableComponent("Single layer yield"), () -> new TextComponent(yieldCalculator.getSingleLayerYieldString())); - listNode.addKeyValueRow(new TranslatableComponent("Yield"), () -> new TextComponent(yieldCalculator.getYieldString())); + listNode.addKeyValueRow(new TranslatableComponent(UL_DIE_SIZE), yieldCalculator::getDieDimensionsText); + listNode.addKeyValueRow(new TranslatableComponent(UL_WAFER_SIZE), yieldCalculator::getWaferDimensionsText); + listNode.addKeyValueRow(new TranslatableComponent(UL_DIES_PER_WAFER), yieldCalculator::getDieCountDimensionsText); + listNode.addKeyValueRow(new TranslatableComponent(UL_SINGLE_LAYER_YIELD), yieldCalculator::getSingleLayerYieldText); + listNode.addKeyValueRow(new TranslatableComponent(UL_YIELD), yieldCalculator::getYieldText); scrollBarNode.setPosition(290, 17); scrollBarNode.setSize(8, 198); diff --git a/fabrication/src/main/java/mrtjp/projectred/fabrication/gui/screen/ICWorkbenchScreen.java b/fabrication/src/main/java/mrtjp/projectred/fabrication/gui/screen/ICWorkbenchScreen.java index ab92a600b..bb7fbe019 100644 --- a/fabrication/src/main/java/mrtjp/projectred/fabrication/gui/screen/ICWorkbenchScreen.java +++ b/fabrication/src/main/java/mrtjp/projectred/fabrication/gui/screen/ICWorkbenchScreen.java @@ -22,6 +22,8 @@ import net.minecraft.resources.ResourceLocation; import net.minecraft.world.item.ItemStack; +import static mrtjp.projectred.fabrication.init.FabricationUnlocal.*; + public class ICWorkbenchScreen extends RedUIScreen { public static final ResourceLocation BACKGROUND = new ResourceLocation(ProjectRedFabrication.MOD_ID, "textures/gui/ic_workbench.png"); @@ -65,9 +67,9 @@ private void initSubNodes() { tabControllerNode.setZPosition(0.1); contentNode.addChild(tabControllerNode); - tabControllerNode.addButtonForTab(new SimpleUVTab(infoTab, "Info", TabButtonNode.TabSide.LEFT, 420, 1)); - tabControllerNode.addButtonForTab(new SimpleUVTab(editTab, "Edit", TabButtonNode.TabSide.LEFT, 420, 16)); - tabControllerNode.addButtonForTab(new SimpleUVTab(compileTab, "Compile", TabButtonNode.TabSide.LEFT, 420, 31)); + tabControllerNode.addButtonForTab(new SimpleUVTab(infoTab, UL_TAB_INFO, TabButtonNode.TabSide.LEFT, 420, 1)); + tabControllerNode.addButtonForTab(new SimpleUVTab(editTab, UL_TAB_EDIT, TabButtonNode.TabSide.LEFT, 420, 16)); + tabControllerNode.addButtonForTab(new SimpleUVTab(compileTab, UL_TAB_COMPILE, TabButtonNode.TabSide.LEFT, 420, 31)); tabControllerNode.selectInitialTab(1); tabControllerNode.spreadButtonsVertically(1); @@ -135,7 +137,7 @@ public void drawBack(PoseStack stack, Point mouse, float partialFrame) { blit(stack, getFrame().x(), getFrame().y(), 0, 222, getFrame().width(), getFrame().height(), 512, 512); Font fontRenderer = getRoot().getFontRenderer(); - Component text = new TranslatableComponent("Place blueprint"); // TODO: localize + Component text = new TranslatableComponent(UL_PLACE_BLUEPRINT); fontRenderer.draw(stack, text, getFrame().midX() - fontRenderer.width(text) / 2f, diff --git a/fabrication/src/main/java/mrtjp/projectred/fabrication/init/FabricationUnlocal.java b/fabrication/src/main/java/mrtjp/projectred/fabrication/init/FabricationUnlocal.java new file mode 100644 index 000000000..72ee30483 --- /dev/null +++ b/fabrication/src/main/java/mrtjp/projectred/fabrication/init/FabricationUnlocal.java @@ -0,0 +1,83 @@ +package mrtjp.projectred.fabrication.init; + +public class FabricationUnlocal { + + private static final String PREFIX = "projectred-fabrication."; + + // ICWorkbench tabs + public static final String UL_TAB_INFO = PREFIX + "tab.info"; + public static final String UL_TAB_EDIT = PREFIX + "tab.edit"; + public static final String UL_TAB_COMPILE = PREFIX + "tab.compile"; + public static final String UL_TAB_STACK = PREFIX + "tab.stack"; + public static final String UL_TAB_TREE = PREFIX + "tab.tree"; + public static final String UL_TAB_PROBLEMS = PREFIX + "tab.problems"; + + // Workbench tools + public static final String UL_ERASER_TOOL = PREFIX + "tool.eraser"; + public static final String UL_INTERACT_TOOL = PREFIX + "tool.interact"; + public static final String UL_WIRE_TOOL = PREFIX + "tool.wires"; + public static final String UL_GATE_TOOL = PREFIX + "tool.gates"; + + // Tile interactions + public static final String UL_TOGGLE_STATE = PREFIX + "interact.toggle_state"; + public static final String UL_TOGGLE_IO_MODE = PREFIX + "interact.toggle_io_mode"; + public static final String UL_IO_MODE_INPUT = PREFIX + "interact.io_mode.input"; + public static final String UL_IO_MODE_OUTPUT = PREFIX + "interact.io_mode.output"; + public static final String UL_TOGGLE_COLOUR = PREFIX + "interact.toggle_colour"; + public static final String UL_TOGGLE_DELAY = PREFIX + "interact.toggle_delay"; + public static final String UL_SIDE_ENABLED = PREFIX + "interact.side_enabled"; + public static final String UL_SIDE_DISABLED = PREFIX + "interact.side_disabled"; + + // General workbench UI + public static final String UL_PLACE_BLUEPRINT = PREFIX + "ui.place_blueprint"; + public static final String UL_BLUEPRINT_INFO = PREFIX + "ui.blueprint_info"; + public static final String UL_BLUEPRINT_NAME = PREFIX + "ui.blueprint_name"; + public static final String UL_BLUEPRINT_OWNER = PREFIX + "ui.blueprint_owner"; + public static final String UL_BLUEPRINT_DIM = PREFIX + "ui.blueprint_dim"; + public static final String UL_BLUEPRINT_LAYERS = PREFIX + "ui.blueprint_layers"; + + public static final String UL_YIELD_CALCULATOR = PREFIX + "ui.yield_calculator"; + public static final String UL_LITHOGRAPHY_PIPELINE = PREFIX + "ui.lithography_pipeline"; + public static final String UL_PROCESS_NODE = PREFIX + "ui.process_node"; + public static final String UL_WAFER_TYPE = PREFIX + "ui.wafer_type"; + public static final String UL_DIE_SIZE = PREFIX + "ui.die_size"; + public static final String UL_WAFER_SIZE = PREFIX + "ui.wafer_size"; + public static final String UL_DIES_PER_WAFER = PREFIX + "ui.dies_per_wafer"; + public static final String UL_SINGLE_LAYER_YIELD = PREFIX + "ui.single_layer_yield"; + public static final String UL_YIELD = PREFIX + "ui.yield"; + + // IC Tiles + public static final String UL_IO_GATE_TILE = PREFIX + "tiles.io_gate"; + + // Tile Groups + public static final String UL_TILEGROUP_REDWIRE = PREFIX + "tilegroup.redwire"; + public static final String UL_TILEGROUP_BUNDLED = PREFIX + "tilegroup.bundled"; + public static final String UL_TILEGROUP_IO = PREFIX + "tilegroup.io"; + public static final String UL_TILEGROUP_BASIC = PREFIX + "tilegroup.basic"; + public static final String UL_TILEGROUP_TIMING = PREFIX + "tilegroup.timing"; + public static final String UL_TILEGROUP_MEMORY = PREFIX + "tilegroup.memory"; + + // Item tooltips + public static final String UL_SIZE = PREFIX + "tooltip.size"; + public static final String UL_DEFECT_CHANCE = PREFIX + "tooltip.defect_chance"; + public static final String UL_CORRUPTED_DISCARD = PREFIX + "tooltip.corrupted_discard"; //"Corrupted NBT data, please discard" + public static final String UL_NAME = PREFIX + "tooltip.name"; + public static final String UL_TILE_COUNT = PREFIX + "tooltip.tile_count"; + public static final String UL_IO_TYPES = PREFIX + "tooltip.io_types"; + public static final String UL_TOP = PREFIX + "tooltip.top"; + public static final String UL_RIGHT = PREFIX + "tooltip.right"; + public static final String UL_BOTTOM = PREFIX + "tooltip.bottom"; + public static final String UL_LEFT = PREFIX + "tooltip.left"; + public static final String UL_BUNDLED_INPUT = PREFIX + "tooltip.bundled_input"; + public static final String UL_BUNDLED_OUTPUT = PREFIX + "tooltip.bundled_output"; + public static final String UL_IO_NONE = PREFIX + "tooltip.io_none"; + + // Numbers and measurements + public static final String UL_UNIT_TICKS = PREFIX + "unit.ticks"; + public static final String UL_DIMENSIONS_NM = PREFIX + "dimensions.nm"; + public static final String UL_DIMENSIONS_TILES = PREFIX + "dimensions.tiles"; + public static final String UL_DIMENSIONS_DIES = PREFIX + "dimensions.dies"; + public static final String UL_DIMENSIONS_NM_TOTAL = PREFIX + "dimensions.nm_total"; + public static final String UL_DIMENSIONS_TILES_TOTAL = PREFIX + "dimensions.tiles_total"; + public static final String UL_DIMENSIONS_DIES_TOTAL = PREFIX + "dimensions.dies_total"; +} diff --git a/fabrication/src/main/java/mrtjp/projectred/fabrication/item/BaseSiliconWaferItem.java b/fabrication/src/main/java/mrtjp/projectred/fabrication/item/BaseSiliconWaferItem.java index 9185bb1c5..2c0916760 100644 --- a/fabrication/src/main/java/mrtjp/projectred/fabrication/item/BaseSiliconWaferItem.java +++ b/fabrication/src/main/java/mrtjp/projectred/fabrication/item/BaseSiliconWaferItem.java @@ -13,6 +13,9 @@ import javax.annotation.Nullable; import java.util.List; +import static mrtjp.projectred.fabrication.init.FabricationUnlocal.UL_DEFECT_CHANCE; +import static mrtjp.projectred.fabrication.init.FabricationUnlocal.UL_SIZE; + public class BaseSiliconWaferItem extends Item { private final WaferType waferType; @@ -27,9 +30,8 @@ public BaseSiliconWaferItem(WaferType waferType) { public void appendHoverText(ItemStack stack, @Nullable Level world, List tooltipList, TooltipFlag tooltipFlag) { super.appendHoverText(stack, world, tooltipList, tooltipFlag); - //TODO localize - tooltipList.add(new TextComponent("Size").append(": " + waferType.getWaferWidth() + "nm x " + waferType.getWaferHeight() + "nm").withStyle(ChatFormatting.GRAY)); - tooltipList.add(new TextComponent("Defect chance").append(": " + waferType.getDefectRatePerUnitArea()*100 + "% / nm^2").withStyle(ChatFormatting.GRAY)); + tooltipList.add(new TextComponent(UL_SIZE).append(": " + waferType.getWaferWidth() + "nm x " + waferType.getWaferHeight() + "nm").withStyle(ChatFormatting.GRAY)); + tooltipList.add(new TextComponent(UL_DEFECT_CHANCE).append(": " + waferType.getDefectRatePerUnitArea()*100 + "% / nm^2").withStyle(ChatFormatting.GRAY)); } public WaferType getWaferType() { diff --git a/fabrication/src/main/java/mrtjp/projectred/fabrication/item/ICBlueprintItem.java b/fabrication/src/main/java/mrtjp/projectred/fabrication/item/ICBlueprintItem.java index db35dff00..a9d4c1406 100644 --- a/fabrication/src/main/java/mrtjp/projectred/fabrication/item/ICBlueprintItem.java +++ b/fabrication/src/main/java/mrtjp/projectred/fabrication/item/ICBlueprintItem.java @@ -7,6 +7,7 @@ import net.minecraft.nbt.CompoundTag; import net.minecraft.network.chat.Component; import net.minecraft.network.chat.TextComponent; +import net.minecraft.network.chat.TranslatableComponent; import net.minecraft.world.InteractionResult; import net.minecraft.world.item.Item; import net.minecraft.world.item.ItemStack; @@ -19,6 +20,7 @@ import java.util.List; import static mrtjp.projectred.fabrication.editor.EditorDataUtils.*; +import static mrtjp.projectred.fabrication.init.FabricationUnlocal.*; public class ICBlueprintItem extends Item { @@ -59,29 +61,29 @@ public static void buildTooltip(CompoundTag blueprintTag, List toolti if (!hasFabricationTarget(blueprintTag)) { tooltipList.add(new TextComponent(" ").withStyle(ChatFormatting.RED) - .append(new TextComponent("Corrupted NBT data, please discard").withStyle(ChatFormatting.GRAY))); + .append(new TranslatableComponent(UL_CORRUPTED_DISCARD).withStyle(ChatFormatting.GRAY))); return; } - //TODO localize - tooltipList.add(new TextComponent("Name: " + blueprintTag.getString(KEY_IC_NAME)).withStyle(ChatFormatting.GRAY)); - tooltipList.add(new TextComponent("Tile count: " + blueprintTag.getInt(KEY_TILE_COUNT)).withStyle(ChatFormatting.GRAY)); - tooltipList.add(new TextComponent("IO Types: ").withStyle(ChatFormatting.GRAY)); + tooltipList.add(new TranslatableComponent(UL_NAME).append(": " + blueprintTag.getString(KEY_IC_NAME)).withStyle(ChatFormatting.GRAY)); + tooltipList.add(new TranslatableComponent(UL_TILE_COUNT).append(": " + blueprintTag.getInt(KEY_TILE_COUNT)).withStyle(ChatFormatting.GRAY)); + tooltipList.add(new TranslatableComponent(UL_IO_TYPES).append(": ").withStyle(ChatFormatting.GRAY)); //TODO handle other types of IO byte bmask = blueprintTag.getByte(KEY_IO_BUNDLED); - tooltipList.add(new TextComponent(" Top: " + getBundledIOString(bmask, 0)).withStyle(ChatFormatting.GRAY)); - tooltipList.add(new TextComponent(" Right: " + getBundledIOString(bmask, 1)).withStyle(ChatFormatting.GRAY)); - tooltipList.add(new TextComponent(" Bottom: " + getBundledIOString(bmask, 2)).withStyle(ChatFormatting.GRAY)); - tooltipList.add(new TextComponent(" Left: " + getBundledIOString(bmask, 3)).withStyle(ChatFormatting.GRAY)); + TextComponent indent = new TextComponent(" "); + tooltipList.add(indent.copy().append(new TranslatableComponent(UL_TOP)).append(": ").append(getBundledIOTextComponent(bmask, 0)).withStyle(ChatFormatting.GRAY)); + tooltipList.add(indent.copy().append(new TranslatableComponent(UL_RIGHT)).append(": ").append(getBundledIOTextComponent(bmask, 1)).withStyle(ChatFormatting.GRAY)); + tooltipList.add(indent.copy().append(new TranslatableComponent(UL_BOTTOM)).append(": ").append(getBundledIOTextComponent(bmask, 2)).withStyle(ChatFormatting.GRAY)); + tooltipList.add(indent.copy().append(new TranslatableComponent(UL_LEFT)).append(": ").append(getBundledIOTextComponent(bmask, 3)).withStyle(ChatFormatting.GRAY)); //TODO errors } - private static String getBundledIOString(byte bmask, int r) { + private static TranslatableComponent getBundledIOTextComponent(byte bmask, int r) { int i = 0x01 << r; int o = 0x10 << r; - return ((bmask & i) != 0 ? "Bundled input" : (bmask & o) != 0 ? "Bundled output" : "None"); + return new TranslatableComponent((bmask & i) != 0 ? UL_BUNDLED_INPUT : (bmask & o) != 0 ? UL_BUNDLED_OUTPUT : UL_IO_NONE); } public static ItemStack createPhotomaskStack(ItemStack blueprintStack) { diff --git a/fabrication/src/main/java/mrtjp/projectred/fabrication/lithography/YieldCalculator.java b/fabrication/src/main/java/mrtjp/projectred/fabrication/lithography/YieldCalculator.java index 8dc7c63f1..41d6867bc 100644 --- a/fabrication/src/main/java/mrtjp/projectred/fabrication/lithography/YieldCalculator.java +++ b/fabrication/src/main/java/mrtjp/projectred/fabrication/lithography/YieldCalculator.java @@ -1,6 +1,11 @@ package mrtjp.projectred.fabrication.lithography; import mrtjp.projectred.lib.Size; +import net.minecraft.network.chat.Component; +import net.minecraft.network.chat.TextComponent; +import net.minecraft.network.chat.TranslatableComponent; + +import static mrtjp.projectred.fabrication.init.FabricationUnlocal.*; public class YieldCalculator { @@ -67,25 +72,25 @@ public double getMultiLayerYield() { return Math.pow(getSingleLayerYield(), tileMapLayers); } - public String getDieSizeString() { + public Component getDieDimensionsText() { Size dieSize = getDieSize(); - return String.format("%d nm x %d nm", dieSize.width, dieSize.height); + return new TranslatableComponent(UL_DIMENSIONS_DIES, dieSize.width, dieSize.height); } - public String getWaferSizeString() { - return String.format("%d nm x %d nm", waferType.getWaferWidth(), waferType.getWaferHeight()); + public Component getWaferDimensionsText() { + return new TranslatableComponent(UL_DIMENSIONS_NM, waferType.getWaferWidth(), waferType.getWaferHeight()); } - public String getDiesPerWaferString() { + public Component getDieCountDimensionsText() { Size dieCount = getDieCount(); - return String.format("%d dies x %d dies (%d total)", dieCount.width, dieCount.height, dieCount.width * dieCount.height); + return new TranslatableComponent(UL_DIMENSIONS_DIES_TOTAL, dieCount.width, dieCount.height, dieCount.width * dieCount.height); } - public String getSingleLayerYieldString() { - return String.format("%.2f%%", getSingleLayerYield() * 100); + public Component getSingleLayerYieldText() { + return new TextComponent(String.format("%.2f%%", getSingleLayerYield() * 100)); } - public String getYieldString() { - return String.format("%.2f%%", getMultiLayerYield() * 100); + public Component getYieldText() { + return new TextComponent(String.format("%.2f%%", getMultiLayerYield() * 100)); } } diff --git a/fabrication/src/main/resources/assets/projectred_fabrication/lang/en_us.json b/fabrication/src/main/resources/assets/projectred_fabrication/lang/en_us.json deleted file mode 100644 index cc20307a6..000000000 --- a/fabrication/src/main/resources/assets/projectred_fabrication/lang/en_us.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "itemGroup.projectred-fabrication": "Project Red: Fabrication", - - "item.projectred-fabrication.ic_blueprint": "IC Blueprint", - "item.projectred-fabrication.ic_chip": "IC Chip", - "item.projectred-fabrication.creative_mode_ic_chip": "Creative Mode IC Chip", - "block.projectred-fabrication.ic_workbench": "IC Workbench", - "block.projectred-fabrication.ic_printer": "IC Printer", - - "block.projectred-relocation.frame": "Frame" -} \ No newline at end of file From cb04d812f3f3047fff77666a041cd51022efb752 Mon Sep 17 00:00:00 2001 From: MrTJP Date: Fri, 23 Dec 2022 18:26:35 -0500 Subject: [PATCH 11/23] feat: ic workbench problems overlay --- .../projectred_fabrication/lang/en_us.json | 143 ++++++++++-------- .../fabrication/ProjectRedFabrication.java | 2 +- .../FabricationBlockStateModelProvider.java | 2 - .../data/FabricationLanguageProvider.java | 31 +++- .../fabrication/editor/EditorDataUtils.java | 36 ++++- .../editor/ICEditorStateMachine.java | 106 ++++++++++--- .../fabrication/editor/ICWorkbenchEditor.java | 18 +++ .../fabrication/engine/BaseTileMap.java | 4 + .../engine/gates/SidedRedstoneGateTile.java | 13 +- .../engine/log/CompileProblem.java | 44 ++++++ .../engine/log/CompileProblemSeverity.java | 6 + .../engine/log/CompileProblemType.java | 33 ++++ .../engine/log/DeadGateWarning.java | 33 ++++ .../engine/log/DeadWireWarning.java | 34 +++++ .../engine/{ => log}/ICCompilerLog.java | 120 +++++++++++++-- .../engine/log/IODirectionMismatchError.java | 33 ++++ .../engine/log/MultiPositionProblem.java | 79 ++++++++++ .../engine/log/MultipleDriversError.java | 108 +++++++++++++ .../fabrication/engine/log/NoInputsError.java | 61 ++++++++ .../engine/log/NoOutputsError.java | 61 ++++++++ .../engine/log/SimpleLocatableProblem.java | 66 ++++++++ .../engine/wires/RedstoneWireTile.java | 5 + .../fabrication/gui/CTNListNode.java | 2 +- .../fabrication/gui/CompileProblemsTab.java | 66 +++++++- .../fabrication/gui/CompileStackTab.java | 3 +- .../fabrication/gui/CompileTreeTab.java | 10 ++ .../fabrication/gui/ProblemListNode.java | 118 +++++++++++++++ .../fabrication/gui/SimpleUVTab.java | 36 ++++- .../fabrication/gui/WirePlacerToolTab.java | 2 +- .../gui/screen/ICWorkbenchCompileTab.java | 124 +++++++++++++-- .../gui/screen/ICWorkbenchEditTab.java | 5 +- .../gui/screen/ICWorkbenchInfoTab.java | 6 +- .../gui/screen/ICWorkbenchScreen.java | 73 ++++++++- .../fabrication/init/FabricationUnlocal.java | 29 +++- .../item/BaseSiliconWaferItem.java | 6 +- .../fabrication/item/ICBlueprintItem.java | 16 +- .../lithography/YieldCalculator.java | 5 +- .../fabrication/tile/PlottingTableTile.java | 3 + .../textures/gui/compile_tab.png | Bin 12535 -> 13123 bytes .../textures/gui/ic_workbench.png | Bin 35141 -> 35284 bytes 40 files changed, 1410 insertions(+), 132 deletions(-) create mode 100644 fabrication/src/main/java/mrtjp/projectred/fabrication/engine/log/CompileProblem.java create mode 100644 fabrication/src/main/java/mrtjp/projectred/fabrication/engine/log/CompileProblemSeverity.java create mode 100644 fabrication/src/main/java/mrtjp/projectred/fabrication/engine/log/CompileProblemType.java create mode 100644 fabrication/src/main/java/mrtjp/projectred/fabrication/engine/log/DeadGateWarning.java create mode 100644 fabrication/src/main/java/mrtjp/projectred/fabrication/engine/log/DeadWireWarning.java rename fabrication/src/main/java/mrtjp/projectred/fabrication/engine/{ => log}/ICCompilerLog.java (80%) create mode 100644 fabrication/src/main/java/mrtjp/projectred/fabrication/engine/log/IODirectionMismatchError.java create mode 100644 fabrication/src/main/java/mrtjp/projectred/fabrication/engine/log/MultiPositionProblem.java create mode 100644 fabrication/src/main/java/mrtjp/projectred/fabrication/engine/log/MultipleDriversError.java create mode 100644 fabrication/src/main/java/mrtjp/projectred/fabrication/engine/log/NoInputsError.java create mode 100644 fabrication/src/main/java/mrtjp/projectred/fabrication/engine/log/NoOutputsError.java create mode 100644 fabrication/src/main/java/mrtjp/projectred/fabrication/engine/log/SimpleLocatableProblem.java create mode 100644 fabrication/src/main/java/mrtjp/projectred/fabrication/gui/ProblemListNode.java diff --git a/fabrication/src/main/generated/assets/projectred_fabrication/lang/en_us.json b/fabrication/src/main/generated/assets/projectred_fabrication/lang/en_us.json index 152acff88..8b894049c 100644 --- a/fabrication/src/main/generated/assets/projectred_fabrication/lang/en_us.json +++ b/fabrication/src/main/generated/assets/projectred_fabrication/lang/en_us.json @@ -12,64 +12,87 @@ "item.projectred_fabrication.rough_silicon_wafer": "Rough Silicon Wafer", "item.projectred_fabrication.valid_die": "Valid Die", "itemGroup.projectred_fabrication": "Project Red: Fabrication", - "projectred-fabrication.dimensions.dies": "%d dies x %d dies", - "projectred-fabrication.dimensions.dies_total": "%d dies x %d dies (%d dies^2)", - "projectred-fabrication.dimensions.nm": "%d nm x %d nm", - "projectred-fabrication.dimensions.nm_total": "%d nm x %d nm (%d nm^2)", - "projectred-fabrication.dimensions.tiles": "%d tiles x %d tiles", - "projectred-fabrication.dimensions.tiles_total": "%d tiles x %d tiles (%d tiles^2)", - "projectred-fabrication.interact.io_mode.input": "Input", - "projectred-fabrication.interact.io_mode.output": "Output", - "projectred-fabrication.interact.side_disabled": "Side disabled", - "projectred-fabrication.interact.side_enabled": "Side enabled", - "projectred-fabrication.interact.toggle_colour": "Toggle colour", - "projectred-fabrication.interact.toggle_delay": "Toggle delay", - "projectred-fabrication.interact.toggle_io_mode": "Toggle IO mode", - "projectred-fabrication.interact.toggle_state": "Toggle state", - "projectred-fabrication.tab.compile": "Compile", - "projectred-fabrication.tab.edit": "Edit", - "projectred-fabrication.tab.info": "Info", - "projectred-fabrication.tab.problems": "Problems", - "projectred-fabrication.tab.stack": "Stack", - "projectred-fabrication.tab.tree": "Tree", - "projectred-fabrication.tilegroup.basic": "Basic", - "projectred-fabrication.tilegroup.bundled": "Bundled", - "projectred-fabrication.tilegroup.io": "IO", - "projectred-fabrication.tilegroup.memory": "Memory", - "projectred-fabrication.tilegroup.redwire": "Redwire", - "projectred-fabrication.tilegroup.timing": "Timing", - "projectred-fabrication.tiles.io_gate": "IO Gate", - "projectred-fabrication.tool.eraser": "Erase", - "projectred-fabrication.tool.gates": "Gates", - "projectred-fabrication.tool.interact": "Interact", - "projectred-fabrication.tool.wires": "Wires", - "projectred-fabrication.tooltip.bottom": "Bottom", - "projectred-fabrication.tooltip.bundled_input": "Bundled input", - "projectred-fabrication.tooltip.bundled_output": "Bundled output", - "projectred-fabrication.tooltip.corrupted_discard": "Corrupted NBT data, please discard", - "projectred-fabrication.tooltip.defect_chance": "Defect chance", - "projectred-fabrication.tooltip.io_none": "None", - "projectred-fabrication.tooltip.io_types": "IO types", - "projectred-fabrication.tooltip.left": "Left", - "projectred-fabrication.tooltip.name": "Name", - "projectred-fabrication.tooltip.right": "Right", - "projectred-fabrication.tooltip.size": "Size", - "projectred-fabrication.tooltip.tile_count": "Tile count", - "projectred-fabrication.tooltip.top": "Top", - "projectred-fabrication.ui.blueprint_dim": "Dimensions", - "projectred-fabrication.ui.blueprint_info": "Blueprint Info", - "projectred-fabrication.ui.blueprint_layers": "Layers", - "projectred-fabrication.ui.blueprint_name": "Name", - "projectred-fabrication.ui.blueprint_owner": "Owner", - "projectred-fabrication.ui.die_size": "Die size", - "projectred-fabrication.ui.dies_per_wafer": "Dies per wafer", - "projectred-fabrication.ui.lithography_pipeline": "Lithography pipeline", - "projectred-fabrication.ui.place_blueprint": "Place blueprint", - "projectred-fabrication.ui.process_node": "Process node", - "projectred-fabrication.ui.single_layer_yield": "Single layer yield", - "projectred-fabrication.ui.wafer_size": "Wafer size", - "projectred-fabrication.ui.wafer_type": "Wafer type", - "projectred-fabrication.ui.yield": "Yield", - "projectred-fabrication.ui.yield_calculator": "Yield Calculator", - "projectred-fabrication.unit.ticks": "%d ticks" + "projectred_fabrication.dimensions.dies": "%d dies x %d dies", + "projectred_fabrication.dimensions.dies_total": "%d dies x %d dies (%d dies^2)", + "projectred_fabrication.dimensions.nm": "%d nm x %d nm", + "projectred_fabrication.dimensions.nm_total": "%d nm x %d nm (%d nm^2)", + "projectred_fabrication.dimensions.tiles": "%d tiles x %d tiles", + "projectred_fabrication.dimensions.tiles_total": "%d tiles x %d tiles (%d tiles^2)", + "projectred_fabrication.interact.io_mode.input": "Input", + "projectred_fabrication.interact.io_mode.output": "Output", + "projectred_fabrication.interact.side_disabled": "Side disabled", + "projectred_fabrication.interact.side_enabled": "Side enabled", + "projectred_fabrication.interact.toggle_colour": "Toggle colour", + "projectred_fabrication.interact.toggle_delay": "Toggle delay", + "projectred_fabrication.interact.toggle_io_mode": "Toggle IO mode", + "projectred_fabrication.interact.toggle_state": "Toggle state", + "projectred_fabrication.problems.dead_gate.desc": "No signals drive this gate", + "projectred_fabrication.problems.dead_gate.title": "Dead gate", + "projectred_fabrication.problems.dead_wire.desc": "No signals pass through this wire", + "projectred_fabrication.problems.dead_wire.title": "Dead wire", + "projectred_fabrication.problems.io_dir_mismatch.desc": "Side has IO gates with conflicting directions", + "projectred_fabrication.problems.io_dir_mismatch.title": "IO direction mismatch", + "projectred_fabrication.problems.multiple_drivers.desc": "Multiple registers connected to an input:", + "projectred_fabrication.problems.multiple_drivers.title": "Multiple drivers", + "projectred_fabrication.problems.no_errors": "No errors", + "projectred_fabrication.problems.no_inputs.desc": "Design has no inputs", + "projectred_fabrication.problems.no_inputs.title": "No inputs", + "projectred_fabrication.problems.no_outputs.desc": "Design has no outputs", + "projectred_fabrication.problems.no_outputs.title": "No outputs", + "projectred_fabrication.problems.no_warnings": "No warnings", + "projectred_fabrication.tab.compile": "Compile", + "projectred_fabrication.tab.edit": "Edit", + "projectred_fabrication.tab.info": "Info", + "projectred_fabrication.tab.problems": "Problems", + "projectred_fabrication.tab.stack": "Stack", + "projectred_fabrication.tab.tree": "Tree", + "projectred_fabrication.tilegroup.basic": "Basic", + "projectred_fabrication.tilegroup.bundled": "Bundled", + "projectred_fabrication.tilegroup.io": "IO", + "projectred_fabrication.tilegroup.memory": "Memory", + "projectred_fabrication.tilegroup.redwire": "Redwire", + "projectred_fabrication.tilegroup.timing": "Timing", + "projectred_fabrication.tiles.io_gate": "IO Gate", + "projectred_fabrication.tool.eraser": "Erase", + "projectred_fabrication.tool.gates": "Gates", + "projectred_fabrication.tool.interact": "Interact", + "projectred_fabrication.tool.wires": "Wires", + "projectred_fabrication.tooltip.bottom": "Bottom", + "projectred_fabrication.tooltip.bundled_input": "Bundled input", + "projectred_fabrication.tooltip.bundled_output": "Bundled output", + "projectred_fabrication.tooltip.cannot_fabricate": "Cannot fabricate", + "projectred_fabrication.tooltip.corrupted_discard": "Corrupted NBT data, please discard", + "projectred_fabrication.tooltip.defect_chance": "Defect chance", + "projectred_fabrication.tooltip.io_none": "None", + "projectred_fabrication.tooltip.io_types": "IO types", + "projectred_fabrication.tooltip.left": "Left", + "projectred_fabrication.tooltip.name": "Name", + "projectred_fabrication.tooltip.right": "Right", + "projectred_fabrication.tooltip.size": "Size", + "projectred_fabrication.tooltip.tile_count": "Tile count", + "projectred_fabrication.tooltip.top": "Top", + "projectred_fabrication.ui.blueprint_dim": "Dimensions", + "projectred_fabrication.ui.blueprint_info": "Blueprint Info", + "projectred_fabrication.ui.blueprint_layers": "Layers", + "projectred_fabrication.ui.blueprint_name": "Name", + "projectred_fabrication.ui.blueprint_owner": "Owner", + "projectred_fabrication.ui.compile": "Compile", + "projectred_fabrication.ui.compile_done": "Done (%d/%d)", + "projectred_fabrication.ui.compile_failed": "Compile failed", + "projectred_fabrication.ui.compile_progress": "Compiling (%d/%d)", + "projectred_fabrication.ui.compile_ready": "Ready to compile", + "projectred_fabrication.ui.die_size": "Die size", + "projectred_fabrication.ui.dies_per_wafer": "Dies per wafer", + "projectred_fabrication.ui.lithography_pipeline": "Lithography pipeline", + "projectred_fabrication.ui.place_blueprint": "Place blueprint", + "projectred_fabrication.ui.process_node": "Process node", + "projectred_fabrication.ui.sim_running": "Simulation running", + "projectred_fabrication.ui.single_layer_yield": "Single layer yield", + "projectred_fabrication.ui.wafer_size": "Wafer size", + "projectred_fabrication.ui.wafer_type": "Wafer type", + "projectred_fabrication.ui.yield": "Yield", + "projectred_fabrication.ui.yield_calculator": "Yield Calculator", + "projectred_fabrication.unit.errors": "%d errors", + "projectred_fabrication.unit.ticks": "%d ticks", + "projectred_fabrication.unit.warnings": "%d warnings" } \ No newline at end of file diff --git a/fabrication/src/main/java/mrtjp/projectred/fabrication/ProjectRedFabrication.java b/fabrication/src/main/java/mrtjp/projectred/fabrication/ProjectRedFabrication.java index 7302f7059..be535a819 100644 --- a/fabrication/src/main/java/mrtjp/projectred/fabrication/ProjectRedFabrication.java +++ b/fabrication/src/main/java/mrtjp/projectred/fabrication/ProjectRedFabrication.java @@ -56,7 +56,7 @@ public ProjectRedFabrication() { modEventBus.addListener(this::commonSetup); modEventBus.addListener(this::onGatherDataEvent); - DistExecutor.safeRunWhenOn(Dist.CLIENT, () -> FabricationClientInit::init); + DistExecutor.unsafeRunWhenOn(Dist.CLIENT, () -> FabricationClientInit::init); BLOCKS.register(modEventBus); ITEMS.register(modEventBus); diff --git a/fabrication/src/main/java/mrtjp/projectred/fabrication/data/FabricationBlockStateModelProvider.java b/fabrication/src/main/java/mrtjp/projectred/fabrication/data/FabricationBlockStateModelProvider.java index 59928e736..c23b9d3e6 100644 --- a/fabrication/src/main/java/mrtjp/projectred/fabrication/data/FabricationBlockStateModelProvider.java +++ b/fabrication/src/main/java/mrtjp/projectred/fabrication/data/FabricationBlockStateModelProvider.java @@ -5,7 +5,6 @@ import mrtjp.projectred.fabrication.block.FabricationMachineBlock; import mrtjp.projectred.fabrication.block.ICWorkbenchBlock; import net.minecraft.data.DataGenerator; -import net.minecraft.resources.ResourceLocation; import net.minecraft.world.level.block.Block; import net.minecraftforge.client.model.generators.BlockModelBuilder; import net.minecraftforge.client.model.generators.BlockStateProvider; @@ -13,7 +12,6 @@ import net.minecraftforge.client.model.generators.ModelFile; import net.minecraftforge.common.data.ExistingFileHelper; -import static mrtjp.projectred.fabrication.ProjectRedFabrication.MOD_ID; import static mrtjp.projectred.fabrication.init.FabricationReferences.*; public class FabricationBlockStateModelProvider extends BlockStateProvider { diff --git a/fabrication/src/main/java/mrtjp/projectred/fabrication/data/FabricationLanguageProvider.java b/fabrication/src/main/java/mrtjp/projectred/fabrication/data/FabricationLanguageProvider.java index 32c1a2b6a..cd66d28ed 100644 --- a/fabrication/src/main/java/mrtjp/projectred/fabrication/data/FabricationLanguageProvider.java +++ b/fabrication/src/main/java/mrtjp/projectred/fabrication/data/FabricationLanguageProvider.java @@ -13,6 +13,11 @@ public FabricationLanguageProvider(DataGenerator gen) { super(gen, MOD_ID, "en_us"); } + @Override + public String getName() { + return "ProjectRed-Fabrication Languages: en_us"; + } + @Override protected void addTranslations() { @@ -54,13 +59,34 @@ protected void addTranslations() { add(UL_TOGGLE_DELAY, "Toggle delay"); add(UL_SIDE_ENABLED, "Side enabled"); add(UL_SIDE_DISABLED, "Side disabled"); - add(UL_PLACE_BLUEPRINT, "Place blueprint"); + add(UL_MULTIPLE_DRIVERS_TITLE, "Multiple drivers"); + add(UL_MULTIPLE_DRIVERS_DESC, "Multiple registers connected to an input:"); + add(UL_DEAD_WIRE_TITLE, "Dead wire"); + add(UL_DEAD_WIRE_DESC, "No signals pass through this wire"); + add(UL_DEAD_GATE_TITLE, "Dead gate"); + add(UL_DEAD_GATE_DESC, "No signals drive this gate"); + add(UL_IO_DIR_MISMATCH_TITLE, "IO direction mismatch"); + add(UL_IO_DIR_MISMATCH_DESC, "Side has IO gates with conflicting directions"); + add(UL_NO_INPUTS_TITLE, "No inputs"); + add(UL_NO_INPUTS_DESC, "Design has no inputs"); + add(UL_NO_OUTPUTS_TITLE, "No outputs"); + add(UL_NO_OUTPUTS_DESC, "Design has no outputs"); + add(UL_NO_ERRORS, "No errors"); + add(UL_NO_WARNINGS, "No warnings"); + + add(UL_PLACE_BLUEPRINT, "Place blueprint"); add(UL_BLUEPRINT_INFO, "Blueprint Info"); add(UL_BLUEPRINT_NAME, "Name"); add(UL_BLUEPRINT_OWNER, "Owner"); add(UL_BLUEPRINT_DIM, "Dimensions"); add(UL_BLUEPRINT_LAYERS, "Layers"); + add(UL_COMPILE, "Compile"); + add(UL_COMPILE_PROGRESS, "Compiling (%d/%d)"); + add(UL_COMPILE_DONE, "Done (%d/%d)"); + add(UL_COMPILE_READY, "Ready to compile"); + add(UL_COMPILE_FAILED, "Compile failed"); + add(UL_SIM_RUNNING, "Simulation running"); add(UL_YIELD_CALCULATOR, "Yield Calculator"); add(UL_LITHOGRAPHY_PIPELINE, "Lithography pipeline"); @@ -85,6 +111,7 @@ protected void addTranslations() { add(UL_BUNDLED_INPUT, "Bundled input"); add(UL_BUNDLED_OUTPUT, "Bundled output"); add(UL_IO_NONE, "None"); + add(UL_CANNOT_FABRICATE, "Cannot fabricate"); add(UL_IO_GATE_TILE, "IO Gate"); @@ -95,6 +122,8 @@ protected void addTranslations() { add(UL_TILEGROUP_TIMING, "Timing"); add(UL_TILEGROUP_MEMORY, "Memory"); + add(UL_UNIT_WARNINGS, "%d warnings"); + add(UL_UNIT_ERRORS, "%d errors"); add(UL_UNIT_TICKS, "%d ticks"); add(UL_DIMENSIONS_NM, "%d nm x %d nm"); add(UL_DIMENSIONS_TILES, "%d tiles x %d tiles"); diff --git a/fabrication/src/main/java/mrtjp/projectred/fabrication/editor/EditorDataUtils.java b/fabrication/src/main/java/mrtjp/projectred/fabrication/editor/EditorDataUtils.java index 754d8ff33..8b9ae1086 100644 --- a/fabrication/src/main/java/mrtjp/projectred/fabrication/editor/EditorDataUtils.java +++ b/fabrication/src/main/java/mrtjp/projectred/fabrication/editor/EditorDataUtils.java @@ -2,6 +2,10 @@ import mrtjp.fengine.TileCoord; import net.minecraft.nbt.CompoundTag; +import net.minecraft.nbt.ListTag; +import net.minecraft.nbt.Tag; + +import java.util.List; public class EditorDataUtils { @@ -21,6 +25,13 @@ public class EditorDataUtils { public static final String KEY_SIMULATION = "sim_cont"; // CompoundTag public static final String KEY_COMPILER_LOG = "compiler_log"; // CompoundTag + // ICIssuesLog + public static final String KEY_COMPLETED_STEPS = "completed_steps"; // int + public static final String KEY_CURRENT_PATH = "current_path"; // int array + public static final String KEY_PROBLEMS_LIST = "problems"; // ListTag + public static final String KEY_ERROR_COUNT = "error_count"; // int + public static final String KEY_WARNING_COUNT = "warning_count"; // int + public static int getFormat(CompoundTag tag) { return tag.getInt(KEY_FORMAT); } @@ -40,9 +51,15 @@ public static boolean hasFabricationTarget(CompoundTag tag) { } public static boolean canFabricate(CompoundTag tag) { - return hasFabricationTarget(tag) && tag.getBoolean(KEY_IS_BUILT); + return hasFabricationTarget(tag) && tag.getBoolean(KEY_IS_BUILT) && getErrorCount(tag) == 0; + } + + public static int getErrorCount(CompoundTag tag) { + return tag.getCompound(KEY_COMPILER_LOG).getInt(KEY_ERROR_COUNT); + } - //TODO check errors + public static int getWarningCount(CompoundTag tag) { + return tag.getCompound(KEY_COMPILER_LOG).getInt(KEY_WARNING_COUNT); } // Creates copy of editor tag with only the data required to fabricate a gate @@ -71,6 +88,21 @@ public static TileCoord loadTileCoord(CompoundTag tag, String key) { ); } + public static void saveTileCoordList(CompoundTag tag, String key, Iterable coordList) { + ListTag list = new ListTag(); + for (TileCoord coord : coordList) { + list.add(tileCoordToNBT(coord)); + } + tag.put(key, list); + } + + public static void loadTileCoordList(CompoundTag tag, String key, List coordList) { + ListTag list = tag.getList(key, Tag.TAG_COMPOUND); + for (int i = 0; i < list.size(); i++) { + coordList.add(tileCoordFromNBT(list.getCompound(i))); + } + } + public static CompoundTag tileCoordToNBT(TileCoord coord) { CompoundTag tag = new CompoundTag(); saveTileCoord(tag, "", coord); diff --git a/fabrication/src/main/java/mrtjp/projectred/fabrication/editor/ICEditorStateMachine.java b/fabrication/src/main/java/mrtjp/projectred/fabrication/editor/ICEditorStateMachine.java index 424b85dfb..99e1ede23 100644 --- a/fabrication/src/main/java/mrtjp/projectred/fabrication/editor/ICEditorStateMachine.java +++ b/fabrication/src/main/java/mrtjp/projectred/fabrication/editor/ICEditorStateMachine.java @@ -2,14 +2,22 @@ import codechicken.lib.data.MCDataInput; import codechicken.lib.data.MCDataOutput; +import mrtjp.fengine.TileCoord; import mrtjp.fengine.api.ICFlatMap; import mrtjp.fengine.api.ICStepThroughAssembler; -import mrtjp.projectred.fabrication.engine.ICCompilerLog; +import mrtjp.projectred.fabrication.engine.BaseTile; import mrtjp.projectred.fabrication.engine.ICSimulationContainer; +import mrtjp.projectred.fabrication.engine.IIOConnectionTile; import mrtjp.projectred.fabrication.engine.PRFabricationEngine; +import mrtjp.projectred.fabrication.engine.log.ICCompilerLog; +import mrtjp.projectred.fabrication.engine.log.IODirectionMismatchError; +import mrtjp.projectred.fabrication.engine.log.NoInputsError; +import mrtjp.projectred.fabrication.engine.log.NoOutputsError; import net.minecraft.nbt.CompoundTag; +import java.util.Collection; import java.util.Collections; +import java.util.List; import java.util.function.Function; import static mrtjp.projectred.fabrication.ProjectRedFabrication.LOGGER; @@ -18,8 +26,10 @@ public class ICEditorStateMachine { public static final int KEY_STATE_CHANGED = 0; - public static final int KEY_COMPILER_LOG_NODE_ADDED = 1; - public static final int KEY_COMPILER_LOG_NODE_EXECUTED = 2; + public static final int KEY_COMPILER_LOG_CLEARED = 1; + public static final int KEY_COMPILER_LOG_NODE_ADDED = 2; + public static final int KEY_COMPILER_LOG_NODE_EXECUTED = 3; + public static final int KEY_COMPILER_LOG_PROBLEM_ADDED = 4; public static final int KEY_CLIENT_COMPILE_CLICKED = 10; @@ -29,12 +39,14 @@ public class ICEditorStateMachine { private static final int STATE_AWAITING_COMPILE = 1; private static final int STATE_COMPILING = 2; private static final int STATE_SIMULATING = 3; + private static final int STATE_COMPILE_FAILED = 4; private final State[] states = { new StateInitial(), new StateAwaitingCompile(), new StateCompiling(), - new StateSimulating() + new StateSimulating(), + new CompileFailed(), }; private int currentState = STATE_INITIAL; @@ -98,8 +110,10 @@ public void readStateMachineStream(MCDataInput in, int key) { case KEY_STATE_CHANGED: enterStateOnClient(in.readUByte()); break; + case KEY_COMPILER_LOG_CLEARED: case KEY_COMPILER_LOG_NODE_ADDED: case KEY_COMPILER_LOG_NODE_EXECUTED: + case KEY_COMPILER_LOG_PROBLEM_ADDED: compilerLog.readLogStream(in, key); break; case KEY_CLIENT_COMPILE_CLICKED: @@ -146,6 +160,9 @@ public boolean isCompiling() { public boolean isSimulating() { return currentState == STATE_SIMULATING; } + public boolean didLastCompileFailed() { + return getCompilerLog().getErrorCount() > 0; + } //endregion private void enterState(int id, boolean force) { @@ -161,6 +178,7 @@ private void enterState(int id, boolean force) { states[currentState].onStateEntered(oldState); LOGGER.info("State transition: " + oldState + " -> " + currentState); + editor.markDirty(); } private void enterStateAndSend(int id) { @@ -187,6 +205,8 @@ public interface StateMachineCallback { void onCompileComplete(); + void onCompileFailed(); + void onSimulationComplete(int changeMask, ICSimulationContainer container); } @@ -229,12 +249,7 @@ public boolean canTransitionTo(int id) { @Override public void onStateEntered(int previousStateId) { - compilerLog.clear(); - } - - @Override - public void onClientStateEntered(int previousStateId) { - compilerLog.clear(); + compilerLog.clearAndSend(); } } @@ -271,7 +286,12 @@ public void onTick(long time) { } if (!assembler.isDone()) { - assembler.stepIn(); + long nanoTime = System.nanoTime(); + long elapsedTime; + do { + assembler.stepIn(); + elapsedTime = System.nanoTime() - nanoTime; + } while (elapsedTime < 500000L && !assembler.isDone()); // Use up to 0.5ms to compile } if (assembler.isDone()) { @@ -279,8 +299,14 @@ public void onTick(long time) { assembler = null; //TODO make assemblers clearable lastCompiledFlatMap = PRFabricationEngine.instance.serializeFlatMap(map); simulationContainer.setFlatMap(map); - enterStateAndSend(STATE_SIMULATING); - if (callback != null) callback.onCompileComplete(); + + if (compilerLog.getErrorCount() > 0) { + enterStateAndSend(STATE_COMPILE_FAILED); + if (callback != null) callback.onCompileFailed(); + } else { + enterStateAndSend(STATE_SIMULATING); + if (callback != null) callback.onCompileComplete(); + } } } @@ -291,7 +317,7 @@ public void onTileMapChanged() { @Override public boolean canTransitionTo(int id) { - return id == STATE_SIMULATING; + return id == STATE_SIMULATING || id == STATE_COMPILE_FAILED; } @Override @@ -304,18 +330,45 @@ public void onStateLeaving(int nextStateId) { assembler = null; } - @Override - public void onClientStateEntered(int previousStateId) { - compilerLog.clear(); - } - private void restartAssembly() { assembler = PRFabricationEngine.instance.newStepThroughAssembler(); assembler.setEventReceiver(compilerLog); - compilerLog.clear(); + compilerLog.clearAndSend(); assembler.addTileMap(editor.getTileMap(), Collections.emptyMap()); if (callback != null) callback.onCompileStart(); + + // Check for problems detectable before compilation + + int ioMask = 0; // 2 bits per side, 0x1 = input, 0x2 = output, lookup with 0x3 << side*2 + Collection ioTiles = editor.getTileMap().getIOTiles(); + for (var io : ioTiles) { + int s = io.getIOSide(); + int m = io.isInputIOMode() ? 0x1 : 0x2; + ioMask |= m << s*2; + } + + // Check for sides marked as both input and output + for (int r = 0; r < 4; r++) { + int m = ioMask >> r*2 & 0x3; + if (m == 0x3) { + int finalR = r; + List coordList = ioTiles.stream() + .filter(io -> io.getIOSide() == finalR) + .map(io -> ((BaseTile)io).getPos()) + .toList(); + + compilerLog.addProblem(new IODirectionMismatchError(coordList)); + } + } + + if ((ioMask & 0x55) == 0) { + compilerLog.addProblem(new NoInputsError()); + } + + if ((ioMask & 0xAA) == 0) { + compilerLog.addProblem(new NoOutputsError()); + } } } @@ -376,4 +429,17 @@ public void onStateEntered(int previousStateId) { lastTime = -1; } } + + private class CompileFailed implements State { + + @Override + public boolean canTransitionTo(int id) { + return id == STATE_AWAITING_COMPILE; + } + + @Override + public void onTileMapChanged() { + enterStateAndSend(STATE_AWAITING_COMPILE); + } + } } diff --git a/fabrication/src/main/java/mrtjp/projectred/fabrication/editor/ICWorkbenchEditor.java b/fabrication/src/main/java/mrtjp/projectred/fabrication/editor/ICWorkbenchEditor.java index c164bb136..e860b50fc 100644 --- a/fabrication/src/main/java/mrtjp/projectred/fabrication/editor/ICWorkbenchEditor.java +++ b/fabrication/src/main/java/mrtjp/projectred/fabrication/editor/ICWorkbenchEditor.java @@ -8,7 +8,10 @@ import mrtjp.projectred.fabrication.engine.BaseTileMap; import mrtjp.projectred.fabrication.engine.ICSimulationContainer; import mrtjp.projectred.fabrication.engine.ICTileType; +import net.minecraft.ChatFormatting; import net.minecraft.nbt.CompoundTag; +import net.minecraft.network.chat.Style; +import net.minecraft.resources.ResourceLocation; import javax.annotation.Nullable; import java.util.*; @@ -18,6 +21,12 @@ public class ICWorkbenchEditor implements ICEditorStateMachine.StateMachineCallback { + public static final Style UNIFORM = Style.EMPTY.withFont(new ResourceLocation("minecraft", "uniform")); + public static final Style UNIFORM_DARK_GRAY = UNIFORM.withColor(ChatFormatting.DARK_GRAY); + public static final Style UNIFORM_GRAY = UNIFORM.withColor(ChatFormatting.GRAY); + public static final Style UNIFORM_RED = UNIFORM.withColor(ChatFormatting.RED); + public static final Style UNIFORM_YELLOW = UNIFORM.withColor(ChatFormatting.YELLOW); + public static final int EDITOR_FORMAT = 1; private static final int STREAM_ID_GENERAL = 0; @@ -286,6 +295,10 @@ public void markTileChange() { network.markSave(); stateMachine.onTileMapChanged(); } + + public void markDirty() { + network.markSave(); + } //endregion //region Client Utils @@ -306,6 +319,11 @@ public void onCompileComplete() { LOGGER.info("Compilation complete"); } + @Override + public void onCompileFailed() { + LOGGER.info("Compilation failed"); + } + @Override public void onSimulationComplete(int changeMask, ICSimulationContainer container) { for (BaseTileMap.BaseTileEntry entry : tileMap.getBaseTileEntries()) { diff --git a/fabrication/src/main/java/mrtjp/projectred/fabrication/engine/BaseTileMap.java b/fabrication/src/main/java/mrtjp/projectred/fabrication/engine/BaseTileMap.java index 876acb197..df02b61b2 100644 --- a/fabrication/src/main/java/mrtjp/projectred/fabrication/engine/BaseTileMap.java +++ b/fabrication/src/main/java/mrtjp/projectred/fabrication/engine/BaseTileMap.java @@ -101,6 +101,10 @@ public Collection getTilesOnLayer(int y) { .collect(Collectors.toList()); } + public Collection getIOTiles() { + return ioTiles; + } + public void removeAll() { ioTiles.clear(); diff --git a/fabrication/src/main/java/mrtjp/projectred/fabrication/engine/gates/SidedRedstoneGateTile.java b/fabrication/src/main/java/mrtjp/projectred/fabrication/engine/gates/SidedRedstoneGateTile.java index 9b352c718..e0dd87d51 100644 --- a/fabrication/src/main/java/mrtjp/projectred/fabrication/engine/gates/SidedRedstoneGateTile.java +++ b/fabrication/src/main/java/mrtjp/projectred/fabrication/engine/gates/SidedRedstoneGateTile.java @@ -5,6 +5,8 @@ import mrtjp.fengine.simulate.ByteRegister; import mrtjp.projectred.fabrication.engine.ICSimulationContainer; import mrtjp.projectred.fabrication.engine.IRotatableICTile; +import mrtjp.projectred.fabrication.engine.log.DeadGateWarning; +import mrtjp.projectred.fabrication.engine.log.MultipleDriversError; import net.minecraft.nbt.CompoundTag; import java.util.Arrays; @@ -90,11 +92,19 @@ public void allocate(Allocator allocator) { @Override public void locate(IPathFinder pathFinder) { + int req = 0; + int found = 0; for (int r = 0; r < 4; r++) { if (canInputRedstone(r)) { + req++; inputRegisters[r] = searchInputRegister(r, pathFinder); + if (inputRegisters[r] != REG_ZERO) found++; } } + + if (req > 0 && found == 0) { + getEditor().getStateMachine().getCompilerLog().addProblem(new DeadGateWarning(getPos())); + } } @Override @@ -146,8 +156,7 @@ private int searchInputRegister(int r, IPathFinder pathFinder) { int absDir = IRotatableICTile.rotationToDir(absR); PathFinderResult pfr = pathFinder.doPathFinding((d, p) -> d == absDir); if (pfr.outputRegisters.size() > 1) { - // TODO log this somewhere - System.out.println("ERR: Unexpected multiple drivers: " + pfr.outputRegisters); + getEditor().getStateMachine().getCompilerLog().addProblem(new MultipleDriversError(getPos(), pfr.outputRegisters)); } if (!pfr.outputRegisters.isEmpty()) { return pfr.outputRegisters.get(0); diff --git a/fabrication/src/main/java/mrtjp/projectred/fabrication/engine/log/CompileProblem.java b/fabrication/src/main/java/mrtjp/projectred/fabrication/engine/log/CompileProblem.java new file mode 100644 index 000000000..ac9387e1d --- /dev/null +++ b/fabrication/src/main/java/mrtjp/projectred/fabrication/engine/log/CompileProblem.java @@ -0,0 +1,44 @@ +package mrtjp.projectred.fabrication.engine.log; + +import codechicken.lib.data.MCDataInput; +import codechicken.lib.data.MCDataOutput; +import codechicken.lib.render.CCRenderState; +import codechicken.lib.vec.Vector3; +import com.mojang.blaze3d.vertex.PoseStack; +import mrtjp.fengine.TileCoord; +import mrtjp.projectred.fabrication.gui.ICRenderNode; +import net.minecraft.client.renderer.MultiBufferSource; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.network.chat.Component; +import net.minecraftforge.api.distmarker.Dist; +import net.minecraftforge.api.distmarker.OnlyIn; + +import java.util.List; + +public abstract class CompileProblem { + + public final CompileProblemType type; + public final CompileProblemSeverity severity; + + public CompileProblem(CompileProblemType type, CompileProblemSeverity severity) { + this.type = type; + this.severity = severity; + } + + public abstract void save(CompoundTag tag); + + public abstract void load(CompoundTag tag); + + public abstract void writeDesc(MCDataOutput out); + + public abstract void readDesc(MCDataInput in); + + public abstract Component getName(); + + public abstract void buildToolTip(List tooltip, TileCoord hoverPosition); + + public abstract void buildToolTip(List tooltip); + + @OnlyIn(Dist.CLIENT) + public abstract void renderOverlay(Vector3 mousePosition, CCRenderState ccrs, MultiBufferSource getter, PoseStack matrixStack); +} diff --git a/fabrication/src/main/java/mrtjp/projectred/fabrication/engine/log/CompileProblemSeverity.java b/fabrication/src/main/java/mrtjp/projectred/fabrication/engine/log/CompileProblemSeverity.java new file mode 100644 index 000000000..b8730c4f5 --- /dev/null +++ b/fabrication/src/main/java/mrtjp/projectred/fabrication/engine/log/CompileProblemSeverity.java @@ -0,0 +1,6 @@ +package mrtjp.projectred.fabrication.engine.log; + +public enum CompileProblemSeverity { + ERROR, + WARNING +} diff --git a/fabrication/src/main/java/mrtjp/projectred/fabrication/engine/log/CompileProblemType.java b/fabrication/src/main/java/mrtjp/projectred/fabrication/engine/log/CompileProblemType.java new file mode 100644 index 000000000..4dc79ed14 --- /dev/null +++ b/fabrication/src/main/java/mrtjp/projectred/fabrication/engine/log/CompileProblemType.java @@ -0,0 +1,33 @@ +package mrtjp.projectred.fabrication.engine.log; + +import java.util.function.Supplier; + +public enum CompileProblemType { + MULTIPLE_DRIVERS(MultipleDriversError::new), + DEAD_WIRE(DeadWireWarning::new), + DEAD_GATE(DeadGateWarning::new), + IO_DIR_MISMATCH(IODirectionMismatchError::new), + NO_INPUTS(NoInputsError::new), + NO_OUTPUTS(NoOutputsError::new), + ; + + public static final CompileProblemType[] VALUES = values(); + + private final Supplier issueSupplier; + + CompileProblemType(Supplier issueSupplier) { + this.issueSupplier = issueSupplier; + } + + public CompileProblem newInstance() { + return issueSupplier.get(); + } + + public int getID() { + return ordinal(); + } + + public static CompileProblem createById(int type) { + return VALUES[type].newInstance(); + } +} diff --git a/fabrication/src/main/java/mrtjp/projectred/fabrication/engine/log/DeadGateWarning.java b/fabrication/src/main/java/mrtjp/projectred/fabrication/engine/log/DeadGateWarning.java new file mode 100644 index 000000000..4451ca4c3 --- /dev/null +++ b/fabrication/src/main/java/mrtjp/projectred/fabrication/engine/log/DeadGateWarning.java @@ -0,0 +1,33 @@ +package mrtjp.projectred.fabrication.engine.log; + +import mrtjp.fengine.TileCoord; +import mrtjp.projectred.fabrication.editor.ICWorkbenchEditor; +import net.minecraft.ChatFormatting; +import net.minecraft.network.chat.Component; +import net.minecraft.network.chat.TranslatableComponent; + +import java.util.List; + +import static mrtjp.projectred.fabrication.init.FabricationUnlocal.UL_DEAD_GATE_DESC; +import static mrtjp.projectred.fabrication.init.FabricationUnlocal.UL_DEAD_GATE_TITLE; + +public class DeadGateWarning extends SimpleLocatableProblem { + + public DeadGateWarning() { + super(CompileProblemType.DEAD_GATE, CompileProblemSeverity.WARNING); + } + + public DeadGateWarning(TileCoord coord) { + super(CompileProblemType.DEAD_GATE, CompileProblemSeverity.WARNING, coord); + } + + @Override + public Component getName() { + return new TranslatableComponent(UL_DEAD_GATE_TITLE); + } + + @Override + public void buildToolTip(List tooltip) { + tooltip.add(new TranslatableComponent(UL_DEAD_GATE_DESC).withStyle(ICWorkbenchEditor.UNIFORM_GRAY)); + } +} diff --git a/fabrication/src/main/java/mrtjp/projectred/fabrication/engine/log/DeadWireWarning.java b/fabrication/src/main/java/mrtjp/projectred/fabrication/engine/log/DeadWireWarning.java new file mode 100644 index 000000000..6ad09807b --- /dev/null +++ b/fabrication/src/main/java/mrtjp/projectred/fabrication/engine/log/DeadWireWarning.java @@ -0,0 +1,34 @@ +package mrtjp.projectred.fabrication.engine.log; + +import mrtjp.fengine.TileCoord; +import mrtjp.projectred.fabrication.editor.ICWorkbenchEditor; +import net.minecraft.ChatFormatting; +import net.minecraft.network.chat.Component; +import net.minecraft.network.chat.TextComponent; +import net.minecraft.network.chat.TranslatableComponent; + +import java.util.List; + +import static mrtjp.projectred.fabrication.init.FabricationUnlocal.UL_DEAD_WIRE_DESC; +import static mrtjp.projectred.fabrication.init.FabricationUnlocal.UL_DEAD_WIRE_TITLE; + +public class DeadWireWarning extends SimpleLocatableProblem { + + public DeadWireWarning() { + super(CompileProblemType.DEAD_WIRE, CompileProblemSeverity.WARNING); + } + + public DeadWireWarning(TileCoord coord) { + super(CompileProblemType.DEAD_WIRE, CompileProblemSeverity.WARNING, coord); + } + + @Override + public Component getName() { + return new TranslatableComponent(UL_DEAD_WIRE_TITLE); + } + + @Override + public void buildToolTip(List tooltip) { + tooltip.add(new TranslatableComponent(UL_DEAD_WIRE_DESC).withStyle(ICWorkbenchEditor.UNIFORM_GRAY)); + } +} diff --git a/fabrication/src/main/java/mrtjp/projectred/fabrication/engine/ICCompilerLog.java b/fabrication/src/main/java/mrtjp/projectred/fabrication/engine/log/ICCompilerLog.java similarity index 80% rename from fabrication/src/main/java/mrtjp/projectred/fabrication/engine/ICCompilerLog.java rename to fabrication/src/main/java/mrtjp/projectred/fabrication/engine/log/ICCompilerLog.java index 44a415daf..b6c5dc7d2 100644 --- a/fabrication/src/main/java/mrtjp/projectred/fabrication/engine/ICCompilerLog.java +++ b/fabrication/src/main/java/mrtjp/projectred/fabrication/engine/log/ICCompilerLog.java @@ -1,4 +1,4 @@ -package mrtjp.projectred.fabrication.engine; +package mrtjp.projectred.fabrication.engine.log; import codechicken.lib.data.MCDataInput; import codechicken.lib.data.MCDataOutput; @@ -12,33 +12,57 @@ import java.util.*; import java.util.stream.Collectors; -import static mrtjp.projectred.fabrication.editor.ICEditorStateMachine.KEY_COMPILER_LOG_NODE_ADDED; -import static mrtjp.projectred.fabrication.editor.ICEditorStateMachine.KEY_COMPILER_LOG_NODE_EXECUTED; +import static mrtjp.projectred.fabrication.editor.EditorDataUtils.*; +import static mrtjp.projectred.fabrication.editor.ICEditorStateMachine.*; public class ICCompilerLog implements ICStepThroughAssembler.EventReceiver { private final ICEditorStateMachine stateMachine; + // Compile steps tracking private final CompileTree compileTree = new CompileTree(); - private final List currentPath = new LinkedList<>(); private int completedSteps = 0; //TODO ideally this would be a feature in the compile tree object + // Compile problems + private final List problems = new ArrayList<>(); + private int warningCount = 0; + private int errorCount = 0; + public ICCompilerLog(ICEditorStateMachine stateMachine) { this.stateMachine = stateMachine; } public void save(CompoundTag tag) { - tag.putInt("completed_steps", completedSteps); - tag.putIntArray("current_path", currentPath); + tag.putInt(KEY_COMPLETED_STEPS, completedSteps); + tag.putIntArray(KEY_CURRENT_PATH, currentPath); compileTree.save(tag); + + ListTag list = new ListTag(); + for (CompileProblem problem : problems) { + CompoundTag problemTag = new CompoundTag(); + problemTag.putByte("_type", (byte) problem.type.getID()); + problem.save(problemTag); + list.add(problemTag); + } + tag.put(KEY_PROBLEMS_LIST, list); + tag.putInt(KEY_WARNING_COUNT, warningCount); + tag.putInt(KEY_ERROR_COUNT, errorCount); } public void load(CompoundTag tag) { - completedSteps = tag.getInt("completed_steps"); + completedSteps = tag.getInt(KEY_COMPLETED_STEPS); currentPath.clear(); - currentPath.addAll(Arrays.stream(tag.getIntArray("current_path")).boxed().collect(Collectors.toList())); + currentPath.addAll(Arrays.stream(tag.getIntArray(KEY_CURRENT_PATH)).boxed().toList()); compileTree.load(tag); + + ListTag list = tag.getList(KEY_PROBLEMS_LIST, 10); + for (int i = 0; i < list.size(); i++) { + CompoundTag problemTag = list.getCompound(i); + CompileProblem problem = CompileProblemType.createById(problemTag.getByte("_type") & 0xFF); + problem.load(problemTag); + addProblemInternal(problem); + } } public void writeDesc(MCDataOutput out) { @@ -46,20 +70,56 @@ public void writeDesc(MCDataOutput out) { out.writeInt(completedSteps); out.writeInt(currentPath.size()); for (int i : currentPath) out.writeInt(i); + + out.writeVarInt(problems.size()); + for (CompileProblem problem : problems) { + out.writeByte(problem.type.getID()); + problem.writeDesc(out); + } } public void readDesc(MCDataInput in) { + clear(); compileTree.readDesc(in); completedSteps = in.readInt(); - currentPath.clear(); int size = in.readInt(); for (int i = 0; i < size; i++) currentPath.add(in.readInt()); + + size = in.readVarInt(); + for (int i = 0; i < size; i++) { + CompileProblem problem = CompileProblemType.createById(in.readUByte()); + problem.readDesc(in); + addProblemInternal(problem); + } } public void clear() { compileTree.clear(); currentPath.clear(); completedSteps = 0; + problems.clear(); + warningCount = 0; + errorCount = 0; + } + + public int getTotalSteps() { + return compileTree.size(); + } + + public int getCompletedSteps() { + return completedSteps; + } + + public List getProblems() { + return problems; + } + + public int getErrorCount() { + return errorCount; + } + + public int getWarningCount() { + return warningCount; } //region ICStepThroughAssembler.EventReceiver @@ -87,15 +147,33 @@ public void onStepExecuted(ICStepThroughAssembler.AssemblerStepResult result) { } //endregion + //region Compile-time logging + public void clearAndSend() { + clear(); + sendClear(); + } + + public void addProblem(CompileProblem problem) { + addProblemInternal(problem); + sendProblemAdded(problem); + } + //endregion + //region Packet handling public void readLogStream(MCDataInput in, int key) { switch (key) { + case KEY_COMPILER_LOG_CLEARED: + clear(); + break; case KEY_COMPILER_LOG_NODE_ADDED: readNodeAdded(in); break; case KEY_COMPILER_LOG_NODE_EXECUTED: readNodeExecuted(in); break; + case KEY_COMPILER_LOG_PROBLEM_ADDED: + readProblemAdded(in); + break; default: throw new IllegalArgumentException("Unknown compiler stream key: " + key); } @@ -103,6 +181,10 @@ public void readLogStream(MCDataInput in, int key) { //endregion //region Server-side utilities + private void sendClear() { + stateMachine.getStateMachineStream(KEY_COMPILER_LOG_CLEARED); + } + private void sendNodeAdded(CompileTreeNode node, List treePath) { MCDataOutput out = stateMachine.getStateMachineStream(KEY_COMPILER_LOG_NODE_ADDED); out.writeByte(treePath.size()); @@ -120,6 +202,20 @@ private void sendNodeExecuted(CompileTreeNode node, List treePath) { } node.write(out); } + + private void sendProblemAdded(CompileProblem problem) { + MCDataOutput out = stateMachine.getStateMachineStream(KEY_COMPILER_LOG_PROBLEM_ADDED); + out.writeByte(problem.type.ordinal()); + problem.writeDesc(out); + } + + private void addProblemInternal(CompileProblem problem) { + problems.add(problem); + switch (problem.severity) { + case WARNING -> warningCount++; + case ERROR -> errorCount++; + } + } //endregion //region Client-side utilities @@ -147,6 +243,12 @@ private void readNodeExecuted(MCDataInput in) { completedSteps++; } + private void readProblemAdded(MCDataInput in) { + CompileProblem problem = CompileProblemType.createById(in.readUByte()); + problem.readDesc(in); + addProblemInternal(problem); + } + public List getCurrentStack() { return compileTree.getStack(currentPath); } diff --git a/fabrication/src/main/java/mrtjp/projectred/fabrication/engine/log/IODirectionMismatchError.java b/fabrication/src/main/java/mrtjp/projectred/fabrication/engine/log/IODirectionMismatchError.java new file mode 100644 index 000000000..26be91d2d --- /dev/null +++ b/fabrication/src/main/java/mrtjp/projectred/fabrication/engine/log/IODirectionMismatchError.java @@ -0,0 +1,33 @@ +package mrtjp.projectred.fabrication.engine.log; + +import mrtjp.fengine.TileCoord; +import net.minecraft.network.chat.Component; +import net.minecraft.network.chat.TranslatableComponent; + +import java.util.Collection; +import java.util.List; + +import static mrtjp.projectred.fabrication.editor.ICWorkbenchEditor.UNIFORM_GRAY; +import static mrtjp.projectred.fabrication.init.FabricationUnlocal.UL_IO_DIR_MISMATCH_DESC; +import static mrtjp.projectred.fabrication.init.FabricationUnlocal.UL_IO_DIR_MISMATCH_TITLE; + +public class IODirectionMismatchError extends MultiPositionProblem { + + public IODirectionMismatchError(Collection coordList) { + super(CompileProblemType.IO_DIR_MISMATCH, CompileProblemSeverity.ERROR, coordList); + } + + public IODirectionMismatchError() { + super(CompileProblemType.IO_DIR_MISMATCH, CompileProblemSeverity.ERROR); + } + + @Override + public Component getName() { + return new TranslatableComponent(UL_IO_DIR_MISMATCH_TITLE); + } + + @Override + public void buildToolTip(List tooltip) { + tooltip.add(new TranslatableComponent(UL_IO_DIR_MISMATCH_DESC).withStyle(UNIFORM_GRAY)); + } +} diff --git a/fabrication/src/main/java/mrtjp/projectred/fabrication/engine/log/MultiPositionProblem.java b/fabrication/src/main/java/mrtjp/projectred/fabrication/engine/log/MultiPositionProblem.java new file mode 100644 index 000000000..87de47b58 --- /dev/null +++ b/fabrication/src/main/java/mrtjp/projectred/fabrication/engine/log/MultiPositionProblem.java @@ -0,0 +1,79 @@ +package mrtjp.projectred.fabrication.engine.log; + +import codechicken.lib.colour.EnumColour; +import codechicken.lib.data.MCDataInput; +import codechicken.lib.data.MCDataOutput; +import codechicken.lib.render.CCRenderState; +import codechicken.lib.vec.Vector3; +import com.mojang.blaze3d.vertex.PoseStack; +import mrtjp.fengine.TileCoord; +import mrtjp.projectred.fabrication.editor.EditorDataUtils; +import mrtjp.projectred.fabrication.gui.ICRenderTypes; +import net.minecraft.client.renderer.MultiBufferSource; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.network.chat.Component; + +import java.util.Collection; +import java.util.LinkedList; +import java.util.List; + +import static mrtjp.projectred.fabrication.engine.log.CompileProblemSeverity.ERROR; + +public abstract class MultiPositionProblem extends CompileProblem { + + public final List coordList = new LinkedList<>(); + + public MultiPositionProblem(CompileProblemType type, CompileProblemSeverity severity) { + super(type, severity); + } + + public MultiPositionProblem(CompileProblemType type, CompileProblemSeverity severity, Collection coordList) { + this(type, severity); + this.coordList.addAll(coordList); + } + + @Override + public void save(CompoundTag tag) { + EditorDataUtils.saveTileCoordList(tag, "coordList", coordList); + } + + @Override + public void load(CompoundTag tag) { + coordList.clear(); + EditorDataUtils.loadTileCoordList(tag, "coordList", coordList); + } + + @Override + public void writeDesc(MCDataOutput out) { + out.writeShort(coordList.size()); + for (TileCoord coord : coordList) { + out.writeByte(coord.x).writeByte(coord.y).writeByte(coord.z); + } + } + + @Override + public void readDesc(MCDataInput in) { + coordList.clear(); + int size = in.readUShort(); + for (int i = 0; i < size; i++) { + coordList.add(new TileCoord(in.readByte(), in.readByte(), in.readByte())); + } + } + + @Override + public void buildToolTip(List tooltip, TileCoord hoverPosition) { + if (coordList.contains(hoverPosition)) { + buildToolTip(tooltip); + } + } + + @Override + public void renderOverlay(Vector3 mousePosition, CCRenderState ccrs, MultiBufferSource getter, PoseStack matrixStack) { + ccrs.baseColour = severity == ERROR ? EnumColour.RED.rgba(200) : EnumColour.YELLOW.rgba(200); + Vector3 vec = new Vector3(); + for (TileCoord coord : coordList) { + vec.set(coord.x, coord.y, coord.z).add(0.5); + ICRenderTypes.renderSelection(ccrs, vec, vec, 3 / 16D, 2 / 16D); + } + } +} diff --git a/fabrication/src/main/java/mrtjp/projectred/fabrication/engine/log/MultipleDriversError.java b/fabrication/src/main/java/mrtjp/projectred/fabrication/engine/log/MultipleDriversError.java new file mode 100644 index 000000000..467050440 --- /dev/null +++ b/fabrication/src/main/java/mrtjp/projectred/fabrication/engine/log/MultipleDriversError.java @@ -0,0 +1,108 @@ +package mrtjp.projectred.fabrication.engine.log; + +import codechicken.lib.colour.EnumColour; +import codechicken.lib.data.MCDataInput; +import codechicken.lib.data.MCDataOutput; +import codechicken.lib.render.CCRenderState; +import codechicken.lib.vec.Vector3; +import com.mojang.blaze3d.vertex.PoseStack; +import mrtjp.fengine.TileCoord; +import mrtjp.projectred.fabrication.editor.EditorDataUtils; +import mrtjp.projectred.fabrication.editor.ICWorkbenchEditor; +import mrtjp.projectred.fabrication.gui.ICRenderTypes; +import net.minecraft.ChatFormatting; +import net.minecraft.client.renderer.MultiBufferSource; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.network.chat.Component; +import net.minecraft.network.chat.TextComponent; +import net.minecraft.network.chat.TranslatableComponent; + +import java.util.ArrayList; +import java.util.List; + +import static mrtjp.projectred.fabrication.editor.ICWorkbenchEditor.UNIFORM_GRAY; +import static mrtjp.projectred.fabrication.engine.log.CompileProblemSeverity.ERROR; +import static mrtjp.projectred.fabrication.init.FabricationUnlocal.UL_MULTIPLE_DRIVERS_DESC; +import static mrtjp.projectred.fabrication.init.FabricationUnlocal.UL_MULTIPLE_DRIVERS_TITLE; + +public class MultipleDriversError extends CompileProblem { + + public TileCoord coord; + public final List registerList = new ArrayList<>(); + + public MultipleDriversError() { + super(CompileProblemType.MULTIPLE_DRIVERS, CompileProblemSeverity.ERROR); + } + + public MultipleDriversError(TileCoord coord, List registerList) { + super(CompileProblemType.MULTIPLE_DRIVERS, CompileProblemSeverity.ERROR); + this.coord = coord; + this.registerList.addAll(registerList); + } + + @Override + public void save(CompoundTag tag) { + tag.put("coord", EditorDataUtils.tileCoordToNBT(coord)); + tag.putIntArray("registers", registerList.stream().mapToInt(i -> i).toArray()); + } + + @Override + public void load(CompoundTag tag) { + coord = EditorDataUtils.tileCoordFromNBT(tag.getCompound("coord")); + registerList.clear(); + for (int i : tag.getIntArray("registers")) { + registerList.add(i); + } + } + + @Override + public void writeDesc(MCDataOutput out) { + out.writeByte(coord.x).writeByte(coord.y).writeByte(coord.z); + out.writeShort(registerList.size()); + for (int i : registerList) { + out.writeVarInt(i); + } + } + + @Override + public void readDesc(MCDataInput in) { + coord = new TileCoord(in.readByte(), in.readByte(), in.readByte()); + registerList.clear(); + int size = in.readUShort(); + for (int i = 0; i < size; i++) { + registerList.add(in.readVarInt()); + } + } + + @Override + public Component getName() { + return new TranslatableComponent(UL_MULTIPLE_DRIVERS_TITLE); + } + + @Override + public void buildToolTip(List tooltip, TileCoord hoverPosition) { + if (coord.equals(hoverPosition)) { + buildToolTip(tooltip); + } + } + + @Override + public void buildToolTip(List tooltip) { + tooltip.add(new TranslatableComponent(UL_MULTIPLE_DRIVERS_DESC).withStyle(UNIFORM_GRAY)); + + StringBuilder s = new StringBuilder(); + for (int r : registerList) { + s.append("R").append(r).append(", "); + } + s.delete(s.length() - 2, s.length()); // remove trailing comma + tooltip.add(new TextComponent(" ").withStyle(UNIFORM_GRAY).append( + new TextComponent(s.toString()).withStyle(UNIFORM_GRAY))); + } + + @Override + public void renderOverlay(Vector3 mousePosition, CCRenderState ccrs, MultiBufferSource getter, PoseStack matrixStack) { + ccrs.baseColour = severity == ERROR ? EnumColour.RED.rgba(200) : EnumColour.YELLOW.rgba(200); + Vector3 vec = new Vector3(coord.x, coord.y, coord.z).add(0.5); + ICRenderTypes.renderSelection(ccrs, vec, vec, 3 / 16D, 2 / 16D); + } +} diff --git a/fabrication/src/main/java/mrtjp/projectred/fabrication/engine/log/NoInputsError.java b/fabrication/src/main/java/mrtjp/projectred/fabrication/engine/log/NoInputsError.java new file mode 100644 index 000000000..e36736876 --- /dev/null +++ b/fabrication/src/main/java/mrtjp/projectred/fabrication/engine/log/NoInputsError.java @@ -0,0 +1,61 @@ +package mrtjp.projectred.fabrication.engine.log; + +import codechicken.lib.data.MCDataInput; +import codechicken.lib.data.MCDataOutput; +import codechicken.lib.render.CCRenderState; +import codechicken.lib.vec.Vector3; +import com.mojang.blaze3d.vertex.PoseStack; +import mrtjp.fengine.TileCoord; +import net.minecraft.client.renderer.MultiBufferSource; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.network.chat.Component; +import net.minecraft.network.chat.TranslatableComponent; + +import java.util.List; + +import static mrtjp.projectred.fabrication.editor.ICWorkbenchEditor.UNIFORM_GRAY; +import static mrtjp.projectred.fabrication.init.FabricationUnlocal.UL_NO_INPUTS_DESC; +import static mrtjp.projectred.fabrication.init.FabricationUnlocal.UL_NO_INPUTS_TITLE; + +public class NoInputsError extends CompileProblem { + + public NoInputsError() { + super(CompileProblemType.NO_INPUTS, CompileProblemSeverity.ERROR); + } + + @Override + public void save(CompoundTag tag) { + } + + @Override + public void load(CompoundTag tag) { + } + + @Override + public void writeDesc(MCDataOutput out) { + } + + @Override + public void readDesc(MCDataInput in) { + } + + @Override + public Component getName() { + return new TranslatableComponent(UL_NO_INPUTS_TITLE); + } + + @Override + public void buildToolTip(List tooltip, TileCoord hoverPosition) { + + } + + @Override + public void buildToolTip(List tooltip) { + tooltip.add(new TranslatableComponent(UL_NO_INPUTS_DESC).withStyle(UNIFORM_GRAY)); + } + + @Override + public void renderOverlay(Vector3 mousePosition, CCRenderState ccrs, MultiBufferSource getter, PoseStack matrixStack) { + + } +} diff --git a/fabrication/src/main/java/mrtjp/projectred/fabrication/engine/log/NoOutputsError.java b/fabrication/src/main/java/mrtjp/projectred/fabrication/engine/log/NoOutputsError.java new file mode 100644 index 000000000..41b3ed6f9 --- /dev/null +++ b/fabrication/src/main/java/mrtjp/projectred/fabrication/engine/log/NoOutputsError.java @@ -0,0 +1,61 @@ +package mrtjp.projectred.fabrication.engine.log; + +import codechicken.lib.data.MCDataInput; +import codechicken.lib.data.MCDataOutput; +import codechicken.lib.render.CCRenderState; +import codechicken.lib.vec.Vector3; +import com.mojang.blaze3d.vertex.PoseStack; +import mrtjp.fengine.TileCoord; +import mrtjp.projectred.fabrication.editor.ICWorkbenchEditor; +import net.minecraft.client.renderer.MultiBufferSource; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.network.chat.Component; +import net.minecraft.network.chat.TranslatableComponent; + +import java.util.List; + +import static mrtjp.projectred.fabrication.editor.ICWorkbenchEditor.UNIFORM_GRAY; +import static mrtjp.projectred.fabrication.init.FabricationUnlocal.*; + +public class NoOutputsError extends CompileProblem { + + public NoOutputsError() { + super(CompileProblemType.NO_OUTPUTS, CompileProblemSeverity.ERROR); + } + + @Override + public void save(CompoundTag tag) { + } + + @Override + public void load(CompoundTag tag) { + } + + @Override + public void writeDesc(MCDataOutput out) { + } + + @Override + public void readDesc(MCDataInput in) { + } + + @Override + public Component getName() { + return new TranslatableComponent(UL_NO_OUTPUTS_TITLE); + } + + @Override + public void buildToolTip(List tooltip, TileCoord hoverPosition) { + + } + + @Override + public void buildToolTip(List tooltip) { + tooltip.add(new TranslatableComponent(UL_NO_OUTPUTS_DESC).withStyle(UNIFORM_GRAY)); + } + + @Override + public void renderOverlay(Vector3 mousePosition, CCRenderState ccrs, MultiBufferSource getter, PoseStack matrixStack) { + + } +} diff --git a/fabrication/src/main/java/mrtjp/projectred/fabrication/engine/log/SimpleLocatableProblem.java b/fabrication/src/main/java/mrtjp/projectred/fabrication/engine/log/SimpleLocatableProblem.java new file mode 100644 index 000000000..60db2f7b1 --- /dev/null +++ b/fabrication/src/main/java/mrtjp/projectred/fabrication/engine/log/SimpleLocatableProblem.java @@ -0,0 +1,66 @@ +package mrtjp.projectred.fabrication.engine.log; + +import codechicken.lib.colour.EnumColour; +import codechicken.lib.data.MCDataInput; +import codechicken.lib.data.MCDataOutput; +import codechicken.lib.render.CCRenderState; +import codechicken.lib.vec.Vector3; +import com.mojang.blaze3d.vertex.PoseStack; +import mrtjp.fengine.TileCoord; +import mrtjp.projectred.fabrication.editor.EditorDataUtils; +import mrtjp.projectred.fabrication.gui.ICRenderTypes; +import net.minecraft.client.renderer.MultiBufferSource; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.network.chat.Component; + +import java.util.List; + +import static mrtjp.projectred.fabrication.engine.log.CompileProblemSeverity.ERROR; + +public abstract class SimpleLocatableProblem extends CompileProblem { + + public TileCoord coord; + + public SimpleLocatableProblem(CompileProblemType type, CompileProblemSeverity severity) { + super(type, severity); + } + + public SimpleLocatableProblem(CompileProblemType type, CompileProblemSeverity severity, TileCoord coord) { + this(type, severity); + this.coord = coord; + } + + @Override + public void save(CompoundTag tag) { + tag.put("coord", EditorDataUtils.tileCoordToNBT(coord)); + } + + @Override + public void load(CompoundTag tag) { + coord = EditorDataUtils.tileCoordFromNBT(tag.getCompound("coord")); + } + + @Override + public void writeDesc(MCDataOutput out) { + out.writeByte(coord.x).writeByte(coord.y).writeByte(coord.z); + } + + @Override + public void readDesc(MCDataInput in) { + coord = new TileCoord(in.readByte(), in.readByte(), in.readByte()); + } + + @Override + public void buildToolTip(List tooltip, TileCoord hoverPosition) { + if (coord.equals(hoverPosition)) { + buildToolTip(tooltip); + } + } + + @Override + public void renderOverlay(Vector3 mousePosition, CCRenderState ccrs, MultiBufferSource getter, PoseStack matrixStack) { + ccrs.baseColour = severity == ERROR ? EnumColour.RED.rgba(200) : EnumColour.YELLOW.rgba(200); + Vector3 vec = new Vector3(coord.x, coord.y, coord.z).add(0.5); + ICRenderTypes.renderSelection(ccrs, vec, vec, 3 / 16D, 2 / 16D); + } +} diff --git a/fabrication/src/main/java/mrtjp/projectred/fabrication/engine/wires/RedstoneWireTile.java b/fabrication/src/main/java/mrtjp/projectred/fabrication/engine/wires/RedstoneWireTile.java index 9cbf30787..dbd88a16f 100644 --- a/fabrication/src/main/java/mrtjp/projectred/fabrication/engine/wires/RedstoneWireTile.java +++ b/fabrication/src/main/java/mrtjp/projectred/fabrication/engine/wires/RedstoneWireTile.java @@ -7,6 +7,7 @@ import mrtjp.projectred.fabrication.engine.ICTileType; import mrtjp.projectred.fabrication.engine.IConnectableICTile; import mrtjp.projectred.fabrication.engine.IRedstoneConnectableICTile; +import mrtjp.projectred.fabrication.engine.log.DeadWireWarning; import mrtjp.projectred.transmission.WireType; import net.minecraft.nbt.CompoundTag; @@ -98,6 +99,10 @@ public void onSimRegistersChanged(int rMask, ICSimulationContainer container) { public void searchManifest(IPathFinderManifest manifest) { inputRegisters.clear(); inputRegisters.addAll(manifest.getOutputRegisters()); + + if (inputRegisters.isEmpty()) { + getEditor().getStateMachine().getCompilerLog().addProblem(new DeadWireWarning(getPos())); + } } @Override diff --git a/fabrication/src/main/java/mrtjp/projectred/fabrication/gui/CTNListNode.java b/fabrication/src/main/java/mrtjp/projectred/fabrication/gui/CTNListNode.java index 2a161fcc5..700f8916c 100644 --- a/fabrication/src/main/java/mrtjp/projectred/fabrication/gui/CTNListNode.java +++ b/fabrication/src/main/java/mrtjp/projectred/fabrication/gui/CTNListNode.java @@ -2,7 +2,7 @@ import com.mojang.blaze3d.systems.RenderSystem; import com.mojang.blaze3d.vertex.PoseStack; -import mrtjp.projectred.fabrication.engine.ICCompilerLog.CompileTreeNode; +import mrtjp.projectred.fabrication.engine.log.ICCompilerLog.CompileTreeNode; import mrtjp.projectred.fabrication.gui.screen.ICWorkbenchCompileTab; import mrtjp.projectred.lib.Point; import mrtjp.projectred.lib.Rect; diff --git a/fabrication/src/main/java/mrtjp/projectred/fabrication/gui/CompileProblemsTab.java b/fabrication/src/main/java/mrtjp/projectred/fabrication/gui/CompileProblemsTab.java index f95bf2e98..e63e1f686 100644 --- a/fabrication/src/main/java/mrtjp/projectred/fabrication/gui/CompileProblemsTab.java +++ b/fabrication/src/main/java/mrtjp/projectred/fabrication/gui/CompileProblemsTab.java @@ -2,9 +2,19 @@ import codechicken.lib.render.CCRenderState; import codechicken.lib.vec.Vector3; +import com.mojang.blaze3d.systems.RenderSystem; import com.mojang.blaze3d.vertex.PoseStack; +import mrtjp.fengine.TileCoord; import mrtjp.projectred.fabrication.editor.ICWorkbenchEditor; +import mrtjp.projectred.fabrication.editor.tools.IICEditorTool; +import mrtjp.projectred.fabrication.engine.log.CompileProblem; +import mrtjp.projectred.fabrication.gui.screen.ICWorkbenchCompileTab; +import mrtjp.projectred.lib.Point; +import mrtjp.projectred.lib.Rect; import mrtjp.projectred.redui.AbstractGuiNode; +import mrtjp.projectred.redui.ScrollBarNode; +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.GuiComponent; import net.minecraft.client.renderer.MultiBufferSource; import net.minecraft.network.chat.Component; @@ -13,6 +23,7 @@ public class CompileProblemsTab extends AbstractGuiNode implements ICompileOverlayRenderer { private final ICWorkbenchEditor editor; + private final ProblemListNode issueListNode = new ProblemListNode(); public CompileProblemsTab(ICWorkbenchEditor editor) { this.editor = editor; @@ -21,17 +32,70 @@ public CompileProblemsTab(ICWorkbenchEditor editor) { } private void initSubNodes() { + + // Stack + issueListNode.setPosition(6, 31); + issueListNode.setSize(67, 95); + addChild(issueListNode); + + // Scrollbar //TODO + ScrollBar scrollBar = new ScrollBar(); + scrollBar.setPosition(77, 31); + scrollBar.setZPosition(0.2); + scrollBar.setSize(8, 95); + scrollBar.setSliderSize(8, 16); + addChild(scrollBar); } - //region ICompileTabOverlayRenderer @Override + public void drawBack(PoseStack stack, Point mouse, float partialFrame) { + RenderSystem.setShaderTexture(0, ICWorkbenchCompileTab.TAB_BACKGROUND); + GuiComponent.blit(stack, getFrame().x(), getFrame().y(), 184, 223, getFrame().width(), getFrame().height(), 512, 512); + } + + @Override + public void update() { + if (!isHidden()) { + // TODO only do this when issue log changes + issueListNode.setProblemList(editor.getStateMachine().getCompilerLog().getProblems()); + } + } + + //region ICompileTabOverlayRenderer public void renderOverlay(ICRenderNode renderNode, Vector3 mousePosition, boolean isFirstHit, CCRenderState ccrs, MultiBufferSource getter, PoseStack matrixStack) { + ccrs.reset(); + ccrs.bind(ICRenderTypes.selectionRenderType, Minecraft.getInstance().renderBuffers().bufferSource(), matrixStack); + for (CompileProblem problem : editor.getStateMachine().getCompilerLog().getProblems()) { + problem.renderOverlay(mousePosition, ccrs, getter, matrixStack); + } } @Override public void buildTooltip(ICRenderNode renderNode, Vector3 mousePosition, List tooltip) { + TileCoord pos = IICEditorTool.toNearestPosition(mousePosition); + for (CompileProblem issue : editor.getStateMachine().getCompilerLog().getProblems()) { + issue.buildToolTip(tooltip, pos); + } } //endregion + + private class ScrollBar extends ScrollBarNode { + + public ScrollBar() { + super(ScrollAxis.VERTICAL); + } + + @Override + protected void drawSlider(PoseStack stack, Rect sliderFrame) { + RenderSystem.setShaderTexture(0, ICWorkbenchCompileTab.TAB_BACKGROUND); + GuiComponent.blit(stack, sliderFrame.x(), sliderFrame.y(), 305, 58, sliderFrame.width(), sliderFrame.height(), 512, 512); + } + + @Override + protected void adjustContent(double scrollPercentage) { + issueListNode.setScrollPercentage(scrollPercentage); + } + } } diff --git a/fabrication/src/main/java/mrtjp/projectred/fabrication/gui/CompileStackTab.java b/fabrication/src/main/java/mrtjp/projectred/fabrication/gui/CompileStackTab.java index 3002fae1e..d095abcf4 100644 --- a/fabrication/src/main/java/mrtjp/projectred/fabrication/gui/CompileStackTab.java +++ b/fabrication/src/main/java/mrtjp/projectred/fabrication/gui/CompileStackTab.java @@ -7,7 +7,7 @@ import com.mojang.blaze3d.vertex.PoseStack; import mrtjp.fengine.TileCoord; import mrtjp.projectred.fabrication.editor.ICWorkbenchEditor; -import mrtjp.projectred.fabrication.engine.ICCompilerLog; +import mrtjp.projectred.fabrication.engine.log.ICCompilerLog; import mrtjp.projectred.fabrication.gui.screen.ICWorkbenchCompileTab; import mrtjp.projectred.lib.Point; import mrtjp.projectred.lib.Rect; @@ -58,6 +58,7 @@ public void drawBack(PoseStack stack, Point mouse, float partialFrame) { @Override public void update() { if (!isHidden()) { + // TODO only do this when the stack changes List execStack = editor.getStateMachine().getCompilerLog().getCurrentStack(); ctnListNode.setNodeList(execStack); } diff --git a/fabrication/src/main/java/mrtjp/projectred/fabrication/gui/CompileTreeTab.java b/fabrication/src/main/java/mrtjp/projectred/fabrication/gui/CompileTreeTab.java index 644ea41f2..555cd1eef 100644 --- a/fabrication/src/main/java/mrtjp/projectred/fabrication/gui/CompileTreeTab.java +++ b/fabrication/src/main/java/mrtjp/projectred/fabrication/gui/CompileTreeTab.java @@ -2,9 +2,13 @@ import codechicken.lib.render.CCRenderState; import codechicken.lib.vec.Vector3; +import com.mojang.blaze3d.systems.RenderSystem; import com.mojang.blaze3d.vertex.PoseStack; import mrtjp.projectred.fabrication.editor.ICWorkbenchEditor; +import mrtjp.projectred.fabrication.gui.screen.ICWorkbenchCompileTab; +import mrtjp.projectred.lib.Point; import mrtjp.projectred.redui.AbstractGuiNode; +import net.minecraft.client.gui.GuiComponent; import net.minecraft.client.renderer.MultiBufferSource; import net.minecraft.network.chat.Component; @@ -23,6 +27,12 @@ public CompileTreeTab(ICWorkbenchEditor editor) { private void initSubNodes() { } + @Override + public void drawBack(PoseStack stack, Point mouse, float partialFrame) { + RenderSystem.setShaderTexture(0, ICWorkbenchCompileTab.TAB_BACKGROUND); + GuiComponent.blit(stack, getFrame().x(), getFrame().y(), 92, 223, getFrame().width(), getFrame().height(), 512, 512); + } + //region ICompileTabOverlayRenderer @Override public void renderOverlay(ICRenderNode renderNode, Vector3 mousePosition, boolean isFirstHit, CCRenderState ccrs, MultiBufferSource getter, PoseStack matrixStack) { diff --git a/fabrication/src/main/java/mrtjp/projectred/fabrication/gui/ProblemListNode.java b/fabrication/src/main/java/mrtjp/projectred/fabrication/gui/ProblemListNode.java new file mode 100644 index 000000000..0ab125ecd --- /dev/null +++ b/fabrication/src/main/java/mrtjp/projectred/fabrication/gui/ProblemListNode.java @@ -0,0 +1,118 @@ +package mrtjp.projectred.fabrication.gui; + +import com.mojang.blaze3d.systems.RenderSystem; +import com.mojang.blaze3d.vertex.PoseStack; +import mrtjp.projectred.fabrication.engine.log.CompileProblem; +import mrtjp.projectred.fabrication.gui.screen.ICWorkbenchCompileTab; +import mrtjp.projectred.lib.Point; +import mrtjp.projectred.lib.Rect; +import mrtjp.projectred.redui.AbstractGuiNode; +import net.minecraft.client.gui.GuiComponent; +import net.minecraft.network.chat.Component; + +import java.util.LinkedList; +import java.util.List; + +public class ProblemListNode extends AbstractGuiNode { + + private final List problemList = new LinkedList<>(); + + private final AbstractGuiNode listParent = new AbstractGuiNode() { + }; + + private double scroll = 0; + + public ProblemListNode() { + initSubNodes(); + } + + private void initSubNodes() { + addChild(listParent); + } + + public void setProblemList(List list) { + this.problemList.clear(); + this.problemList.addAll(list); + refreshListItems(); + } + + private void refreshListItems() { + + listParent.removeAllChildren(); + listParent.setPosition(0, 0); + + int y = 0; + for (CompileProblem issue : problemList) { + IssueListItemNode item = new IssueListItemNode(issue); + item.setPosition(0, y); + listParent.addChild(item); + y += item.calculateAccumulatedFrame().height(); + } + + moveListToScroll(); + } + + public void setScrollPercentage(double scrollPercentage) { + this.scroll = scrollPercentage; + moveListToScroll(); + } + + private void moveListToScroll() { + Rect subFrame = calculateChildrenFrame(); + if (subFrame.height() <= getFrame().height()) return; + + int totalScroll = subFrame.height() - getFrame().height(); // How much scroll is possible + int dist = (int) (totalScroll * scroll); // How much we want to scroll + + listParent.setPosition(0, -dist); + } + + @Override + public void onSubTreePreDrawBack() { + // This node's frame converted to GL11 window coordinates + Rect gl11Rect = calculateGL11Frame(); + + // Enable scissor using the calculated rect + RenderSystem.enableScissor(gl11Rect.x(), gl11Rect.y(), gl11Rect.width(), gl11Rect.height()); + } + + @Override + public void onSubTreePostDrawBack() { + // Disable scissor + RenderSystem.disableScissor(); + } + + private class IssueListItemNode extends AbstractGuiNode { + + private final CompileProblem issue; + + public IssueListItemNode(CompileProblem issue) { + this.issue = issue; + setSize(67, 12); + } + + @Override + public void drawBack(PoseStack stack, Point mouse, float partialFrame) { + RenderSystem.setShaderTexture(0, ICWorkbenchCompileTab.TAB_BACKGROUND); + + GuiComponent.blit(stack, getFrame().x(), getFrame().y(), 1, 375, getFrame().width(), getFrame().height(), 512, 512); + + Component s = issue.getName(); + getRoot().getFontRenderer().draw(stack, s, getFrame().x() + 2, getFrame().y() + 2, 0xFFFFFF); + } + + @Override + public void drawFront(PoseStack stack, Point mouse, float partialFrame) { + if (!isFirstHit(mouse)) return; + + List toolTip = new LinkedList<>(); + issue.buildToolTip(toolTip); + renderTooltip(stack, mouse, toolTip); + } + + @Override + public boolean checkHit(Point absPoint) { + return super.checkHit(absPoint) && ProblemListNode.this.convertParentRectToScreen(ProblemListNode.this.getFrame()).contains(absPoint); + } + } +} diff --git a/fabrication/src/main/java/mrtjp/projectred/fabrication/gui/SimpleUVTab.java b/fabrication/src/main/java/mrtjp/projectred/fabrication/gui/SimpleUVTab.java index 137dae5c6..164f6fd27 100644 --- a/fabrication/src/main/java/mrtjp/projectred/fabrication/gui/SimpleUVTab.java +++ b/fabrication/src/main/java/mrtjp/projectred/fabrication/gui/SimpleUVTab.java @@ -39,6 +39,17 @@ public AbstractGuiNode getTabBodyNode() { return tabBodyNode; } + //region Customization + protected StatusDot getStatusDot() { + return StatusDot.NONE; + } + + protected void buildTooltip(List tooltip) { + tooltip.add(tabName); + } + //endregion + + //region TabControllerNode.IToolbarTab @Override public void onTabClosed() { tabBodyNode.setHidden(true); @@ -61,12 +72,35 @@ public TabButtonNode createButtonNode() { public void renderIcon(PoseStack stack, Point mouse, float partialFrame) { RenderSystem.setShaderTexture(0, texture); GuiComponent.blit(stack, getFrame().x() + 3, getFrame().y() + 3, u, v, 14, 14, 512, 512); + + StatusDot statusDot = SimpleUVTab.this.getStatusDot(); + if (statusDot != StatusDot.NONE) { + RenderSystem.setShaderTexture(0, ICWorkbenchScreen.BACKGROUND); + GuiComponent.blit(stack, getFrame().x() + 3 + 7, getFrame().y() + 3, 7, 7, statusDot.u, statusDot.v, 14, 14, 512, 512); + } } @Override public void buildTooltip(List tooltip) { - tooltip.add(tabName); + SimpleUVTab.this.buildTooltip(tooltip); } }; } + //endregion + + public enum StatusDot { + NONE(0, 0), + GREEN(435, 1), + YELLOW(450, 1), + RED(465, 1) + ; + + public final int u; + public final int v; + + StatusDot(int u, int v) { + this.u = u; + this.v = v; + } + } } diff --git a/fabrication/src/main/java/mrtjp/projectred/fabrication/gui/WirePlacerToolTab.java b/fabrication/src/main/java/mrtjp/projectred/fabrication/gui/WirePlacerToolTab.java index b4df61546..013b10312 100644 --- a/fabrication/src/main/java/mrtjp/projectred/fabrication/gui/WirePlacerToolTab.java +++ b/fabrication/src/main/java/mrtjp/projectred/fabrication/gui/WirePlacerToolTab.java @@ -105,7 +105,7 @@ public void renderIcon(PoseStack stack, Point mouse, float partialFrame) { @Override public void buildTooltip(List tooltip) { - tooltip.add(new TextComponent(UL_WIRE_TOOL)); + tooltip.add(new TranslatableComponent(UL_WIRE_TOOL)); } }; } diff --git a/fabrication/src/main/java/mrtjp/projectred/fabrication/gui/screen/ICWorkbenchCompileTab.java b/fabrication/src/main/java/mrtjp/projectred/fabrication/gui/screen/ICWorkbenchCompileTab.java index 0b2befa11..66312fbdc 100644 --- a/fabrication/src/main/java/mrtjp/projectred/fabrication/gui/screen/ICWorkbenchCompileTab.java +++ b/fabrication/src/main/java/mrtjp/projectred/fabrication/gui/screen/ICWorkbenchCompileTab.java @@ -9,6 +9,7 @@ import mrtjp.projectred.fabrication.ProjectRedFabrication; import mrtjp.projectred.fabrication.editor.ICWorkbenchEditor; import mrtjp.projectred.fabrication.editor.tools.IICEditorTool; +import mrtjp.projectred.fabrication.engine.log.ICCompilerLog; import mrtjp.projectred.fabrication.gui.*; import mrtjp.projectred.lib.Point; import mrtjp.projectred.redui.AbstractButtonNode; @@ -17,11 +18,16 @@ import net.minecraft.client.gui.GuiComponent; import net.minecraft.client.renderer.MultiBufferSource; import net.minecraft.network.chat.Component; +import net.minecraft.network.chat.TextComponent; +import net.minecraft.network.chat.TranslatableComponent; import net.minecraft.resources.ResourceLocation; import org.lwjgl.glfw.GLFW; +import java.util.LinkedList; import java.util.List; +import static mrtjp.projectred.fabrication.editor.ICWorkbenchEditor.*; +import static mrtjp.projectred.fabrication.editor.ICWorkbenchEditor.UNIFORM_DARK_GRAY; import static mrtjp.projectred.fabrication.init.FabricationUnlocal.*; public class ICWorkbenchCompileTab extends AbstractGuiNode implements ICRenderNode.IICRenderNodeEventReceiver { @@ -30,7 +36,7 @@ public class ICWorkbenchCompileTab extends AbstractGuiNode implements ICRenderNo private final ICWorkbenchEditor editor; - private TabControllerNode tabControllerNode; + private List overlays = new LinkedList<>(); private boolean upPressed = false; private boolean rightPressed = false; @@ -71,15 +77,20 @@ private void initSubNodes() { compileProblemsTab.setPosition(208, 77); addChild(compileProblemsTab); + // Keep track of overlays + overlays.add(compileStackTab); + overlays.add(compileTreeTab); + overlays.add(compileProblemsTab); + // Bottom tabs - tabControllerNode = new TabControllerNode(); + TabControllerNode tabControllerNode = new TabControllerNode(); tabControllerNode.setPosition(212, 210); tabControllerNode.setZPosition(0.1); addChild(tabControllerNode); tabControllerNode.addButtonForTab(new SimpleUVTab(compileStackTab, UL_TAB_STACK, TabButtonNode.TabSide.BOTTOM, 350, 11, TAB_BACKGROUND)); tabControllerNode.addButtonForTab(new SimpleUVTab(compileTreeTab, UL_TAB_TREE, TabButtonNode.TabSide.BOTTOM, 365, 11, TAB_BACKGROUND)); - tabControllerNode.addButtonForTab(new SimpleUVTab(compileProblemsTab, UL_TAB_PROBLEMS, TabButtonNode.TabSide.BOTTOM, 380, 11, TAB_BACKGROUND)); + tabControllerNode.addButtonForTab(new ProblemsTab(compileProblemsTab, UL_TAB_PROBLEMS, TabButtonNode.TabSide.BOTTOM, 380, 11, TAB_BACKGROUND)); tabControllerNode.selectInitialTab(0); tabControllerNode.spreadButtonsHorizontally(1); @@ -90,9 +101,8 @@ public void drawBack(PoseStack stack, Point mouse, float partialFrame) { RenderSystem.setShaderTexture(0, TAB_BACKGROUND); GuiComponent.blit(stack, getFrame().x(), getFrame().y(), 0, 0, getFrame().width(), getFrame().height(), 512, 512); - if (editor.isActive()) { - getRoot().getFontRenderer().draw(stack, editor.getIcName(), getFrame().x() + 8, getFrame().y() + 6, EnumColour.GRAY.argb()); - } + // Blueprint name in top left corner + getRoot().getFontRenderer().draw(stack, editor.getIcName(), getFrame().x() + 8, getFrame().y() + 6, EnumColour.GRAY.argb()); // Progress bar RenderSystem.setShaderTexture(0, TAB_BACKGROUND); @@ -100,6 +110,35 @@ public void drawBack(PoseStack stack, Point mouse, float partialFrame) { int progress = editor.getStateMachine().getCompilerLog().getProgressScaled(barWidth); GuiComponent.blit(stack, getFrame().x() + 208, getFrame().y() + 36, 304, 0, barWidth, 5, 512, 512); GuiComponent.blit(stack, getFrame().x() + 208, getFrame().y() + 36, 304, 5, progress, 5, 512, 512); + + // Progress text + ICCompilerLog log = editor.getStateMachine().getCompilerLog(); + getRoot().getFontRenderer().draw(stack, + new TranslatableComponent(editor.getStateMachine().isCompiling() ? UL_COMPILE_PROGRESS : UL_COMPILE_DONE, log.getCompletedSteps(), log.getTotalSteps()) + .withStyle(UNIFORM_DARK_GRAY), + getFrame().x() + 208, getFrame().y() + 42, EnumColour.GRAY.argb()); + + // Error Count + Component errorText = log.getErrorCount() == 0 ? + new TextComponent(" ") + .append(new TranslatableComponent(UL_NO_ERRORS)) + .withStyle(UNIFORM_DARK_GRAY) : + new TextComponent(" ") + .withStyle(ICWorkbenchEditor.UNIFORM_RED) + .append(new TranslatableComponent(UL_UNIT_ERRORS, log.getErrorCount()) + .withStyle(UNIFORM_DARK_GRAY)); + + Component warningText = log.getWarningCount() == 0 ? + new TextComponent(" ") + .append(new TranslatableComponent(UL_NO_WARNINGS)) + .withStyle(UNIFORM_DARK_GRAY) : + new TextComponent(" ") + .withStyle(ICWorkbenchEditor.UNIFORM_YELLOW) + .append(new TranslatableComponent(UL_UNIT_WARNINGS, log.getWarningCount()) + .withStyle(UNIFORM_DARK_GRAY)); + + getRoot().getFontRenderer().draw(stack, errorText, getFrame().x() + 208, getFrame().y() + 52, EnumColour.GRAY.argb()); + getRoot().getFontRenderer().draw(stack, warningText, getFrame().x() + 208, getFrame().y() + 60, EnumColour.GRAY.argb()); } //TODO Reduce this reused code (ICEditorToolManager) @@ -160,13 +199,6 @@ public boolean onKeyReleased(int glfwKeyCode, int glfwScanCode, int glfwFlags, b return true; } - protected ICompileOverlayRenderer getOverlayRenderer() { - - // Overlay rendering is handled by the currently open tab - SimpleUVTab tab = (SimpleUVTab) tabControllerNode.getSelectedTab().orElse(tabControllerNode.getTab(0)); - return (ICompileOverlayRenderer) tab.getTabBodyNode(); - } - //region ICRenderNode.IICRenderNodeEventReceiver @Override @@ -200,16 +232,45 @@ public void buildTooltip(ICRenderNode renderNode, Vector3 mousePosition, boolean TileCoord pos = IICEditorTool.toNearestPosition(mousePosition); editor.getTileMap().getBaseTile(pos).ifPresent(tile -> tile.buildToolTip(tooltip)); - getOverlayRenderer().buildTooltip(renderNode, mousePosition, tooltip); + for (ICompileOverlayRenderer overlay : overlays) { + overlay.buildTooltip(renderNode, mousePosition, tooltip); + } } @Override public void onRenderOverlay(ICRenderNode renderNode, Vector3 mousePosition, boolean isFirstHit, CCRenderState ccrs, MultiBufferSource getter, PoseStack matrixStack) { - getOverlayRenderer().renderOverlay(renderNode, mousePosition, isFirstHit, ccrs, getter, matrixStack); + for (ICompileOverlayRenderer overlay : overlays) { + overlay.renderOverlay(renderNode, mousePosition, isFirstHit, ccrs, getter, matrixStack); + } } //endregion + //region Utilities + public static void appendProblemsInfo(ICCompilerLog log, List tooltip) { + Component errorText = log.getErrorCount() == 0 ? + new TextComponent(" ") + .append(new TranslatableComponent(UL_NO_ERRORS)) + .withStyle(UNIFORM_GRAY) : + new TextComponent(" ") + .withStyle(UNIFORM_RED) + .append(new TranslatableComponent(UL_UNIT_ERRORS, log.getErrorCount()) + .withStyle(UNIFORM_GRAY)); + + Component warningText = log.getWarningCount() == 0 ? + new TextComponent(" ") + .append(new TranslatableComponent(UL_NO_WARNINGS)) + .withStyle(UNIFORM_GRAY) : + new TextComponent(" ") + .withStyle(ICWorkbenchEditor.UNIFORM_YELLOW) + .append(new TranslatableComponent(UL_UNIT_WARNINGS, log.getWarningCount()) + .withStyle(UNIFORM_GRAY)); + + tooltip.add(errorText); + tooltip.add(warningText); + } + //endregion + public class CompileButton extends AbstractButtonNode { @Override @@ -244,5 +305,38 @@ private void blitCentered(PoseStack stack, int u, int v, int width, int height) getFrame().y() + (getFrame().height() - height) / 2, u, v, width, height, 512, 512); } + + @Override + protected void buildTooltip(List tooltip) { + tooltip.add(new TranslatableComponent(UL_COMPILE)); + if (editor.getStateMachine().canTriggerCompile()) { + tooltip.add(new TranslatableComponent(UL_COMPILE_READY).withStyle(UNIFORM_GRAY)); + } + } + } + + private class ProblemsTab extends SimpleUVTab { + + public ProblemsTab(AbstractGuiNode tabBodyNode, String unlocalTabName, TabButtonNode.TabSide side, int u, int v, ResourceLocation texture) { + super(tabBodyNode, unlocalTabName, side, u, v, texture); + } + + @Override + protected StatusDot getStatusDot() { + if (editor.getStateMachine().getCompilerLog().getErrorCount() > 0) { + return StatusDot.RED; + } else if (editor.getStateMachine().getCompilerLog().getWarningCount() > 0) { + return StatusDot.YELLOW; + } else { + return StatusDot.NONE; + } + } + + @Override + protected void buildTooltip(List tooltip) { + super.buildTooltip(tooltip); + ICCompilerLog log = editor.getStateMachine().getCompilerLog(); + appendProblemsInfo(log, tooltip); + } } } diff --git a/fabrication/src/main/java/mrtjp/projectred/fabrication/gui/screen/ICWorkbenchEditTab.java b/fabrication/src/main/java/mrtjp/projectred/fabrication/gui/screen/ICWorkbenchEditTab.java index ca89029f9..090d7d20d 100644 --- a/fabrication/src/main/java/mrtjp/projectred/fabrication/gui/screen/ICWorkbenchEditTab.java +++ b/fabrication/src/main/java/mrtjp/projectred/fabrication/gui/screen/ICWorkbenchEditTab.java @@ -76,9 +76,8 @@ public void drawBack(PoseStack stack, Point mouse, float partialFrame) { GuiComponent.blit(stack, frame.x(), frame.y(), 0, 0, frame.width(), frame.height(), 512, 512); - if (editor.isActive()) { - fontRenderer.draw(stack, editor.getIcName(), frame.x() + 8, frame.y() + 6, EnumColour.GRAY.argb()); - } + // Blueprint name in top left corner + fontRenderer.draw(stack, editor.getIcName(), frame.x() + 8, frame.y() + 6, EnumColour.GRAY.argb()); } @Override diff --git a/fabrication/src/main/java/mrtjp/projectred/fabrication/gui/screen/ICWorkbenchInfoTab.java b/fabrication/src/main/java/mrtjp/projectred/fabrication/gui/screen/ICWorkbenchInfoTab.java index 825ff4fe9..5fe8caca4 100644 --- a/fabrication/src/main/java/mrtjp/projectred/fabrication/gui/screen/ICWorkbenchInfoTab.java +++ b/fabrication/src/main/java/mrtjp/projectred/fabrication/gui/screen/ICWorkbenchInfoTab.java @@ -21,6 +21,7 @@ import mrtjp.projectred.redui.TextBoxNode; import net.minecraft.client.gui.GuiComponent; import net.minecraft.network.chat.Component; +import net.minecraft.network.chat.Style; import net.minecraft.network.chat.TextComponent; import net.minecraft.network.chat.TranslatableComponent; import net.minecraft.resources.ResourceLocation; @@ -121,9 +122,8 @@ public void drawBack(PoseStack stack, Point mouse, float partialFrame) { RenderSystem.setShaderTexture(0, TAB_BACKGROUND); GuiComponent.blit(stack, getFrame().x(), getFrame().y(), 0, 0, getFrame().width(), getFrame().height(), 512, 512); - if (editor.isActive()) { - getRoot().getFontRenderer().draw(stack, editor.getIcName(), getFrame().x() + 8, getFrame().y() + 6, EnumColour.GRAY.argb()); - } + // Blueprint name in top left corner + getRoot().getFontRenderer().draw(stack, editor.getIcName(), getFrame().x() + 8, getFrame().y() + 6, EnumColour.GRAY.argb()); } private ButtonArrayNode createPipelineButtons() { diff --git a/fabrication/src/main/java/mrtjp/projectred/fabrication/gui/screen/ICWorkbenchScreen.java b/fabrication/src/main/java/mrtjp/projectred/fabrication/gui/screen/ICWorkbenchScreen.java index bb7fbe019..e29fde264 100644 --- a/fabrication/src/main/java/mrtjp/projectred/fabrication/gui/screen/ICWorkbenchScreen.java +++ b/fabrication/src/main/java/mrtjp/projectred/fabrication/gui/screen/ICWorkbenchScreen.java @@ -5,6 +5,7 @@ import com.mojang.blaze3d.vertex.PoseStack; import mrtjp.projectred.fabrication.ProjectRedFabrication; import mrtjp.projectred.fabrication.editor.ICWorkbenchEditor; +import mrtjp.projectred.fabrication.engine.log.ICCompilerLog; import mrtjp.projectred.fabrication.gui.SimpleUVTab; import mrtjp.projectred.fabrication.gui.TabButtonNode; import mrtjp.projectred.fabrication.gui.TabControllerNode; @@ -14,6 +15,7 @@ import mrtjp.projectred.redui.AbstractGuiNode; import mrtjp.projectred.redui.ItemStackNode; import mrtjp.projectred.redui.RedUIScreen; +import net.minecraft.ChatFormatting; import net.minecraft.client.Minecraft; import net.minecraft.client.gui.Font; import net.minecraft.network.chat.Component; @@ -22,6 +24,9 @@ import net.minecraft.resources.ResourceLocation; import net.minecraft.world.item.ItemStack; +import java.util.List; + +import static mrtjp.projectred.fabrication.editor.ICWorkbenchEditor.*; import static mrtjp.projectred.fabrication.init.FabricationUnlocal.*; public class ICWorkbenchScreen extends RedUIScreen { @@ -68,8 +73,8 @@ private void initSubNodes() { contentNode.addChild(tabControllerNode); tabControllerNode.addButtonForTab(new SimpleUVTab(infoTab, UL_TAB_INFO, TabButtonNode.TabSide.LEFT, 420, 1)); - tabControllerNode.addButtonForTab(new SimpleUVTab(editTab, UL_TAB_EDIT, TabButtonNode.TabSide.LEFT, 420, 16)); - tabControllerNode.addButtonForTab(new SimpleUVTab(compileTab, UL_TAB_COMPILE, TabButtonNode.TabSide.LEFT, 420, 31)); + tabControllerNode.addButtonForTab(new EditTab(editTab, UL_TAB_EDIT, TabButtonNode.TabSide.LEFT, 420, 16)); + tabControllerNode.addButtonForTab(new CompileTab(compileTab, UL_TAB_COMPILE, TabButtonNode.TabSide.LEFT, 420, 31)); tabControllerNode.selectInitialTab(1); tabControllerNode.spreadButtonsVertically(1); @@ -144,4 +149,68 @@ public void drawBack(PoseStack stack, Point mouse, float partialFrame) { getFrame().y() + 6, EnumColour.GRAY.argb()); } } + + private class EditTab extends SimpleUVTab { + + public EditTab(AbstractGuiNode tabBodyNode, String unlocalTabName, TabButtonNode.TabSide side, int u, int v) { + super(tabBodyNode, unlocalTabName, side, u, v); + } + + @Override + protected StatusDot getStatusDot() { + if (editor.getStateMachine().isSimulating()) { + return StatusDot.GREEN; + } + return StatusDot.NONE; + } + + @Override + protected void buildTooltip(List tooltip) { + super.buildTooltip(tooltip); + if (editor.getStateMachine().isSimulating()) { + tooltip.add(new TranslatableComponent(UL_SIM_RUNNING).withStyle(UNIFORM_GRAY)); + } + } + } + + private class CompileTab extends SimpleUVTab { + + public CompileTab(AbstractGuiNode tabBodyNode, String unlocalTabName, TabButtonNode.TabSide side, int u, int v) { + super(tabBodyNode, unlocalTabName, side, u, v); + } + + @Override + protected StatusDot getStatusDot() { + if (editor.getStateMachine().isCompiling()) { + return StatusDot.GREEN; + } + if (editor.getStateMachine().didLastCompileFailed()) { + return StatusDot.RED; + } + if (editor.getStateMachine().canTriggerCompile()) { + return StatusDot.YELLOW; + } + return StatusDot.NONE; + } + + @Override + protected void buildTooltip(List tooltip) { + super.buildTooltip(tooltip); + + ICCompilerLog log = editor.getStateMachine().getCompilerLog(); + if (editor.getStateMachine().canTriggerCompile()) { + tooltip.add(new TranslatableComponent(UL_COMPILE_READY).withStyle(UNIFORM_GRAY)); + } + + if (editor.getStateMachine().isCompiling()) { + tooltip.add(new TranslatableComponent(UL_COMPILE_PROGRESS, log.getCompletedSteps(), log.getTotalSteps()).withStyle(UNIFORM_GRAY)); + } + + if (editor.getStateMachine().didLastCompileFailed()) { + tooltip.add(new TranslatableComponent(UL_COMPILE_FAILED).withStyle(UNIFORM_RED)); + } + + ICWorkbenchCompileTab.appendProblemsInfo(log, tooltip); + } + } } diff --git a/fabrication/src/main/java/mrtjp/projectred/fabrication/init/FabricationUnlocal.java b/fabrication/src/main/java/mrtjp/projectred/fabrication/init/FabricationUnlocal.java index 72ee30483..e3ec5e4ce 100644 --- a/fabrication/src/main/java/mrtjp/projectred/fabrication/init/FabricationUnlocal.java +++ b/fabrication/src/main/java/mrtjp/projectred/fabrication/init/FabricationUnlocal.java @@ -1,8 +1,10 @@ package mrtjp.projectred.fabrication.init; +import static mrtjp.projectred.fabrication.ProjectRedFabrication.MOD_ID; + public class FabricationUnlocal { - private static final String PREFIX = "projectred-fabrication."; + private static final String PREFIX = MOD_ID + "."; // ICWorkbench tabs public static final String UL_TAB_INFO = PREFIX + "tab.info"; @@ -28,6 +30,22 @@ public class FabricationUnlocal { public static final String UL_SIDE_ENABLED = PREFIX + "interact.side_enabled"; public static final String UL_SIDE_DISABLED = PREFIX + "interact.side_disabled"; + // Problems + public static final String UL_MULTIPLE_DRIVERS_TITLE = PREFIX + "problems.multiple_drivers.title"; + public static final String UL_MULTIPLE_DRIVERS_DESC = PREFIX + "problems.multiple_drivers.desc"; + public static final String UL_DEAD_WIRE_TITLE = PREFIX + "problems.dead_wire.title"; + public static final String UL_DEAD_WIRE_DESC = PREFIX + "problems.dead_wire.desc"; + public static final String UL_DEAD_GATE_TITLE = PREFIX + "problems.dead_gate.title"; + public static final String UL_DEAD_GATE_DESC = PREFIX + "problems.dead_gate.desc"; + public static final String UL_IO_DIR_MISMATCH_TITLE = PREFIX + "problems.io_dir_mismatch.title"; + public static final String UL_IO_DIR_MISMATCH_DESC = PREFIX + "problems.io_dir_mismatch.desc"; + public static final String UL_NO_INPUTS_TITLE = PREFIX + "problems.no_inputs.title"; + public static final String UL_NO_INPUTS_DESC = PREFIX + "problems.no_inputs.desc"; + public static final String UL_NO_OUTPUTS_TITLE = PREFIX + "problems.no_outputs.title"; + public static final String UL_NO_OUTPUTS_DESC = PREFIX + "problems.no_outputs.desc"; + public static final String UL_NO_ERRORS = PREFIX + "problems.no_errors"; + public static final String UL_NO_WARNINGS = PREFIX + "problems.no_warnings"; + // General workbench UI public static final String UL_PLACE_BLUEPRINT = PREFIX + "ui.place_blueprint"; public static final String UL_BLUEPRINT_INFO = PREFIX + "ui.blueprint_info"; @@ -35,6 +53,12 @@ public class FabricationUnlocal { public static final String UL_BLUEPRINT_OWNER = PREFIX + "ui.blueprint_owner"; public static final String UL_BLUEPRINT_DIM = PREFIX + "ui.blueprint_dim"; public static final String UL_BLUEPRINT_LAYERS = PREFIX + "ui.blueprint_layers"; + public static final String UL_COMPILE = PREFIX + "ui.compile"; + public static final String UL_COMPILE_PROGRESS = PREFIX + "ui.compile_progress"; + public static final String UL_COMPILE_DONE = PREFIX + "ui.compile_done"; + public static final String UL_COMPILE_READY = PREFIX + "ui.compile_ready"; + public static final String UL_COMPILE_FAILED = PREFIX + "ui.compile_failed"; + public static final String UL_SIM_RUNNING = PREFIX + "ui.sim_running"; public static final String UL_YIELD_CALCULATOR = PREFIX + "ui.yield_calculator"; public static final String UL_LITHOGRAPHY_PIPELINE = PREFIX + "ui.lithography_pipeline"; @@ -71,8 +95,11 @@ public class FabricationUnlocal { public static final String UL_BUNDLED_INPUT = PREFIX + "tooltip.bundled_input"; public static final String UL_BUNDLED_OUTPUT = PREFIX + "tooltip.bundled_output"; public static final String UL_IO_NONE = PREFIX + "tooltip.io_none"; + public static final String UL_CANNOT_FABRICATE = PREFIX + "tooltip.cannot_fabricate"; // Numbers and measurements + public static final String UL_UNIT_WARNINGS = PREFIX + "unit.warnings"; + public static final String UL_UNIT_ERRORS = PREFIX + "unit.errors"; public static final String UL_UNIT_TICKS = PREFIX + "unit.ticks"; public static final String UL_DIMENSIONS_NM = PREFIX + "dimensions.nm"; public static final String UL_DIMENSIONS_TILES = PREFIX + "dimensions.tiles"; diff --git a/fabrication/src/main/java/mrtjp/projectred/fabrication/item/BaseSiliconWaferItem.java b/fabrication/src/main/java/mrtjp/projectred/fabrication/item/BaseSiliconWaferItem.java index 2c0916760..246f43f6f 100644 --- a/fabrication/src/main/java/mrtjp/projectred/fabrication/item/BaseSiliconWaferItem.java +++ b/fabrication/src/main/java/mrtjp/projectred/fabrication/item/BaseSiliconWaferItem.java @@ -4,7 +4,7 @@ import mrtjp.projectred.fabrication.lithography.WaferType; import net.minecraft.ChatFormatting; import net.minecraft.network.chat.Component; -import net.minecraft.network.chat.TextComponent; +import net.minecraft.network.chat.TranslatableComponent; import net.minecraft.world.item.Item; import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.TooltipFlag; @@ -30,8 +30,8 @@ public BaseSiliconWaferItem(WaferType waferType) { public void appendHoverText(ItemStack stack, @Nullable Level world, List tooltipList, TooltipFlag tooltipFlag) { super.appendHoverText(stack, world, tooltipList, tooltipFlag); - tooltipList.add(new TextComponent(UL_SIZE).append(": " + waferType.getWaferWidth() + "nm x " + waferType.getWaferHeight() + "nm").withStyle(ChatFormatting.GRAY)); - tooltipList.add(new TextComponent(UL_DEFECT_CHANCE).append(": " + waferType.getDefectRatePerUnitArea()*100 + "% / nm^2").withStyle(ChatFormatting.GRAY)); + tooltipList.add(new TranslatableComponent(UL_SIZE).append(": " + waferType.getWaferWidth() + "nm x " + waferType.getWaferHeight() + "nm").withStyle(ChatFormatting.GRAY)); + tooltipList.add(new TranslatableComponent(UL_DEFECT_CHANCE).append(": " + waferType.getDefectRatePerUnitArea()*100 + "% / nm^2").withStyle(ChatFormatting.GRAY)); } public WaferType getWaferType() { diff --git a/fabrication/src/main/java/mrtjp/projectred/fabrication/item/ICBlueprintItem.java b/fabrication/src/main/java/mrtjp/projectred/fabrication/item/ICBlueprintItem.java index a9d4c1406..fa351307a 100644 --- a/fabrication/src/main/java/mrtjp/projectred/fabrication/item/ICBlueprintItem.java +++ b/fabrication/src/main/java/mrtjp/projectred/fabrication/item/ICBlueprintItem.java @@ -77,7 +77,21 @@ public static void buildTooltip(CompoundTag blueprintTag, List toolti tooltipList.add(indent.copy().append(new TranslatableComponent(UL_BOTTOM)).append(": ").append(getBundledIOTextComponent(bmask, 2)).withStyle(ChatFormatting.GRAY)); tooltipList.add(indent.copy().append(new TranslatableComponent(UL_LEFT)).append(": ").append(getBundledIOTextComponent(bmask, 3)).withStyle(ChatFormatting.GRAY)); - //TODO errors + int warningCount = getWarningCount(blueprintTag); + int errorCount = getErrorCount(blueprintTag); + if (warningCount > 0) { + tooltipList.add(new TextComponent(" ").withStyle(ChatFormatting.YELLOW) + .append(new TranslatableComponent(UL_UNIT_WARNINGS, warningCount).withStyle(ChatFormatting.GRAY))); + } + if (errorCount > 0) { + tooltipList.add(new TextComponent(" ").withStyle(ChatFormatting.RED) + .append(new TranslatableComponent(UL_UNIT_ERRORS, errorCount).withStyle(ChatFormatting.GRAY))); + } + + if (!canFabricate(blueprintTag)) { + tooltipList.add(new TextComponent(" - ") + .append(new TranslatableComponent(UL_CANNOT_FABRICATE).withStyle(ChatFormatting.GRAY))); + } } private static TranslatableComponent getBundledIOTextComponent(byte bmask, int r) { diff --git a/fabrication/src/main/java/mrtjp/projectred/fabrication/lithography/YieldCalculator.java b/fabrication/src/main/java/mrtjp/projectred/fabrication/lithography/YieldCalculator.java index 41d6867bc..aab7ca107 100644 --- a/fabrication/src/main/java/mrtjp/projectred/fabrication/lithography/YieldCalculator.java +++ b/fabrication/src/main/java/mrtjp/projectred/fabrication/lithography/YieldCalculator.java @@ -5,7 +5,8 @@ import net.minecraft.network.chat.TextComponent; import net.minecraft.network.chat.TranslatableComponent; -import static mrtjp.projectred.fabrication.init.FabricationUnlocal.*; +import static mrtjp.projectred.fabrication.init.FabricationUnlocal.UL_DIMENSIONS_DIES_TOTAL; +import static mrtjp.projectred.fabrication.init.FabricationUnlocal.UL_DIMENSIONS_NM; public class YieldCalculator { @@ -74,7 +75,7 @@ public double getMultiLayerYield() { public Component getDieDimensionsText() { Size dieSize = getDieSize(); - return new TranslatableComponent(UL_DIMENSIONS_DIES, dieSize.width, dieSize.height); + return new TranslatableComponent(UL_DIMENSIONS_NM, dieSize.width, dieSize.height); } public Component getWaferDimensionsText() { diff --git a/fabrication/src/main/java/mrtjp/projectred/fabrication/tile/PlottingTableTile.java b/fabrication/src/main/java/mrtjp/projectred/fabrication/tile/PlottingTableTile.java index 3822e8945..911ee730b 100644 --- a/fabrication/src/main/java/mrtjp/projectred/fabrication/tile/PlottingTableTile.java +++ b/fabrication/src/main/java/mrtjp/projectred/fabrication/tile/PlottingTableTile.java @@ -4,6 +4,7 @@ import codechicken.lib.data.MCDataOutput; import codechicken.lib.util.ServerUtils; import mrtjp.projectred.core.inventory.BaseInventory; +import mrtjp.projectred.fabrication.editor.EditorDataUtils; import mrtjp.projectred.fabrication.init.FabricationReferences; import mrtjp.projectred.fabrication.inventory.container.PlottingTableContainer; import mrtjp.projectred.fabrication.item.BlankPhotomaskItem; @@ -110,6 +111,8 @@ protected boolean canStartWork() { if (!(slot1.getItem() instanceof BlankPhotomaskItem)) return false; + if (!EditorDataUtils.canFabricate(slot1.getTag())) return false; + return inventory.getItem(2).isEmpty(); } diff --git a/fabrication/src/main/resources/assets/projectred_fabrication/textures/gui/compile_tab.png b/fabrication/src/main/resources/assets/projectred_fabrication/textures/gui/compile_tab.png index ed92ef537e4d9fbd73c022d05a4dc562f10f32bf..22f3fb54769beaa8564822f69c18f843731394f5 100644 GIT binary patch literal 13123 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 diff --git a/fabrication/src/main/resources/assets/projectred_fabrication/textures/gui/ic_workbench.png b/fabrication/src/main/resources/assets/projectred_fabrication/textures/gui/ic_workbench.png index 276a4bf16f96b00b78adf9fec84ffd143a1496aa..29e205d6f765a1b3e1c4f971c223833c0234d9e5 100644 GIT binary patch literal 35284 zcmb@t2V7Iz(l)*+0xAM3ibxey5Df_lA%qr+fS`h+(u9PPP^1&8lmHeK6;u>NI*N!i zsgaI?^eRek(h-mzYT(-eJ@=e@&w0Q5fB&C9l$gEtUbAM+%zEaT+4nDLsqfo!bPoUk z`!vp-)d2u{@FP9I!UXbk9$-@c;lTz4cXn7yXMDWXv7x z#7*%IW(08$J4bLd0LWoH98Jw_2rhzV1WRjsd7+uYQXxTWyu6Se@*?b_qYA;w`rJ)t z!j+p^SIuwQn4|GR7zIH&4;k3$bqjOg6*L2|j=60*yvPVQ?rM4gp6%h@SQ? zrXCP`qVVr0oFx#=ovj^RtR3tHX-_mYb8vN$7XpRdS%sbBACI*s{?ZhvGpL8DBUC~h zMqAbPK)m@M;~ZU`ZMP@Kn?nh<1UrJg3lSVE@yA$4D+d<`qLsrxJo=Bzf0+Q(?!}9L z%<;Ff*xCIt1<^&-4P3@Ah5YSk;#E&a0#t`UbZ~VxC#brCVhaCWjf=I#zts7cyJ=Vc zA{W8K`X7eUuKY37QAWj?VCv%FeAU6h_O}IG`mG2-6%}y1C6I!m7fsEr?P=OMMU&;% zU4*lyE(CcYa0F-yFbEud6%LnyOUWP*5Ey6~u$`e79q`r`p1+5}!D}dp1nQ~;Tm~Tt z+Rk5wf(D5bfx(b)h@`o>8AKY5M?uU@5imU3!a@Rx zH2;17SqF1hn$ghi-*F+lgE{z&f6WS$fDsUqNNI?qv^fHTBuGj@q~Qb$2m+2mqAjG& zq)g5KkVf0t8uVgQ+dn^*CKVohBGO#K0zp8TLEvTt@L_1ABm|9?!b1p>2q|fV6wK62 z3Y3br$<`J<@&!aU$eIcRSXvr zq#4bQR;$I5;y?7;XTZo_$ z5`V=HWmC&vpKPraq~TI1GzzJPR+dH}Q4&gOaG0cu3Q}5GS{kOLf{>Jh(gFlHa3}VF zAO82d^WQ#88Z;HSv>5_|mqx)L5)vpB1dWoCf|#SFrBP-Q1SvSu?7w{$-b`9rN)jOf z!6V_IXV9J{jj{l35RH;XOPRtf%%utc`K;fzB4L4sA>ign2p(;UfJh=OK%0|*OF~e1 z6bdgXWk$dwrT_VEgsFuY5(P7bz${RBh@=@z5+aR6f}+4sW(Y}1Q)%1jH1DkdQJnL%}5p7XLiABwh;i2{ayDvLpfYJp?$nqy!v1 zRHQ+vB;n>#c+@}N{onY=Ki@4S1v5huz~BSUZ2^&l5u_ldW(Xw2%+yR$0);>$@D`^3 zd^ZXqg)%cY#Y3dcq+t+ANi%bB-R5Wr41utag2T+v(&n&#zFQiJhoQ}+P!KZ-aLJMu zNCE_n1Vg4Il7NE4C8Q8Y_}|#hZ=IvzFoJ{ys4yf9G#N>RDfk>ov^0c(LYd-0;SnfF z_&?9BgiuyGi995eo#jPh1&O^POO5PCM)fc%ffkTmQ|G@ZT8L z@B7`Y2w>R#AI`s>*@+GoF7Bqz1SLx_R{zr>EBTj07Wz*sAey@U&+bRcg*zPT@v)Ff8DJe5Q z4&Oi?*=@>^2P7xz+T1CoIC7tH>p*64K~46WmsNHMtC?6>*kvpu-d9!&ix`4}2- zbBn}yXkDxHj2V*~Lu=aX11@QP#&9TCGrr2zjSgPm&h!1^^YVxKi6Iq?J{5PayQuV$ zhMlZcAzK#nkJE+4Ukp`FCAJgyE3PPN68lzT?urnp=_Fq>%AG`hR zzDgh)fjVvT3a2xvkB2)AG%9-Yrs>dv{>pO67&_2U}|y>-OCu zwXVj~1>(ww!WlwWaZyKm?SSP?zm;=FfH27 zzhWoDO&=gX+wB5pWb_&!PvBWnnG-qFOV)1etB5JRU!rL9NHpkD$~Sn`D^X=mRV%4T z4aR}=!k;=?YY7{J9Llwe2Ex}!UAe#yc_H1_8|cLNh)2&ISm%# z%I?qj(sf;n$cu(CTy7r^$nlx$-qc~f%yP|rzoM{2GndZlW6-u62cZV#;y4z#=NPYRYJSeY%=mEtecWau0hf=vW z2yx7hk1$UVkI)I;=J>KdjnjA9heTKQS(dZ~ol6Zbv1mYR`CPGIzdBwzqtvvZ%RzT3 z{edD15gWZAWVI_th22nn*45QVfA=zj21XO2bQ)S+Olj)xFuD3_8rtQAwU|TJJQ7G4Nsx*lxRl&hh&S5xN zp?GeL8PNCX9gjSDn?r{!>ZY*l>}jq`;`Up;xU%bPQ)OFYTN|EdeIIu#$V)GsH(qzl zWp8&VXO}yBS*)szj#sbTNm$w*NGcfGdO7R6_JVcRjOFZQ#x!Jr;JIK1NdS~?_)=`c z$H)F`7=lpM_ChK{Xn(S>BJm)9K^`+%mmeuy)=n7`Fy z-s+yP?g5kM=PbAOPMq+k_{B!7k8uLWZa=p7C<*E03pa7AI`N`&lODk=FtD|;74zvy zZ^q}+!XZW@GFinYjcL4Vz$VZEIqC2IvTN#sLG34HeXqAF9Os<_;&$Q zo!Loat~x1nYlDSkYF5GG-4JUs`TZ?oH2>qKs0$GIijeKY}y*J~#(U9LBN>>uA zQziv3TfVZVLyc+0SCcLzzy$&T5kiW}GW#zH(K|n6qD{!y$$F0IIb@95@sfz8WQC99 zO}kH*PA7KRm3nnwznUcHA2<>iQktLCZ8Zbz zf~QvZR$xnyFy1HQQcgtDX+#Dym3j5A_nFQ-;!sxmWP?4(6`Mc$(q_%R+*03tZM=2K zoxO>?fxQ#yYTLDstp6ePuxb^qFV|9%53=j5c!+|12J ze0A*HQ2#_&!7AVKTN9Mnsul-((O#u9rF~IVb=Y}fpQVYoUEUR~ygA0GE|I2$Odkc} zRJp(=3>dH^Q7nl`T<`oQ#$IQ$^GY`_t-Fpl$6vUf_;q*;cr73_Z}N=!7GAP;%=Cy5 zYx(eZVK2eD)hr8mhWz8S47uHxNI!6|H&tu7nDHH(-DFF);DdEWFovYkXAmr+y`HTa z{&+2ZVsAEaErClf(dOHrf2UJ6>2#fiQ4Dd&E8M>i*^U;L9b4rQCK-GV@enaYiY-q^ zsG#t`R++0q8`tJIu|>i8z~+5~m2Iqg8uk{OP>yz#+T_KIvNyVW3*Be@ojEBuS5=EX zk~|Y5P(&>y!Ar)js;!gz*TaU3+>0lTUqnQF%qNaH&JWl4<1g&r<5xoIvWb88X?`9K zhWsyq>5~bawn8ic6{6CP1B&xhM5W)48$dPJ73}9OLoAl*ahhsRvT^pQHk*wqdoNAr zn4)mz^4E&gWYSvhjWunCrJD@PTLT^~WC;n@F9NbL)HAk`owr9z4oB^U`hD4d_0`?c zFi*)bl(|!X_Itv@;V5H$#qoVc`(WY4Ud!}=+s~f+Lsfb+OI(4#zf@N>tlZBh8Dl8??-AU_;zN`jhlxI2J97AY-nIR z5xdcyv3TOuLFmd8FQ=N%4br!a=`bE&%e{Pu@88^`coU>%7Pr-SwTTHDUSyjmnNg9*(|HiD^7iHA~ z8W;Ojy)8I#t|a<-j7T2$YmAo9m}!(emub^N?5)|JJ%{+59RXsQ&VTc!ou1%AYI4JM0Y&}1Iz83&IQUi^gPd!E^0E}}+@0SB!Pfy~A(*-jU z@S17ay!=_87q#>$v7}*P0Xkr#He*9Gux)ZI9Y>W1%8&x9y-%?2Mz0TAv^KqUsp(&o zFhM4_yBZg5BHOjx7~{s79k(}{GpTgClj{WOh&RS>j6tzzDkFZ-D^emQDJRs2Q9LKD z-=~nsnLv=!Ho&&S$v;#xqYSbGsi{G(#%-DEeJ=GX=si+rHy=JJO&BUMo(|~~ZCBMN zI?msJ<;cs7=pNfY!KB6SbF|iJAU#Jyw)In^<+L)a7B9Cir~7FCdP$&wPao?I*E?Hd zVV1Kt4t;chM;)|uS9Y3#M~vRYDPZ?lQmF{MBPpCWDG8XeQo^MGjO!12Cg}*~o!zq5ZLq3ZhhtYdQpQeS z|3ai!lf$bred;zpLB6`-(NE$`jq63-%^Rk%D<3ra)O+!t&$E@Ku6lQpM>ng^kUl>k z0u~pv{K1G&G*Z5m{&q@ZY3c!GTtLB_^E&zKT(b)44gbyYrl;(f)tV1lWhpr7jWcH+ z+S`*r`Mysvggl(O$#W++NqHW7fN`3Sq4hK~li@BC49B{U;^>Km4)$P;hPFh|pWdc# z5-P8WQ>Hr~ip267huw^LviZV=riCSD0qR|*IE4*=90OqF?X=NZhufUTUz&W*D9sXH zG?DvZroRWCHTj5V_oRF6u5;}SkLfVQW^oy({50Z!u$zGU;6JzsHQa+^lD}uF z#{xjT^jw)lxSpA!W${q;%PzK8sg3dXkDoin8xj0mne>!_<3&EzKwWcbG}ZA)rgse; z3w6a^l-jb7FkOvexp5C-pE#YUSIiTR-Bq;4B{Oq+7P>W3YDDxtl5d^vvGu4NYgT^F zaHsZ$nv!5#Q99C zx0t1jtj$)xp#u5y{kr$*)>PPUJWl?4m>j!SAI;F$`2%_P$@LR#d@|2CSN8K(8DxLe zR?yC1lXe;BP*{qP6_KTXjN-D{@_${cwkU?FFlU%bNRT!{O|m*Uk1hsNrO zcE@q#3TeoFD<`(@0xNulq1ra}#D0zYm+0pf>X)e(oTtyK13|t3*FNx|RCHSFKC~Y6 z6vN6cU*gBNkP zw+_&aTZUAc?xCYAyP_?BhqUgnWtXnEH5WoM>Q+;P+EeQe8e_KFW=O1n=J(aeC}!`a z6x_vNK50i_2YJ2`{mk)Up>Zmw9=ZXAwt{#OTO&I`*kwJhd4Kc{Q{rr3vBS+4b~Dgy zWiKD1CedZ|<`3Inn@Gags?7Ax_>#l28WE*)JRV`_wi~$sP`d0@n)Jo4bYlcMGy)~9 zmMvS<`G6ofse(lxYgp?|iC&)(sAgFi$GK(r%swbxdGKLwS2;I?=Mi_$L24-_H)G!y zU511FbfRl?MvF!?AQ9amN?i~&+!VZRde6sev>84*`8@J@G`SJ`UfyYWFR7F%QU>I`R9F6s8~! z(xdC)iyt50NT-2ae7o*hUXgruGm1T# zN1fYmYf0|$^PS+aXLzREfep}n{#-YBZ&I5gXHGmXm&~5o!S?Vue(i3xw(oTXUObm;*w{tCe&nrfL zW1en4?`F+=+q`OUI6n<&j6ySv%?X&9t~dH;Wb&n`4EW{;!L- zup6CKg=4!e$Xq@$6P6>hk`#7~nO}E7?2rrRr(|UOm2V=2M*+7it>>%5@@7lY5yVahZJG}$l~U*2n>y3z23%hI$8M?0&9q@Evw4t3+=}bV zzU(9_FuSBT^D$|Qj2gh;KAdML125K}PAtN#jh~xYjSLJKI1wHdQWY$o_2!o8H;*=b zzG2q`KXFJ#Nf*ut^UTYFl>u!xvxqd08zaa&>`3t7OR3drx#MC5T)eB0yB6QlUf<(U z9Pvo)tnbtz=*wN}3rkZy1^A)UrwwhJzK@Ln!+ZkdjiayWO}vf3;BztYeXr~LgJpVM zc5-WzsPC5n%v|5{;8W7p%-r`!}+EsX7Y3$D%d74yW5neHkB^NCCS%e*;1T%+9kJUf2M zux4^rysKh&IlAI%k$q~R$2n?v1q?qs$Pq(*=?<<(J7~jnmI}nMpUL$R7WSRJQ$RdX z78c~XKcu_y6PNDT_>ir4@>k1@a<2K{kn5Yy*Mll5s-9mDM49~T`|{;L2^jXwCfm|F zJX(HW1vAuahNDTq=!g4R5yus++r#Oa zPkScy*AggPJ#2@xYNb-8Xp2pLxk(t^K`Jgd2JDHo>5%F4S9y^^{sJ2V%m>d;-4##t ztEm+FzTq+$%K_bWJ7Oke0kFMA_hOdC?^gn1EoDdp#VQ<3v$p_5R+C@8TU~v0H*wsP zpDcK2^=xbPyRRY!Yw3w9eRG+0s1#P^)~YW8#nlTx)y}RxS0mL zJz!J5e$W9|%iLnr;4#O`wrZ~Szn z#8eC&9@eguC}gj7-GH?vr)N!9LHZ@en4e5sX%#5G1A6stKUB8&Y|#}O_%Zjb2#Bs>zn8?Y_JaPg7P)jKpopw;n*!(e>I@OY zxvUP3)tuTxgEc>XVD?F;*X0hKVj2%w@@TczL2&_m*7&N?bng`>;MKFcyd7h%cp2YOB^@xm`o2 zzi;bwl7%K?)dd&ExE;XPn&BB6a(+wW$?qe6uLhrA1M=YK_hNKGV|Kz-1mhCH&Na6- zUn{Y-e67?;-V1jym^SP4z2jCw3`1cv$HzX;CxTX!dv_tjXk&o~cT3j2pF!`N)96HL zL(x`4|IGvBjZtw)1viBf@Z_}tJXY&)3YqaM(PS!XaQ|#)f`j?+YvwI2RexP(QkfIa zy-#iyt#L7EAbs*A?yG3ffHa$Tf8dbxy#y8z7o0wQTI0y2VA%CV~4Hhm$tkszwc@2t21u$IHf@_zN@+H!ZX>$mE76QV3F z`MQY@gqkSQG7VH6P|j;q5v7u798A>oh*^IOT3XASeQ%{OB|NKhk=T%`E`Dg~b)Lf2 zje_yd{B9|Sy+$cfn^{iPV?DNPem3dEN{?|$p5M^ZQd=o+S3H*z=rXhAn9G=j^sQZ+ zk^P7rD~JiXxXmSQXnnEBMD z)Ym|uPzL>m!CVLBMh7XvW^HOQGOWadm9mDL;}ngZKNUN#uJnsvvDQ7jGB;_IVj3Os zNZ}mBr}LWj=l}|3#us+{iJ0Zb>V(Ye$C*uhPlj==MiYU`6F6sJ^yNuh2csF!u_TL^-`%1c81#`< ze|kY0!rCQ(qdt*eTa5KRpjN=dH;2v8pzvUdGN0T(u%a0 zO`LUYe@@aWwtZO3GJXTNcPEC--_b~!etyxmeKTy~#OvckKe*)!J)0<+Hj{9hqG8Hw zzCaW6pwE=w-JlsewLOW_o$3S1-Cd-(Ui6+8_~pmDvP((`F`u!VbrFxuLayIfhfa0~ zJG?x)RcqTWW50?}+YAa`cgw}Bjg?NxYBP_zlUrSzukN{S%-oOUy6N`nZdEs(*4_Pm zl&`xR$q%`&I5{0}H)HhUfInd^1UoIoOBa>pW~*!V_cXY`tVl+b<|{w4qMESJ)>g|d zxvMe}RNesd6gqM{^YXhRVeMEfL8~RkCMP=pT)?SPnR)g7bS$3$Uk;N>xd~nRE2p$| z71a%d&55tpd%T>DL!Xx#c0v{GpDtf^H}`+a0JBlRQPT3aBv+p;rXK#PWIe zK@-edO^3Sc3i`}6$v&jZE@}dL`5ok>t=D90OTWz{9*cU<`@+aktT}ti@~YQ!n-{V? z7jE3WqA&vfgain(zIRxblB0|t1pK(Koc0lKN^drpkeD;G^6T6w>14lTOB@_}5(L;dlK>d=SFm}bA2pd%L&k2x+hpoZQ=+SkfrYu_>x zw|9D|z~^~M+8!TDpp3`t0GDz59i2TO4_+gAk%RGV`y^PPV+jCg3GL&lh$k^pV#IZ@ z>{>hsRyrG9YKxcq_6qXP%JM;l!K|k!U%FeTse8IEZ)19aaSk?BYyM1o^%>51^_8Of zv7ENqKT_0Up4j@{x;eZ&W{^TmZ)p*GbCjFCSAxG}s*UUDb7NrvUEiS(!x`iHzWCwu zq{UlPmQT`GL`%!v3Zpm9c;O@?8|v@s66~QpuIb#-pw~+@02q(n+=D+azTKOn0ZbjvmW}5YmsT_kTh6(T)HVgms;0@eb4M0 zKgCem{0(@YOA_XE=qFY^ zW@z*EMsCHV){LJ)C54_=uFwJ8YQ8TGR) zW1Jo(U4NG1>6u%xFv@gdSV;GJ2E8Cn#~A9o`ekN8R+Xu4L|~W!E~6)Ps>qcRFm3vP z8JbHOv+2zD>K{J*6@n(hIU}eDXEL*e&k^jKz>U5A?Ae3m zY2IX|%Wh25AujifMyo$xZ!^r$n0=TaN~C6yGh7(U8r!DbjU5ZhTRRSyOdlKeWZSkw z`PEkg^9Alpt+#9ElH))z4;nU{Q9e0Vj7;`6f%-|B};l4}5A@u$11FK~^-6*(O zi1b$j10AP~M7)CZ^_nIN*IDDCJp|eZ1-%Ase#v_Tw_O-tYP-<(mI~K)L$s zpcvOW#kO)NBpR}&dy*csxgKJZd`5>~cZ9xu$?9lu;l>Cb^t8`4`e&|Bbdu|07P7|} z?btsy3gtB&tgBx(pF|bA3e%#Z-jz*Jxy(OBMnL_u4EiK<*>V>DO6t>dO2M|#OEI58 z=pM$Gy&h*&#cm$`L#*4kXP%Gf%MsC^49;!j`t2G{Q{5MD-?L1`gVl@rq|-AsDZH_H zln}Z3b5#^(Hr^Gp0&2WUAht6*RK%~vvKQ=mVY!!JWhGqZ)LWw2uY1RLT}5+H(@IX> z{bzx=h2_w5M)+I$b4+@9P#O6_I9!Y$s$0jN6ZiM%di&X6)jr2;xMIde&AqBC$h~L&`NWl)-H$iN znLD|)eYGc+7N*@~7rgeBb2L~WhBWl@eGE+4XhCnnJ?_Vy$*?j1qWz1l0u)OAQ;Art zW>T(J))-%v|ClEj(OCinLtSy7DFjnvS755?v-7fChPkX)qjq06GIIKiNo|sMZASXW z<=#>1coIg2+X`%z zST%mlEVF8y*pz&89p0?RrkFwfNMO@$%+B_m&X>;=w|mf^7exbWr3D~bJ94*UyA;`9 z9x!*0nrQpNEj?nXIx!*UYg=Ftj;pw%-2R(cQ%_7QPKs?cDzbsjvB9C;BhJ5lnc%ve(Bz%xuQ~yPda{xTh+biN>gd z^x>rrRZdSUKD^6=?gas${@>U4ticpy#Wnrg`^I`Tf!ARrQ}0BGvynWRZ0G&klMOy4 z?0$KUt!(4M8R)$181V3X$uRJ%xCfn@%{%^)E(N(nz#0WJD?Ltqq_LxMcBeD%WSlq)@ji04%R<%=zIpRp;0HqR^&;aMKjy4f zg^5YMV(M!|%YNXmygRRa=EDaRd#%yNJEE4+#b3XM>wQe`>{s5%Pc7vNQGgRS<`oQ@ z1Pte=md&4TEp|#9GQ294qP9G0FC8`9s9AR%T+Iz* z!GCRIe}BpMwYfRHnnAS6 zkjkByVMs+)Vsq>;z-VDlYO8jSj`BDAGja_Wqkj4puj&4@@&Km`C!k4ZsDegX@hP9; z@?(kvtZrXwmO1-;+hY~6qF*-?YQ1Ewt2YO`$97NDYEHCoTL4&uqLp5@F)p|PI^w)! zrV(kDq7!egW+mu|_oy+%_uthKci~h-&l{SrACPEqzrN#}f6ysLjo(_;xa{T+e@fM& z*n7j>p;e(v8~3`K^3~Lz``lK0^6b{5ks5oS_{*KhdD8~bN9V!RWkg-A1gx-~H3e?V zAm66t?e$^j(AGOOE_(aAgU}uo>GTJptf#?UcllG%q$#|s?$l1vWZ@J|mEXRR41Xb5 z40V5C9^dg>ydWK`j6U#Fs>+2kuLCV84uaNzid;nVPwGWGKTg>HZ(pBVM6o4(+;>>d<40A~NXbQud<6o}jZU+;;i{Avw{xIyNW_vFya(8oODBA_c_?CM!4eYY& z1{JM&Ph3~Be)d&j1N$dwP}TxUH>cknA3pV^)BADky=WpK{> zoPifkQd-Zml$matxjAA2MmOb*sqen$le*X) zywc$g!P&G*F0J~`1tA>?fcXh9zIfupRG)j@;%85cO4GuJUCGrVFV%Dt6>7e?L-;_B z-?+qp!0}QcY;*ih+x{LyVS{~-PX&dF-OT<0Y2SaR>)H{kbb&_?D@Xt{9)YdNDKXRox0=M6n` zvVE>xKdGQLPk`)Q6(w-?jrK*-;^1WLifgx~Xw%y~g_{ucL?S8k{M|MU9EcyGC4w{4 z9PwbG4oeATLH#F{-EBG1eFJ7fy09J>dopdZ>(17s4QB3Nye?SCkL6q~k9);oX!GI! ziic~kK&QeHvNvJvsx$p-3=3VG0dv`=QOSpxF;`p5z>VSJ;)$x)CrmHXJfUIT+i)rN zuu(WQ;x1L`_WfYs>dpbXhMZY&n!ucz5Bwfq#r59Y_gFH+`+SRpBf2LP=ZfrxKcv=i z9lze+*u{QP71Ms-HTqWa>{ykIT`~{fMZ8JReDrXUJ{a8vuAbU(K&1XmoG47!mPteM zR)NTrr5v^zuvQYwOXOwV=75`=qL4M`CnirNKBat78}68Xuw#pueIC=B$`jZ8sY+iK z9|9mXTR&H$qIt&m6jmrUNg!yx3`}UzIGaZ>R$@0pCYMRmF-n(!5&vuFm}pnqCP+{_H@efK#g zUp}eSmUkYFiewmgITGep06=9j9$BdjF0Wy<n&O3hEtV6Apu-fp~!}wnWTY94E0u_%(cKt94rfL*916L^tOY z`_nfzjDimClK(qi@iIXm{_^oina}fha>-8jOP=15@Qp)!bs-PE!43D@-Ou)dL&sPx z_jJM}ym>oJfcal^bfhJ^E3CNK>xKTJr$Lz~@qycC*mhzZym9#mu+w9*w`TpKmUjk1 zH&MRk9Xb2w$Oq#H?VlIqyp`PMLJc>>N6ag?5PuiFW@1GI7W&huGZixLy z=f*7#KNsBf3y(<;tViLgfNX^^9x1+O~u&9y^;@qej?%r)c3n5-vdv&VY`eFg!Z9z$ysguijm!T< z3qi_RfBC@Ja0ZZf>Y2BByvJ|OX(Gg))@JBNjk>^2BjZjUNLy;|9LIK_f6BUh{T7}! zr(?TEHL49))zM9`ks9Gz?dr1@43IYht@iQ?ZpQZ8WUODj&2t`iW=oF!7LDjl5g~Dc2~OKld*iHu zhT<2?&gxH9p`9!9C0tL>3&u#@aMCT|Njrj`TQ|(&Qp{togy13+o<{+{Bk#f5w@hN~ zgm+h7VyPczNv`^Oe84&}vq!#ZvZFC(A#|CNZtiyYcd!%n7@ylU^#XV92Vk2XF&=Pj z_a!+89<=!6{H~fdayCWfN=uWgnemv3*v4w6*7YB1>Ib<&n4(ZaiXtw=ym3*`!l8=Jt{VJq#}L)SG?10 zK%Ny?O{h)L9|k$56Q?u=Gsk`mZ&+OUq-QblXf>gZp&Yv@%pRoSzYVazEka*j9tOTn z?(5mQH6;8Ya>5UU3>OwT{{Yk|!|l5GbY7ra;iLRF2Au;{8N{@^t`<^jg1L(XJ^6@R z{XO?w_4gEMH5@p6vH2`mwxqR)_oJCjjKETnNxHR=;P$~U2^`N6IVQ6@xYx6rR4ee( z$B3WN+1T@v?b&mV@_+8v7Opw*;xKq1HGt{I?ROYjXDV}0>z}%T&=Im+2~n;Tohvx( zu0jja-np@?O|0Bnb^To3I$oY+Rg>KxqOsX(*-(k0bx+^ohzq0>#5EUOV{1TM9QARIAM;74=a_;zXD~l| z)QiQQcx@GU^Z~_>mIGWtQj`4apv4^Qa?V-54rZDjesu#is7*Rpj(}N${EpX~$GDvK zPkttHZRM5iqg($U=o{u^Wqv8Z6th_=dvy^$rs!#WDATVb7Lo3p>Cj{$w>oULlMHas zU+`d5e7nZ*Vy7+iK^TTr>4-`HPdksP77+kIXz^Z)s5>nYm)+-tZwL>(tUK0x_JFeX z{NceNopEhvfF41{*bEnHHSP)AUl-2n*Bn9${31XzRllN3Z>g#c-Bab;+{(OP=H3v_ z?WRlDrC6pvf`bK^GX2qDv-P@KfQj!;vtjxFNS#!wxIYYp7B1aUBeYis<`#eYSJ97y zei8Pseo_a1A>4S;@wmThDBVS2-cQSU78yR!QZ&#E`_nsUq~GrV(dXbi=oOtQHm#vs z9PJ9Nny&RWdwD+)S}pFYQ-_mVLcCFm8B-8nO_&L=Hd$s)mfB%DJl2bfbP_z{l}>FO ztMi?I8Z346-#R!=L4^4Kme#n%VWP+&2)$p0tuzm$OdW^|@Zs}>UHIXA<`-3~_G5|Z z=hnwLuo=aS22jE2-zWcR*Gu{TRBIF8skM!XKJe(0%3{N{^>%km&U(>$@XDr6#5Mf5 z};x@LSB4`n_u1^qzvt3JO+jMk6TnsKd_bo7Hqf8%}Rc+hs-0XuSN zJ^hmeS~Gg-;Y6@gGVuF$|N#k-fA4{g(`G<->O3IIvD9C!l|0T}^Fjf8hVzahFv?cdy=Qr0u(F$?;@CA8w%d zsry=*kp=1F^ri2wZOd<{(8$+!6FV#ct$W~4TK@Hx2nO`-U;HN69H2(whPB&ALzZQzMI%@EI?fCirT$gHD1-Dg;=So&<`n2HIr0J*gLS>I@$Fb5Pf?`1QS$wPr z`;q>Tt(8Q^8!frbv;Yb=NlOm=Tb+ysQbT?vu9!z6sV9O;~o}*0n-L2yHp$7)u zuDlGcp_?sEWmZTzuJd@Iu)WjkK*;sS81AYm1<}7r=t1A2rOktT=lj_9chz}J5is{1 z7gWQczA;e=AOTEk-KVjpXM7?9Xh+Q-O<4cGlJ)A!_-9{$xLolf`p}-e9Q{oNKY)(d zI zbWk!ctIIx&$kupff=NKu9IuSaTbOWM>i~PITAWNm?%g42FqbwxauNqNfrgp~519}M zCw32^gR@V1p7N1Ty!r*(b&t2u=igenKsjRyXG(b7`+ZRM`6GvoNYteWnD>)q#znB1 zq#PD86dL$Ue?#-s*~`zoV|+zx84y7U!`^AgPq2DB_6n?@d|-zS$n*U)f9u^3%c+l!e+MXV-v!Agc|N4YorcgNBT z-o6@%tyG8p3Of6HFRq%BIO~!y)QO&^`A>^fGi_+~Gb2>N(O6>QUT+_W#_0fATH_CV=Cqpv=jI&F@cfJfrP<|i$=*oysRt)Cf-}$MnHqvBW@b@snqqF`yu!8Y$nz&f2%L`00;(PWn&V_G3FM+@>ASxTlBkY?n3_7j8V- z*2rR=fT}zbtqA~tF#uL?SNbeWe%90|&~tUQ4RrkEy<-(2S{-13>xZ|J|Fc<2?9VSn zvBNc3Bc}?mI~ht=s`HUwZ0Amb5>oT}ZI^&g8a;>Y`4YX`WtH~O40w`N6SB+T<2Jr6fJIbC+>5&G(=KhY!Dp(@Jj{{_tPI>EUlVyR>u#EDyg6LuYOp4?Yuy}v>IOkgFI(6_yfN?Vg4=o)WdFLH zk{oN{{E=V8iRgCItel-o%Snf0^*``4l_JDtXE}qWkPp--8q#({*lvmeX(LXivR`p)-Z%7M|K!7K*4kM=rc=Gp_IjhCvIp65kBv88hn0H#u)J_f zuF1z}UbTN$YuQhBxX(km-H$nxrCwe>uI4%2Cz}8!h*gV-a|%j0G$57t*&#Mu@4TFY z{Uv+-Hoj%CO(mL&TcIRQR{(tVu|%F|6|uBb+fdth-4fctpXV{FV?!zli!NNgXs^`! z6d`i?5K*pnZbcok6~(nosH?_FP?g?1xNe_MFrMBqu2(PUe>Y-+T_$wvucYUhCQ>p= zjvCq|KKl~L#%H)}(w9-h<4`2A>L~~!ng{LJDlnz$M3(JZmzlrQ6#1(Yq87)#own?= zlba}GL>+y!(zo$G`^mAGyho|!;jYV46qyYy$p2$tUc0Tb*W&nY)`&mCXK@G*tW9R% zmXY?QR5z z>Op(GBG0~bGGKbCEWqx2H@|Ysm?BMC-$F5af@Ab6RlQIu5ogw3M(|{yvRm#|hZGO0 zW}A>oVxq5y+j* z*R7{s4n5@!ubv;GBX(Y`ce+MdfQ@@Y?O(|AzgR}v#5KwOpWePYEUIs9dk;C%2uPQx zh^QbTog%3qps0Y9NOw0wE3K3$9U>wj-Hmh$L#Kjtcg(kD_?`2e^Som6*!2J=GfV@k`P&KoUpUbs!OjBBKcfm_g<~H|A!tX9 z>xXk=JvA0wCmO%gyHC9P@>4x-KDECkHp3y-G?Hr8&+=3c-64yQ{tDe#QH&JD&oi zcUwkbQiFHRF31bSGRkM(b?@P_W-QP%CLdpX7c_ga#asf?CItEz%LkBQV?=Kw6|#nw zdnFn9FI)>q^odLeR;4Pjb}RGbccbDy7GYx39}#0C2x@(9kZzK7 zŘ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 literal 35141 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 Pq-9!r!Q>Df{>}ptEf$ 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 From c4aa39a2bf276cd9a43e56cc5d1b5f34c1444e39 Mon Sep 17 00:00:00 2001 From: MrTJP Date: Thu, 10 Aug 2023 17:18:13 -0400 Subject: [PATCH 12/23] fix: scrollbar node going too far --- .../main/java/mrtjp/projectred/lib/Rect.java | 4 ++-- .../mrtjp/projectred/redui/ScrollBarNode.java | 19 ++++++------------- 2 files changed, 8 insertions(+), 15 deletions(-) diff --git a/core/src/main/java/mrtjp/projectred/lib/Rect.java b/core/src/main/java/mrtjp/projectred/lib/Rect.java index 00aa2575b..8e75091be 100644 --- a/core/src/main/java/mrtjp/projectred/lib/Rect.java +++ b/core/src/main/java/mrtjp/projectred/lib/Rect.java @@ -98,8 +98,8 @@ public Rect expand(int x, int y) { } public Rect trap(Rect rect) { - int dx = (rect.x() < x() ? x() - rect.x() : 0) + (rect.maxX() > maxX() ? rect.maxX() - maxX() : 0); - int dy = (rect.y() < y() ? y() - rect.y() : 0) + (rect.maxY() > maxY() ? rect.maxY() - maxY() : 0); + int dx = (rect.x() < x() ? x() - rect.x() : 0) - (rect.maxX() > maxX() ? rect.maxX() - maxX() : 0); + int dy = (rect.y() < y() ? y() - rect.y() : 0) - (rect.maxY() > maxY() ? rect.maxY() - maxY() : 0); return new Rect(rect.x() + dx, rect.y() + dy, rect.width(), rect.height()); } diff --git a/core/src/main/java/mrtjp/projectred/redui/ScrollBarNode.java b/core/src/main/java/mrtjp/projectred/redui/ScrollBarNode.java index 3db506774..8f3f1b5ad 100644 --- a/core/src/main/java/mrtjp/projectred/redui/ScrollBarNode.java +++ b/core/src/main/java/mrtjp/projectred/redui/ScrollBarNode.java @@ -12,7 +12,8 @@ public abstract class ScrollBarNode extends AbstractGuiNode { private final ScrollAxis axis; - private Point lastDragPosition = Point.ZERO; + private Point initialClickPosition = Point.ZERO; + private Rect initialSliderFrame = new Rect(0, 0, 0, 0); private boolean isDraggingSlider = false; private Rect sliderFrame = new Rect(0, 0, 0, 0); @@ -34,19 +35,13 @@ public void drawBack(PoseStack stack, Point mouse, float partialFrame) { drawSlider(stack, sliderFrame); } - @Override - public void drawFront(PoseStack stack, Point mouse, float partialFrame) { - if (!isFirstHit(mouse)) return; - - renderTooltip(stack, mouse, Collections.singletonList(new TextComponent("Scroll (" + scrollPercentage + ")"))); - } - @Override public boolean mouseClicked(Point p, int glfwMouseButton, boolean consumed) { if (isFirstHit(p)) { if (sliderFrame.contains(p)) { isDraggingSlider = true; - lastDragPosition = p; + initialClickPosition = p; + initialSliderFrame = sliderFrame; return true; } @@ -71,10 +66,8 @@ public boolean mouseDragged(Point p, int glfwMouseButton, long timeHeld, boolean if (!isDraggingSlider) return false; - Point delta = p.subtract(lastDragPosition).multiply(axis.vec); - lastDragPosition = p; - - Rect targetSliderFrame = new Rect(sliderFrame.origin.add(delta), sliderFrame.size); + Point delta = p.subtract(initialClickPosition).multiply(axis.vec); + Rect targetSliderFrame = new Rect(initialSliderFrame.origin.add(delta), sliderFrame.size); sliderFrame = getFrame().trap(targetSliderFrame); recalcScrollPercentage(); From f8f64df3da87ecd902b9cda5bba255b7a81d440e Mon Sep 17 00:00:00 2001 From: MrTJP Date: Thu, 10 Aug 2023 17:59:11 -0400 Subject: [PATCH 13/23] fix: fabrication machines not dropping contents when broken --- .../projectred/fabrication/tile/LithographyTableTile.java | 7 +++++++ .../projectred/fabrication/tile/PackagingTableTile.java | 7 +++++++ .../projectred/fabrication/tile/PlottingTableTile.java | 7 +++++++ 3 files changed, 21 insertions(+) diff --git a/fabrication/src/main/java/mrtjp/projectred/fabrication/tile/LithographyTableTile.java b/fabrication/src/main/java/mrtjp/projectred/fabrication/tile/LithographyTableTile.java index 7830123d0..eb40f8525 100644 --- a/fabrication/src/main/java/mrtjp/projectred/fabrication/tile/LithographyTableTile.java +++ b/fabrication/src/main/java/mrtjp/projectred/fabrication/tile/LithographyTableTile.java @@ -3,6 +3,7 @@ import codechicken.lib.data.MCDataInput; import codechicken.lib.data.MCDataOutput; import codechicken.lib.util.ServerUtils; +import codechicken.lib.vec.Vector3; import mrtjp.projectred.core.inventory.BaseInventory; import mrtjp.projectred.fabrication.init.FabricationReferences; import mrtjp.projectred.fabrication.inventory.container.LithographyTableContainer; @@ -89,6 +90,12 @@ public InteractionResult onBlockActivated(Player player, InteractionHand hand, B return InteractionResult.SUCCESS; } + @Override + public void onBlockRemoved() { + super.onBlockRemoved(); + dropInventory(inventory, getLevel(), Vector3.fromBlockPos(getBlockPos())); + } + @Nonnull @Override public LazyOptional getCapability(@Nonnull Capability cap, @Nullable Direction side) { diff --git a/fabrication/src/main/java/mrtjp/projectred/fabrication/tile/PackagingTableTile.java b/fabrication/src/main/java/mrtjp/projectred/fabrication/tile/PackagingTableTile.java index a040ca24a..8cc9477a8 100644 --- a/fabrication/src/main/java/mrtjp/projectred/fabrication/tile/PackagingTableTile.java +++ b/fabrication/src/main/java/mrtjp/projectred/fabrication/tile/PackagingTableTile.java @@ -3,6 +3,7 @@ import codechicken.lib.data.MCDataInput; import codechicken.lib.data.MCDataOutput; import codechicken.lib.util.ServerUtils; +import codechicken.lib.vec.Vector3; import mrtjp.projectred.core.inventory.BaseInventory; import mrtjp.projectred.fabrication.init.FabricationReferences; import mrtjp.projectred.fabrication.inventory.container.PackagingTableContainer; @@ -89,6 +90,12 @@ public InteractionResult onBlockActivated(Player player, InteractionHand hand, B return InteractionResult.SUCCESS; } + @Override + public void onBlockRemoved() { + super.onBlockRemoved(); + dropInventory(inventory, getLevel(), Vector3.fromBlockPos(getBlockPos())); + } + @Nonnull @Override public LazyOptional getCapability(@Nonnull Capability cap, @Nullable Direction side) { diff --git a/fabrication/src/main/java/mrtjp/projectred/fabrication/tile/PlottingTableTile.java b/fabrication/src/main/java/mrtjp/projectred/fabrication/tile/PlottingTableTile.java index 911ee730b..fede6abfb 100644 --- a/fabrication/src/main/java/mrtjp/projectred/fabrication/tile/PlottingTableTile.java +++ b/fabrication/src/main/java/mrtjp/projectred/fabrication/tile/PlottingTableTile.java @@ -3,6 +3,7 @@ import codechicken.lib.data.MCDataInput; import codechicken.lib.data.MCDataOutput; import codechicken.lib.util.ServerUtils; +import codechicken.lib.vec.Vector3; import mrtjp.projectred.core.inventory.BaseInventory; import mrtjp.projectred.fabrication.editor.EditorDataUtils; import mrtjp.projectred.fabrication.init.FabricationReferences; @@ -91,6 +92,12 @@ public InteractionResult onBlockActivated(Player player, InteractionHand hand, B return InteractionResult.SUCCESS; } + @Override + public void onBlockRemoved() { + super.onBlockRemoved(); + dropInventory(inventory, getLevel(), Vector3.fromBlockPos(getBlockPos())); + } + @Nonnull @Override public LazyOptional getCapability(@Nonnull Capability cap, @Nullable Direction side) { From 61c0913c333d300b29d49e015afc3a7e92a945c6 Mon Sep 17 00:00:00 2001 From: MrTJP Date: Thu, 10 Aug 2023 21:30:53 -0400 Subject: [PATCH 14/23] fix: fabrication machines not saving contents --- .../mrtjp/projectred/fabrication/tile/LithographyTableTile.java | 1 + .../mrtjp/projectred/fabrication/tile/PackagingTableTile.java | 1 + .../mrtjp/projectred/fabrication/tile/PlottingTableTile.java | 1 + 3 files changed, 3 insertions(+) diff --git a/fabrication/src/main/java/mrtjp/projectred/fabrication/tile/LithographyTableTile.java b/fabrication/src/main/java/mrtjp/projectred/fabrication/tile/LithographyTableTile.java index eb40f8525..c98c09f0a 100644 --- a/fabrication/src/main/java/mrtjp/projectred/fabrication/tile/LithographyTableTile.java +++ b/fabrication/src/main/java/mrtjp/projectred/fabrication/tile/LithographyTableTile.java @@ -55,6 +55,7 @@ public void setChanged() { public LithographyTableTile(BlockPos pos, BlockState state) { super(FabricationReferences.LITHOGRAPHY_TABLE_TILE, pos, state); + inventory.addListener(c -> setChanged()); } public Container getInventory() { diff --git a/fabrication/src/main/java/mrtjp/projectred/fabrication/tile/PackagingTableTile.java b/fabrication/src/main/java/mrtjp/projectred/fabrication/tile/PackagingTableTile.java index 8cc9477a8..385222f3b 100644 --- a/fabrication/src/main/java/mrtjp/projectred/fabrication/tile/PackagingTableTile.java +++ b/fabrication/src/main/java/mrtjp/projectred/fabrication/tile/PackagingTableTile.java @@ -53,6 +53,7 @@ public void setChanged() { }; public PackagingTableTile(BlockPos pos, BlockState state) { super(FabricationReferences.PACKAGING_TABLE_TILE, pos, state); + inventory.addListener(c -> setChanged()); } public Container getInventory() { diff --git a/fabrication/src/main/java/mrtjp/projectred/fabrication/tile/PlottingTableTile.java b/fabrication/src/main/java/mrtjp/projectred/fabrication/tile/PlottingTableTile.java index fede6abfb..bedbaaacf 100644 --- a/fabrication/src/main/java/mrtjp/projectred/fabrication/tile/PlottingTableTile.java +++ b/fabrication/src/main/java/mrtjp/projectred/fabrication/tile/PlottingTableTile.java @@ -54,6 +54,7 @@ public void setChanged() { public PlottingTableTile(BlockPos pos, BlockState state) { super(FabricationReferences.PLOTTING_TABLE_TILE, pos, state); + inventory.addListener(c -> setChanged()); } public Container getInventory() { From bb3f5f523f06bca99a615db767c343c8839638d0 Mon Sep 17 00:00:00 2001 From: MrTJP Date: Wed, 15 Nov 2023 15:34:43 -0500 Subject: [PATCH 15/23] feat: packaging machine ingredient handling --- .../projectred_fabrication/lang/en_us.json | 5 + .../data/FabricationLanguageProvider.java | 6 + .../fabrication/editor/EditorDataUtils.java | 11 +- .../fabrication/editor/ICWorkbenchEditor.java | 3 +- .../fabrication/engine/BaseTileMap.java | 20 +-- .../fabrication/engine/ICConnectionType.java | 7 - .../fabrication/engine/ICInterfaceType.java | 28 ++++ .../engine/ICSimulationContainer.java | 16 +++ .../fabrication/engine/IIOConnectionTile.java | 5 +- .../fabrication/engine/InterfaceSpec.java | 130 ++++++++++++++++++ .../fabrication/engine/gates/IOGateTile.java | 6 +- .../inventory/PackagingTableScreen.java | 20 ++- .../fabrication/init/FabricationUnlocal.java | 7 + .../container/PackagingTableContainer.java | 27 ++-- .../fabrication/item/ICBlueprintItem.java | 17 ++- .../fabrication/part/FabricatedGatePart.java | 73 +++++----- .../tile/LithographyTableTile.java | 4 +- .../fabrication/tile/PackagingTableTile.java | 95 ++++++++++--- .../fabrication/tile/PlottingTableTile.java | 7 +- .../textures/gui/packaging_table.png | Bin 5045 -> 8019 bytes .../integration/client/GateModelRenderer.java | 9 +- 21 files changed, 382 insertions(+), 114 deletions(-) delete mode 100644 fabrication/src/main/java/mrtjp/projectred/fabrication/engine/ICConnectionType.java create mode 100644 fabrication/src/main/java/mrtjp/projectred/fabrication/engine/ICInterfaceType.java create mode 100644 fabrication/src/main/java/mrtjp/projectred/fabrication/engine/InterfaceSpec.java diff --git a/fabrication/src/main/generated/assets/projectred_fabrication/lang/en_us.json b/fabrication/src/main/generated/assets/projectred_fabrication/lang/en_us.json index 8b894049c..39cba5c16 100644 --- a/fabrication/src/main/generated/assets/projectred_fabrication/lang/en_us.json +++ b/fabrication/src/main/generated/assets/projectred_fabrication/lang/en_us.json @@ -26,6 +26,9 @@ "projectred_fabrication.interact.toggle_delay": "Toggle delay", "projectred_fabrication.interact.toggle_io_mode": "Toggle IO mode", "projectred_fabrication.interact.toggle_state": "Toggle state", + "projectred_fabrication.interface.bundled": "Bundled", + "projectred_fabrication.interface.nc": "Not connected", + "projectred_fabrication.interface.redstone": "Redstone", "projectred_fabrication.problems.dead_gate.desc": "No signals drive this gate", "projectred_fabrication.problems.dead_gate.title": "Dead gate", "projectred_fabrication.problems.dead_wire.desc": "No signals pass through this wire", @@ -63,10 +66,12 @@ "projectred_fabrication.tooltip.cannot_fabricate": "Cannot fabricate", "projectred_fabrication.tooltip.corrupted_discard": "Corrupted NBT data, please discard", "projectred_fabrication.tooltip.defect_chance": "Defect chance", + "projectred_fabrication.tooltip.input_mask": "Input mask", "projectred_fabrication.tooltip.io_none": "None", "projectred_fabrication.tooltip.io_types": "IO types", "projectred_fabrication.tooltip.left": "Left", "projectred_fabrication.tooltip.name": "Name", + "projectred_fabrication.tooltip.output_mask": "Output mask", "projectred_fabrication.tooltip.right": "Right", "projectred_fabrication.tooltip.size": "Size", "projectred_fabrication.tooltip.tile_count": "Tile count", diff --git a/fabrication/src/main/java/mrtjp/projectred/fabrication/data/FabricationLanguageProvider.java b/fabrication/src/main/java/mrtjp/projectred/fabrication/data/FabricationLanguageProvider.java index cd66d28ed..3cd2b138d 100644 --- a/fabrication/src/main/java/mrtjp/projectred/fabrication/data/FabricationLanguageProvider.java +++ b/fabrication/src/main/java/mrtjp/projectred/fabrication/data/FabricationLanguageProvider.java @@ -104,6 +104,8 @@ protected void addTranslations() { add(UL_NAME, "Name"); add(UL_TILE_COUNT, "Tile count"); add(UL_IO_TYPES, "IO types"); + add(UL_INPUT_MASK, "Input mask"); + add(UL_OUTPUT_MASK, "Output mask"); add(UL_TOP, "Top"); add(UL_RIGHT, "Right"); add(UL_BOTTOM, "Bottom"); @@ -122,6 +124,10 @@ protected void addTranslations() { add(UL_TILEGROUP_TIMING, "Timing"); add(UL_TILEGROUP_MEMORY, "Memory"); + add(UL_INTERFACE_NC, "Not connected"); + add(UL_INTERFACE_REDSTONE, "Redstone"); + add(UL_INTERFACE_BUNDLED, "Bundled"); + add(UL_UNIT_WARNINGS, "%d warnings"); add(UL_UNIT_ERRORS, "%d errors"); add(UL_UNIT_TICKS, "%d ticks"); diff --git a/fabrication/src/main/java/mrtjp/projectred/fabrication/editor/EditorDataUtils.java b/fabrication/src/main/java/mrtjp/projectred/fabrication/editor/EditorDataUtils.java index 8b9ae1086..312f46590 100644 --- a/fabrication/src/main/java/mrtjp/projectred/fabrication/editor/EditorDataUtils.java +++ b/fabrication/src/main/java/mrtjp/projectred/fabrication/editor/EditorDataUtils.java @@ -1,6 +1,7 @@ package mrtjp.projectred.fabrication.editor; import mrtjp.fengine.TileCoord; +import mrtjp.projectred.fabrication.engine.InterfaceSpec; import net.minecraft.nbt.CompoundTag; import net.minecraft.nbt.ListTag; import net.minecraft.nbt.Tag; @@ -16,8 +17,7 @@ public class EditorDataUtils { public static final String KEY_TILE_MAP = "tile_map"; // CompoundTag public static final String KEY_TILE_COUNT = "tile_count"; // int public static final String KEY_IS_BUILT = "is_built"; // boolean - public static final String KEY_IO_RS = "rsmask"; // CompoundTag - public static final String KEY_IO_BUNDLED = "bmask"; // CompoundTag + public static final String KEY_IO_SPEC = "io_spec"; // ICEditorStateMachine public static final String KEY_COMP_STATE = "state"; // byte @@ -68,12 +68,15 @@ public static CompoundTag createFabricationCopy(CompoundTag editorTag) { copy.putBoolean(KEY_IS_BUILT, editorTag.getBoolean(KEY_IS_BUILT)); copy.putString(KEY_IC_NAME, editorTag.getString(KEY_IC_NAME)); copy.putInt(KEY_TILE_COUNT, editorTag.getInt(KEY_TILE_COUNT)); - //TODO handle other types of IO - copy.putByte(KEY_IO_BUNDLED, editorTag.getByte(KEY_IO_BUNDLED)); + copy.put(KEY_IO_SPEC, editorTag.getCompound(KEY_IO_SPEC)); copy.putString(KEY_FLAT_MAP, editorTag.getString(KEY_FLAT_MAP)); return copy; } + public static InterfaceSpec getInterfaceSpec(CompoundTag tag) { + return InterfaceSpec.createFrom(tag, KEY_IO_SPEC); + } + public static void saveTileCoord(CompoundTag tag, String key, TileCoord coord) { tag.putByte(key + "_x", (byte) coord.x); tag.putByte(key + "_y", (byte) coord.y); diff --git a/fabrication/src/main/java/mrtjp/projectred/fabrication/editor/ICWorkbenchEditor.java b/fabrication/src/main/java/mrtjp/projectred/fabrication/editor/ICWorkbenchEditor.java index e860b50fc..14308bb7a 100644 --- a/fabrication/src/main/java/mrtjp/projectred/fabrication/editor/ICWorkbenchEditor.java +++ b/fabrication/src/main/java/mrtjp/projectred/fabrication/editor/ICWorkbenchEditor.java @@ -138,8 +138,7 @@ public void writeBlueprintTagAndDeactivate(CompoundTag tag) { save(tag); // Save additional metadata for blueprints - tag.putByte(KEY_IO_RS, tileMap.calcRedstoneIOMask()); - tag.putByte(KEY_IO_BUNDLED, tileMap.calcBundledIOMask()); + tileMap.getInterfaceSpec().saveTo(tag, KEY_IO_SPEC); tag.putInt(KEY_TILE_COUNT, tileMap.getTileCount()); tag.putBoolean(KEY_IS_BUILT, stateMachine.isSimulating()); diff --git a/fabrication/src/main/java/mrtjp/projectred/fabrication/engine/BaseTileMap.java b/fabrication/src/main/java/mrtjp/projectred/fabrication/engine/BaseTileMap.java index df02b61b2..8d9036bbe 100644 --- a/fabrication/src/main/java/mrtjp/projectred/fabrication/engine/BaseTileMap.java +++ b/fabrication/src/main/java/mrtjp/projectred/fabrication/engine/BaseTileMap.java @@ -123,22 +123,10 @@ private void uncacheType(BaseTile tile) { if (tile instanceof IIOConnectionTile) ioTiles.remove(tile); } - public byte calcBundledIOMask() { - // OOOO IIII - int bmask = 0; - - for (IIOConnectionTile t : ioTiles) { - if (t.getConnectionType() == ICConnectionType.BUNDLED) { - int m = (t.isInputIOMode() ? 0x1 : 0x10) << t.getIOSide(); - bmask |= m; - } - } - - return (byte) bmask; - } - - public byte calcRedstoneIOMask() { - return 0; //TODO + public InterfaceSpec getInterfaceSpec() { + InterfaceSpec spec = new InterfaceSpec(); + spec.setFromIOTiles(ioTiles); + return spec; } public void save(CompoundTag tag) { diff --git a/fabrication/src/main/java/mrtjp/projectred/fabrication/engine/ICConnectionType.java b/fabrication/src/main/java/mrtjp/projectred/fabrication/engine/ICConnectionType.java deleted file mode 100644 index cdd9349d1..000000000 --- a/fabrication/src/main/java/mrtjp/projectred/fabrication/engine/ICConnectionType.java +++ /dev/null @@ -1,7 +0,0 @@ -package mrtjp.projectred.fabrication.engine; - -public enum ICConnectionType { - REDSTONE, - BUNDLED, - ANALOG; -} diff --git a/fabrication/src/main/java/mrtjp/projectred/fabrication/engine/ICInterfaceType.java b/fabrication/src/main/java/mrtjp/projectred/fabrication/engine/ICInterfaceType.java new file mode 100644 index 000000000..c6e16ecbb --- /dev/null +++ b/fabrication/src/main/java/mrtjp/projectred/fabrication/engine/ICInterfaceType.java @@ -0,0 +1,28 @@ +package mrtjp.projectred.fabrication.engine; + +import static mrtjp.projectred.fabrication.init.FabricationUnlocal.*; + +public enum ICInterfaceType { + NC(UL_INTERFACE_NC), + REDSTONE(UL_INTERFACE_REDSTONE), + BUNDLED(UL_INTERFACE_BUNDLED), + ; + + private final String unlocalName; + + ICInterfaceType(String unlocalName) { + this.unlocalName = unlocalName; + } + + public int getId() { + return ordinal(); + } + + public String getUnlocalName() { + return unlocalName; + } + + public static ICInterfaceType fromId(int id) { + return values()[id]; + } +} diff --git a/fabrication/src/main/java/mrtjp/projectred/fabrication/engine/ICSimulationContainer.java b/fabrication/src/main/java/mrtjp/projectred/fabrication/engine/ICSimulationContainer.java index ac6699f4f..004ab2f80 100644 --- a/fabrication/src/main/java/mrtjp/projectred/fabrication/engine/ICSimulationContainer.java +++ b/fabrication/src/main/java/mrtjp/projectred/fabrication/engine/ICSimulationContainer.java @@ -160,6 +160,22 @@ public int pullOutputs() { return changeMask; } + public int outputMask() { + int mask = 0; + for (int r = 0; r < 4; r++) { + if (outputs[r] != 0) mask |= 1 << r; + } + return mask; + } + + public int inputMask() { + int mask = 0; + for (int r = 0; r < 4; r++) { + if (inputs[r] != 0) mask |= 1 << r; + } + return mask; + } + public byte pullRegisterValue(int regId) { return simulation.getRegByteVal(regId); } diff --git a/fabrication/src/main/java/mrtjp/projectred/fabrication/engine/IIOConnectionTile.java b/fabrication/src/main/java/mrtjp/projectred/fabrication/engine/IIOConnectionTile.java index 259ddef5f..3f72e4d60 100644 --- a/fabrication/src/main/java/mrtjp/projectred/fabrication/engine/IIOConnectionTile.java +++ b/fabrication/src/main/java/mrtjp/projectred/fabrication/engine/IIOConnectionTile.java @@ -12,5 +12,8 @@ public interface IIOConnectionTile { */ int getIOSide(); - ICConnectionType getConnectionType(); + /** + * @return The edge interface type for this IO connection tile. + */ + ICInterfaceType getInterfaceType(); } diff --git a/fabrication/src/main/java/mrtjp/projectred/fabrication/engine/InterfaceSpec.java b/fabrication/src/main/java/mrtjp/projectred/fabrication/engine/InterfaceSpec.java new file mode 100644 index 000000000..210ac69ad --- /dev/null +++ b/fabrication/src/main/java/mrtjp/projectred/fabrication/engine/InterfaceSpec.java @@ -0,0 +1,130 @@ +package mrtjp.projectred.fabrication.engine; + +import codechicken.lib.data.MCDataInput; +import codechicken.lib.data.MCDataOutput; +import net.minecraft.nbt.CompoundTag; + +import java.util.Arrays; +import java.util.Set; + +public class InterfaceSpec { + + private final ICInterfaceType[] sideInterfaces = new ICInterfaceType[4]; + private int redstoneMask = 0; // OOOO IIII + private int bundledMask = 0; // OOOO IIII + + { + Arrays.fill(sideInterfaces, ICInterfaceType.NC); + } + + //region Save/load + public void save(CompoundTag tag) { + for (int r = 0; r < 4; r++) { + tag.putByte("if" + r, (byte) sideInterfaces[r].getId()); + } + tag.putByte("rmask", (byte) redstoneMask); + tag.putByte("bmask", (byte) bundledMask); + } + + public void load(CompoundTag tag) { + for (int r = 0; r < 4; r++) { + sideInterfaces[r] = ICInterfaceType.fromId(tag.getByte("if" + r) & 0xFF); + } + redstoneMask = tag.getByte("rmask") & 0xFF; + bundledMask = tag.getByte("bmask") & 0xFF; + } + + public void writeDesc(MCDataOutput packet) { + for (int r = 0; r < 4; r++) { + packet.writeByte(sideInterfaces[r].getId()); + } + packet.writeByte(bundledMask); + packet.writeByte(redstoneMask); + } + + public void readDesc(MCDataInput packet) { + for (int r = 0; r < 4; r++) { + sideInterfaces[r] = ICInterfaceType.fromId(packet.readByte() & 0xFF); + } + bundledMask = packet.readByte(); + redstoneMask = packet.readByte(); + } + //endregion + + public void setFromIOTiles(Set ioTiles) { + + Arrays.fill(sideInterfaces, ICInterfaceType.NC); + bundledMask = 0; + redstoneMask = 0; + + for (IIOConnectionTile t : ioTiles) { + int side = t.getIOSide(); + ICInterfaceType type = t.getInterfaceType(); + int dir = t.isInputIOMode() ? 0x1 : 0x10; + + sideInterfaces[side] = type; + + switch (type) { + case REDSTONE -> redstoneMask |= dir << side; + case BUNDLED -> bundledMask |= dir << side; + } + } + } + + public ICInterfaceType getInterfaceType(int side) { + return sideInterfaces[side]; + } + + public int getInputMask() { + return (redstoneMask | bundledMask) & 0xF; + } + + public int getOutputMask() { + return (redstoneMask | bundledMask) >> 4 & 0xF; + } + + public boolean isInput(int side) { + return ((redstoneMask | bundledMask) & 1 << side) != 0; + } + + public boolean isOutput(int side) { + return ((redstoneMask | bundledMask) & 0x10 << side) != 0; + } + + public int getRedstoneInputMask() { + return redstoneMask & 0xF; + } + + public int getRedstoneOutputMask() { + return redstoneMask >> 4 & 0xF; + } + + public int getBundledInputMask() { + return bundledMask & 0xF; + } + + public int getBundledOutputMask() { + return bundledMask >> 4 & 0xF; + } + + //region Utilities + public void saveTo(CompoundTag tag, String key) { + CompoundTag tag1 = new CompoundTag(); + save(tag1); + tag.put(key, tag1); + } + + public void loadFrom(CompoundTag tag, String key) { + CompoundTag tag1 = tag.getCompound(key); + load(tag1); + } + + public static InterfaceSpec createFrom(CompoundTag tag, String key) { + CompoundTag tag1 = tag.getCompound(key); + InterfaceSpec spec = new InterfaceSpec(); + spec.load(tag1); + return spec; + } + + //endregion +} diff --git a/fabrication/src/main/java/mrtjp/projectred/fabrication/engine/gates/IOGateTile.java b/fabrication/src/main/java/mrtjp/projectred/fabrication/engine/gates/IOGateTile.java index 01ac2a4fd..0b321e006 100644 --- a/fabrication/src/main/java/mrtjp/projectred/fabrication/engine/gates/IOGateTile.java +++ b/fabrication/src/main/java/mrtjp/projectred/fabrication/engine/gates/IOGateTile.java @@ -9,7 +9,7 @@ import codechicken.lib.vec.Vector3; import mrtjp.fengine.api.IPathFinder; import mrtjp.fengine.assemble.PathFinderResult; -import mrtjp.projectred.fabrication.engine.ICConnectionType; +import mrtjp.projectred.fabrication.engine.ICInterfaceType; import mrtjp.projectred.fabrication.engine.ICSimulationContainer; import mrtjp.projectred.fabrication.engine.IIOConnectionTile; import mrtjp.projectred.fabrication.engine.IRotatableICTile; @@ -92,8 +92,8 @@ public int getIOSide() { } @Override - public ICConnectionType getConnectionType() { - return ICConnectionType.BUNDLED; + public ICInterfaceType getInterfaceType() { + return ICInterfaceType.BUNDLED; } protected void toggleWorldInput() { diff --git a/fabrication/src/main/java/mrtjp/projectred/fabrication/gui/screen/inventory/PackagingTableScreen.java b/fabrication/src/main/java/mrtjp/projectred/fabrication/gui/screen/inventory/PackagingTableScreen.java index b61fc0c32..fa9e8c124 100644 --- a/fabrication/src/main/java/mrtjp/projectred/fabrication/gui/screen/inventory/PackagingTableScreen.java +++ b/fabrication/src/main/java/mrtjp/projectred/fabrication/gui/screen/inventory/PackagingTableScreen.java @@ -1,5 +1,6 @@ package mrtjp.projectred.fabrication.gui.screen.inventory; +import codechicken.lib.colour.EnumColour; import com.mojang.blaze3d.systems.RenderSystem; import com.mojang.blaze3d.vertex.PoseStack; import mrtjp.projectred.fabrication.ProjectRedFabrication; @@ -10,6 +11,7 @@ import net.minecraft.network.chat.Component; import net.minecraft.resources.ResourceLocation; import net.minecraft.world.entity.player.Inventory; +import net.minecraft.world.inventory.Slot; public class PackagingTableScreen extends RedUIContainerScreen { @@ -32,8 +34,8 @@ public void drawBack(PoseStack stack, Point mouse, float partialFrame) { blit(stack, x, y, 0, 0, getFrame().width(), getFrame().height()); - int s = getMenu().getProgressScaled(88); - blit(stack, x + 39, y + 25, 0, 171, s + 1, 33); + int s = getMenu().getProgressScaled(20); + blit(stack, x + 104, y + 41, 176, 0, s + 1, 16); if (getMenu().canConductorWork()) blit(stack, x + 16, y + 16, 177, 18, 7, 9); @@ -44,5 +46,19 @@ public void drawBack(PoseStack stack, Point mouse, float partialFrame) { blit(stack, x + 27, y + 16, 185, 18, 7, 9); GuiLib.drawVerticalTank(stack, this, x + 27, y + 26, 185, 27, 7, 48, getMenu().getFlowScaled(48)); + + // Highlight problematic slots red. + int mask = getMenu().getProblematicSlotMask(); + for (int i = 0; i < 9; i++) { + if ((mask & 1 << i) != 0) { + Slot slot = getMenu().getSlot(i + 36); // Offset past player inventory + int colour = EnumColour.RED.argb(0x55); + fillGradient(stack, + x + slot.x, + y + slot.y, + x + slot.x + 16, + y + slot.y + 16, colour, colour); + } + } } } diff --git a/fabrication/src/main/java/mrtjp/projectred/fabrication/init/FabricationUnlocal.java b/fabrication/src/main/java/mrtjp/projectred/fabrication/init/FabricationUnlocal.java index e3ec5e4ce..2488fe874 100644 --- a/fabrication/src/main/java/mrtjp/projectred/fabrication/init/FabricationUnlocal.java +++ b/fabrication/src/main/java/mrtjp/projectred/fabrication/init/FabricationUnlocal.java @@ -88,6 +88,8 @@ public class FabricationUnlocal { public static final String UL_NAME = PREFIX + "tooltip.name"; public static final String UL_TILE_COUNT = PREFIX + "tooltip.tile_count"; public static final String UL_IO_TYPES = PREFIX + "tooltip.io_types"; + public static final String UL_INPUT_MASK = PREFIX + "tooltip.input_mask"; + public static final String UL_OUTPUT_MASK = PREFIX + "tooltip.output_mask"; public static final String UL_TOP = PREFIX + "tooltip.top"; public static final String UL_RIGHT = PREFIX + "tooltip.right"; public static final String UL_BOTTOM = PREFIX + "tooltip.bottom"; @@ -97,6 +99,11 @@ public class FabricationUnlocal { public static final String UL_IO_NONE = PREFIX + "tooltip.io_none"; public static final String UL_CANNOT_FABRICATE = PREFIX + "tooltip.cannot_fabricate"; + // Interfaces + public static final String UL_INTERFACE_NC = PREFIX + "interface.nc"; + public static final String UL_INTERFACE_REDSTONE = PREFIX + "interface.redstone"; + public static final String UL_INTERFACE_BUNDLED = PREFIX + "interface.bundled"; ; + // Numbers and measurements public static final String UL_UNIT_WARNINGS = PREFIX + "unit.warnings"; public static final String UL_UNIT_ERRORS = PREFIX + "unit.errors"; diff --git a/fabrication/src/main/java/mrtjp/projectred/fabrication/inventory/container/PackagingTableContainer.java b/fabrication/src/main/java/mrtjp/projectred/fabrication/inventory/container/PackagingTableContainer.java index 33872cf95..3869cb6d7 100644 --- a/fabrication/src/main/java/mrtjp/projectred/fabrication/inventory/container/PackagingTableContainer.java +++ b/fabrication/src/main/java/mrtjp/projectred/fabrication/inventory/container/PackagingTableContainer.java @@ -1,6 +1,7 @@ package mrtjp.projectred.fabrication.inventory.container; import codechicken.lib.inventory.container.ICCLContainerFactory; +import mrtjp.projectred.core.inventory.container.SimpleDataSlot; import mrtjp.projectred.core.inventory.container.TakeOnlySlot; import mrtjp.projectred.fabrication.init.FabricationReferences; import mrtjp.projectred.fabrication.item.ValidDieItem; @@ -24,6 +25,8 @@ public class PackagingTableContainer extends FabricationMachineContainer { private final Inventory playerInventory; private final PackagingTableTile tile; + protected int problematicSlotMask; + public PackagingTableContainer(Inventory playerInventory, PackagingTableTile tile, int windowId) { super(FabricationReferences.PACKAGING_TABLE_CONTAINER, windowId, tile); this.playerInventory = playerInventory; @@ -31,16 +34,19 @@ public PackagingTableContainer(Inventory playerInventory, PackagingTableTile til InventoryLib.addPlayerInventory(playerInventory, 8, 89, this::addSlot); addPackagingTableInventory(); + + addDataSlot(new SimpleDataSlot(tile::getProblematicSlotMask, value -> problematicSlotMask = value)); } private void addPackagingTableInventory() { - addSlot(new Slot(tile.getInventory(), 0, 64, 32)); // die input - addSlot(new Slot(tile.getInventory(), 1, 46, 57)); // A - addSlot(new Slot(tile.getInventory(), 2, 64, 57)); // B - addSlot(new Slot(tile.getInventory(), 3, 82, 57)); // C - addSlot(new TakeOnlySlot(tile.getInventory(), 4, 135, 40)); // output + // Input slots + InventoryLib.addInventory(tile.getInventory(), 0, 46, 22, 3, 3, this::addSlot); + + // Output slot + addSlot(new TakeOnlySlot(tile.getInventory(), 9, 135, 40)); } + @Override public ItemStack quickMoveStack(Player player, int slotIndex) { Slot slot = slots.get(slotIndex); @@ -55,7 +61,6 @@ public ItemStack quickMoveStack(Player player, int slotIndex) { } else if (isHotbar(slotIndex) || isPlayerInventory(slotIndex)) { if (isValidDie(stack)) { if (!moveToDieInput(stack, false)) return ItemStack.EMPTY; - //TODO A, B, C inputs transfer } else if (isPlayerInventory(slotIndex)) { if (!moveToHotbar(stack, false)) return ItemStack.EMPTY; @@ -82,6 +87,10 @@ public ItemStack quickMoveStack(Player player, int slotIndex) { return originalStack; } + public int getProblematicSlotMask() { + return problematicSlotMask; + } + //@formatter:off private boolean isHotbar(int slotIndex) { return slotIndex >= 27 && slotIndex < 36; @@ -90,10 +99,10 @@ private boolean isPlayerInventory(int slotIndex) { return slotIndex >= 0 && slotIndex < 27; } private boolean isInputs(int slotIndex) { - return slotIndex >= 36 && slotIndex < 40; + return slotIndex >= 36 && slotIndex < 45; } private boolean isOutput(int slotIndex) { - return slotIndex == 40; + return slotIndex == 45; } private boolean moveToHotbar(ItemStack stack, boolean reverse) { @@ -106,7 +115,7 @@ private boolean moveToEntireInventory(ItemStack stack, boolean reverse) { return moveItemStackTo(stack, 0, 36, reverse); } private boolean moveToDieInput(ItemStack stack, boolean reverse) { - return moveItemStackTo(stack, 36, 37, reverse); + return moveItemStackTo(stack, 40, 41, reverse); } //@formatter:on diff --git a/fabrication/src/main/java/mrtjp/projectred/fabrication/item/ICBlueprintItem.java b/fabrication/src/main/java/mrtjp/projectred/fabrication/item/ICBlueprintItem.java index fa351307a..72bb024e8 100644 --- a/fabrication/src/main/java/mrtjp/projectred/fabrication/item/ICBlueprintItem.java +++ b/fabrication/src/main/java/mrtjp/projectred/fabrication/item/ICBlueprintItem.java @@ -1,6 +1,7 @@ package mrtjp.projectred.fabrication.item; import mrtjp.projectred.fabrication.ProjectRedFabrication; +import mrtjp.projectred.fabrication.engine.InterfaceSpec; import mrtjp.projectred.fabrication.init.FabricationReferences; import mrtjp.projectred.integration.GateType; import net.minecraft.ChatFormatting; @@ -69,13 +70,15 @@ public static void buildTooltip(CompoundTag blueprintTag, List toolti tooltipList.add(new TranslatableComponent(UL_TILE_COUNT).append(": " + blueprintTag.getInt(KEY_TILE_COUNT)).withStyle(ChatFormatting.GRAY)); tooltipList.add(new TranslatableComponent(UL_IO_TYPES).append(": ").withStyle(ChatFormatting.GRAY)); - //TODO handle other types of IO - byte bmask = blueprintTag.getByte(KEY_IO_BUNDLED); + InterfaceSpec spec = getInterfaceSpec(blueprintTag); TextComponent indent = new TextComponent(" "); - tooltipList.add(indent.copy().append(new TranslatableComponent(UL_TOP)).append(": ").append(getBundledIOTextComponent(bmask, 0)).withStyle(ChatFormatting.GRAY)); - tooltipList.add(indent.copy().append(new TranslatableComponent(UL_RIGHT)).append(": ").append(getBundledIOTextComponent(bmask, 1)).withStyle(ChatFormatting.GRAY)); - tooltipList.add(indent.copy().append(new TranslatableComponent(UL_BOTTOM)).append(": ").append(getBundledIOTextComponent(bmask, 2)).withStyle(ChatFormatting.GRAY)); - tooltipList.add(indent.copy().append(new TranslatableComponent(UL_LEFT)).append(": ").append(getBundledIOTextComponent(bmask, 3)).withStyle(ChatFormatting.GRAY)); + tooltipList.add(indent.copy().append(new TranslatableComponent(UL_TOP)).append(": ").append(new TranslatableComponent(spec.getInterfaceType(0).getUnlocalName())).withStyle(ChatFormatting.GRAY)); + tooltipList.add(indent.copy().append(new TranslatableComponent(UL_RIGHT)).append(": ").append(new TranslatableComponent(spec.getInterfaceType(1).getUnlocalName())).withStyle(ChatFormatting.GRAY)); + tooltipList.add(indent.copy().append(new TranslatableComponent(UL_BOTTOM)).append(": ").append(new TranslatableComponent(spec.getInterfaceType(2).getUnlocalName())).withStyle(ChatFormatting.GRAY)); + tooltipList.add(indent.copy().append(new TranslatableComponent(UL_LEFT)).append(": ").append(new TranslatableComponent(spec.getInterfaceType(3).getUnlocalName())).withStyle(ChatFormatting.GRAY)); + + tooltipList.add(new TranslatableComponent(UL_INPUT_MASK).append(String.format(": 0x%X", spec.getInputMask())).withStyle(ChatFormatting.GRAY)); + tooltipList.add(new TranslatableComponent(UL_OUTPUT_MASK).append(String.format(": 0x%X", spec.getOutputMask())).withStyle(ChatFormatting.GRAY)); int warningCount = getWarningCount(blueprintTag); int errorCount = getErrorCount(blueprintTag); @@ -90,7 +93,7 @@ public static void buildTooltip(CompoundTag blueprintTag, List toolti if (!canFabricate(blueprintTag)) { tooltipList.add(new TextComponent(" - ") - .append(new TranslatableComponent(UL_CANNOT_FABRICATE).withStyle(ChatFormatting.GRAY))); + .append(new TranslatableComponent(UL_CANNOT_FABRICATE)).withStyle(ChatFormatting.RED)); } } diff --git a/fabrication/src/main/java/mrtjp/projectred/fabrication/part/FabricatedGatePart.java b/fabrication/src/main/java/mrtjp/projectred/fabrication/part/FabricatedGatePart.java index e3ee79be5..3a8a6974a 100644 --- a/fabrication/src/main/java/mrtjp/projectred/fabrication/part/FabricatedGatePart.java +++ b/fabrication/src/main/java/mrtjp/projectred/fabrication/part/FabricatedGatePart.java @@ -4,7 +4,9 @@ import codechicken.lib.data.MCDataOutput; import mrtjp.fengine.api.ICFlatMap; import mrtjp.projectred.core.BundledSignalsLib; +import mrtjp.projectred.fabrication.engine.ICInterfaceType; import mrtjp.projectred.fabrication.engine.ICSimulationContainer; +import mrtjp.projectred.fabrication.engine.InterfaceSpec; import mrtjp.projectred.fabrication.engine.PRFabricationEngine; import mrtjp.projectred.integration.GateType; import mrtjp.projectred.integration.part.BundledGatePart; @@ -21,8 +23,7 @@ public class FabricatedGatePart extends BundledGatePart { private final ICSimulationContainer simulationContainer = new ICSimulationContainer(); private String icName = "untitled"; - private byte bundledMask = 0; - private byte redstoneMask = 0; + private final InterfaceSpec ifSpec = new InterfaceSpec(); private long simulationTimeStart = -1L; @@ -34,6 +35,8 @@ public FabricatedGatePart() { public void preparePlacement(Player player, BlockPos pos, int side) { super.preparePlacement(player, pos, side); + if (player.level.isClientSide) return; + ItemStack stack = player.getItemInHand(InteractionHand.MAIN_HAND); // TODO handle offhand if (stack.isEmpty() || !stack.hasTag()) { LOGGER.warn("Gate placement issue: no NBT on gate item"); @@ -44,44 +47,40 @@ public void preparePlacement(Player player, BlockPos pos, int side) { icName = tag.getString(KEY_IC_NAME); ICFlatMap flatMap = PRFabricationEngine.instance.deserializeFlatMap(tag.getString(KEY_FLAT_MAP)); simulationContainer.setFlatMap(flatMap); - bundledMask = tag.getByte(KEY_IO_BUNDLED); - redstoneMask = tag.getByte(KEY_IO_RS); + + ifSpec.loadFrom(tag, KEY_IO_SPEC); } @Override public void save(CompoundTag tag) { super.save(tag); tag.putString("ic_name", icName); - tag.putByte("bmask", bundledMask); - tag.putByte("rmask", redstoneMask); tag.putLong("sim_time", level().getGameTime() - simulationTimeStart); simulationContainer.save(tag); + ifSpec.saveTo(tag, "io_spec"); } @Override public void load(CompoundTag tag) { super.load(tag); icName = tag.getString("ic_name"); - bundledMask = tag.getByte("bmask"); - redstoneMask = tag.getByte("rmask"); simulationTimeStart = tag.getLong("sim_time"); simulationContainer.load(tag); + ifSpec.loadFrom(tag, "io_spec"); } @Override public void writeDesc(MCDataOutput packet) { super.writeDesc(packet); packet.writeString(icName); - packet.writeByte(bundledMask); - packet.writeByte(redstoneMask); + ifSpec.writeDesc(packet); } @Override public void readDesc(MCDataInput packet) { super.readDesc(packet); icName = packet.readString(); - bundledMask = packet.readByte(); - redstoneMask = packet.readByte(); + ifSpec.readDesc(packet); } @Override @@ -92,22 +91,22 @@ public ItemStack getItem() { //region RedstoneGatePart overrides @Override protected int outputMask(int shape) { - return (redstoneMask >> 4) & 0xF; + return ifSpec.getRedstoneOutputMask(); } @Override protected int inputMask(int shape) { - return redstoneMask & 0xF; + return ifSpec.getRedstoneInputMask(); } @Override protected int getOutput(int r) { - if ((outputMask(shape()) & 1 << r) != 0) { - return 0; - } + if (!ifSpec.isOutput(r)) return 0; - // TODO interpret analog - return (simulationContainer.getOutput(r) & 1) != 0 ? 15 : 0; + return switch (ifSpec.getInterfaceType(r)) { + case NC, BUNDLED -> 0; // Bundled output handled by getBundledOutput + case REDSTONE -> (simulationContainer.getOutput(r) & 1) != 0 ? 15 : 0; + }; } //endregion @@ -115,18 +114,22 @@ protected int getOutput(int r) { //region BundledGatePart overrides @Override protected int bundledInputMask(int shape) { - return bundledMask & 0xF; + return ifSpec.getBundledInputMask(); } @Override protected int bundledOutputMask(int shape) { - return (bundledMask >> 4) & 0xF; + return ifSpec.getBundledOutputMask(); } @Override protected byte[] getBundledOutput(int r) { - return (bundledOutputMask(shape()) & (1 << r)) != 0 ? - BundledSignalsLib.unpackDigital(null, simulationContainer.getOutput(r)) : null; //TODO reuse an array + if (!ifSpec.isOutput(r)) return null; + + return switch (ifSpec.getInterfaceType(r)) { + case NC, REDSTONE -> null; // Redstone output handled by getOutput + case BUNDLED -> BundledSignalsLib.unpackDigital(null, simulationContainer.getOutput(r)); //TODO reuse an array + }; } //endregion @@ -134,8 +137,12 @@ protected byte[] getBundledOutput(int r) { @Override public int state2() { - // TODO Temporary: Mask used to render Bundled side conns by FabricatedGateRenderer - return bundledMask; + // TODO Temporary: state2 contains IO details for rendering + // TODO May let ifSpec pack this? + int rsMask = ifSpec.getRedstoneInputMask() | ifSpec.getRedstoneOutputMask(); + int analogMask = 0; //TODO + int bundledMask = ifSpec.getBundledInputMask() | ifSpec.getBundledOutputMask(); + return (rsMask & 0xF) | (analogMask & 0xF) << 4 | (bundledMask & 0xF) << 8; } //endregion @@ -156,14 +163,13 @@ protected void gateLogicSetup() { @Override protected void gateLogicOnChange() { - // Latch new input states short[] newInputs = new short[4]; for (int r = 0; r < 4; r++) newInputs[r] = getModeBasedInput(r); int changeMask = simulationContainer.setInputs(newInputs); // Schedule update if inputs changed if (changeMask != 0) { - // TODO set gate state for client rendering here + setState(state() & 0xF0 | simulationContainer.inputMask()); onInputChange(); scheduleTick(2); } @@ -179,7 +185,7 @@ protected void gateLogicOnScheduledTick() { simulationContainer.simulate(); int changeMask = simulationContainer.pullOutputs(); if (changeMask != 0) { - // TODO set gate state for client rendering here + setState(state() & 0xF | simulationContainer.outputMask() << 4); onOutputChange(changeMask); } @@ -200,14 +206,19 @@ protected void gateLogicOnTick() { simulationContainer.simulate(); int changeMask = simulationContainer.pullOutputs(); if (changeMask != 0) { - // TODO set gate state for client rendering here + setState(state() & 0xF | simulationContainer.outputMask() << 4); onOutputChange(changeMask); } } } private short getModeBasedInput(int r) { - if ((bundledInputMask(shape()) & (1 << r)) == 0) return 0; - return (short) BundledSignalsLib.packDigital(getBundledInput(r)); + if (!ifSpec.isInput(r)) return 0; + + return switch (ifSpec.getInterfaceType(r)) { + case NC -> 0; + case REDSTONE -> (short) (getRedstoneInput(r) != 0 ? 0xFFFF : 0); + case BUNDLED -> (short) BundledSignalsLib.packDigital(getBundledInput(r)); + }; } } diff --git a/fabrication/src/main/java/mrtjp/projectred/fabrication/tile/LithographyTableTile.java b/fabrication/src/main/java/mrtjp/projectred/fabrication/tile/LithographyTableTile.java index c98c09f0a..326b22ee0 100644 --- a/fabrication/src/main/java/mrtjp/projectred/fabrication/tile/LithographyTableTile.java +++ b/fabrication/src/main/java/mrtjp/projectred/fabrication/tile/LithographyTableTile.java @@ -71,7 +71,7 @@ public void saveToNBT(CompoundTag tag) { @Override public void loadFromNBT(CompoundTag tag) { super.loadFromNBT(tag); - inventory.fromTag(tag.getList("inventory", 10)); + inventory.loadFrom(tag, "inventory"); } @Override @@ -127,7 +127,7 @@ protected int startWork() { @Override protected int tickWork(int remainingWork) { if (canConductorWork()) { - conductor.applyPower(-1100); // draw at rate of 1.1kW + conductor.applyPower(-100); // draw at rate of 100W return 1; } return 0; diff --git a/fabrication/src/main/java/mrtjp/projectred/fabrication/tile/PackagingTableTile.java b/fabrication/src/main/java/mrtjp/projectred/fabrication/tile/PackagingTableTile.java index 385222f3b..55d33a75b 100644 --- a/fabrication/src/main/java/mrtjp/projectred/fabrication/tile/PackagingTableTile.java +++ b/fabrication/src/main/java/mrtjp/projectred/fabrication/tile/PackagingTableTile.java @@ -4,7 +4,11 @@ import codechicken.lib.data.MCDataOutput; import codechicken.lib.util.ServerUtils; import codechicken.lib.vec.Vector3; +import mrtjp.projectred.core.init.CoreReferences; import mrtjp.projectred.core.inventory.BaseInventory; +import mrtjp.projectred.core.tile.IPacketReceiverTile; +import mrtjp.projectred.fabrication.engine.ICInterfaceType; +import mrtjp.projectred.fabrication.engine.InterfaceSpec; import mrtjp.projectred.fabrication.init.FabricationReferences; import mrtjp.projectred.fabrication.inventory.container.PackagingTableContainer; import mrtjp.projectred.fabrication.item.ValidDieItem; @@ -23,26 +27,28 @@ import net.minecraft.world.phys.BlockHitResult; import net.minecraftforge.common.capabilities.Capability; import net.minecraftforge.common.util.LazyOptional; +import org.jetbrains.annotations.NotNull; import javax.annotation.Nonnull; import javax.annotation.Nullable; -public class PackagingTableTile extends FabricationMachineTile { +import static mrtjp.projectred.fabrication.editor.EditorDataUtils.getInterfaceSpec; +import static mrtjp.projectred.fabrication.editor.EditorDataUtils.hasFabricationTarget; - private final BaseInventory inventory = new BaseInventory(5) { +public class PackagingTableTile extends FabricationMachineTile implements IPacketReceiverTile { + + private static final int DIE_SLOT = 4; + private static final int OUTPUT_SLOT = 9; + + private final BaseInventory inventory = new BaseInventory(10) { @Override - public boolean canPlaceItem(int slot, ItemStack stack) { - switch (slot) { - case 0: - return stack.getItem() instanceof ValidDieItem; - case 1: - case 2: - case 3: - //TODO - default: - return false; - } + public boolean canPlaceItem(int slot, @NotNull ItemStack stack) { + return switch (slot) { + case DIE_SLOT -> stack.getItem() instanceof ValidDieItem; + case OUTPUT_SLOT -> false; + default -> true; + }; } @Override @@ -51,6 +57,9 @@ public void setChanged() { cancelWorkIfNeeded(); } }; + + private int problematicSlotMask = 0; // Masks of slots that client should render red highlights + public PackagingTableTile(BlockPos pos, BlockState state) { super(FabricationReferences.PACKAGING_TABLE_TILE, pos, state); inventory.addListener(c -> setChanged()); @@ -69,7 +78,7 @@ public void saveToNBT(CompoundTag tag) { @Override public void loadFromNBT(CompoundTag tag) { super.loadFromNBT(tag); - inventory.fromTag(tag.getList("inventory", 10)); + inventory.loadFrom(tag, "inventory"); } @Override @@ -106,13 +115,47 @@ public LazyOptional getCapability(@Nonnull Capability cap, @Nullable D @Override protected boolean canStartWork() { - ItemStack slot0 = inventory.getItem(0); + problematicSlotMask = 0; - if (slot0.isEmpty()) return false; + ItemStack dieItem = inventory.getItem(DIE_SLOT); + CompoundTag dieTag = dieItem.getTag(); - if (!(slot0.getItem() instanceof ValidDieItem)) return false; + if (dieItem.isEmpty() || !(dieItem.getItem() instanceof ValidDieItem) || !hasFabricationTarget(dieTag)) { + problematicSlotMask |= 1 << DIE_SLOT; + return false; // Fail-fast. Can't do ingredient checks without valid die item + } + + if (!inventory.getItem(OUTPUT_SLOT).isEmpty()) { + problematicSlotMask |= 1 << OUTPUT_SLOT; + } - return inventory.getItem(4).isEmpty(); //TODO or output can be stackable (made from same blueprint) + // Check IO ingredients + InterfaceSpec iospec = getInterfaceSpec(dieTag); + int[] slotMap = { 1, 5, 7, 3 }; // Maps rotation to grid slot + for (int r = 0; r < 4; r++) { + ICInterfaceType type = iospec.getInterfaceType(r); + + // Each type of IO corresponds to a particular ingredient + boolean match = inventory.getItem(slotMap[r]).is(switch (type) { + case NC -> CoreReferences.PLATE_ITEM; + case REDSTONE -> CoreReferences.CONDUCTIVE_PLATE_ITEM; + case BUNDLED -> CoreReferences.BUNDLED_PLATE_ITEM; + }); + + if (!match) { + problematicSlotMask |= 1 << slotMap[r]; + } + } + + // Check corner slots + int[] cornerSlots = { 0, 2, 6, 8 }; + for (int slot : cornerSlots) { + if (!inventory.getItem(slot).is(CoreReferences.PLATE_ITEM)) { + problematicSlotMask |= 1 << slot; + } + } + + return problematicSlotMask == 0; } @Override @@ -123,7 +166,7 @@ protected int startWork() { @Override protected int tickWork(int remainingWork) { if (canConductorWork()) { - conductor.applyPower(-1100); // draw at rate of 1.1kW + conductor.applyPower(-100); // draw at rate of 100W return 1; } return 0; @@ -131,10 +174,18 @@ protected int tickWork(int remainingWork) { @Override protected void finishWork() { - ItemStack gatePart = ValidDieItem.createGatePart(inventory.getItem(0)); - inventory.setItem(4, gatePart); //TODO or stack + ItemStack gatePart = ValidDieItem.createGatePart(inventory.getItem(DIE_SLOT)); + inventory.setItem(OUTPUT_SLOT, gatePart); //TODO or stack // Consume inputs - inventory.removeItem(0, 1); + for (int i = 0; i < 9; i++) { + inventory.removeItem(i, 1); + } + } + + //region Container data + public int getProblematicSlotMask() { + return problematicSlotMask; } + //endregion } diff --git a/fabrication/src/main/java/mrtjp/projectred/fabrication/tile/PlottingTableTile.java b/fabrication/src/main/java/mrtjp/projectred/fabrication/tile/PlottingTableTile.java index bedbaaacf..bd92cbc76 100644 --- a/fabrication/src/main/java/mrtjp/projectred/fabrication/tile/PlottingTableTile.java +++ b/fabrication/src/main/java/mrtjp/projectred/fabrication/tile/PlottingTableTile.java @@ -70,7 +70,7 @@ public void saveToNBT(CompoundTag tag) { @Override public void loadFromNBT(CompoundTag tag) { super.loadFromNBT(tag); - inventory.fromTag(tag.getList("inventory", 10)); + inventory.loadFrom(tag, "inventory"); } @Override @@ -81,7 +81,6 @@ public void writeDesc(MCDataOutput out) { public void readDesc(MCDataInput in) { } - @Override public InteractionResult onBlockActivated(Player player, InteractionHand hand, BlockHitResult hit) { if (!getLevel().isClientSide) { @@ -119,7 +118,7 @@ protected boolean canStartWork() { if (!(slot1.getItem() instanceof BlankPhotomaskItem)) return false; - if (!EditorDataUtils.canFabricate(slot1.getTag())) return false; + if (!EditorDataUtils.canFabricate(slot0.getTag())) return false; return inventory.getItem(2).isEmpty(); } @@ -132,7 +131,7 @@ protected int startWork() { @Override protected int tickWork(int remainingWork) { if (canConductorWork()) { - conductor.applyPower(-1100); // draw at rate of 1.1kW + conductor.applyPower(-100); // draw at rate of 100W return 1; } return 0; diff --git a/fabrication/src/main/resources/assets/projectred_fabrication/textures/gui/packaging_table.png b/fabrication/src/main/resources/assets/projectred_fabrication/textures/gui/packaging_table.png index 5fd023f17a33bfe8f2eefe0e1e34ec2127418d3a..b9a597440365e14aa459c4213efb7280ed581b77 100755 GIT binary patch delta 5531 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 4) & 0xF; + //TODO set name string + + simpleWires.sidemask = gate.state2() & 0xF; + analogWires.sidemask = (gate.state2() >> 4) & 0xF; + bundledWires.sidemask = (gate.state2() >> 8) & 0xF; simpleWires.wires[0].on = (gate.state() & 0x11) != 0; simpleWires.wires[1].on = (gate.state() & 0x22) != 0; From 7385ae7985852c673c5ad3e28b028eed6ae3a43b Mon Sep 17 00:00:00 2001 From: MrTJP Date: Sat, 18 Nov 2023 17:09:07 -0500 Subject: [PATCH 16/23] fix: finished fabricated gate renderer --- .../fabrication/engine/BaseTile.java | 2 + .../fabrication/engine/gates/GateTile.java | 15 +- .../fabrication/part/FabricatedGatePart.java | 5 +- .../client/GateComponentModels.java | 42 +++- .../integration/client/GateModelRenderer.java | 226 +++++++++++------- .../client/GatePartItemRenderer.java | 2 +- .../integration/client/GatePartRenderer.java | 6 +- .../integration/part/BundledGatePart.java | 5 + .../projectred/integration/part/GatePart.java | 6 + .../integration/part/IGateRenderData.java | 12 + 10 files changed, 223 insertions(+), 98 deletions(-) diff --git a/fabrication/src/main/java/mrtjp/projectred/fabrication/engine/BaseTile.java b/fabrication/src/main/java/mrtjp/projectred/fabrication/engine/BaseTile.java index 480be3d9f..87887c56f 100644 --- a/fabrication/src/main/java/mrtjp/projectred/fabrication/engine/BaseTile.java +++ b/fabrication/src/main/java/mrtjp/projectred/fabrication/engine/BaseTile.java @@ -5,9 +5,11 @@ import codechicken.lib.render.CCRenderState; import codechicken.lib.vec.Cuboid6; import codechicken.lib.vec.Transformation; +import com.mojang.blaze3d.vertex.PoseStack; import mrtjp.fengine.TileCoord; import mrtjp.fengine.tiles.FETile; import mrtjp.projectred.fabrication.editor.ICWorkbenchEditor; +import net.minecraft.client.renderer.MultiBufferSource; import net.minecraft.nbt.CompoundTag; import net.minecraft.network.chat.Component; import net.minecraft.network.chat.TranslatableComponent; diff --git a/fabrication/src/main/java/mrtjp/projectred/fabrication/engine/gates/GateTile.java b/fabrication/src/main/java/mrtjp/projectred/fabrication/engine/gates/GateTile.java index 500004473..e0ea9dbf1 100644 --- a/fabrication/src/main/java/mrtjp/projectred/fabrication/engine/gates/GateTile.java +++ b/fabrication/src/main/java/mrtjp/projectred/fabrication/engine/gates/GateTile.java @@ -137,8 +137,8 @@ public void onRemoved() { @Override public void renderTile(CCRenderState ccrs, Transformation t, float partialFrame) { GateModelRenderer r = GateModelRenderer.instance(); - r.renderStatic(ccrs, gateTileType.renderIndex, this, getRotation() & 0x3, t); - r.renderDynamic(ccrs, gateTileType.renderIndex, this, getRotation() & 0x3, t, partialFrame); + r.renderStatic(ccrs, this, t); + r.renderDynamic(ccrs, this, t, partialFrame); } protected void notifyNeighbors(int rMask) { @@ -191,6 +191,17 @@ public void onMaskChanged() { //endregion //region IGateRenderKey implementation + + @Override + public int getRenderIndex() { + return gateTileType.renderIndex; + } + + @Override + public int getOrientation() { + return getRotation() & 0x3; + } + @Override public int shape() { return this.gateShape; diff --git a/fabrication/src/main/java/mrtjp/projectred/fabrication/part/FabricatedGatePart.java b/fabrication/src/main/java/mrtjp/projectred/fabrication/part/FabricatedGatePart.java index 3a8a6974a..9c1306746 100644 --- a/fabrication/src/main/java/mrtjp/projectred/fabrication/part/FabricatedGatePart.java +++ b/fabrication/src/main/java/mrtjp/projectred/fabrication/part/FabricatedGatePart.java @@ -134,7 +134,6 @@ protected byte[] getBundledOutput(int r) { //endregion //region IGateRenderKey overrides - @Override public int state2() { // TODO Temporary: state2 contains IO details for rendering @@ -145,6 +144,10 @@ public int state2() { return (rsMask & 0xF) | (analogMask & 0xF) << 4 | (bundledMask & 0xF) << 8; } + @Override + public String getGateName() { + return icName; + } //endregion @Override diff --git a/integration/src/main/java/mrtjp/projectred/integration/client/GateComponentModels.java b/integration/src/main/java/mrtjp/projectred/integration/client/GateComponentModels.java index fa71c3043..f684304c8 100644 --- a/integration/src/main/java/mrtjp/projectred/integration/client/GateComponentModels.java +++ b/integration/src/main/java/mrtjp/projectred/integration/client/GateComponentModels.java @@ -20,8 +20,15 @@ import mrtjp.projectred.core.BundledSignalsLib; import mrtjp.projectred.core.client.HaloRenderer; import mrtjp.projectred.integration.part.GatePart; +import mrtjp.projectred.integration.part.IGateRenderData; import mrtjp.projectred.lib.VecLib; +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.Font; import net.minecraft.client.renderer.MultiBufferSource; +import net.minecraft.core.BlockPos; +import net.minecraft.network.chat.Component; +import net.minecraft.network.chat.Style; +import net.minecraft.network.chat.TextComponent; import net.minecraft.resources.ResourceLocation; import java.util.*; @@ -1070,8 +1077,8 @@ public void renderModel(Transformation t, int orient, CCRenderState ccrs) { } } - public void renderLights(CCRenderState ccrs, GatePart gate, PoseStack mStack, MultiBufferSource buffers, Transformation t) { - Transformation t2 = t.with(new Translation(gate.pos())); + public void renderLights(CCRenderState ccrs, BlockPos lightPos, PoseStack mStack, MultiBufferSource buffers, Transformation t) { + Transformation t2 = t.with(new Translation(lightPos)); for (int i = 0; i < 16; i++) { if ((pressMask & 1 << i) != 0) { HaloRenderer.addLight(t2, i, LIGHT_BOXES[i]); @@ -1479,6 +1486,7 @@ public static class FabricatedICModel extends ComponentModel { public static final FabricatedICModel INSTANCE = new FabricatedICModel(); + private static final Style UNIFORM = Style.EMPTY.withFont(new ResourceLocation("minecraft", "uniform")); private static final CCModel[] platformModel = bakeOrients(fabIC.get("platform")); private static final CCModel[] icChipModel = bakeOrients(fabIC.get("ic")); @@ -1488,7 +1496,35 @@ public void renderModel(Transformation t, int orient, CCRenderState ccrs) { icChipModel[orient].render(ccrs, t, icChipIcon); } - public void renderDynamic(Transformation t, CCRenderState ccrs) { + public void renderName(String name, PoseStack mStack, Transformation t1) { + + Component nameComponent = new TextComponent(name).withStyle(UNIFORM); + Font fr = Minecraft.getInstance().font; + + // Calculate font scale + int tw = fr.width(nameComponent); + int th = fr.lineHeight; + double wScale = 8/16D * (1.0/tw); // Cap width to 8/16 block + double hScale = 2/16D * (1.0/th); // Cap height to 2/16 block + double scale = Math.min(wScale, hScale); // Use the limiting scale + + // Create the transform + Transformation t = new Rotation(90 * MathHelper.torad, 1, 0, 0) + .with(new Scale(scale, 1, scale)) + .with(new Translation(8/16D, 2.2501/16D, 11.5/16D)) + .with(new Translation(-(tw / 2.0) * scale, 0, -(th / 2.0) * scale)) + .with(t1); + Matrix4 m = new Matrix4(); + t.apply(m); + + // Draw text + mStack.pushPose(); + mStack.mulPoseMatrix(m.toMatrix4f()); + fr.draw(mStack, nameComponent, 0, 0, 0xFFFFFFFF); + mStack.popPose(); + } + + public void renderGlass(Transformation t, CCRenderState ccrs) { fabIC.get("glass").render(ccrs, t, icHousingIcon); } } diff --git a/integration/src/main/java/mrtjp/projectred/integration/client/GateModelRenderer.java b/integration/src/main/java/mrtjp/projectred/integration/client/GateModelRenderer.java index b3f01ddbb..e08cd8481 100644 --- a/integration/src/main/java/mrtjp/projectred/integration/client/GateModelRenderer.java +++ b/integration/src/main/java/mrtjp/projectred/integration/client/GateModelRenderer.java @@ -3,10 +3,11 @@ import codechicken.lib.colour.EnumColour; import codechicken.lib.math.MathHelper; import codechicken.lib.render.CCRenderState; +import codechicken.lib.render.buffer.TransformingVertexConsumer; import codechicken.lib.texture.AtlasRegistrar; -import codechicken.lib.vec.RedundantTransformation; import codechicken.lib.vec.Transformation; import codechicken.lib.vec.Vector3; +import com.mojang.blaze3d.vertex.DefaultVertexFormat; import com.mojang.blaze3d.vertex.PoseStack; import com.mojang.math.Vector3f; import mrtjp.projectred.integration.GateType; @@ -14,9 +15,13 @@ import mrtjp.projectred.integration.part.IGateRenderData; import mrtjp.projectred.lib.VecLib; import net.minecraft.client.renderer.MultiBufferSource; +import net.minecraft.client.renderer.RenderType; +import net.minecraft.core.BlockPos; import net.minecraft.core.particles.DustParticleOptions; +import net.minecraft.nbt.CompoundTag; import net.minecraft.server.packs.resources.ResourceManager; import net.minecraft.world.item.ItemStack; +import org.jetbrains.annotations.Nullable; import java.util.*; @@ -74,60 +79,46 @@ public static GateModelRenderer instance() { }; //region Static rendering - public void renderStatic(CCRenderState ccrs, GatePart gate) { - renderStatic(ccrs, gate.getGateType(), gate, gate.getOrientation(), RedundantTransformation.INSTANCE); - } - - public void renderStatic(CCRenderState ccrs, GateType type, IGateRenderData key, int orientation, Transformation t) { - renderStatic(ccrs, type.ordinal(), key, orientation, t); - } - - public void renderStatic(CCRenderState ccrs, int renderIndex, IGateRenderData key, int orientation, Transformation t) { - GateRenderer r = getRenderer(renderIndex); + public void renderStatic(CCRenderState ccrs, IGateRenderData key, Transformation t) { + GateRenderer r = getRenderer(key.getRenderIndex()); r.prepare(key); - r.renderStatic(ccrs, orientation, t); + r.renderStatic(ccrs, key.getOrientation(), t); } //endregion //region Dynamic rendering - public void renderDynamic(CCRenderState ccrs, GatePart gate, float partialFrame) { - renderDynamic(ccrs, gate.getGateType(), gate, gate.getOrientation(), RedundantTransformation.INSTANCE, partialFrame); + public void renderDynamic(CCRenderState ccrs, IGateRenderData key, Transformation t, float partialFrame) { + renderDynamic(ccrs, key, t, null, null, 0, 0, partialFrame); } - public void renderDynamic(CCRenderState ccrs, GateType type, IGateRenderData key, int orientation, Transformation t, float partialTicks) { - renderDynamic(ccrs, type.ordinal(), key, orientation, t, partialTicks); - } - - public void renderDynamic(CCRenderState ccrs, int renderIndex, IGateRenderData key, int orientation, Transformation t, float partialTicks) { - GateRenderer r = getRenderer(renderIndex); + public void renderDynamic(CCRenderState ccrs, IGateRenderData key, Transformation t, PoseStack mStack, MultiBufferSource buffers, int packedLight, int packedOverlay, float partialTicks) { + GateRenderer r = getRenderer(key.getRenderIndex()); if (r.hasSpecials()) { + Transformation t2 = VecLib.orientT(key.getOrientation()).with(t); r.prepareDynamic(key, partialTicks); - r.renderDynamic(ccrs, VecLib.orientT(orientation).with(t)); + r.renderDynamic(ccrs, t2); + if (mStack != null) { + r.renderCustomDynamic(ccrs, t2, mStack, buffers, packedLight, packedOverlay, partialTicks); + } } } //endregion - //region Custom dynamic rendering - public void renderCustomDynamic(CCRenderState ccrs, GatePart gate, PoseStack mStack, MultiBufferSource buffers, int packedLight, int packedOverlay, float partialTicks) { - GateRenderer r = getRenderer(gate.getGateType().ordinal()); - r.renderCustomDynamic(ccrs, gate, VecLib.orientT(gate.getOrientation()), mStack, buffers, packedLight, packedOverlay, partialTicks); - } - //endregion - //region Inventory rendering - public void renderInventory(CCRenderState ccrs, ItemStack stack, Transformation t, GateType type) { - renderInventory(ccrs, stack, type, 0, t); + public void renderInventory(CCRenderState ccrs, @Nullable ItemStack stack, int renderIndex, int orient, Transformation t) { + renderInventory(ccrs, stack, renderIndex, orient, t, null, null, 0, 0); } - public void renderInventory(CCRenderState ccrs, ItemStack stack, GateType type, int orient, Transformation t) { - renderInventory(ccrs, stack, type.ordinal(), orient, t); - } - - public void renderInventory(CCRenderState ccrs, ItemStack stack, int renderIndex, int orient, Transformation t) { + public void renderInventory(CCRenderState ccrs, @Nullable ItemStack stack, int renderIndex, int orient, Transformation t, PoseStack mStack, MultiBufferSource buffers, int packedLight, int packedOverlay) { GateRenderer r = getRenderer(renderIndex); - r.prepareInventory(); + r.prepareInventory(stack); r.renderStatic(ccrs, orient, t); - if (r.hasSpecials()) r.renderDynamic(ccrs, t); + if (r.hasSpecials()) { + r.renderDynamic(ccrs, t); + if (mStack != null) { + r.renderCustomDynamic(ccrs, t, mStack, buffers, packedLight, packedOverlay, 0); + } + } } //endregion @@ -169,7 +160,7 @@ public static abstract class GateRenderer { protected abstract List getModels(); - protected abstract void prepareInventory(); + protected abstract void prepareInventory(@Nullable ItemStack stack); protected abstract void prepare(IGateRenderData gate); @@ -217,7 +208,7 @@ public boolean hasSpecials() { public void renderDynamic(CCRenderState ccrs, Transformation t) { } - public void renderCustomDynamic(CCRenderState ccrs, GatePart gate, Transformation t, PoseStack mStack, MultiBufferSource buffers, int packedLight, int packedOverlay, float partialTicks) { + public void renderCustomDynamic(CCRenderState ccrs, Transformation t, PoseStack mStack, MultiBufferSource buffers, int packedLight, int packedOverlay, float partialTicks) { } } @@ -240,7 +231,7 @@ protected List getModels() { } @Override - protected void prepareInventory() { + protected void prepareInventory(@Nullable ItemStack stack) { wires[0].on = true; wires[1].on = false; wires[2].on = false; @@ -285,7 +276,7 @@ protected List getModels() { } @Override - protected void prepareInventory() { + protected void prepareInventory(@Nullable ItemStack stack) { wires[0].on = true; wires[1].on = false; wires[2].on = false; @@ -328,7 +319,7 @@ protected List getModels() { } @Override - protected void prepareInventory() { + protected void prepareInventory(@Nullable ItemStack stack) { wires[0].on = true; wires[1].on = true; wires[2].on = false; @@ -373,7 +364,7 @@ protected List getModels() { } @Override - protected void prepareInventory() { + protected void prepareInventory(@Nullable ItemStack stack) { wires[0].on = true; wires[1].on = false; wires[2].on = false; @@ -424,7 +415,7 @@ protected List getModels() { } @Override - protected void prepareInventory() { + protected void prepareInventory(@Nullable ItemStack stack) { wires[0].on = true; wires[1].on = false; wires[2].on = false; @@ -473,7 +464,7 @@ protected List getModels() { } @Override - protected void prepareInventory() { + protected void prepareInventory(@Nullable ItemStack stack) { wires[0].on = false; wires[3].on = false; wires[2].on = false; @@ -516,7 +507,7 @@ protected List getModels() { } @Override - protected void prepareInventory() { + protected void prepareInventory(@Nullable ItemStack stack) { wires[0].on = false; wires[3].on = false; wires[2].on = false; @@ -561,7 +552,7 @@ protected List getModels() { } @Override - protected void prepareInventory() { + protected void prepareInventory(@Nullable ItemStack stack) { wires[0].on = true; wires[1].on = false; wires[2].on = false; @@ -606,7 +597,7 @@ protected List getModels() { } @Override - protected void prepareInventory() { + protected void prepareInventory(@Nullable ItemStack stack) { wires[0].on = false; wires[1].on = true; wires[2].on = true; @@ -655,7 +646,7 @@ protected List getModels() { } @Override - protected void prepareInventory() { + protected void prepareInventory(@Nullable ItemStack stack) { wires[0].on = true; wires[1].on = false; wires[2].on = false; @@ -708,7 +699,7 @@ protected List getModels() { } @Override - protected void prepareInventory() { + protected void prepareInventory(@Nullable ItemStack stack) { wires[0].on = true; wires[1].on = false; endTorch.on = false; @@ -746,7 +737,7 @@ protected List getModels() { } @Override - protected void prepareInventory() { + protected void prepareInventory(@Nullable ItemStack stack) { wires[0].on = false; wires[1].on = false; wires[2].on = false; @@ -820,7 +811,7 @@ protected List getModels() { } @Override - protected void prepareInventory() { + protected void prepareInventory(@Nullable ItemStack stack) { reflect = false; shape = 0; wires1[0].on = false; @@ -873,7 +864,7 @@ protected List getModels() { } @Override - protected void prepareInventory() { + protected void prepareInventory(@Nullable ItemStack stack) { wires[0].on = false; wires[1].on = false; torches[0].on = true; @@ -912,7 +903,7 @@ protected List getModels() { } @Override - protected void prepareInventory() { + protected void prepareInventory(@Nullable ItemStack stack) { reflect = false; wires[0].on = true; wires[1].on = false; @@ -962,7 +953,7 @@ protected List getModels() { } @Override - protected void prepareInventory() { + protected void prepareInventory(@Nullable ItemStack stack) { wires[0].on = false; solar.state = 0; } @@ -993,7 +984,7 @@ protected List getModels() { } @Override - protected void prepareInventory() { + protected void prepareInventory(@Nullable ItemStack stack) { wires[0].on = false; } @@ -1024,7 +1015,7 @@ protected List getModels() { } @Override - protected void prepareInventory() { + protected void prepareInventory(@Nullable ItemStack stack) { wires[0].on = false; wires[1].on = false; wires[2].on = false; @@ -1077,7 +1068,7 @@ protected List getModels() { } @Override - protected void prepareInventory() { + protected void prepareInventory(@Nullable ItemStack stack) { torches[0].on = true; torches[1].on = true; torches[2].on = false; @@ -1136,7 +1127,7 @@ protected List getModels() { } @Override - protected void prepareInventory() { + protected void prepareInventory(@Nullable ItemStack stack) { reflect = false; wires[0].on = false; wires[1].on = false; @@ -1195,7 +1186,7 @@ protected List getModels() { } @Override - protected void prepareInventory() { + protected void prepareInventory(@Nullable ItemStack stack) { reflect = false; wires[0].on = false; wires[1].on = false; @@ -1264,7 +1255,7 @@ protected List getModels() { } @Override - protected void prepareInventory() { + protected void prepareInventory(@Nullable ItemStack stack) { wires[0].on = true; wires[1].on = true; wires[2].on = false; @@ -1313,7 +1304,7 @@ protected List getModels() { } @Override - protected void prepareInventory() { + protected void prepareInventory(@Nullable ItemStack stack) { reflect = false; wires[0].on = false; wires[1].on = false; @@ -1355,7 +1346,7 @@ protected List getModels() { } @Override - protected void prepareInventory() { + protected void prepareInventory(@Nullable ItemStack stack) { bottomWire.signal = 0; topWire.signal = 0; topWire.conn = 0; @@ -1390,8 +1381,8 @@ public RenderInvertCell() { } @Override - protected void prepareInventory() { - super.prepareInventory(); + protected void prepareInventory(@Nullable ItemStack stack) { + super.prepareInventory(stack); topWire.signal = (byte) 255; wires[0].on = false; torch.on = true; @@ -1418,8 +1409,8 @@ public RenderBufferCell() { } @Override - protected void prepareInventory() { - super.prepareInventory(); + protected void prepareInventory(@Nullable ItemStack stack) { + super.prepareInventory(stack); wires[0].on = false; wires[1].on = true; torches[0].on = true; @@ -1457,7 +1448,7 @@ protected List getModels() { } @Override - protected void prepareInventory() { + protected void prepareInventory(@Nullable ItemStack stack) { topWire.signal = 0; topWire.conn = 0; torches[0].on = true; @@ -1501,7 +1492,7 @@ protected List getModels() { } @Override - protected void prepareInventory() { + protected void prepareInventory(@Nullable ItemStack stack) { topWire.signal = 0; topWire.conn = 0; wires[0].on = true; @@ -1552,7 +1543,7 @@ protected List getModels() { } @Override - protected void prepareInventory() { + protected void prepareInventory(@Nullable ItemStack stack) { reflect = false; wires[0].on = true; wires[1].on = false; @@ -1626,7 +1617,7 @@ protected List getModels() { } @Override - protected void prepareInventory() { + protected void prepareInventory(@Nullable ItemStack stack) { shape = 0; panel.signal = 0; panel.disableMask = 0; @@ -1670,7 +1661,7 @@ protected List getModels() { } @Override - protected void prepareInventory() { + protected void prepareInventory(@Nullable ItemStack stack) { wires[0].on = false; wires[1].on = false; wires[2].on = false; @@ -1695,6 +1686,8 @@ public static class RenderBusInputPanel extends GateRenderer { private final WireModel[] wires = generateWireModels("businput", 1); private final InputPanelButtonsModel buttons = new InputPanelButtonsModel(); + private BlockPos.MutableBlockPos lightPos = new BlockPos.MutableBlockPos(); + public RenderBusInputPanel() { models.add(BaseComponentModel.INSTANCE); models.add(BusInputPanelCableModel.INSTANCE); @@ -1708,9 +1701,10 @@ protected List getModels() { } @Override - protected void prepareInventory() { + protected void prepareInventory(@Nullable ItemStack stack) { wires[0].on = false; buttons.pressMask = 0; + lightPos.set(0, 0, 0); } @Override @@ -1720,9 +1714,19 @@ protected void prepare(IGateRenderData gate) { } @Override - public void renderCustomDynamic(CCRenderState ccrs, GatePart gate, Transformation t, PoseStack mStack, MultiBufferSource buffers, int packedLight, int packedOverlay, float partialTicks) { + public boolean hasSpecials() { + return true; + } + + @Override + protected void prepareDynamic(IGateRenderData gate, float partialFrame) { buttons.pressMask = gate.bInput0(); - buttons.renderLights(ccrs, gate, mStack, buffers, t); + lightPos.set(gate.worldPos()); + } + + @Override + public void renderCustomDynamic(CCRenderState ccrs, Transformation t, PoseStack mStack, MultiBufferSource buffers, int packedLight, int packedOverlay, float partialTicks) { + buttons.renderLights(ccrs, lightPos, mStack, buffers, t); } } @@ -1758,7 +1762,7 @@ protected List getModels() { } @Override - protected void prepareInventory() { + protected void prepareInventory(@Nullable ItemStack stack) { shape = 0; sevenSeg1.signal = 64; sevenSeg0.signal = 64; @@ -1805,7 +1809,7 @@ protected List getModels() { } @Override - protected void prepareInventory() { + protected void prepareInventory(@Nullable ItemStack stack) { wires[0].on = false; wires[1].on = false; wires[2].on = false; @@ -1853,6 +1857,25 @@ public static class RenderFabricatedGate extends GateRenderer { private final SidedICBundledCableModel bundledWires = new SidedICBundledCableModel(); private final FabricatedICModel icHousing = FabricatedICModel.INSTANCE; + //**** Copied from EditorDataUtils.class ****/ + public static final String KEY_FORMAT = "format"; // int + public static final String KEY_ACTIVE = "active"; // boolean + public static final String KEY_IC_NAME = "ic_name"; // String + public static final String KEY_TILE_MAP = "tile_map"; // CompoundTag + public static final String KEY_IS_BUILT = "is_built"; // boolean + public static final String KEY_IO_SPEC = "io_spec"; + public static final String KEY_COMP_STATE = "state"; // byte + public static final String KEY_FLAT_MAP = "flat_map"; // String + public static final String KEY_SIMULATION = "sim_cont"; // CompoundTag + public static final String KEY_COMPILER_LOG = "compiler_log"; // CompoundTag + + // Minimum subset of data required to fabricate gate (i.e. create photomask) + public static boolean hasFabricationTarget(CompoundTag tag) { + return tag != null && + tag.contains(KEY_IS_BUILT) && + tag.contains(KEY_FLAT_MAP); + } + private String name = "untitled"; public RenderFabricatedGate() { @@ -1869,19 +1892,33 @@ protected List getModels() { } @Override - protected void prepareInventory() { - //TODO load from stack - name = "ERROR!"; - simpleWires.sidemask = 0; - analogWires.sidemask = 0; - bundledWires.sidemask = 0; + protected void prepareInventory(@Nullable ItemStack stack) { + if (stack == null || !hasFabricationTarget(stack.getTag())) { + name = "ERROR!"; + simpleWires.sidemask = 0; + analogWires.sidemask = 0; + bundledWires.sidemask = 0; + return; + } + + //TODO use EditorDataUtils helpers once this class is moved to Fabrication + + CompoundTag tag = stack.getTag(); + name = tag.getString("ic_name"); + + CompoundTag ifspecTag = tag.getCompound("io_spec"); + byte rMask = ifspecTag.getByte("rmask"); + byte aMask = 0; //TODO analog stuff + byte bMask = ifspecTag.getByte("bmask"); + + simpleWires.sidemask = rMask & 0xF | (rMask >> 4) & 0xF; + analogWires.sidemask = aMask; + bundledWires.sidemask = bMask & 0xF | (bMask >> 4) & 0xF; } @Override protected void prepare(IGateRenderData gate) { - //TODO set name string - simpleWires.sidemask = gate.state2() & 0xF; analogWires.sidemask = (gate.state2() >> 4) & 0xF; bundledWires.sidemask = (gate.state2() >> 8) & 0xF; @@ -1904,12 +1941,25 @@ public boolean hasSpecials() { @Override protected void prepareDynamic(IGateRenderData gate, float partialFrame) { - // TODO set name string + name = gate.getGateName(); } @Override public void renderDynamic(CCRenderState ccrs, Transformation t) { - icHousing.renderDynamic(t, ccrs); + } + + @Override + public void renderCustomDynamic(CCRenderState ccrs, Transformation t, PoseStack mStack, MultiBufferSource buffers, int packedLight, int packedOverlay, float partialTicks) { + + // Render name + icHousing.renderName(name, mStack, t); + + // Render glass + ccrs.reset(); + ccrs.brightness = packedLight; + ccrs.overlay = packedOverlay; + ccrs.bind(new TransformingVertexConsumer(buffers.getBuffer(RenderType.translucentMovingBlock()), mStack), DefaultVertexFormat.BLOCK); + icHousing.renderGlass(t, ccrs); } } @@ -1935,7 +1985,7 @@ protected List getModels() { } @Override - protected void prepareInventory() { + protected void prepareInventory(@Nullable ItemStack stack) { crimpWire.signal = 0; colourBox.colour = 0; } diff --git a/integration/src/main/java/mrtjp/projectred/integration/client/GatePartItemRenderer.java b/integration/src/main/java/mrtjp/projectred/integration/client/GatePartItemRenderer.java index 39a62df04..d423efb5e 100644 --- a/integration/src/main/java/mrtjp/projectred/integration/client/GatePartItemRenderer.java +++ b/integration/src/main/java/mrtjp/projectred/integration/client/GatePartItemRenderer.java @@ -48,6 +48,6 @@ public void renderItem(ItemStack stack, ItemTransforms.TransformType transformTy ccrs.brightness = packedLight; ccrs.overlay = packedOverlay; ccrs.bind(RenderType.cutout(), getter, mStack); - GateModelRenderer.instance().renderInventory(ccrs, stack, RedundantTransformation.INSTANCE, gateItem.getGateType()); + GateModelRenderer.instance().renderInventory(ccrs, stack, gateItem.getGateType().ordinal(), 0, RedundantTransformation.INSTANCE, mStack, getter, packedLight, packedOverlay); } } diff --git a/integration/src/main/java/mrtjp/projectred/integration/client/GatePartRenderer.java b/integration/src/main/java/mrtjp/projectred/integration/client/GatePartRenderer.java index b1b0d304c..b7d750cab 100644 --- a/integration/src/main/java/mrtjp/projectred/integration/client/GatePartRenderer.java +++ b/integration/src/main/java/mrtjp/projectred/integration/client/GatePartRenderer.java @@ -2,6 +2,7 @@ import codechicken.lib.render.CCRenderState; import codechicken.lib.render.buffer.TransformingVertexConsumer; +import codechicken.lib.vec.RedundantTransformation; import codechicken.multipart.api.part.render.PartRenderer; import com.mojang.blaze3d.vertex.DefaultVertexFormat; import com.mojang.blaze3d.vertex.PoseStack; @@ -23,7 +24,7 @@ private GatePartRenderer() { public boolean renderStatic(GatePart part, @Nullable RenderType layer, CCRenderState ccrs) { if (layer == null || (layer == RenderType.cutout() && Configurator.staticGates)) { ccrs.setBrightness(part.level(), part.pos()); - GateModelRenderer.instance().renderStatic(ccrs, part); + GateModelRenderer.instance().renderStatic(ccrs, part, RedundantTransformation.INSTANCE); return true; } return false; @@ -36,7 +37,6 @@ public void renderDynamic(GatePart part, PoseStack mStack, MultiBufferSource buf ccrs.brightness = packedLight; ccrs.overlay = packedOverlay; ccrs.bind(new TransformingVertexConsumer(buffers.getBuffer(RenderType.cutout()), mStack), DefaultVertexFormat.BLOCK); - GateModelRenderer.instance().renderDynamic(ccrs, part, partialTicks); - GateModelRenderer.instance().renderCustomDynamic(ccrs, part, mStack, buffers, packedLight, packedOverlay, partialTicks); + GateModelRenderer.instance().renderDynamic(ccrs, part, RedundantTransformation.INSTANCE, mStack, buffers, packedLight, packedOverlay, partialTicks); } } diff --git a/integration/src/main/java/mrtjp/projectred/integration/part/BundledGatePart.java b/integration/src/main/java/mrtjp/projectred/integration/part/BundledGatePart.java index c483bb681..3adb3ef0a 100644 --- a/integration/src/main/java/mrtjp/projectred/integration/part/BundledGatePart.java +++ b/integration/src/main/java/mrtjp/projectred/integration/part/BundledGatePart.java @@ -781,6 +781,11 @@ public short bOutput2() { public short bInput0() { return pressMask; } + + @Override + public BlockPos worldPos() { + return pos(); + } //endregion //region Gate logic diff --git a/integration/src/main/java/mrtjp/projectred/integration/part/GatePart.java b/integration/src/main/java/mrtjp/projectred/integration/part/GatePart.java index 6b7909421..dbe453844 100644 --- a/integration/src/main/java/mrtjp/projectred/integration/part/GatePart.java +++ b/integration/src/main/java/mrtjp/projectred/integration/part/GatePart.java @@ -88,10 +88,16 @@ public final GateType getGateType() { return type; } + @Override public int getOrientation() { return orientation & 0xFF; } + @Override + public int getRenderIndex() { + return type.ordinal(); + } + @Override public int shape() { return gateShape; diff --git a/integration/src/main/java/mrtjp/projectred/integration/part/IGateRenderData.java b/integration/src/main/java/mrtjp/projectred/integration/part/IGateRenderData.java index 9149fbe34..b8a956197 100644 --- a/integration/src/main/java/mrtjp/projectred/integration/part/IGateRenderData.java +++ b/integration/src/main/java/mrtjp/projectred/integration/part/IGateRenderData.java @@ -1,8 +1,14 @@ package mrtjp.projectred.integration.part; +import net.minecraft.core.BlockPos; + public interface IGateRenderData { //@formatter:off + // Render type + int getRenderIndex(); // Unique identifier that selects exact model to render + int getOrientation(); // Packed orientation data. See {@link VecLib.orientT} + // General stuff int shape(); int state(); @@ -30,9 +36,15 @@ public interface IGateRenderData { default int bInHigh() { return 0; } //TODO this is just bundled input side 0 default byte segmentColour() { return 0; } // TODO this can be a state2 + // Bus input panel + default BlockPos worldPos() { return BlockPos.ZERO; } + // Array Cells default byte bottomSignal() { return 0; } default byte topSignal() { return 0; } default int topSignalConnMask() { return 0; } + + // Fabricated Gate + default String getGateName() { return "???"; } //@formatter:on } From b74fd0c6f9ca090f16b59706183f6b791bd46f58 Mon Sep 17 00:00:00 2001 From: MrTJP Date: Sat, 18 Nov 2023 17:14:47 -0500 Subject: [PATCH 17/23] feat: add tooltips to fabricated gate items --- .../fabrication/init/FabricationParts.java | 4 ++-- .../item/FabricatedGatePartItem.java | 23 +++++++++++++++++++ 2 files changed, 25 insertions(+), 2 deletions(-) create mode 100644 fabrication/src/main/java/mrtjp/projectred/fabrication/item/FabricatedGatePartItem.java diff --git a/fabrication/src/main/java/mrtjp/projectred/fabrication/init/FabricationParts.java b/fabrication/src/main/java/mrtjp/projectred/fabrication/init/FabricationParts.java index a383477a5..5e93d0579 100644 --- a/fabrication/src/main/java/mrtjp/projectred/fabrication/init/FabricationParts.java +++ b/fabrication/src/main/java/mrtjp/projectred/fabrication/init/FabricationParts.java @@ -2,9 +2,9 @@ import codechicken.multipart.api.MultipartType; import codechicken.multipart.api.SimpleMultipartType; +import mrtjp.projectred.fabrication.item.FabricatedGatePartItem; import mrtjp.projectred.fabrication.part.FabricatedGatePart; import mrtjp.projectred.integration.GateType; -import mrtjp.projectred.integration.item.GatePartItem; import mrtjp.projectred.integration.part.GatePart; import net.minecraft.world.item.Item; import net.minecraftforge.registries.RegistryObject; @@ -19,7 +19,7 @@ public class FabricationParts { public static void register() { // Items - RegistryObject registeredItem = ITEMS.register(ID_FABRICATED_GATE, () -> new GatePartItem(GateType.FABRICATED_GATE)); + RegistryObject registeredItem = ITEMS.register(ID_FABRICATED_GATE, () -> new FabricatedGatePartItem(GateType.FABRICATED_GATE)); // Parts RegistryObject> registeredPartType = PARTS.register(ID_FABRICATED_GATE, () -> new SimpleMultipartType<>(b -> new FabricatedGatePart())); diff --git a/fabrication/src/main/java/mrtjp/projectred/fabrication/item/FabricatedGatePartItem.java b/fabrication/src/main/java/mrtjp/projectred/fabrication/item/FabricatedGatePartItem.java new file mode 100644 index 000000000..3b2e1f5ad --- /dev/null +++ b/fabrication/src/main/java/mrtjp/projectred/fabrication/item/FabricatedGatePartItem.java @@ -0,0 +1,23 @@ +package mrtjp.projectred.fabrication.item; + +import mrtjp.projectred.integration.GateType; +import mrtjp.projectred.integration.item.GatePartItem; +import net.minecraft.network.chat.Component; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.TooltipFlag; +import net.minecraft.world.level.Level; +import org.jetbrains.annotations.Nullable; + +import java.util.List; + +public class FabricatedGatePartItem extends GatePartItem { + + public FabricatedGatePartItem(GateType gateType) { + super(gateType); + } + + @Override + public void appendHoverText(ItemStack stack, @Nullable Level level, List tooltipList, TooltipFlag flag) { + ICBlueprintItem.buildTooltip(stack.getTag(), tooltipList); + } +} From 7b6b121ecafa694c7d6a76f2e8e42d19c6d80a02 Mon Sep 17 00:00:00 2001 From: MrTJP Date: Wed, 22 Nov 2023 17:52:08 -0500 Subject: [PATCH 18/23] fix: fit all tiles in initial workbench zoom --- .../projectred/redui/ViewportRenderNode.java | 10 +++++ .../fabrication/gui/ICRenderNode.java | 37 ++++++++++++++++++- .../gui/LinearVectorAnimation.java | 5 +++ .../gui/screen/ICWorkbenchCompileTab.java | 1 - 4 files changed, 51 insertions(+), 2 deletions(-) diff --git a/core/src/main/java/mrtjp/projectred/redui/ViewportRenderNode.java b/core/src/main/java/mrtjp/projectred/redui/ViewportRenderNode.java index 6a7891996..5efdad449 100644 --- a/core/src/main/java/mrtjp/projectred/redui/ViewportRenderNode.java +++ b/core/src/main/java/mrtjp/projectred/redui/ViewportRenderNode.java @@ -58,6 +58,16 @@ protected Vector3 ndcMouseToWorld(Vec2 ndcMouse) { return pvMatrix.ndcToWorldCoordinates(ndcMouse.dx, ndcMouse.dy, getTargetPlaneDistance()); } + protected double distanceToEncloseRect(double width, double height) { + double fovY = getVerticalFOV(); + double fovX = fovY * getFrame().width() / getFrame().height(); + + double xDist = width / (2 * Math.tan(fovX / 2)); + double yDist = height / (2 * Math.tan(fovY / 2)); + + return Math.max(xDist, yDist); + } + @Override public void drawBack(PoseStack stack, Point mouse, float partialFrame) { diff --git a/fabrication/src/main/java/mrtjp/projectred/fabrication/gui/ICRenderNode.java b/fabrication/src/main/java/mrtjp/projectred/fabrication/gui/ICRenderNode.java index 8a9d29ae0..3a2fc2577 100644 --- a/fabrication/src/main/java/mrtjp/projectred/fabrication/gui/ICRenderNode.java +++ b/fabrication/src/main/java/mrtjp/projectred/fabrication/gui/ICRenderNode.java @@ -18,6 +18,7 @@ import net.minecraft.network.chat.Component; import org.lwjgl.glfw.GLFW; +import java.util.Iterator; import java.util.LinkedList; import java.util.List; @@ -26,6 +27,7 @@ public class ICRenderNode extends ViewportRenderNode { private static final int ZOOM_ANIMATION_TIME_MS = 100; private static final int LAYER_ANIMATION_TIME_MS = 200; private static final int CAMERA_ANIMATION_TIME_MS = 100; + private static final int FOCUS_ANIMATION_TIME_MS = 400; private static final int ZOOM_DIST_MAX = 18; private static final int ZOOM_DIST_MIN = 3; @@ -35,7 +37,7 @@ public class ICRenderNode extends ViewportRenderNode { private final Vector3 cameraPosition = new Vector3(); private final LinearVectorAnimation cameraLayerAnimator = new LinearVectorAnimation(); - private final LinearVectorAnimation cameraZoomAnimator = new LinearVectorAnimation(0, 5, 0); + private final LinearVectorAnimation cameraZoomAnimator = new LinearVectorAnimation(0, 8, 0); private int currentLayer = 0; @@ -68,6 +70,33 @@ public void applyCameraDelta(Vector3 delta) { cameraZoomAnimator.addDeltaWithNewDuration(delta, CAMERA_ANIMATION_TIME_MS); } + public void focusCameraAtTiles(List positions) { + + if (positions.isEmpty()) return; + + // Create cuboid enclosing all tiles + Cuboid6 bounds = new Cuboid6(); + + Iterator it = positions.iterator(); + TileCoord first = it.next(); + bounds.set(first.x, first.y, first.z, first.x+1, first.y+1, first.z+1); + while (it.hasNext()) { + TileCoord next = it.next(); + bounds.enclose(next.x, next.y, next.z, next.x+1, next.y+1, next.z+1); + } + bounds.expand(1.0); // Expand by 1 tile in all directions + + // X and Z will be at midpoints + double midX = (bounds.min.x + bounds.max.x) / 2D; + double midZ = (bounds.min.z + bounds.max.z) / 2D; + + // Y will be far enough away to enclose all tiles inside FOV + double dist = distanceToEncloseRect(bounds.max.x - bounds.min.x, bounds.max.z - bounds.min.z); + + // Set camera position + cameraZoomAnimator.moveToTargetWithDuration(new Vector3(midX, dist, midZ), FOCUS_ANIMATION_TIME_MS); + } + @Override public void frameUpdate(Point mouse, float partialFrame) { @@ -162,6 +191,12 @@ protected void renderInViewport(PoseStack renderStack, Vec2 ndcMouse, float part getter.endBatch(); } + @Override + public void onAddedToParent() { + // Set initial zoom to enclose entire tile map + focusCameraAtTiles(List.of(editor.getTileMap().getMinBounds(), editor.getTileMap().getMaxBounds())); + } + @Override public void update() { super.update(); diff --git a/fabrication/src/main/java/mrtjp/projectred/fabrication/gui/LinearVectorAnimation.java b/fabrication/src/main/java/mrtjp/projectred/fabrication/gui/LinearVectorAnimation.java index 54c353c60..7eb95abae 100644 --- a/fabrication/src/main/java/mrtjp/projectred/fabrication/gui/LinearVectorAnimation.java +++ b/fabrication/src/main/java/mrtjp/projectred/fabrication/gui/LinearVectorAnimation.java @@ -44,6 +44,11 @@ public void addDeltaWithNewDuration(Vector3 delta, long duration) { step.divide(stepsRemaining); } + public void moveToTargetWithDuration(Vector3 target, long duration) { + stepsRemaining = duration; + step.set(target).subtract(vector).divide(stepsRemaining); + } + public void tick(long time) { long dt = lastTime == -1 ? 0 : time - lastTime; diff --git a/fabrication/src/main/java/mrtjp/projectred/fabrication/gui/screen/ICWorkbenchCompileTab.java b/fabrication/src/main/java/mrtjp/projectred/fabrication/gui/screen/ICWorkbenchCompileTab.java index 66312fbdc..10c1801a2 100644 --- a/fabrication/src/main/java/mrtjp/projectred/fabrication/gui/screen/ICWorkbenchCompileTab.java +++ b/fabrication/src/main/java/mrtjp/projectred/fabrication/gui/screen/ICWorkbenchCompileTab.java @@ -27,7 +27,6 @@ import java.util.List; import static mrtjp.projectred.fabrication.editor.ICWorkbenchEditor.*; -import static mrtjp.projectred.fabrication.editor.ICWorkbenchEditor.UNIFORM_DARK_GRAY; import static mrtjp.projectred.fabrication.init.FabricationUnlocal.*; public class ICWorkbenchCompileTab extends AbstractGuiNode implements ICRenderNode.IICRenderNodeEventReceiver { From fd4b7eb7d7eef36174dfc4e2992b041fd46c7a88 Mon Sep 17 00:00:00 2001 From: MrTJP Date: Wed, 22 Nov 2023 18:51:05 -0500 Subject: [PATCH 19/23] fix: wires placing out of bounds in workbench --- .../fabrication/editor/tools/EraseTool.java | 3 ++ .../editor/tools/WirePlacerTool.java | 47 +++++++++++-------- 2 files changed, 30 insertions(+), 20 deletions(-) diff --git a/fabrication/src/main/java/mrtjp/projectred/fabrication/editor/tools/EraseTool.java b/fabrication/src/main/java/mrtjp/projectred/fabrication/editor/tools/EraseTool.java index a00f5f7ab..7809c0a6c 100644 --- a/fabrication/src/main/java/mrtjp/projectred/fabrication/editor/tools/EraseTool.java +++ b/fabrication/src/main/java/mrtjp/projectred/fabrication/editor/tools/EraseTool.java @@ -113,6 +113,9 @@ public void toolDeactivated() { @Override @OnlyIn (Dist.CLIENT) public void renderOverlay(Vector3 mousePosition, boolean isFirstHit, CCRenderState ccrs, MultiBufferSource getter, PoseStack matrixStack) { + + if (!isFirstHit) return; + Vector3 a = leftMouseDown ? initialMouseDown : mousePosition; Vector3 b = mousePosition; diff --git a/fabrication/src/main/java/mrtjp/projectred/fabrication/editor/tools/WirePlacerTool.java b/fabrication/src/main/java/mrtjp/projectred/fabrication/editor/tools/WirePlacerTool.java index 6a11f0847..adc642799 100644 --- a/fabrication/src/main/java/mrtjp/projectred/fabrication/editor/tools/WirePlacerTool.java +++ b/fabrication/src/main/java/mrtjp/projectred/fabrication/editor/tools/WirePlacerTool.java @@ -31,7 +31,7 @@ public class WirePlacerTool extends BaseICEditorTool { private final Vector3 initialMouseDown = new Vector3(); private final List selectedPositionsList = new LinkedList<>(); - private final Set selectedPositions = new HashSet<>(); + private final Set selectedPositionsSet = new HashSet<>(); private boolean leftMouseDown; @@ -63,12 +63,12 @@ public void readPacket(MCDataInput in) { for (int i = 0; i < numPositions; i++) { TileCoord pos = new TileCoord(in.readByte(), y, in.readByte()); + if (!canPlaceAt(pos, overwrite)) continue; + + WireTile tile = (WireTile) wireType.tileType.create(); if (editor.getTileMap().getTile(pos).isPresent()) { - if (!overwrite) continue; editor.removeTile(pos); } - - WireTile tile = (WireTile) wireType.tileType.create(); editor.addTile(tile, pos); } } @@ -87,10 +87,15 @@ protected void sendPlaceWires() { } } + protected boolean canPlaceAt(TileCoord pos, boolean overwrite) { + if (!isInBody(pos) || isOnIOEdge(pos)) return false; + return editor.getTileMap().getTile(pos).isEmpty() || overwrite; + } + protected void addToSelection(Vector3 mousePosition) { TileCoord pos = toNearestPosition(mousePosition); - if (!selectedPositions.contains(pos) && !editor.getTileMap().getBaseTile(pos).isPresent()) { - selectedPositions.add(pos); + if (canPlaceAt(pos, overwrite) && !selectedPositionsSet.contains(pos)) { + selectedPositionsSet.add(pos); selectedPositionsList.add(pos); } } @@ -113,7 +118,7 @@ public boolean toolReleased(Vector3 mousePosition, int glfwMouseButton) { sendPlaceWires(); leftMouseDown = false; - selectedPositions.clear(); + selectedPositionsSet.clear(); selectedPositionsList.clear(); return true; @@ -144,12 +149,12 @@ public void toolLayerChanged(int previousLayer, int newLayer) { initialMouseDown.y += diff; List oldSelection = new LinkedList<>(selectedPositionsList); - selectedPositions.clear(); + selectedPositionsSet.clear(); selectedPositionsList.clear(); for (TileCoord t : oldSelection) { TileCoord newPos = t.add(0, diff, 0); - selectedPositions.add(newPos); + selectedPositionsSet.add(newPos); selectedPositionsList.add(newPos); } } @@ -158,21 +163,21 @@ public void toolLayerChanged(int previousLayer, int newLayer) { @Override public void toolCanceled(Vector3 mousePosition) { leftMouseDown = false; - selectedPositions.clear(); + selectedPositionsSet.clear(); selectedPositionsList.clear(); } @Override public void toolActivated() { leftMouseDown = false; - selectedPositions.clear(); + selectedPositionsSet.clear(); selectedPositionsList.clear(); } @Override public void toolDeactivated() { leftMouseDown = false; - selectedPositions.clear(); + selectedPositionsSet.clear(); selectedPositionsList.clear(); } @@ -180,29 +185,31 @@ public void toolDeactivated() { @OnlyIn(Dist.CLIENT) public void renderOverlay(Vector3 mousePosition, boolean isFirstHit, CCRenderState ccrs, MultiBufferSource getter, PoseStack matrixStack) { - if (leftMouseDown) { - addToSelection(mousePosition); - } + if (!isFirstHit && selectedPositionsList.isEmpty()) return; ccrs.reset(); ccrs.bind(ICRenderTypes.layersRenderType, Minecraft.getInstance().renderBuffers().bufferSource(), matrixStack); ccrs.alphaOverride = leftMouseDown ? 128 : 64; ccrs.brightness = LightTexture.pack(15, 15); - if (!leftMouseDown) { - renderWireAt(toNearestPosition(mousePosition), ccrs, 0); - } - for (TileCoord pos : selectedPositionsList) { int rmask = 0; for (int r = 0; r < 4; r++) { int s = IRotatableICTile.rotationToDir(r); - if (selectedPositions.contains(pos.offset(s))) { + if (selectedPositionsSet.contains(pos.offset(s))) { rmask |= 1 << r; } } renderWireAt(pos, ccrs, rmask); } + + // If just hovering, render overlay + if (!leftMouseDown) { + TileCoord pos = toNearestPosition(mousePosition); + if (canPlaceAt(pos, overwrite)) { + renderWireAt(pos, ccrs, 0); + } + } } private void renderWireAt(TileCoord pos, CCRenderState ccrs, int rmask) { From 11120b8aadff242004d97d10666e852ba3f9fa32 Mon Sep 17 00:00:00 2001 From: MrTJP Date: Thu, 23 Nov 2023 14:26:50 -0500 Subject: [PATCH 20/23] feat: cancel workbench tool when esc is pressed --- .../fabrication/editor/tools/EraseTool.java | 8 +++- .../editor/tools/GatePlacerTool.java | 8 +++- .../editor/tools/IICEditorTool.java | 4 +- .../editor/tools/InteractTool.java | 8 +++- .../editor/tools/WirePlacerTool.java | 12 ++++-- .../fabrication/gui/EraserToolTab.java | 10 ++--- .../fabrication/gui/ICEditorToolManager.java | 22 +++++++++++ .../fabrication/gui/ICEditorToolTab.java | 9 +++++ .../fabrication/gui/InteractToolTab.java | 10 ++--- .../fabrication/gui/SimpleUVTab.java | 5 +++ .../fabrication/gui/TabButtonNode.java | 6 --- .../fabrication/gui/TabControllerNode.java | 37 ++++++++++++++----- .../gui/screen/ICWorkbenchEditTab.java | 10 ++++- .../gui/screen/ICWorkbenchScreen.java | 21 +++++++++++ .../fabrication/tile/ICWorkbenchTile.java | 23 +++++++----- 15 files changed, 146 insertions(+), 47 deletions(-) diff --git a/fabrication/src/main/java/mrtjp/projectred/fabrication/editor/tools/EraseTool.java b/fabrication/src/main/java/mrtjp/projectred/fabrication/editor/tools/EraseTool.java index 7809c0a6c..db7eb13b8 100644 --- a/fabrication/src/main/java/mrtjp/projectred/fabrication/editor/tools/EraseTool.java +++ b/fabrication/src/main/java/mrtjp/projectred/fabrication/editor/tools/EraseTool.java @@ -96,8 +96,12 @@ public boolean toolScrolled(Vector3 mousePosition, double scroll) { } @Override - public void toolCanceled(Vector3 mousePosition) { - leftMouseDown = false; + public boolean toolCanceled() { + if (leftMouseDown) { + leftMouseDown = false; + return true; + } + return false; } @Override diff --git a/fabrication/src/main/java/mrtjp/projectred/fabrication/editor/tools/GatePlacerTool.java b/fabrication/src/main/java/mrtjp/projectred/fabrication/editor/tools/GatePlacerTool.java index 6ed15bd98..224349930 100644 --- a/fabrication/src/main/java/mrtjp/projectred/fabrication/editor/tools/GatePlacerTool.java +++ b/fabrication/src/main/java/mrtjp/projectred/fabrication/editor/tools/GatePlacerTool.java @@ -136,8 +136,12 @@ public void toolLayerChanged(int previousLayer, int newLayer) { } @Override - public void toolCanceled(Vector3 mousePosition) { - leftMouseDown = false; + public boolean toolCanceled() { + if (leftMouseDown) { + leftMouseDown = false; + return true; + } + return false; } @Override diff --git a/fabrication/src/main/java/mrtjp/projectred/fabrication/editor/tools/IICEditorTool.java b/fabrication/src/main/java/mrtjp/projectred/fabrication/editor/tools/IICEditorTool.java index 2ac55c8bb..e7984c6f6 100644 --- a/fabrication/src/main/java/mrtjp/projectred/fabrication/editor/tools/IICEditorTool.java +++ b/fabrication/src/main/java/mrtjp/projectred/fabrication/editor/tools/IICEditorTool.java @@ -31,9 +31,9 @@ public interface IICEditorTool { boolean toolScrolled(Vector3 mousePosition, double scroll); - void toolLayerChanged(int previousLayer, int newLayer); + boolean toolCanceled(); - void toolCanceled(Vector3 mousePosition); + void toolLayerChanged(int previousLayer, int newLayer); void toolActivated(); diff --git a/fabrication/src/main/java/mrtjp/projectred/fabrication/editor/tools/InteractTool.java b/fabrication/src/main/java/mrtjp/projectred/fabrication/editor/tools/InteractTool.java index dfc012aa0..f24bd2b20 100644 --- a/fabrication/src/main/java/mrtjp/projectred/fabrication/editor/tools/InteractTool.java +++ b/fabrication/src/main/java/mrtjp/projectred/fabrication/editor/tools/InteractTool.java @@ -109,8 +109,12 @@ public void toolLayerChanged(int previousLayer, int newLayer) { } @Override - public void toolCanceled(Vector3 mousePosition) { - leftMouseDown = false; + public boolean toolCanceled() { + if (leftMouseDown) { + leftMouseDown = false; + return true; + } + return false; } @Override diff --git a/fabrication/src/main/java/mrtjp/projectred/fabrication/editor/tools/WirePlacerTool.java b/fabrication/src/main/java/mrtjp/projectred/fabrication/editor/tools/WirePlacerTool.java index adc642799..55265fced 100644 --- a/fabrication/src/main/java/mrtjp/projectred/fabrication/editor/tools/WirePlacerTool.java +++ b/fabrication/src/main/java/mrtjp/projectred/fabrication/editor/tools/WirePlacerTool.java @@ -161,10 +161,14 @@ public void toolLayerChanged(int previousLayer, int newLayer) { } @Override - public void toolCanceled(Vector3 mousePosition) { - leftMouseDown = false; - selectedPositionsSet.clear(); - selectedPositionsList.clear(); + public boolean toolCanceled() { + if (leftMouseDown) { + leftMouseDown = false; + selectedPositionsSet.clear(); + selectedPositionsList.clear(); + return true; + } + return false; } @Override diff --git a/fabrication/src/main/java/mrtjp/projectred/fabrication/gui/EraserToolTab.java b/fabrication/src/main/java/mrtjp/projectred/fabrication/gui/EraserToolTab.java index 9b2a37389..a3222bfe2 100644 --- a/fabrication/src/main/java/mrtjp/projectred/fabrication/gui/EraserToolTab.java +++ b/fabrication/src/main/java/mrtjp/projectred/fabrication/gui/EraserToolTab.java @@ -40,11 +40,11 @@ public void renderIcon(PoseStack stack, Point mouse, float partialFrame) { public void buildTooltip(List tooltip) { tooltip.add(new TranslatableComponent(UL_ERASER_TOOL)); } - - @Override - public boolean hasBody() { - return false; - } }; } + + @Override + public boolean hasBody() { + return false; + } } diff --git a/fabrication/src/main/java/mrtjp/projectred/fabrication/gui/ICEditorToolManager.java b/fabrication/src/main/java/mrtjp/projectred/fabrication/gui/ICEditorToolManager.java index 42478ed56..9dab5c952 100644 --- a/fabrication/src/main/java/mrtjp/projectred/fabrication/gui/ICEditorToolManager.java +++ b/fabrication/src/main/java/mrtjp/projectred/fabrication/gui/ICEditorToolManager.java @@ -10,7 +10,9 @@ import org.lwjgl.glfw.GLFW; import java.util.ArrayList; +import java.util.LinkedList; import java.util.List; +import java.util.function.Consumer; public class ICEditorToolManager implements ICRenderNode.IICRenderNodeEventReceiver { @@ -30,6 +32,8 @@ public class ICEditorToolManager implements ICRenderNode.IICRenderNodeEventRecei private boolean layerUpPressed = false; private boolean layerDownPressed = false; + private final List> toolSwappedListeners = new LinkedList<>(); + public ICEditorToolManager(ArrayList toolList) { this.toolList = toolList; selectedTool = toolList.get(0); @@ -41,11 +45,29 @@ public void swapTools(ICEditorToolType nextToolType) { selectedTool.toolDeactivated(); selectedTool = nextTool; selectedTool.toolActivated(); + + for (Consumer listener : toolSwappedListeners) { + listener.accept(nextToolType); + } } } + public void addToolSwappedListener(Consumer listener) { + toolSwappedListeners.add(listener); + } + public boolean keyPressed(int glfwKeyCode, int glfwFlags) { switch (glfwKeyCode) { + case GLFW.GLFW_KEY_ESCAPE: + // Try to cancel current tool + if (selectedTool.toolCanceled()) break; + + // Otherwise, try to swap to the interact tool + if (selectedTool.getToolType() != ICEditorToolType.INTERACT_TOOL) { + swapTools(ICEditorToolType.INTERACT_TOOL); + break; + } + return false; case GLFW.GLFW_KEY_W: upPressed = true; break; diff --git a/fabrication/src/main/java/mrtjp/projectred/fabrication/gui/ICEditorToolTab.java b/fabrication/src/main/java/mrtjp/projectred/fabrication/gui/ICEditorToolTab.java index 9d20ebfc4..cc6b8431e 100644 --- a/fabrication/src/main/java/mrtjp/projectred/fabrication/gui/ICEditorToolTab.java +++ b/fabrication/src/main/java/mrtjp/projectred/fabrication/gui/ICEditorToolTab.java @@ -92,6 +92,10 @@ protected void addSingleButton(ButtonController controller) { addChild(button); } + public IICEditorTool getTool() { + return tool; + } + @Override public void drawBack(PoseStack stack, Point mouse, float partialFrame) { RenderSystem.setShaderTexture(0, ICWorkbenchScreen.BACKGROUND); @@ -101,6 +105,11 @@ public void drawBack(PoseStack stack, Point mouse, float partialFrame) { //TODO: Render tool name on header } + @Override + public boolean hasBody() { + return true; + } + @Override public void onTabClosed() { setHidden(true); diff --git a/fabrication/src/main/java/mrtjp/projectred/fabrication/gui/InteractToolTab.java b/fabrication/src/main/java/mrtjp/projectred/fabrication/gui/InteractToolTab.java index ea44e4f12..7ea2edde5 100644 --- a/fabrication/src/main/java/mrtjp/projectred/fabrication/gui/InteractToolTab.java +++ b/fabrication/src/main/java/mrtjp/projectred/fabrication/gui/InteractToolTab.java @@ -40,11 +40,11 @@ public void renderIcon(PoseStack stack, Point mouse, float partialFrame) { public void buildTooltip(List tooltip) { tooltip.add(new TranslatableComponent(UL_INTERACT_TOOL)); } - - @Override - public boolean hasBody() { - return false; - } }; } + + @Override + public boolean hasBody() { + return false; + } } diff --git a/fabrication/src/main/java/mrtjp/projectred/fabrication/gui/SimpleUVTab.java b/fabrication/src/main/java/mrtjp/projectred/fabrication/gui/SimpleUVTab.java index 164f6fd27..03ae5fe81 100644 --- a/fabrication/src/main/java/mrtjp/projectred/fabrication/gui/SimpleUVTab.java +++ b/fabrication/src/main/java/mrtjp/projectred/fabrication/gui/SimpleUVTab.java @@ -50,6 +50,11 @@ protected void buildTooltip(List tooltip) { //endregion //region TabControllerNode.IToolbarTab + @Override + public boolean hasBody() { + return true; + } + @Override public void onTabClosed() { tabBodyNode.setHidden(true); diff --git a/fabrication/src/main/java/mrtjp/projectred/fabrication/gui/TabButtonNode.java b/fabrication/src/main/java/mrtjp/projectred/fabrication/gui/TabButtonNode.java index 3e77b56a6..1812ecee2 100644 --- a/fabrication/src/main/java/mrtjp/projectred/fabrication/gui/TabButtonNode.java +++ b/fabrication/src/main/java/mrtjp/projectred/fabrication/gui/TabButtonNode.java @@ -107,9 +107,7 @@ public boolean mouseClicked(Point p, int glfwMouseButton, boolean consumed) { public void onClicked() { TabControllerNode tabControllerNode = (TabControllerNode) getParent(); - tabControllerNode.openTab(tab); - if (!hasBody()) tabControllerNode.minimizeTab(tab); // If no body, minimize tab } public void onTabStateChanged(TabState prevState, TabState newState) { @@ -126,10 +124,6 @@ public void onTabStateChanged(TabState prevState, TabState newState) { } } - public boolean hasBody() { - return true; - } - public abstract void renderIcon(PoseStack stack, Point mouse, float partialFrame); public abstract void buildTooltip(List tooltip); diff --git a/fabrication/src/main/java/mrtjp/projectred/fabrication/gui/TabControllerNode.java b/fabrication/src/main/java/mrtjp/projectred/fabrication/gui/TabControllerNode.java index 56487f1eb..9a1bb4c2d 100644 --- a/fabrication/src/main/java/mrtjp/projectred/fabrication/gui/TabControllerNode.java +++ b/fabrication/src/main/java/mrtjp/projectred/fabrication/gui/TabControllerNode.java @@ -1,10 +1,12 @@ package mrtjp.projectred.fabrication.gui; import mrtjp.projectred.redui.AbstractGuiNode; +import net.covers1624.quack.collection.FastStream; import java.util.LinkedList; import java.util.List; import java.util.Optional; +import java.util.function.Predicate; import static mrtjp.projectred.fabrication.gui.TabButtonNode.TabState.*; @@ -57,25 +59,40 @@ public void spreadButtonsHorizontally(int padding) { } public void selectInitialTab(int tabIndex) { - - TabEntry tab = tabs.get(tabIndex); - if (tab.buttonNode.hasBody()) { - for (int i = 0; i < tabs.size(); i++) { - tabs.get(i).buttonNode.setTabState(i == tabIndex ? OPEN : CLOSED); - } - } else { - tab.buttonNode.setTabState(MINIMIZED); - } + openTab(tabs.get(tabIndex).tab); } public void openTab(IToolbarTab tab) { + + boolean tabsOpen = false; + for (TabEntry entry : tabs) { if (entry.tab == tab) { entry.buttonNode.setTabState(OPEN); + if (!tab.hasBody()) { + entry.buttonNode.setTabState(MINIMIZED); + } else { + tabsOpen = true; + } } else { entry.buttonNode.setTabState(CLOSED); } } + + if (!tabsOpen) { + for (TabEntry entry : tabs) { + if (entry.tab != tab) entry.buttonNode.setTabState(ALL_CLOSED); + } + } + } + + public void openTab(Predicate selector) { + for (TabEntry entry : tabs) { + if (selector.test(entry.tab)) { + openTab(entry.tab); + return; + } + } } public void closeTab(IToolbarTab tab) { @@ -137,6 +154,8 @@ public TabEntry(int i, TabButtonNode buttonNode, IToolbarTab tab) { public interface IToolbarTab { + boolean hasBody(); // Tabs without bodies will be immediately minimized after open + void onTabClosed(); void onTabOpened(); diff --git a/fabrication/src/main/java/mrtjp/projectred/fabrication/gui/screen/ICWorkbenchEditTab.java b/fabrication/src/main/java/mrtjp/projectred/fabrication/gui/screen/ICWorkbenchEditTab.java index 090d7d20d..c1dbad28d 100644 --- a/fabrication/src/main/java/mrtjp/projectred/fabrication/gui/screen/ICWorkbenchEditTab.java +++ b/fabrication/src/main/java/mrtjp/projectred/fabrication/gui/screen/ICWorkbenchEditTab.java @@ -3,6 +3,7 @@ import codechicken.lib.colour.EnumColour; import com.mojang.blaze3d.systems.RenderSystem; import com.mojang.blaze3d.vertex.PoseStack; +import mrtjp.projectred.fabrication.editor.ICEditorToolType; import mrtjp.projectred.fabrication.editor.ICWorkbenchEditor; import mrtjp.projectred.fabrication.editor.tools.*; import mrtjp.projectred.fabrication.gui.*; @@ -17,17 +18,20 @@ public class ICWorkbenchEditTab extends AbstractGuiNode { private final ICWorkbenchEditor editor; private final ICEditorToolManager toolManager; + private final TabControllerNode toolbarNode = new TabControllerNode(); + public ICWorkbenchEditTab(ICWorkbenchEditor editor) { this.editor = editor; this.toolManager = new ICEditorToolManager(editor.getToolList()); + toolManager.addToolSwappedListener(this::onToolSwapped); + setSize(304, 222); initSubNodes(); } private void initSubNodes() { - TabControllerNode toolbarNode = new TabControllerNode(); toolbarNode.setPosition(286, 24); toolbarNode.setZPosition(0.1); addChild(toolbarNode); @@ -67,6 +71,10 @@ private ICEditorToolTab getTabForTool(IICEditorTool tool) { return new ICEditorToolTab(toolManager, tool); } + private void onToolSwapped(ICEditorToolType newToolType) { + toolbarNode.openTab(tab -> ((ICEditorToolTab) tab).getTool().getToolType() == newToolType); + } + @Override public void drawBack(PoseStack stack, Point mouse, float partialFrame) { RenderSystem.setShaderTexture(0, ICWorkbenchScreen.BACKGROUND); diff --git a/fabrication/src/main/java/mrtjp/projectred/fabrication/gui/screen/ICWorkbenchScreen.java b/fabrication/src/main/java/mrtjp/projectred/fabrication/gui/screen/ICWorkbenchScreen.java index e29fde264..4388fd4cc 100644 --- a/fabrication/src/main/java/mrtjp/projectred/fabrication/gui/screen/ICWorkbenchScreen.java +++ b/fabrication/src/main/java/mrtjp/projectred/fabrication/gui/screen/ICWorkbenchScreen.java @@ -23,6 +23,7 @@ import net.minecraft.network.chat.TranslatableComponent; import net.minecraft.resources.ResourceLocation; import net.minecraft.world.item.ItemStack; +import org.lwjgl.glfw.GLFW; import java.util.List; @@ -112,6 +113,26 @@ public void update() { refreshOverlay(); } + @Override + public boolean shouldCloseOnEsc() { + // Suppress Vanilla logic to always close screen on ESC press + return false; + } + + @Override + public boolean keyPressed(int glfwKeyCode, int glfwScanCode, int glfwFlags) { + // This gives our UI elements a chance to consume ESC before we close the screen + if (super.keyPressed(glfwKeyCode, glfwScanCode, glfwFlags)) return true; + + // Since we didn't consume ESC, we'll close the screen if it was pressed + if (glfwKeyCode == GLFW.GLFW_KEY_ESCAPE) { + onClose(); + return true; + } + + return false; + } + private void refreshOverlay() { // If active, hide overlay and show every thing else. Otherwise, do opposite boolean isActive = editor.isActive(); diff --git a/fabrication/src/main/java/mrtjp/projectred/fabrication/tile/ICWorkbenchTile.java b/fabrication/src/main/java/mrtjp/projectred/fabrication/tile/ICWorkbenchTile.java index b5151d10b..5d269ebcf 100644 --- a/fabrication/src/main/java/mrtjp/projectred/fabrication/tile/ICWorkbenchTile.java +++ b/fabrication/src/main/java/mrtjp/projectred/fabrication/tile/ICWorkbenchTile.java @@ -33,6 +33,11 @@ public class ICWorkbenchTile extends ProjectRedTile implements IPacketReceiverTile, IICWorkbenchEditorNetwork { + private static final int KEY_CLIENT_OPENED_SCREEN = 0; + private static final int KEY_CLIENT_CLOSED_SCREEN = 1; + private static final int KEY_EDITOR_DESCRIPTION_UPDATE = 50; + private static final int KEY_EDITOR_PACKET = 100; + private final ICWorkbenchEditor editor = new ICWorkbenchEditor(this); private final Map editorBufferedStreams = new HashMap<>(); @@ -146,12 +151,12 @@ private void openGuiFromServer(Player player) { if (getLevel().isClientSide || !(player instanceof ServerPlayer)) { throw new RuntimeException("Server only"); } filterAndGetWatchers().add((ServerPlayer) player); LOGGER.info("Watcher added. Size: " + playersWatchingScreen.size()); - sendUpdateToPlayer(0, editor::writeDesc, (ServerPlayer) player); + sendUpdateToPlayer(KEY_CLIENT_OPENED_SCREEN, editor::writeDesc, (ServerPlayer) player); } private void sendEditorDescription() { - sendUpdateToPlayerList(50, editor::writeDesc, playersWatchingScreen); + sendUpdateToPlayerList(KEY_EDITOR_DESCRIPTION_UPDATE, editor::writeDesc, playersWatchingScreen); } public void closeGuiFromClient() { @@ -161,14 +166,14 @@ public void closeGuiFromClient() { @Override public void receiveUpdateFromServer(int key, MCDataInput input) { switch (key) { - case 0: // Client opened screen + case KEY_CLIENT_OPENED_SCREEN: // Client opened screen editor.readDesc(input); ICWorkbenchScreen.openGuiOnClient(this); break; - case 50: // Editor description update + case KEY_EDITOR_DESCRIPTION_UPDATE: // Editor description update editor.readDesc(input); break; - case 100: // Some packet for the editor + case KEY_EDITOR_PACKET: // Some packet for the editor receiveBufferedStream(input); break; default: @@ -179,11 +184,11 @@ public void receiveUpdateFromServer(int key, MCDataInput input) { @Override public void receiveUpdateFromClient(int key, MCDataInput input, ServerPlayer player) { switch (key) { - case 1: // Client closed screen + case KEY_CLIENT_CLOSED_SCREEN: // Client closed screen filterAndGetWatchers().remove(player); LOGGER.info("Watcher removed. Size: " + playersWatchingScreen.size()); break; - case 100: // Some packet for the editor + case KEY_EDITOR_PACKET: // Some packet for the editor receiveBufferedStream(input); break; default: @@ -204,8 +209,8 @@ private void receiveBufferedStream(MCDataInput in) { public MCDataOutput getBufferedStream(int streamKey, int frameKey) { MCDataOutput out = editorBufferedStreams.computeIfAbsent(streamKey, k -> { PacketCustom packet = getLevel().isClientSide ? - CoreNetwork.createTileServerPacket(this, (byte) 100) : - CoreNetwork.createTileClientPacket(this, (byte) 100); + CoreNetwork.createTileServerPacket(this, (byte) KEY_EDITOR_PACKET) : + CoreNetwork.createTileClientPacket(this, (byte) KEY_EDITOR_PACKET); packet.writeByte(k); // One-time key that identifies the entire stream return packet; }); From 36c8462de7c2c1ed9df02021ad451ac89ad92636 Mon Sep 17 00:00:00 2001 From: MrTJP Date: Fri, 24 Nov 2023 17:20:16 -0500 Subject: [PATCH 21/23] perf: optimize BaseTileMap data structures --- .../fabrication/editor/ICWorkbenchEditor.java | 4 +- .../fabrication/engine/BaseTileMap.java | 53 +++++++------------ .../fabrication/gui/ICRenderNode.java | 7 ++- 3 files changed, 25 insertions(+), 39 deletions(-) diff --git a/fabrication/src/main/java/mrtjp/projectred/fabrication/editor/ICWorkbenchEditor.java b/fabrication/src/main/java/mrtjp/projectred/fabrication/editor/ICWorkbenchEditor.java index 14308bb7a..533a127b1 100644 --- a/fabrication/src/main/java/mrtjp/projectred/fabrication/editor/ICWorkbenchEditor.java +++ b/fabrication/src/main/java/mrtjp/projectred/fabrication/editor/ICWorkbenchEditor.java @@ -325,8 +325,8 @@ public void onCompileFailed() { @Override public void onSimulationComplete(int changeMask, ICSimulationContainer container) { - for (BaseTileMap.BaseTileEntry entry : tileMap.getBaseTileEntries()) { - entry.getTile().onSimRegistersChanged(changeMask, container); + for (var entry : tileMap.getBaseTileEntries()) { + entry.getValue().onSimRegistersChanged(changeMask, container); } } //endregion diff --git a/fabrication/src/main/java/mrtjp/projectred/fabrication/engine/BaseTileMap.java b/fabrication/src/main/java/mrtjp/projectred/fabrication/engine/BaseTileMap.java index 8d9036bbe..c7a4443ee 100644 --- a/fabrication/src/main/java/mrtjp/projectred/fabrication/engine/BaseTileMap.java +++ b/fabrication/src/main/java/mrtjp/projectred/fabrication/engine/BaseTileMap.java @@ -6,6 +6,7 @@ import mrtjp.fengine.tiles.FETile; import mrtjp.fengine.tiles.FETileMap; import mrtjp.projectred.fabrication.editor.ICWorkbenchEditor; +import net.covers1624.quack.collection.FastStream; import net.minecraft.nbt.CompoundTag; import net.minecraft.nbt.ListTag; @@ -24,6 +25,7 @@ public class BaseTileMap implements FETileMap { private final ICWorkbenchEditor editor; private final Set ioTiles = new HashSet<>(); + private final Map> layerToTileMap = new HashMap<>(); private TileCoord minBounds = defaultMinBounds; private TileCoord maxBounds = defaultMaxBounds; @@ -64,7 +66,7 @@ public boolean addTile(TileCoord coord, BaseTile tile) { if (!tileMap.containsKey(coord)) { tileMap.put(coord, tile); tile.bindMap(this, coord); - cacheType(tile); + cacheType(coord, tile); return true; } return false; @@ -75,7 +77,7 @@ public Optional removeTile(TileCoord coord) { BaseTile removed = tileMap.remove(coord); if (removed != null) { removed.unbindMap(); - uncacheType(removed); + uncacheType(coord, removed); } return Optional.ofNullable(removed); } @@ -88,17 +90,12 @@ public int getTileCount() { return tileMap.size(); } - public Collection getBaseTileEntries() { - return tileMap.entrySet().stream() - .map(e -> new BaseTileEntry(e.getKey(), e.getValue())) - .collect(Collectors.toList()); + public Collection> getBaseTileEntries() { + return tileMap.entrySet(); } - // TODO keep track of tiles by layer - public Collection getTilesOnLayer(int y) { - return getBaseTileEntries().stream() - .filter(t -> t.getCoord().y == y) - .collect(Collectors.toList()); + public Collection> getTilesOnLayer(int y) { + return layerToTileMap.computeIfAbsent(y, k -> new HashMap<>()).entrySet(); } public Collection getIOTiles() { @@ -115,12 +112,20 @@ public void removeAll() { maxBounds = defaultMaxBounds; } - private void cacheType(BaseTile tile) { + private void cacheType(TileCoord coord, BaseTile tile) { + // Type caching if (tile instanceof IIOConnectionTile) ioTiles.add((IIOConnectionTile) tile); + + // Layer caching + layerToTileMap.computeIfAbsent(coord.y, k -> new HashMap<>()).put(coord, tile); } - private void uncacheType(BaseTile tile) { + private void uncacheType(TileCoord coord, BaseTile tile) { + // Type caching if (tile instanceof IIOConnectionTile) ioTiles.remove(tile); + + // Layer caching + layerToTileMap.get(coord.y).remove(coord); } public InterfaceSpec getInterfaceSpec() { @@ -198,24 +203,6 @@ public void readDesc(MCDataInput in) { } } - public static class BaseTileEntry { - private final TileCoord coord; - private final BaseTile tile; - - public BaseTileEntry(TileCoord coord, BaseTile tile) { - this.coord = coord; - this.tile = tile; - } - - public BaseTile getTile() { - return tile; - } - - public TileCoord getCoord() { - return coord; - } - } - @Override public Optional getTile(TileCoord coord) { return Optional.ofNullable(tileMap.get(coord)); @@ -224,11 +211,11 @@ public Optional getTile(TileCoord coord) { @Override public Collection getEntries() { - return tileMap.entrySet().stream().map(e -> new TileMapEntry() { + return FastStream.of(tileMap.entrySet()).map(e -> (TileMapEntry) new TileMapEntry() { //@formatter:off @Override public TileCoord getCoord() { return e.getKey(); } @Override public FETile getTile() { return e.getValue(); } //@formatter:on - }).collect(Collectors.toList()); + }).toImmutableList(); } } diff --git a/fabrication/src/main/java/mrtjp/projectred/fabrication/gui/ICRenderNode.java b/fabrication/src/main/java/mrtjp/projectred/fabrication/gui/ICRenderNode.java index 3a2fc2577..cd1cbf440 100644 --- a/fabrication/src/main/java/mrtjp/projectred/fabrication/gui/ICRenderNode.java +++ b/fabrication/src/main/java/mrtjp/projectred/fabrication/gui/ICRenderNode.java @@ -16,7 +16,6 @@ import net.minecraft.client.renderer.LightTexture; import net.minecraft.client.renderer.MultiBufferSource; import net.minecraft.network.chat.Component; -import org.lwjgl.glfw.GLFW; import java.util.Iterator; import java.util.LinkedList; @@ -172,12 +171,12 @@ protected void renderInViewport(PoseStack renderStack, Vec2 ndcMouse, float part renderStack.popPose(); // Render tiles - for (BaseTileMap.BaseTileEntry entry : editor.getTileMap().getTilesOnLayer(y)) { + for (var entry : editor.getTileMap().getTilesOnLayer(y)) { renderStack.pushPose(); - renderStack.translate(entry.getCoord().x, y, entry.getCoord().z); + renderStack.translate(entry.getKey().x, y, entry.getKey().z); ccrs.bind(ICRenderTypes.layersRenderType, getter, renderStack); - entry.getTile().renderTile(ccrs, RedundantTransformation.INSTANCE, partialFrame); + entry.getValue().renderTile(ccrs, RedundantTransformation.INSTANCE, partialFrame); renderStack.popPose(); } From 4adb54388b12ba304c98dbcfa4f24d04ada20e4b Mon Sep 17 00:00:00 2001 From: MrTJP Date: Sun, 26 Nov 2023 16:50:12 -0500 Subject: [PATCH 22/23] ci: enable Fabrication curse upload --- fabrication/build.gradle | 42 ++++++++++++++++++++-------------------- 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/fabrication/build.gradle b/fabrication/build.gradle index d65d4e240..e16737b9e 100644 --- a/fabrication/build.gradle +++ b/fabrication/build.gradle @@ -1,7 +1,7 @@ plugins { id 'net.minecraftforge.gradle' + id 'com.matthewprenger.cursegradle' id 'com.github.johnrengelman.shadow' -// id 'com.matthewprenger.cursegradle' } String mod_id = 'projectred_fabrication' @@ -59,23 +59,23 @@ reobf { shadowJar { } // Enable shadow jar reobf } -//TODO -//curseforge { -// apiKey = System.getenv('CURSE_TOKEN') ?: 'XXX' -// -// // Fabrication -// project { -// id = '230111' -// releaseType = System.getenv('CURSE_RELEASE_TYPE') ?: 'alpha' -// changelogType = 'markdown' -// changelog = rootProject.file('CHANGELOG.md') -// relations { -// requiredDependency 'project-red-core' -// requiredDependency 'project-red-integration' -// requiredDependency 'project-red-transmission' -// } -// // Java/ForgeGradle integrations don't work after 1.18.2 port -// addGameVersion "${mc_version}" -// addGameVersion "Java ${java_lang_version}" -// } -//} +curseforge { + apiKey = System.getenv('CURSE_TOKEN') ?: 'XXX' + + // Fabrication + project { + id = '230111' + releaseType = System.getenv('CURSE_RELEASE_TYPE') ?: 'alpha' + changelogType = 'markdown' + changelog = rootProject.file('CHANGELOG.md') + relations { + requiredDependency 'project-red-core' + requiredDependency 'project-red-integration' + requiredDependency 'project-red-transmission' + } + + // Java/ForgeGradle integrations don't work after 1.18.2 port + addGameVersion "${mc_version}" + addGameVersion "Java ${java_lang_version}" + } +} From 343af6f36a3eea189e979bcef59e87350dea9535 Mon Sep 17 00:00:00 2001 From: MrTJP Date: Sun, 26 Nov 2023 20:12:22 -0500 Subject: [PATCH 23/23] feat: zoom-sensitive pan speed in workbench --- .../fabrication/gui/ICEditorToolManager.java | 14 +++++++------ .../fabrication/gui/ICRenderNode.java | 21 +++++++++++++++++++ .../gui/screen/ICWorkbenchCompileTab.java | 14 +++++++------ 3 files changed, 37 insertions(+), 12 deletions(-) diff --git a/fabrication/src/main/java/mrtjp/projectred/fabrication/gui/ICEditorToolManager.java b/fabrication/src/main/java/mrtjp/projectred/fabrication/gui/ICEditorToolManager.java index 9dab5c952..1628cf4ba 100644 --- a/fabrication/src/main/java/mrtjp/projectred/fabrication/gui/ICEditorToolManager.java +++ b/fabrication/src/main/java/mrtjp/projectred/fabrication/gui/ICEditorToolManager.java @@ -120,12 +120,14 @@ public boolean keyReleased(int glfwKeyCode, int glfwFlags) { } public void update(ICRenderNode renderNode) { - // Move camera - Vector3 cameraDelta = new Vector3(); - double deltaPerTick = 0.5D; - cameraDelta.z = (upPressed ? -deltaPerTick : 0) + (downPressed ? deltaPerTick : 0); - cameraDelta.x = (leftPressed ? -deltaPerTick : 0) + (rightPressed ? deltaPerTick : 0); - renderNode.applyCameraDelta(cameraDelta); + // Pan camera + if (upPressed || downPressed || leftPressed || rightPressed) { + Vector3 panDelta = new Vector3(); + double deltaPerTick = 0.05D; + panDelta.z = (upPressed ? -deltaPerTick : 0) + (downPressed ? deltaPerTick : 0); + panDelta.x = (leftPressed ? -deltaPerTick : 0) + (rightPressed ? deltaPerTick : 0); + renderNode.applyPanningDelta(panDelta); + } // Shift Layers if (layerUpPressed) { diff --git a/fabrication/src/main/java/mrtjp/projectred/fabrication/gui/ICRenderNode.java b/fabrication/src/main/java/mrtjp/projectred/fabrication/gui/ICRenderNode.java index cd1cbf440..2befba91b 100644 --- a/fabrication/src/main/java/mrtjp/projectred/fabrication/gui/ICRenderNode.java +++ b/fabrication/src/main/java/mrtjp/projectred/fabrication/gui/ICRenderNode.java @@ -69,6 +69,27 @@ public void applyCameraDelta(Vector3 delta) { cameraZoomAnimator.addDeltaWithNewDuration(delta, CAMERA_ANIMATION_TIME_MS); } + /** + * Apply a camera delta based on NDC delta + * @param delta Amount to pan camera in frame NDC units + */ + public void applyPanningDelta(Vector3 delta) { + + // Calculate scale based on how many tiles are visible in the viewport across its largest dimension + double scale; + if (getFrame().width() > getFrame().height()) { + scale = ndcMouseToWorld(new Vec2(1, 0)).subtract(ndcMouseToWorld(new Vec2(-1, 0))).x; + } else { + scale = ndcMouseToWorld(new Vec2(0, -1)).subtract(ndcMouseToWorld(new Vec2(0, 1))).z; // Z because top-down view + } + + // Scale delta to world units + Vector3 scaledDelta = delta.copy().multiply(scale); + + // Move camera + applyCameraDelta(scaledDelta); + } + public void focusCameraAtTiles(List positions) { if (positions.isEmpty()) return; diff --git a/fabrication/src/main/java/mrtjp/projectred/fabrication/gui/screen/ICWorkbenchCompileTab.java b/fabrication/src/main/java/mrtjp/projectred/fabrication/gui/screen/ICWorkbenchCompileTab.java index 10c1801a2..f2eea7329 100644 --- a/fabrication/src/main/java/mrtjp/projectred/fabrication/gui/screen/ICWorkbenchCompileTab.java +++ b/fabrication/src/main/java/mrtjp/projectred/fabrication/gui/screen/ICWorkbenchCompileTab.java @@ -202,12 +202,14 @@ public boolean onKeyReleased(int glfwKeyCode, int glfwScanCode, int glfwFlags, b @Override public void update(ICRenderNode renderNode) { - // Move camera - Vector3 cameraDelta = new Vector3(); - double deltaPerTick = 0.5D; - cameraDelta.z = (upPressed ? -deltaPerTick : 0) + (downPressed ? deltaPerTick : 0); - cameraDelta.x = (leftPressed ? -deltaPerTick : 0) + (rightPressed ? deltaPerTick : 0); - renderNode.applyCameraDelta(cameraDelta); + // Pan camera + if (upPressed || downPressed || leftPressed || rightPressed) { + Vector3 panDelta = new Vector3(); + double deltaPerTick = 0.05D; + panDelta.z = (upPressed ? -deltaPerTick : 0) + (downPressed ? deltaPerTick : 0); + panDelta.x = (leftPressed ? -deltaPerTick : 0) + (rightPressed ? deltaPerTick : 0); + renderNode.applyPanningDelta(panDelta); + } // Shift Layers if (layerUpPressed) {

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℘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 K8*}iFfBy&hw}7<( literal 550688 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 D<^w67 diff --git a/integration/src/main/resources/assets/projectred_integration/obj/array/icbundled.obj b/integration/src/main/resources/assets/projectred_integration/obj/array/icbundled.obj index c8b8fc770..6ab2cc15d 100644 --- a/integration/src/main/resources/assets/projectred_integration/obj/array/icbundled.obj +++ b/integration/src/main/resources/assets/projectred_integration/obj/array/icbundled.obj @@ -1,4 +1,4 @@ -# Blender v2.71 (sub 5) OBJ File: 'icbundled.blend' +# Blender v3.1.2 OBJ File: 'icbundled.blend' # www.blender.org g base.002 v -0.187500 0.000000 -0.312600 @@ -9,23 +9,23 @@ v -0.187500 0.250000 -0.312600 v -0.187500 0.250000 -0.500010 v 0.187500 0.250000 -0.500010 v 0.187500 0.250000 -0.312600 -vt 0.312500 0.375000 -vt 0.312500 0.468750 -vt 0.437500 0.468750 -vt 0.437500 0.375000 -vt 0.125000 0.375000 -vt 0.125000 0.250000 -vt 0.312500 0.250000 -vt 0.125000 0.468750 -vt 0.000000 0.468750 -vt 0.000000 0.375000 +vt 0.125000 0.781250 vt 0.125000 0.875000 +vt -0.000000 0.875000 +vt -0.000000 0.781250 vt 0.312500 0.875000 vt 0.312500 1.000000 vt 0.125000 1.000000 +vt 0.312500 0.781250 +vt 0.437500 0.781250 +vt 0.437500 0.875000 +vt 0.312500 0.375000 +vt 0.125000 0.375000 +vt 0.125000 0.250000 +vt 0.312500 0.250000 s off f 5/1 6/2 2/3 1/4 -f 6/1 7/5 3/6 2/7 +f 6/2 7/5 3/6 2/7 f 7/5 8/8 4/9 3/10 f 8/11 5/12 1/13 4/14 -f 8/8 7/5 6/1 5/2 +f 8/8 7/5 6/2 5/1 diff --git a/integration/src/main/resources/assets/projectred_integration/obj/fab_ic.blend b/integration/src/main/resources/assets/projectred_integration/obj/fab_ic.blend new file mode 100644 index 0000000000000000000000000000000000000000..cc79a9bec8c7ccc2d80f7c9dd6edbc048330dcff GIT binary patch literal 666140 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Ξ{mHUJP~E>Kw00m+g=3z%8HfET8##x~BXv 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 literal 0 HcmV?d00001 diff --git a/integration/src/main/resources/assets/projectred_integration/obj/fab_ic.obj b/integration/src/main/resources/assets/projectred_integration/obj/fab_ic.obj new file mode 100644 index 000000000..50124709b --- /dev/null +++ b/integration/src/main/resources/assets/projectred_integration/obj/fab_ic.obj @@ -0,0 +1,287 @@ +# Blender v3.1.2 OBJ File: 'fab_ic.blend' +# www.blender.org +g ic +v -0.080277 0.125000 -0.169473 +v -0.080277 0.125000 0.169473 +v -0.169473 0.125000 0.169473 +v -0.169473 0.125000 -0.169473 +v -0.080277 0.171875 -0.169473 +v -0.080277 0.171875 0.169473 +v -0.169473 0.171875 0.169473 +v -0.169473 0.171875 -0.169473 +v 0.169473 0.125000 -0.169473 +v 0.169473 0.125000 0.169473 +v 0.080277 0.125000 0.169473 +v 0.080277 0.125000 -0.169473 +v 0.169473 0.171875 -0.169473 +v 0.169473 0.171875 0.169473 +v 0.080277 0.171875 0.169473 +v 0.080277 0.171875 -0.169473 +v 0.044598 0.125000 -0.169473 +v 0.044598 0.125000 0.169473 +v -0.044598 0.125000 0.169473 +v -0.044598 0.125000 -0.169473 +v 0.044598 0.171875 -0.169473 +v 0.044598 0.171875 0.169473 +v -0.044598 0.171875 0.169473 +v -0.044598 0.171875 -0.169473 +v 0.187312 0.125000 -0.133795 +v 0.187313 0.125000 0.133795 +v -0.187312 0.125000 0.133795 +v -0.187313 0.125000 -0.133795 +v 0.187312 0.187500 -0.133795 +v 0.187313 0.187500 0.133795 +v -0.187312 0.187500 0.133795 +v -0.187313 0.187500 -0.133795 +vt 0.343750 0.812500 +vt 0.343750 0.218750 +vt 0.375000 0.218750 +vt 0.375000 0.812500 +vt 0.375000 0.250000 +vt 0.218750 0.250000 +vt 0.218750 0.218750 +vt 0.250000 0.218750 +vt 0.250000 0.812500 +vt 0.218750 0.812500 +vt 0.218750 0.812500 +vt 0.375000 0.812500 +vt 0.375000 0.781250 +vt 0.218750 0.781250 +vt 0.218750 0.218750 +vt 0.375000 0.218750 +vt 0.718750 0.812500 +vt 0.718750 0.218750 +vt 0.750000 0.218750 +vt 0.750000 0.812500 +vt 0.750000 0.250000 +vt 0.593750 0.250000 +vt 0.593750 0.218750 +vt 0.625000 0.218750 +vt 0.625000 0.812500 +vt 0.593750 0.812500 +vt 0.593750 0.812500 +vt 0.750000 0.812500 +vt 0.750000 0.781250 +vt 0.593750 0.781250 +vt 0.593750 0.218750 +vt 0.750000 0.218750 +vt 0.531250 0.812500 +vt 0.531250 0.218750 +vt 0.562500 0.218750 +vt 0.562500 0.812500 +vt 0.562500 0.250000 +vt 0.406250 0.250000 +vt 0.406250 0.218750 +vt 0.437500 0.218750 +vt 0.437500 0.812500 +vt 0.406250 0.812500 +vt 0.406250 0.812500 +vt 0.562500 0.812500 +vt 0.562500 0.781250 +vt 0.406250 0.781250 +vt 0.406250 0.218750 +vt 0.562500 0.218750 +vt 0.781250 0.750000 +vt 0.781250 0.281250 +vt 0.812500 0.281250 +vt 0.812500 0.750000 +vt 0.812500 0.312500 +vt 0.156250 0.312500 +vt 0.156250 0.281250 +vt 0.187500 0.281250 +vt 0.187500 0.750000 +vt 0.156250 0.750000 +vt 0.812500 0.750000 +vt 0.156250 0.750000 +vt 0.156250 0.718750 +vt 0.812500 0.718750 +vt 0.156250 0.750000 +vt 0.156250 0.281250 +vt 0.812500 0.281250 +vt 0.812500 0.750000 +s off +f 5/1 6/2 2/3 1/4 +f 6/5 7/6 3/7 2/3 +f 7/8 8/9 4/10 3/7 +f 8/11 5/12 1/13 4/14 +f 8/11 7/15 6/16 5/12 +f 13/17 14/18 10/19 9/20 +f 14/21 15/22 11/23 10/19 +f 15/24 16/25 12/26 11/23 +f 16/27 13/28 9/29 12/30 +f 16/27 15/31 14/32 13/28 +f 21/33 22/34 18/35 17/36 +f 22/37 23/38 19/39 18/35 +f 23/40 24/41 20/42 19/39 +f 24/43 21/44 17/45 20/46 +f 24/43 23/47 22/48 21/44 +f 29/49 30/50 26/51 25/52 +f 30/53 31/54 27/55 26/51 +f 31/56 32/57 28/58 27/55 +f 32/59 29/60 25/61 28/62 +f 32/63 31/64 30/65 29/66 +g glass +v -0.312500 0.000010 0.312500 +v -0.312500 0.000010 -0.312500 +v 0.312500 0.000010 -0.312500 +v 0.312500 0.000010 0.312500 +v -0.312500 0.251000 0.312500 +v -0.312500 0.251000 -0.312500 +v 0.312500 0.251000 -0.312500 +v 0.312500 0.251000 0.312500 +v -0.312500 0.000010 0.312500 +v -0.312500 0.000010 -0.312500 +v 0.312500 0.000010 -0.312500 +v 0.312500 0.000010 0.312500 +v -0.312500 0.251000 0.312500 +v -0.312500 0.251000 -0.312500 +v 0.312500 0.251000 -0.312500 +v 0.312500 0.251000 0.312500 +vt 0.031250 0.468750 +vt 0.531250 0.468750 +vt 0.531250 0.593750 +vt 0.031250 0.593750 +vt 0.031250 0.468750 +vt 0.531250 0.468750 +vt 0.531250 0.593750 +vt 0.031250 0.593750 +vt 0.031250 0.468750 +vt 0.531250 0.468750 +vt 0.531250 0.593750 +vt 0.031250 0.593750 +vt 0.031250 0.468750 +vt 0.531250 0.468750 +vt 0.531250 0.593750 +vt 0.031250 0.593750 +vt 0.531250 0.968750 +vt 0.031250 0.968750 +vt 0.031250 0.468750 +vt 0.031250 0.593750 +vt 0.531250 0.593750 +vt 0.531250 0.468750 +vt 0.031250 0.468750 +vt 0.031250 0.593750 +vt 0.531250 0.593750 +vt 0.531250 0.468750 +vt 0.031250 0.468750 +vt 0.031250 0.593750 +vt 0.531250 0.593750 +vt 0.531250 0.468750 +vt 0.031250 0.468750 +vt 0.031250 0.593750 +vt 0.531250 0.593750 +vt 0.531250 0.468750 +vt 0.031250 0.968750 +vt 0.531250 0.968750 +s off +f 37/67 38/68 34/69 33/70 +f 38/71 39/72 35/73 34/74 +f 39/75 40/76 36/77 35/78 +f 40/79 37/80 33/81 36/82 +f 40/79 39/72 38/83 37/84 +f 45/85 41/86 42/87 46/88 +f 46/89 42/90 43/91 47/92 +f 47/93 43/94 44/95 48/96 +f 48/97 44/98 41/99 45/100 +f 48/97 45/101 46/102 47/92 +g platform +v -0.343750 0.000010 0.343750 +v -0.343750 0.000010 -0.343750 +v -0.281250 0.000010 -0.343750 +v -0.281250 0.000010 0.343750 +v -0.343750 0.153125 0.343750 +v -0.343750 0.153125 -0.343750 +v -0.281250 0.153125 -0.343750 +v -0.281250 0.153125 0.343750 +v 0.281250 0.000010 0.343750 +v 0.281250 0.000010 -0.343750 +v 0.343750 0.000010 -0.343750 +v 0.343750 0.000010 0.343750 +v 0.281250 0.153125 0.343750 +v 0.281250 0.153125 -0.343750 +v 0.343750 0.153125 -0.343750 +v 0.343750 0.153125 0.343750 +v -0.343750 0.000010 0.343750 +v -0.343750 0.000010 0.281250 +v 0.343750 0.000010 0.281250 +v 0.343750 0.000010 0.343750 +v -0.343750 0.153125 0.343750 +v -0.343750 0.153125 0.281250 +v 0.343750 0.153125 0.281250 +v 0.343750 0.153125 0.343750 +v -0.343750 0.000010 -0.281250 +v -0.343750 0.000010 -0.343750 +v 0.343750 0.000010 -0.343750 +v 0.343750 0.000010 -0.281250 +v -0.343750 0.153125 -0.281250 +v -0.343750 0.153125 -0.343750 +v 0.343750 0.153125 -0.343750 +v 0.343750 0.153125 -0.281250 +v -0.312500 0.140625 0.312500 +v 0.312500 0.140625 0.312500 +v -0.312500 0.140625 -0.312500 +v 0.312500 0.140625 -0.312500 +vt 0.093750 0.031250 +vt 0.437500 0.031250 +vt 0.437500 0.093750 +vt 0.093750 0.093750 +vt 0.093750 0.031250 +vt 0.437500 0.031250 +vt 0.437500 0.093750 +vt 0.093750 0.093750 +vt 0.125000 0.031250 +vt 0.125000 0.375000 +vt 0.093750 0.375000 +vt 0.093750 0.031250 +vt 0.437500 0.031250 +vt 0.437500 0.062500 +vt 0.093750 0.062500 +vt 0.093750 0.031250 +vt 0.437500 0.031250 +vt 0.437500 0.062500 +vt 0.093750 0.062500 +vt 0.437500 0.375000 +vt 0.406250 0.375000 +vt 0.406250 0.031250 +vt 0.093750 0.031250 +vt 0.437500 0.031250 +vt 0.437500 0.093750 +vt 0.093750 0.093750 +vt 0.093750 0.031250 +vt 0.437500 0.031250 +vt 0.437500 0.093750 +vt 0.093750 0.093750 +vt 0.437500 0.031250 +vt 0.437500 0.062500 +vt 0.093750 0.062500 +vt 0.093750 0.031250 +vt 0.093750 0.031250 +vt 0.437500 0.031250 +vt 0.437500 0.062500 +vt 0.093750 0.062500 +vt 0.093750 0.031250 +vt 0.437500 0.031250 +vt 0.437500 0.062500 +vt 0.093750 0.062500 +vt 0.437500 0.343750 +vt 0.437500 0.375000 +vt 0.093750 0.375000 +vt 0.093750 0.343750 +vt 0.437500 0.093750 +vt 0.718750 0.093750 +vt 0.718750 0.375000 +vt 0.437500 0.375000 +s off +f 53/103 54/104 50/105 49/106 +f 55/107 56/108 52/109 51/110 +f 56/111 55/112 54/113 53/103 +f 61/114 62/115 58/116 57/117 +f 63/118 64/119 60/120 59/121 +f 64/119 63/122 62/123 61/124 +f 70/125 71/126 67/127 66/128 +f 72/129 69/130 65/131 68/132 +f 72/133 71/134 70/135 69/136 +f 78/137 79/138 75/139 74/140 +f 80/141 77/142 73/143 76/144 +f 80/145 79/146 78/147 77/148 +f 81/149 82/150 84/151 83/152 diff --git a/integration/src/main/resources/assets/projectred_integration/obj/icchip.blend b/integration/src/main/resources/assets/projectred_integration/obj/icchip.blend deleted file mode 100644 index 5865978caf3d256b91cc881fa4f9b1c5682b7450..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 549068 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ã}=O*eDId<~fdYj%$wd@i(h}&GD~T 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 L(90nBuYdm!X9Ej2 diff --git a/integration/src/main/resources/assets/projectred_integration/obj/icchip.obj b/integration/src/main/resources/assets/projectred_integration/obj/icchip.obj deleted file mode 100644 index 3f2e44558..000000000 --- a/integration/src/main/resources/assets/projectred_integration/obj/icchip.obj +++ /dev/null @@ -1,104 +0,0 @@ -# Blender v2.71 (sub 5) OBJ File: 'icchip.blend' -# www.blender.org -g base -v -0.080277 0.000000 -0.169473 -v -0.080277 0.000000 0.169473 -v -0.169473 0.000000 0.169473 -v -0.169473 0.000000 -0.169473 -v -0.080277 0.046875 -0.169473 -v -0.080277 0.046875 0.169473 -v -0.169473 0.046875 0.169473 -v -0.169473 0.046875 -0.169473 -v 0.169473 0.000000 -0.169473 -v 0.169473 0.000000 0.169473 -v 0.080277 0.000000 0.169473 -v 0.080277 0.000000 -0.169473 -v 0.169473 0.046875 -0.169473 -v 0.169473 0.046875 0.169473 -v 0.080277 0.046875 0.169473 -v 0.080277 0.046875 -0.169473 -v 0.044598 0.000000 -0.169473 -v 0.044598 0.000000 0.169473 -v -0.044598 0.000000 0.169473 -v -0.044598 0.000000 -0.169473 -v 0.044598 0.046875 -0.169473 -v 0.044598 0.046875 0.169473 -v -0.044598 0.046875 0.169473 -v -0.044598 0.046875 -0.169473 -v 0.187312 0.000000 -0.133795 -v 0.187313 0.000000 0.133795 -v -0.187312 0.000000 0.133795 -v -0.187313 0.000000 -0.133795 -v 0.187312 0.062500 -0.133795 -v 0.187313 0.062500 0.133795 -v -0.187312 0.062500 0.133795 -v -0.187313 0.062500 -0.133795 -vt 0.343750 0.812500 -vt 0.343750 0.218750 -vt 0.375000 0.218750 -vt 0.375000 0.812500 -vt 0.375000 0.250000 -vt 0.218750 0.250000 -vt 0.218750 0.218750 -vt 0.250000 0.218750 -vt 0.250000 0.812500 -vt 0.218750 0.812500 -vt 0.375000 0.781250 -vt 0.218750 0.781250 -vt 0.718750 0.812500 -vt 0.718750 0.218750 -vt 0.750000 0.218750 -vt 0.750000 0.812500 -vt 0.750000 0.250000 -vt 0.593750 0.250000 -vt 0.593750 0.218750 -vt 0.625000 0.218750 -vt 0.625000 0.812500 -vt 0.593750 0.812500 -vt 0.750000 0.781250 -vt 0.593750 0.781250 -vt 0.531250 0.812500 -vt 0.531250 0.218750 -vt 0.562500 0.218750 -vt 0.562500 0.812500 -vt 0.562500 0.250000 -vt 0.406250 0.250000 -vt 0.406250 0.218750 -vt 0.437500 0.218750 -vt 0.437500 0.812500 -vt 0.406250 0.812500 -vt 0.562500 0.781250 -vt 0.406250 0.781250 -vt 0.781250 0.750000 -vt 0.781250 0.281250 -vt 0.812500 0.281250 -vt 0.812500 0.750000 -vt 0.812500 0.312500 -vt 0.156250 0.312500 -vt 0.156250 0.281250 -vt 0.187500 0.281250 -vt 0.187500 0.750000 -vt 0.156250 0.750000 -vt 0.156250 0.718750 -vt 0.812500 0.718750 -s off -f 5/1 6/2 2/3 1/4 -f 6/5 7/6 3/7 2/3 -f 7/8 8/9 4/10 3/7 -f 8/10 5/4 1/11 4/12 -f 8/10 7/7 6/3 5/4 -f 13/13 14/14 10/15 9/16 -f 14/17 15/18 11/19 10/15 -f 15/20 16/21 12/22 11/19 -f 16/22 13/16 9/23 12/24 -f 16/22 15/19 14/15 13/16 -f 21/25 22/26 18/27 17/28 -f 22/29 23/30 19/31 18/27 -f 23/32 24/33 20/34 19/31 -f 24/34 21/28 17/35 20/36 -f 24/34 23/31 22/27 21/28 -f 29/37 30/38 26/39 25/40 -f 30/41 31/42 27/43 26/39 -f 31/44 32/45 28/46 27/43 -f 32/40 29/46 25/47 28/48 -f 32/46 31/43 30/39 29/40 diff --git a/integration/src/main/resources/assets/projectred_integration/obj/icglass.blend b/integration/src/main/resources/assets/projectred_integration/obj/icglass.blend deleted file mode 100644 index bab8d54d828e76081159cc0cfb9542b9f7968941..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 553840 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 EKQu+hg#Z8m diff --git a/integration/src/main/resources/assets/projectred_integration/obj/ichousing.obj b/integration/src/main/resources/assets/projectred_integration/obj/ichousing.obj deleted file mode 100644 index 856b99a88..000000000 --- a/integration/src/main/resources/assets/projectred_integration/obj/ichousing.obj +++ /dev/null @@ -1,73 +0,0 @@ -# Blender v2.71 (sub 5) OBJ File: 'ichousing.blend' -# www.blender.org -g Plane -v -0.312500 0.140625 0.312500 -v 0.312500 0.140625 0.312500 -v -0.312500 0.140625 -0.312500 -v 0.312500 0.140625 -0.312500 -vt 0.437500 0.093750 -vt 0.718750 0.093750 -vt 0.718750 0.375000 -vt 0.437500 0.375000 -s off -f 1/1 2/2 4/3 3/4 -g base.005 -v -0.343750 0.000010 0.343750 -v -0.343750 0.000010 -0.343750 -v -0.281250 0.000010 -0.343750 -v -0.281250 0.000010 0.343750 -v -0.343750 0.153125 0.343750 -v -0.343750 0.153125 -0.343750 -v -0.281250 0.153125 -0.343750 -v -0.281250 0.153125 0.343750 -v 0.281250 0.000010 0.343750 -v 0.281250 0.000010 -0.343750 -v 0.343750 0.000010 -0.343750 -v 0.343750 0.000010 0.343750 -v 0.281250 0.153125 0.343750 -v 0.281250 0.153125 -0.343750 -v 0.343750 0.153125 -0.343750 -v 0.343750 0.153125 0.343750 -v -0.343750 0.000010 0.343750 -v -0.343750 0.000010 0.281250 -v 0.343750 0.000010 0.281250 -v 0.343750 0.000010 0.343750 -v -0.343750 0.153125 0.343750 -v -0.343750 0.153125 0.281250 -v 0.343750 0.153125 0.281250 -v 0.343750 0.153125 0.343750 -v -0.343750 0.000010 -0.281250 -v -0.343750 0.000010 -0.343750 -v 0.343750 0.000010 -0.343750 -v 0.343750 0.000010 -0.281250 -v -0.343750 0.153125 -0.281250 -v -0.343750 0.153125 -0.343750 -v 0.343750 0.153125 -0.343750 -v 0.343750 0.153125 -0.281250 -vt 0.093750 0.031250 -vt 0.437500 0.031250 -vt 0.437500 0.093750 -vt 0.093750 0.093750 -vt 0.125000 0.031250 -vt 0.125000 0.375000 -vt 0.093750 0.375000 -vt 0.437500 0.062500 -vt 0.093750 0.062500 -vt 0.437500 0.375000 -vt 0.406250 0.375000 -vt 0.406250 0.031250 -vt 0.437500 0.343750 -vt 0.093750 0.343750 -s off -f 9/5 10/6 6/7 5/8 -f 11/5 12/6 8/7 7/8 -f 12/9 11/10 10/11 9/5 -f 17/5 18/6 14/12 13/13 -f 19/5 20/6 16/12 15/13 -f 20/6 19/14 18/15 17/16 -f 26/5 27/6 23/7 22/8 -f 28/5 25/6 21/7 24/8 -f 28/6 27/12 26/13 25/5 -f 34/5 35/6 31/12 30/13 -f 36/5 33/6 29/12 32/13 -f 36/17 35/14 34/11 33/18 diff --git a/integration/src/main/resources/assets/projectred_integration/obj/io_colour_box.blend b/integration/src/main/resources/assets/projectred_integration/obj/io_colour_box.blend new file mode 100644 index 0000000000000000000000000000000000000000..5d05f00aa14e4c6515c50cd62c39eda72b33c982 GIT binary patch literal 621952 zcmeFa31D4SwLX55bO_TE6to~>6ogPp=hAe@oTlkK1t`#xrpaxSHbYHP2x9{x1{r0n zJfRgCf~cUPuRNd={C!d2iTKpu^zb=FoZs`W6_xW_-`@MXci)|J?vMo1)_dBWwTHFV zUi({nI_I9DZ1KFM74ue}eaW=RQ&vi}%JaO}cAeUsB@_oJ!W$A+)kRt&LI-X>`T73Di4*;^&pz9qFkyl}Y0@M=FE7uZ zIdi5e10Tv!_Wt+3UzLC8LmyK7kcZsqr=RY>?|tt}7{G_Rpa=TSI_s=x8hQ{=_i3k{ z=1-kE)rXCc0UziGKls6f`jgfF&tCq44}3uR3HY9R>Z$&mIdlAif&vw0&6?%Ap`@h5 zpFMl_fc(P3!U1`%Y*4zWs3=gM%L}`Ti%SMohpTHO)5I2i`IJ*mQT-WX3S(#P+_}mZ z@I#`2@q#f2c{e1IbIUO1P%p6MSi+da7{mCQK7G0h)22;}QpQ<^b|8-YRLaOhIm+5J ztZc^Y(zrUv_jc4xyNB9t_zw6YU_M1(#Mr^yw|ezzf6A08YW@RXP~d!s`4?l?4bU4T z=jOrRrKP2+zE!JM$=E7Z_P{3236m#J_7O1uk}}RR*qu%py_;@j59aDw}}Gy6P2e@7E~u}!@Pn%fVqO}Zz76* z6;?jnWm5~6_>-m=M(Z1H{b)xbopw7D@g*vQ?}0A@@CNU}5HN3?eDcX^F9o~cf9{Pi zCo#_Xg=x&ejH6FsJwY1n#5iLa`agAIuYo?wvKcdGsC5i!VvIQYBFZRt?q!erE88Dd za;OJ&WBmg!^g|YLtYMh15l6td1ja1G9F90-(KgtFH0%d2;;8$abIys@jkaLUM44MR zbl7#|x&!DC~I`coOJZwC)-L)+J_Tc>OUp4gjVzXzL9hJ7FQDDVl=T)Pm*`hhaU zfzw+NR;*a5_NCajEL*nBudc54SFT*?*VNSbYu2n$dFP*hzK;O=-wGR`v%I|ApFe-T zzhuc0zp}DYrIELI@nXNKs>)xnVudQNsHjkBlr31WK-mYmrAwEp^0&jUsn!Ai16S+? zAOk-lp#P%H?7PSVA9zrPzJYR#6^uEI6L)PHt~9X4*hSsIec{4|3P?O z&Qq{2h0U-PHUm@e;Cun&t*)-l@4V(#zwW~yRdWSoF(<%J@D2Fj69izeeED)UhX4!k zA`f`Le>ew%9Pq+C1IoQNaD-mkf zrhqB124=t!J|Kp$7h@khXfyf)#$d&gHGav$3lu+O*mpqfG~#m#3*ySb17DNRj-&sf zZt$QV!C#1T&OsXEaN6`4e)ZZWziM%{8e@<_f1^Co2&jW`Q0TJLZn@3l@=^}<0IT`u zHu|#*%am;^*Eahz=ai~A`X}(jShz6K;V)deO7(H{f8fo%6vp022iQX25^H;m00a7o z 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