From 334bde9de5cba8d3d968f41c9b1acf986eb92bde Mon Sep 17 00:00:00 2001 From: simibubi <31564874+simibubi@users.noreply.github.com> Date: Fri, 2 Oct 2020 14:28:48 +0200 Subject: [PATCH 1/2] Quality - Visual rework of all active UIs - Fixed large scale renderers such as belts, cannons, pulleys to disappear when partially out of frame - Schematic and Quill now has the ability to convert a selection to a readied schematic instantly - Moved option input of cart assemblers to side faces - Fixed crash when attempting to smelt items on belts/depots - Stockpile switches can now be inverted - Fixed stockpile switches not dynamically updating gui indicators frequently enough - Tanks can no longer be directly interacted with in survival mode - Sequenced gearshifts now emit a comparator signal based on their current instruction index - The Piston instruction for sequencers can now accept distances up to 128m - Fixed some rendering inconsistencies with symmetry mirrors - Reworked symmetry mirror models to match the tool better - Attribute filters can now add inverted conditions to the list - Added the attribute "can be crushed" - Made the schematicannon interface a little less confusing - Fixed launched items of the schematicannon rendering warped --- src/generated/resources/.cache/cache | 22 +- .../create/blockstates/radial_chassis.json | 48 +-- .../resources/assets/create/lang/en_us.json | 44 ++- .../assets/create/lang/unfinished/de_de.json | 42 ++- .../assets/create/lang/unfinished/fr_fr.json | 40 +- .../assets/create/lang/unfinished/it_it.json | 40 +- .../assets/create/lang/unfinished/ja_jp.json | 40 +- .../assets/create/lang/unfinished/ko_kr.json | 40 +- .../assets/create/lang/unfinished/nl_nl.json | 42 ++- .../assets/create/lang/unfinished/pt_br.json | 42 ++- .../assets/create/lang/unfinished/ru_ru.json | 42 ++- .../assets/create/lang/unfinished/zh_cn.json | 40 +- .../components/fan/AirCurrent.java | 3 +- .../mounted/CartAssemblerTileEntity.java | 38 +- .../pulley/PulleyRenderer.java | 5 + .../pulley/PulleyTileEntity.java | 2 +- .../fluids/tank/FluidTankBlock.java | 3 + .../sequencer/SequencedGearshiftBlock.java | 10 + .../sequencer/SequencedGearshiftScreen.java | 90 +++-- .../sequencer/SequencerInstructions.java | 2 +- .../relays/belt/BeltRenderer.java | 5 + .../relays/belt/BeltTileEntity.java | 2 +- .../curiosities/symmetry/SymmetryHandler.java | 11 +- .../symmetry/SymmetryWandScreen.java | 64 ++-- .../curiosities/zapper/ZapperScreen.java | 29 +- .../zapper/blockzapper/BlockzapperScreen.java | 16 +- .../terrainzapper/WorldshaperScreen.java | 26 +- .../inventories/AdjustableCrateContainer.java | 6 +- .../inventories/AdjustableCrateScreen.java | 29 +- .../block/redstone/StockpileSwitchBlock.java | 2 +- .../block/redstone/StockpileSwitchScreen.java | 172 +++++---- .../redstone/StockpileSwitchTileEntity.java | 58 ++- .../item/filter/AbstractFilterScreen.java | 13 +- .../item/filter/AttributeFilterContainer.java | 37 +- .../item/filter/AttributeFilterScreen.java | 104 ++++-- .../item/filter/FilterContainer.java | 6 +- .../logistics/item/filter/FilterItem.java | 15 +- .../logistics/item/filter/FilterScreen.java | 16 +- .../item/filter/FilterScreenPacket.java | 6 +- .../logistics/item/filter/ItemAttribute.java | 50 ++- .../packet/ConfigureStockswitchPacket.java | 7 +- .../schematics/ClientSchematicLoader.java | 22 +- .../schematics/ServerSchematicLoader.java | 95 ++++- .../block/SchematicTableContainer.java | 4 +- .../block/SchematicTableScreen.java | 27 +- .../block/SchematicannonContainer.java | 19 +- .../block/SchematicannonRenderer.java | 21 +- .../block/SchematicannonScreen.java | 318 ++++++++++------ .../client/SchematicAndQuillHandler.java | 52 ++- .../client/SchematicEditScreen.java | 72 ++-- .../client/SchematicHotbarSlotOverlay.java | 6 +- .../client/SchematicPromptScreen.java | 103 ++++++ .../packet/InstantSchematicPacket.java | 52 +++ .../create/foundation/gui/AllGuiTextures.java | 81 ++-- .../create/foundation/gui/AllIcons.java | 8 +- .../foundation/gui/TextInputPromptScreen.java | 106 ------ .../foundation/gui/ToolSelectionScreen.java | 2 +- .../foundation/gui/widgets/ScrollInput.java | 5 + .../foundation/networking/AllPackets.java | 2 + .../assets/create/lang/default/messages.json | 48 ++- .../block/symmetry_effect/crossplane.json | 283 +++++++------- .../models/block/symmetry_effect/plane.json | 200 +++++----- .../block/symmetry_effect/tripleplane.json | 346 +++++++++--------- .../create/textures/block/symmetry_mirror.png | Bin 0 -> 262 bytes .../create/textures/gui/curiosities.png | Bin 0 -> 2097 bytes .../create/textures/gui/curiosities_2.png | Bin 0 -> 1488 bytes .../create/textures/gui/double_flexcrate.png | Bin 2133 -> 0 bytes .../assets/create/textures/gui/filter.png | Bin 15775 -> 0 bytes .../assets/create/textures/gui/filters.png | Bin 0 -> 1855 bytes .../gui/flex_crate_and_stockpile_switch.png | Bin 13655 -> 0 bytes .../assets/create/textures/gui/icons.png | Bin 4434 -> 4289 bytes .../assets/create/textures/gui/logistics.png | Bin 0 -> 4761 bytes .../create/textures/gui/logistics_2.png | Bin 0 -> 1771 bytes .../gui/{background.png => overlay.png} | Bin .../assets/create/textures/gui/schematic.png | Bin 1809 -> 0 bytes .../create/textures/gui/schematic_table.png | Bin 1999 -> 0 bytes .../create/textures/gui/schematicannon.png | Bin 13735 -> 0 bytes .../assets/create/textures/gui/schematics.png | Bin 0 -> 1987 bytes .../create/textures/gui/schematics_2.png | Bin 0 -> 4015 bytes .../assets/create/textures/gui/sequencer.png | Bin 2241 -> 1696 bytes .../create/textures/gui/wand_symmetry.png | Bin 1781 -> 0 bytes .../assets/create/textures/gui/widgets.png | Bin 2992 -> 2406 bytes .../assets/create/textures/gui/zapper.png | Bin 10750 -> 0 bytes 83 files changed, 1949 insertions(+), 1232 deletions(-) create mode 100644 src/main/java/com/simibubi/create/content/schematics/client/SchematicPromptScreen.java create mode 100644 src/main/java/com/simibubi/create/content/schematics/packet/InstantSchematicPacket.java delete mode 100644 src/main/java/com/simibubi/create/foundation/gui/TextInputPromptScreen.java create mode 100644 src/main/resources/assets/create/textures/block/symmetry_mirror.png create mode 100644 src/main/resources/assets/create/textures/gui/curiosities.png create mode 100644 src/main/resources/assets/create/textures/gui/curiosities_2.png delete mode 100644 src/main/resources/assets/create/textures/gui/double_flexcrate.png delete mode 100644 src/main/resources/assets/create/textures/gui/filter.png create mode 100644 src/main/resources/assets/create/textures/gui/filters.png delete mode 100644 src/main/resources/assets/create/textures/gui/flex_crate_and_stockpile_switch.png create mode 100644 src/main/resources/assets/create/textures/gui/logistics.png create mode 100644 src/main/resources/assets/create/textures/gui/logistics_2.png rename src/main/resources/assets/create/textures/gui/{background.png => overlay.png} (100%) delete mode 100644 src/main/resources/assets/create/textures/gui/schematic.png delete mode 100644 src/main/resources/assets/create/textures/gui/schematic_table.png delete mode 100644 src/main/resources/assets/create/textures/gui/schematicannon.png create mode 100644 src/main/resources/assets/create/textures/gui/schematics.png create mode 100644 src/main/resources/assets/create/textures/gui/schematics_2.png delete mode 100644 src/main/resources/assets/create/textures/gui/wand_symmetry.png delete mode 100644 src/main/resources/assets/create/textures/gui/zapper.png diff --git a/src/generated/resources/.cache/cache b/src/generated/resources/.cache/cache index 4e96a6802..4b59050cb 100644 --- a/src/generated/resources/.cache/cache +++ b/src/generated/resources/.cache/cache @@ -298,7 +298,7 @@ e8b0a401c10d1ba67ed71ba31bd5f9bc28571b65 assets/create/blockstates/powered_toggl 3a739f9d4276828d83f2d2750bf3227c87bcd438 assets/create/blockstates/pulley_magnet.json 469e430d96cb0a5e1aaf6b7cc5d401d488c9e600 assets/create/blockstates/pulse_repeater.json 92957119abd5fbcca36a113b2a80255fd70fc303 assets/create/blockstates/purple_seat.json -89b63c6e5875da07226854651079bcea85439f5b assets/create/blockstates/radial_chassis.json +bdd56f32ce0a148b6e466a55ab2777f69fc08cfc assets/create/blockstates/radial_chassis.json da1b08387af7afa0855ee8d040f620c01f20660a assets/create/blockstates/red_seat.json 8929677f2cc5354aa19ef182af69f9f0b41eb242 assets/create/blockstates/redstone_contact.json c29213b77ac0c78d8979c5f6188d2b265696f9b9 assets/create/blockstates/redstone_link.json @@ -352,16 +352,16 @@ a3a11524cd3515fc01d905767b4b7ea782adaf03 assets/create/blockstates/yellow_seat.j 7f39521b211441f5c3e06d60c5978cebe16cacfb assets/create/blockstates/zinc_block.json b7181bcd8182b2f17088e5aa881f374c9c65470c assets/create/blockstates/zinc_ore.json e7a5a4320a332f5ed4341d3c08dd50a2e945d8bb assets/create/lang/en_ud.json -040cb0a702643a865f30bae9eeacaeaa94bbce7d assets/create/lang/en_us.json -5c6ce1933165fecd71fbdf67cb8de955368d1bfc assets/create/lang/unfinished/de_de.json -b8c3464b86dd7a934d3beec6c005e4799cbdf7af assets/create/lang/unfinished/fr_fr.json -c91eb4509e5afe6f288ed737f407914ae983480a assets/create/lang/unfinished/it_it.json -16fb593c1179f58811153b2f7c7cffb55615587f assets/create/lang/unfinished/ja_jp.json -4d975de4cd34e10e7156fe35a0e5f4e40650aa69 assets/create/lang/unfinished/ko_kr.json -f98f523352796c3496c27085182118bbd597a7ad assets/create/lang/unfinished/nl_nl.json -714e68af6c0f614d069ff0b31763bced1f968437 assets/create/lang/unfinished/pt_br.json -a18338a37536490b2f7b6a8836add3e133b16920 assets/create/lang/unfinished/ru_ru.json -e7ad3d9140bb94d5aa2720b651d8bf1308ad0da4 assets/create/lang/unfinished/zh_cn.json +29d60a3aac3eb9c7a1c0e9ce4bf4db0bb83f5d53 assets/create/lang/en_us.json +f1ceb5595b8056d8a452ace3f45d7aa7bda8d89b assets/create/lang/unfinished/de_de.json +32059f6ed1f468e707d59adff9b23bf06d9da2b8 assets/create/lang/unfinished/fr_fr.json +a02eef6cf319384a767d1719846a07c98ba203ad assets/create/lang/unfinished/it_it.json +c9ea726ce46c82709285d6231b5fcda533911d74 assets/create/lang/unfinished/ja_jp.json +548ce211b40c3f68b1f9b2ff503e4c2ef68ae21c assets/create/lang/unfinished/ko_kr.json +9d54d6fee5c0b52c03dcbf0fd7106c2a9a7e7a17 assets/create/lang/unfinished/nl_nl.json +bf617f18f5901015f09c097c4de673ff6a1ab764 assets/create/lang/unfinished/pt_br.json +753697d68b3c1e5aa70aa7ee094c33c8fd195594 assets/create/lang/unfinished/ru_ru.json +4b8c4bd41cd2ee5c1f427aa49748fafa1237edf7 assets/create/lang/unfinished/zh_cn.json 846200eb548d3bfa2e77b41039de159b4b6cfb45 assets/create/models/block/acacia_window.json 1930fa3a3c98d53dd19e4ee7f55bc27fd47aa281 assets/create/models/block/acacia_window_pane_noside.json 1763ea2c9b981d187f5031ba608f3d5d3be3986a assets/create/models/block/acacia_window_pane_noside_alt.json diff --git a/src/generated/resources/assets/create/blockstates/radial_chassis.json b/src/generated/resources/assets/create/blockstates/radial_chassis.json index d60327a8a..1aa3d3728 100644 --- a/src/generated/resources/assets/create/blockstates/radial_chassis.json +++ b/src/generated/resources/assets/create/blockstates/radial_chassis.json @@ -89,8 +89,8 @@ }, { "when": { - "sticky_west": "true", - "axis": "x" + "axis": "x", + "sticky_west": "true" }, "apply": { "model": "create:block/radial_chassis_side_x_sticky", @@ -99,8 +99,8 @@ }, { "when": { - "sticky_west": "true", - "axis": "y" + "axis": "y", + "sticky_west": "true" }, "apply": { "model": "create:block/radial_chassis_side_y_sticky", @@ -109,8 +109,8 @@ }, { "when": { - "sticky_west": "true", - "axis": "z" + "axis": "z", + "sticky_west": "true" }, "apply": { "model": "create:block/radial_chassis_side_z_sticky", @@ -119,8 +119,8 @@ }, { "when": { - "sticky_west": "false", - "axis": "x" + "axis": "x", + "sticky_west": "false" }, "apply": { "model": "create:block/radial_chassis_side_x", @@ -129,8 +129,8 @@ }, { "when": { - "sticky_west": "false", - "axis": "y" + "axis": "y", + "sticky_west": "false" }, "apply": { "model": "create:block/radial_chassis_side_y", @@ -139,8 +139,8 @@ }, { "when": { - "sticky_west": "false", - "axis": "z" + "axis": "z", + "sticky_west": "false" }, "apply": { "model": "create:block/radial_chassis_side_z", @@ -207,8 +207,8 @@ }, { "when": { - "sticky_east": "true", - "axis": "x" + "axis": "x", + "sticky_east": "true" }, "apply": { "model": "create:block/radial_chassis_side_x_sticky", @@ -217,8 +217,8 @@ }, { "when": { - "sticky_east": "true", - "axis": "y" + "axis": "y", + "sticky_east": "true" }, "apply": { "model": "create:block/radial_chassis_side_y_sticky", @@ -227,8 +227,8 @@ }, { "when": { - "sticky_east": "true", - "axis": "z" + "axis": "z", + "sticky_east": "true" }, "apply": { "model": "create:block/radial_chassis_side_z_sticky" @@ -236,8 +236,8 @@ }, { "when": { - "sticky_east": "false", - "axis": "x" + "axis": "x", + "sticky_east": "false" }, "apply": { "model": "create:block/radial_chassis_side_x", @@ -246,8 +246,8 @@ }, { "when": { - "sticky_east": "false", - "axis": "y" + "axis": "y", + "sticky_east": "false" }, "apply": { "model": "create:block/radial_chassis_side_y", @@ -256,8 +256,8 @@ }, { "when": { - "sticky_east": "false", - "axis": "z" + "axis": "z", + "sticky_east": "false" }, "apply": { "model": "create:block/radial_chassis_side_z" diff --git a/src/generated/resources/assets/create/lang/en_us.json b/src/generated/resources/assets/create/lang/en_us.json index 1daf3530c..5d325aa9c 100644 --- a/src/generated/resources/assets/create/lang/en_us.json +++ b/src/generated/resources/assets/create/lang/en_us.json @@ -662,12 +662,9 @@ "create.gui.adjustable_crate.title": "Adjustable Crate", "create.gui.adjustable_crate.storageSpace": "Storage Space", "create.gui.stockpile_switch.title": "Stockpile Switch", - "create.gui.stockpile_switch.lowerLimit": "Lower Threshold", - "create.gui.stockpile_switch.upperLimit": "Upper Threshold", - "create.gui.stockpile_switch.startAt": "Start Signal at", - "create.gui.stockpile_switch.startAbove": "Start Signal above", - "create.gui.stockpile_switch.stopAt": "Stop Signal at", - "create.gui.stockpile_switch.stopBelow": "Stop Signal below", + "create.gui.stockpile_switch.invert_signal": "Invert Signal", + "create.gui.stockpile_switch.move_to_lower_at": "Move to lower lane at %1$s%%", + "create.gui.stockpile_switch.move_to_upper_at": "Move to upper lane at %1$s%%", "create.gui.sequenced_gearshift.title": "Sequenced Gearshift", "create.gui.sequenced_gearshift.instruction": "Instruction", "create.gui.sequenced_gearshift.instruction.turn_angle": "Turn", @@ -688,7 +685,8 @@ "create.schematicAndQuill.secondPos": "Second position set.", "create.schematicAndQuill.noTarget": "Hold [Ctrl] to select Air blocks.", "create.schematicAndQuill.abort": "Removed selection.", - "create.schematicAndQuill.prompt": "Enter a name for the Schematic:", + "create.schematicAndQuill.title": "Schematic Name:", + "create.schematicAndQuill.convert": "Save and Deploy Immediately", "create.schematicAndQuill.fallbackName": "My Schematic", "create.schematicAndQuill.saved": "Saved as %1$s", @@ -735,28 +733,33 @@ "create.schematic.tool.flip.description.3": "", "create.schematics.synchronizing": "Syncing...", - "create.schematics.uploadTooLarge": "Your schematic is too big.", + "create.schematics.uploadTooLarge": "Your schematic exceeds limitations specified by the server.", "create.schematics.maxAllowedSize": "The maximum allowed schematic file size is:", "create.gui.schematicTable.title": "Schematic Table", + "create.gui.schematicTable.refresh": "Refresh Files", + "create.gui.schematicTable.open_folder": "Open Folder", "create.gui.schematicTable.availableSchematics": "Available Schematics", "create.gui.schematicTable.noSchematics": "No Schematics Saved", "create.gui.schematicTable.uploading": "Uploading...", "create.gui.schematicTable.finished": "Upload Finished!", "create.gui.schematicannon.title": "Schematicannon", - "create.gui.schematicannon.settingsTitle": "Placement Settings", - "create.gui.schematicannon.listPrinter": "Material List Printer", + "create.gui.schematicannon.listPrinter": "Checklist Printer", "create.gui.schematicannon.gunpowderLevel": "Gunpowder at %1$s%%", "create.gui.schematicannon.shotsRemaining": "Shots left: %1$s", "create.gui.schematicannon.shotsRemainingWithBackup": "With backup: %1$s", "create.gui.schematicannon.optionEnabled": "Currently Enabled", "create.gui.schematicannon.optionDisabled": "Currently Disabled", + "create.gui.schematicannon.showOptions": "Show Printer Settings", "create.gui.schematicannon.option.dontReplaceSolid": "Don't Replace Solid Blocks", "create.gui.schematicannon.option.replaceWithSolid": "Replace Solid with Solid", "create.gui.schematicannon.option.replaceWithAny": "Replace Solid with Any", "create.gui.schematicannon.option.replaceWithEmpty": "Replace Solid with Empty", "create.gui.schematicannon.option.skipMissing": "Skip missing Blocks", "create.gui.schematicannon.option.skipTileEntities": "Protect Tile Entities", + "create.gui.schematicannon.slot.gunpowder": "Add gunpowder to fuel the cannon", + "create.gui.schematicannon.slot.listPrinter": "Place books here to print a Checklist for your Schematic", + "create.gui.schematicannon.slot.schematic": "Add your Schematic here. Make sure it is deployed at a specific location.", "create.gui.schematicannon.option.skipMissing.description": "If the cannon cannot find a required Block for placement, it will continue at the next Location.", "create.gui.schematicannon.option.skipTileEntities.description": "The cannon will avoid replacing data holding blocks such as Chests.", "create.gui.schematicannon.option.dontReplaceSolid.description": "The cannon will never replace any Solid blocks in its working area, only non-Solid and Air.", @@ -792,23 +795,42 @@ "create.gui.filter.ignore_data.description": "Items match regardless of their attributes.", "create.item_attributes.placeable": "is placeable", + "create.item_attributes.placeable.inverted": "is not placeable", "create.item_attributes.consumable": "can be eaten", + "create.item_attributes.consumable.inverted": "cannot be eaten", "create.item_attributes.smeltable": "can be Smelted", + "create.item_attributes.smeltable.inverted": "cannot be Smelted", "create.item_attributes.washable": "can be Washed", + "create.item_attributes.washable.inverted": "cannot be Washed", "create.item_attributes.smokable": "can be Smoked", + "create.item_attributes.smokable.inverted": "cannot be Smoked", + "create.item_attributes.crushable": "can be Crushed", + "create.item_attributes.crushable.inverted": "cannot be Crushed", "create.item_attributes.blastable": "is smeltable in Blast Furnace", + "create.item_attributes.blastable.inverted": "is not smeltable in Blast Furnace", "create.item_attributes.enchanted": "is enchanted", + "create.item_attributes.enchanted.inverted": "is unenchanted", "create.item_attributes.damaged": "is damaged", + "create.item_attributes.damaged.inverted": "is not damaged", "create.item_attributes.badly_damaged": "is heavily damaged", + "create.item_attributes.badly_damaged.inverted": "is not heavily damaged", "create.item_attributes.not_stackable": "cannot stack", + "create.item_attributes.not_stackable.inverted": "can be stacked", "create.item_attributes.equipable": "can be equipped", + "create.item_attributes.equipable.inverted": "cannot be equipped", "create.item_attributes.furnace_fuel": "is furnace fuel", + "create.item_attributes.furnace_fuel.inverted": "is not furnace fuel", "create.item_attributes.in_tag": "is tagged %1$s", - "create.item_attributes.in_item_group": "belongs to %1$s", + "create.item_attributes.in_tag.inverted": "is not tagged %1$s", + "create.item_attributes.in_item_group": "is in group '%1$s'", + "create.item_attributes.in_item_group.inverted": "is not in group '%1$s'", "create.item_attributes.added_by": "was added by %1$s", + "create.item_attributes.added_by.inverted": "was not added by %1$s", "create.gui.attribute_filter.no_selected_attributes": "No attributes selected", "create.gui.attribute_filter.selected_attributes": "Selected attributes:", + "create.gui.attribute_filter.add_attribute": "Add attribute to List", + "create.gui.attribute_filter.add_inverted_attribute": "Add opposite attribute to List", "create.gui.attribute_filter.whitelist_disjunctive": "Whitelist (Any)", "create.gui.attribute_filter.whitelist_disjunctive.description": "Items pass if they have any of the selected attributes.", "create.gui.attribute_filter.whitelist_conjunctive": "Whitelist (All)", diff --git a/src/generated/resources/assets/create/lang/unfinished/de_de.json b/src/generated/resources/assets/create/lang/unfinished/de_de.json index c72d05bb9..576d1eb4c 100644 --- a/src/generated/resources/assets/create/lang/unfinished/de_de.json +++ b/src/generated/resources/assets/create/lang/unfinished/de_de.json @@ -1,5 +1,5 @@ { - "_": "Missing Localizations: 807", + "_": "Missing Localizations: 837", "_": "->------------------------] Game Elements [------------------------<-", @@ -663,12 +663,9 @@ "create.gui.adjustable_crate.title": "adjustable_crate", "create.gui.adjustable_crate.storageSpace": "Lagerraum", "create.gui.stockpile_switch.title": "Vorratssensor", - "create.gui.stockpile_switch.lowerLimit": "Untergrenze", - "create.gui.stockpile_switch.upperLimit": "Obergrenze", - "create.gui.stockpile_switch.startAt": "Signal bei", - "create.gui.stockpile_switch.startAbove": "Signal über", - "create.gui.stockpile_switch.stopAt": "Signalstopp bei", - "create.gui.stockpile_switch.stopBelow": "Signalstopp über", + "create.gui.stockpile_switch.invert_signal": "UNLOCALIZED: Invert Signal", + "create.gui.stockpile_switch.move_to_lower_at": "UNLOCALIZED: Move to lower lane at %1$s%%", + "create.gui.stockpile_switch.move_to_upper_at": "UNLOCALIZED: Move to upper lane at %1$s%%", "create.gui.sequenced_gearshift.title": "UNLOCALIZED: Sequenced Gearshift", "create.gui.sequenced_gearshift.instruction": "UNLOCALIZED: Instruction", "create.gui.sequenced_gearshift.instruction.turn_angle": "UNLOCALIZED: Turn", @@ -689,7 +686,8 @@ "create.schematicAndQuill.secondPos": "Zweite Position festgelegt.", "create.schematicAndQuill.noTarget": "Halte [Strg] zur Auswahl von Luft.", "create.schematicAndQuill.abort": "Auswahl zurückgesetzt.", - "create.schematicAndQuill.prompt": "Gib dem Bauplan einen Namen:", + "create.schematicAndQuill.title": "UNLOCALIZED: Schematic Name:", + "create.schematicAndQuill.convert": "UNLOCALIZED: Save and Deploy Immediately", "create.schematicAndQuill.fallbackName": "Mein Bauplan", "create.schematicAndQuill.saved": "Gespeichert als %1$s", @@ -740,24 +738,29 @@ "create.schematics.maxAllowedSize": "Die maximale Bauplan-Dateigröße ist:", "create.gui.schematicTable.title": "Bauplantisch", + "create.gui.schematicTable.refresh": "UNLOCALIZED: Refresh Files", + "create.gui.schematicTable.open_folder": "UNLOCALIZED: Open Folder", "create.gui.schematicTable.availableSchematics": "Verfügbare Baupläne", "create.gui.schematicTable.noSchematics": "Keine gespeicherten Baupläne", "create.gui.schematicTable.uploading": "Hochladen...", "create.gui.schematicTable.finished": "Hochgeladen!", "create.gui.schematicannon.title": "Bauplankanone", - "create.gui.schematicannon.settingsTitle": "Platzier-Optionen", "create.gui.schematicannon.listPrinter": "Materiallistendruck", "create.gui.schematicannon.gunpowderLevel": "Schwarzpulver bei %1$s%%", "create.gui.schematicannon.shotsRemaining": "%1$s Schuss übrig", "create.gui.schematicannon.shotsRemainingWithBackup": "Mit Reserve: %1$s", "create.gui.schematicannon.optionEnabled": "Aktiviert", "create.gui.schematicannon.optionDisabled": "Deaktiviert", + "create.gui.schematicannon.showOptions": "UNLOCALIZED: Show Printer Settings", "create.gui.schematicannon.option.dontReplaceSolid": "Feste Blöcke nicht ersetzen", "create.gui.schematicannon.option.replaceWithSolid": "Feste Blöcke mit festen ersetzen", "create.gui.schematicannon.option.replaceWithAny": "Feste Blöcke immer ersetzen", "create.gui.schematicannon.option.replaceWithEmpty": "Feste Blöcke mit Leere ersetzen", "create.gui.schematicannon.option.skipMissing": "Fehlende Blöcke ignorieren", "create.gui.schematicannon.option.skipTileEntities": "Tile Entities ignorieren", + "create.gui.schematicannon.slot.gunpowder": "UNLOCALIZED: Add gunpowder to fuel the cannon", + "create.gui.schematicannon.slot.listPrinter": "UNLOCALIZED: Place books here to print a Checklist for your Schematic", + "create.gui.schematicannon.slot.schematic": "UNLOCALIZED: Add your Schematic here. Make sure it is deployed at a specific location.", "create.gui.schematicannon.option.skipMissing.description": "Wenn die Bauplankanone einen benötigten Block nicht finden kann, wird sie einfach beim nächsten weiter machen.", "create.gui.schematicannon.option.skipTileEntities.description": "Die Bauplankanone wird versuchen, Blöcke mit extra Daten, beispielsweise Truhen, nicht zu ersetzen.", "create.gui.schematicannon.option.dontReplaceSolid.description": "Die Kanone wird ausschließlich nicht feste Blöcke und Luft in ihrem Arbeitsbereich ersetzen.", @@ -793,23 +796,42 @@ "create.gui.filter.ignore_data.description": "UNLOCALIZED: Items match regardless of their attributes.", "create.item_attributes.placeable": "UNLOCALIZED: is placeable", + "create.item_attributes.placeable.inverted": "UNLOCALIZED: is not placeable", "create.item_attributes.consumable": "UNLOCALIZED: can be eaten", + "create.item_attributes.consumable.inverted": "UNLOCALIZED: cannot be eaten", "create.item_attributes.smeltable": "UNLOCALIZED: can be Smelted", + "create.item_attributes.smeltable.inverted": "UNLOCALIZED: cannot be Smelted", "create.item_attributes.washable": "UNLOCALIZED: can be Washed", + "create.item_attributes.washable.inverted": "UNLOCALIZED: cannot be Washed", "create.item_attributes.smokable": "UNLOCALIZED: can be Smoked", + "create.item_attributes.smokable.inverted": "UNLOCALIZED: cannot be Smoked", + "create.item_attributes.crushable": "UNLOCALIZED: can be Crushed", + "create.item_attributes.crushable.inverted": "UNLOCALIZED: cannot be Crushed", "create.item_attributes.blastable": "UNLOCALIZED: is smeltable in Blast Furnace", + "create.item_attributes.blastable.inverted": "UNLOCALIZED: is not smeltable in Blast Furnace", "create.item_attributes.enchanted": "UNLOCALIZED: is enchanted", + "create.item_attributes.enchanted.inverted": "UNLOCALIZED: is unenchanted", "create.item_attributes.damaged": "UNLOCALIZED: is damaged", + "create.item_attributes.damaged.inverted": "UNLOCALIZED: is not damaged", "create.item_attributes.badly_damaged": "UNLOCALIZED: is heavily damaged", + "create.item_attributes.badly_damaged.inverted": "UNLOCALIZED: is not heavily damaged", "create.item_attributes.not_stackable": "UNLOCALIZED: cannot stack", + "create.item_attributes.not_stackable.inverted": "UNLOCALIZED: can be stacked", "create.item_attributes.equipable": "UNLOCALIZED: can be equipped", + "create.item_attributes.equipable.inverted": "UNLOCALIZED: cannot be equipped", "create.item_attributes.furnace_fuel": "UNLOCALIZED: is furnace fuel", + "create.item_attributes.furnace_fuel.inverted": "UNLOCALIZED: is not furnace fuel", "create.item_attributes.in_tag": "UNLOCALIZED: is tagged %1$s", - "create.item_attributes.in_item_group": "UNLOCALIZED: belongs to %1$s", + "create.item_attributes.in_tag.inverted": "UNLOCALIZED: is not tagged %1$s", + "create.item_attributes.in_item_group": "UNLOCALIZED: is in group '%1$s'", + "create.item_attributes.in_item_group.inverted": "UNLOCALIZED: is not in group '%1$s'", "create.item_attributes.added_by": "UNLOCALIZED: was added by %1$s", + "create.item_attributes.added_by.inverted": "UNLOCALIZED: was not added by %1$s", "create.gui.attribute_filter.no_selected_attributes": "UNLOCALIZED: No attributes selected", "create.gui.attribute_filter.selected_attributes": "UNLOCALIZED: Selected attributes:", + "create.gui.attribute_filter.add_attribute": "UNLOCALIZED: Add attribute to List", + "create.gui.attribute_filter.add_inverted_attribute": "UNLOCALIZED: Add opposite attribute to List", "create.gui.attribute_filter.whitelist_disjunctive": "UNLOCALIZED: Whitelist (Any)", "create.gui.attribute_filter.whitelist_disjunctive.description": "UNLOCALIZED: Items pass if they have any of the selected attributes.", "create.gui.attribute_filter.whitelist_conjunctive": "UNLOCALIZED: Whitelist (All)", diff --git a/src/generated/resources/assets/create/lang/unfinished/fr_fr.json b/src/generated/resources/assets/create/lang/unfinished/fr_fr.json index 3420ffb7e..1ef35a073 100644 --- a/src/generated/resources/assets/create/lang/unfinished/fr_fr.json +++ b/src/generated/resources/assets/create/lang/unfinished/fr_fr.json @@ -1,5 +1,5 @@ { - "_": "Missing Localizations: 431", + "_": "Missing Localizations: 461", "_": "->------------------------] Game Elements [------------------------<-", @@ -663,12 +663,9 @@ "create.gui.adjustable_crate.title": "Caisse réglable", "create.gui.adjustable_crate.storageSpace": "Espace de stockage", "create.gui.stockpile_switch.title": "Commutateur de stockage", - "create.gui.stockpile_switch.lowerLimit": "Seuil inférieur", - "create.gui.stockpile_switch.upperLimit": "Seuil supérieur", - "create.gui.stockpile_switch.startAt": "Signal de départ à", - "create.gui.stockpile_switch.startAbove": "Signal de démarrage au-dessus", - "create.gui.stockpile_switch.stopAt": "Signal d'arrêt à", - "create.gui.stockpile_switch.stopBelow": "Signal d'arrêt en-dessous", + "create.gui.stockpile_switch.invert_signal": "UNLOCALIZED: Invert Signal", + "create.gui.stockpile_switch.move_to_lower_at": "UNLOCALIZED: Move to lower lane at %1$s%%", + "create.gui.stockpile_switch.move_to_upper_at": "UNLOCALIZED: Move to upper lane at %1$s%%", "create.gui.sequenced_gearshift.title": "Décaleur de rotation séquencé", "create.gui.sequenced_gearshift.instruction": "Instructions", "create.gui.sequenced_gearshift.instruction.turn_angle": "Tourner", @@ -689,7 +686,8 @@ "create.schematicAndQuill.secondPos": "Seconde position définie.", "create.schematicAndQuill.noTarget": "Enfoncez [Ctrl] pour sélectionner les blocs d'air.", "create.schematicAndQuill.abort": "Sélection supprimée.", - "create.schematicAndQuill.prompt": "Entrez un nom pour le schéma:", + "create.schematicAndQuill.title": "UNLOCALIZED: Schematic Name:", + "create.schematicAndQuill.convert": "UNLOCALIZED: Save and Deploy Immediately", "create.schematicAndQuill.fallbackName": "Mon schéma", "create.schematicAndQuill.saved": "Sauvegardé en tant que %1$s", @@ -740,24 +738,29 @@ "create.schematics.maxAllowedSize": "La taille de fichier schématique maximale autorisée est:", "create.gui.schematicTable.title": "Table à schéma", + "create.gui.schematicTable.refresh": "UNLOCALIZED: Refresh Files", + "create.gui.schematicTable.open_folder": "UNLOCALIZED: Open Folder", "create.gui.schematicTable.availableSchematics": "Schémas disponibles", "create.gui.schematicTable.noSchematics": "Aucun schéma enregistré", "create.gui.schematicTable.uploading": "Téléchargement...", "create.gui.schematicTable.finished": "Téléchargement terminé!", "create.gui.schematicannon.title": "Schémacanon", - "create.gui.schematicannon.settingsTitle": "Options de placement", "create.gui.schematicannon.listPrinter": "Imprimante de liste de matériaux", "create.gui.schematicannon.gunpowderLevel": "Poudre à canon à %1$s%%", "create.gui.schematicannon.shotsRemaining": "Tirs restants: %1$s", "create.gui.schematicannon.shotsRemainingWithBackup": "Avec sauvegarde: %1$s", "create.gui.schematicannon.optionEnabled": "Actuellement activé", "create.gui.schematicannon.optionDisabled": "Actuellement désactivé", + "create.gui.schematicannon.showOptions": "UNLOCALIZED: Show Printer Settings", "create.gui.schematicannon.option.dontReplaceSolid": "Ne remplacez pas les blocs solides", "create.gui.schematicannon.option.replaceWithSolid": "Remplacer solide par solide", "create.gui.schematicannon.option.replaceWithAny": "Remplacer le solide par n'importe quoi", "create.gui.schematicannon.option.replaceWithEmpty": "Remplacer le solide par rien", "create.gui.schematicannon.option.skipMissing": "Ignorer les blocs manquants", "create.gui.schematicannon.option.skipTileEntities": "Protéger les Tile Entities", + "create.gui.schematicannon.slot.gunpowder": "UNLOCALIZED: Add gunpowder to fuel the cannon", + "create.gui.schematicannon.slot.listPrinter": "UNLOCALIZED: Place books here to print a Checklist for your Schematic", + "create.gui.schematicannon.slot.schematic": "UNLOCALIZED: Add your Schematic here. Make sure it is deployed at a specific location.", "create.gui.schematicannon.option.skipMissing.description": "Si le canon ne peut pas trouver un bloc requis pour le placement, il continuera au prochain emplacement.", "create.gui.schematicannon.option.skipTileEntities.description": "Le canon évitera de remplacer les blocs de stockage de données tels que les coffres.", "create.gui.schematicannon.option.dontReplaceSolid.description": "Le canon ne remplacera jamais les blocs solides dans sa zone de travail, seulement non solides et air.", @@ -793,23 +796,42 @@ "create.gui.filter.ignore_data.description": "Les éléments correspondent indépendamment de leurs attributs.", "create.item_attributes.placeable": "est placeable", + "create.item_attributes.placeable.inverted": "UNLOCALIZED: is not placeable", "create.item_attributes.consumable": "peut être mangé", + "create.item_attributes.consumable.inverted": "UNLOCALIZED: cannot be eaten", "create.item_attributes.smeltable": "UNLOCALIZED: can be Smelted", + "create.item_attributes.smeltable.inverted": "UNLOCALIZED: cannot be Smelted", "create.item_attributes.washable": "UNLOCALIZED: can be Washed", + "create.item_attributes.washable.inverted": "UNLOCALIZED: cannot be Washed", "create.item_attributes.smokable": "UNLOCALIZED: can be Smoked", + "create.item_attributes.smokable.inverted": "UNLOCALIZED: cannot be Smoked", + "create.item_attributes.crushable": "UNLOCALIZED: can be Crushed", + "create.item_attributes.crushable.inverted": "UNLOCALIZED: cannot be Crushed", "create.item_attributes.blastable": "UNLOCALIZED: is smeltable in Blast Furnace", + "create.item_attributes.blastable.inverted": "UNLOCALIZED: is not smeltable in Blast Furnace", "create.item_attributes.enchanted": "est enchanté", + "create.item_attributes.enchanted.inverted": "UNLOCALIZED: is unenchanted", "create.item_attributes.damaged": "est endommagé", + "create.item_attributes.damaged.inverted": "UNLOCALIZED: is not damaged", "create.item_attributes.badly_damaged": "est fortement damaged", + "create.item_attributes.badly_damaged.inverted": "UNLOCALIZED: is not heavily damaged", "create.item_attributes.not_stackable": "ne peut pas s'empiler", + "create.item_attributes.not_stackable.inverted": "UNLOCALIZED: can be stacked", "create.item_attributes.equipable": "peut être équipé", + "create.item_attributes.equipable.inverted": "UNLOCALIZED: cannot be equipped", "create.item_attributes.furnace_fuel": "est du combustible", + "create.item_attributes.furnace_fuel.inverted": "UNLOCALIZED: is not furnace fuel", "create.item_attributes.in_tag": "est étiqueté %1$s", + "create.item_attributes.in_tag.inverted": "UNLOCALIZED: is not tagged %1$s", "create.item_attributes.in_item_group": "appartient à %1$s", + "create.item_attributes.in_item_group.inverted": "UNLOCALIZED: is not in group '%1$s'", "create.item_attributes.added_by": "a été ajouté par %1$s", + "create.item_attributes.added_by.inverted": "UNLOCALIZED: was not added by %1$s", "create.gui.attribute_filter.no_selected_attributes": "Aucun attribut sélectionné", "create.gui.attribute_filter.selected_attributes": "Attributs sélectionnés:", + "create.gui.attribute_filter.add_attribute": "UNLOCALIZED: Add attribute to List", + "create.gui.attribute_filter.add_inverted_attribute": "UNLOCALIZED: Add opposite attribute to List", "create.gui.attribute_filter.whitelist_disjunctive": "Liste blanche (n'importe)", "create.gui.attribute_filter.whitelist_disjunctive.description": "Les objets réussissent s'ils possèdent l'un des attributs sélectionnés.", "create.gui.attribute_filter.whitelist_conjunctive": "Liste blanche (tout)", diff --git a/src/generated/resources/assets/create/lang/unfinished/it_it.json b/src/generated/resources/assets/create/lang/unfinished/it_it.json index 705586333..0b462f7df 100644 --- a/src/generated/resources/assets/create/lang/unfinished/it_it.json +++ b/src/generated/resources/assets/create/lang/unfinished/it_it.json @@ -1,5 +1,5 @@ { - "_": "Missing Localizations: 415", + "_": "Missing Localizations: 445", "_": "->------------------------] Game Elements [------------------------<-", @@ -663,12 +663,9 @@ "create.gui.adjustable_crate.title": "Baule Regolabile", "create.gui.adjustable_crate.storageSpace": "Spazio di Immagazzinamento", "create.gui.stockpile_switch.title": "Interruttore Accumulatore", - "create.gui.stockpile_switch.lowerLimit": "Soglia Inferiore", - "create.gui.stockpile_switch.upperLimit": "Soglia Superiore", - "create.gui.stockpile_switch.startAt": "Inizia Segnale al", - "create.gui.stockpile_switch.startAbove": "Inizia il Segnale dop.", - "create.gui.stockpile_switch.stopAt": "Ferma Segnale al", - "create.gui.stockpile_switch.stopBelow": "Ferma il Segnale dop.", + "create.gui.stockpile_switch.invert_signal": "UNLOCALIZED: Invert Signal", + "create.gui.stockpile_switch.move_to_lower_at": "UNLOCALIZED: Move to lower lane at %1$s%%", + "create.gui.stockpile_switch.move_to_upper_at": "UNLOCALIZED: Move to upper lane at %1$s%%", "create.gui.sequenced_gearshift.title": "Cambio Sequenziale", "create.gui.sequenced_gearshift.instruction": "Istruzione", "create.gui.sequenced_gearshift.instruction.turn_angle": "Gira", @@ -689,7 +686,8 @@ "create.schematicAndQuill.secondPos": "Seconda posizione impostata.", "create.schematicAndQuill.noTarget": "Premi [Ctrl] per selezionare il Blocco d'Aria.", "create.schematicAndQuill.abort": "Selezione rimossa.", - "create.schematicAndQuill.prompt": "Immettere un nome per lo schema:", + "create.schematicAndQuill.title": "UNLOCALIZED: Schematic Name:", + "create.schematicAndQuill.convert": "UNLOCALIZED: Save and Deploy Immediately", "create.schematicAndQuill.fallbackName": "La mia Schematica", "create.schematicAndQuill.saved": "Salvata come %1$s", @@ -740,24 +738,29 @@ "create.schematics.maxAllowedSize": "La dimensione massima consentita del file schematica è:", "create.gui.schematicTable.title": "Banco Schematico", + "create.gui.schematicTable.refresh": "UNLOCALIZED: Refresh Files", + "create.gui.schematicTable.open_folder": "UNLOCALIZED: Open Folder", "create.gui.schematicTable.availableSchematics": "Schatiche disponibili", "create.gui.schematicTable.noSchematics": "Nessuna Schatica Salvata", "create.gui.schematicTable.uploading": "Caricamento...", "create.gui.schematicTable.finished": "Caricamento Finito!", "create.gui.schematicannon.title": "Cannoneschematico", - "create.gui.schematicannon.settingsTitle": "Impostazioni di Posizionamento", "create.gui.schematicannon.listPrinter": "Stampante Lisra dei Materiali", "create.gui.schematicannon.gunpowderLevel": "Polvere da sparo al %1$s%%", "create.gui.schematicannon.shotsRemaining": "Spari Rimanenti: %1$s", "create.gui.schematicannon.shotsRemainingWithBackup": "Con il backup: %1$s", "create.gui.schematicannon.optionEnabled": "Attualmente Abilitato", "create.gui.schematicannon.optionDisabled": "Attualmente Disabilitato", + "create.gui.schematicannon.showOptions": "UNLOCALIZED: Show Printer Settings", "create.gui.schematicannon.option.dontReplaceSolid": "Non sostituire i Blocchi Solidi", "create.gui.schematicannon.option.replaceWithSolid": "Sostituisci Solidi con Solidi", "create.gui.schematicannon.option.replaceWithAny": "Sostituisci Solidi con Qualsiasi", "create.gui.schematicannon.option.replaceWithEmpty": "Sostituisci Solidi con il Vuoto", "create.gui.schematicannon.option.skipMissing": "Salta i Blocchi Mancanti", "create.gui.schematicannon.option.skipTileEntities": "Proteggi i Blocchi Entità", + "create.gui.schematicannon.slot.gunpowder": "UNLOCALIZED: Add gunpowder to fuel the cannon", + "create.gui.schematicannon.slot.listPrinter": "UNLOCALIZED: Place books here to print a Checklist for your Schematic", + "create.gui.schematicannon.slot.schematic": "UNLOCALIZED: Add your Schematic here. Make sure it is deployed at a specific location.", "create.gui.schematicannon.option.skipMissing.description": "Se il cannone non riesce a trovare un blocco richiesto per il posizionamento, continuerà nella posizione successiva.", "create.gui.schematicannon.option.skipTileEntities.description": "Il cannone eviterà di sostituire i blocchi di dati come bauli.", "create.gui.schematicannon.option.dontReplaceSolid.description": "Il cannone non sostituirà mai alcun blocco Solido nella sua area di lavoro, solo non solidi e aria.", @@ -793,23 +796,42 @@ "create.gui.filter.ignore_data.description": "Gli oggetti corrispondono indipendentemente dai loro attributi.", "create.item_attributes.placeable": "è posizionabile", + "create.item_attributes.placeable.inverted": "UNLOCALIZED: is not placeable", "create.item_attributes.consumable": "può essere mangiato", + "create.item_attributes.consumable.inverted": "UNLOCALIZED: cannot be eaten", "create.item_attributes.smeltable": "può essere Fuso", + "create.item_attributes.smeltable.inverted": "UNLOCALIZED: cannot be Smelted", "create.item_attributes.washable": "può essere Lavato", + "create.item_attributes.washable.inverted": "UNLOCALIZED: cannot be Washed", "create.item_attributes.smokable": "può essere Affumicato", + "create.item_attributes.smokable.inverted": "UNLOCALIZED: cannot be Smoked", + "create.item_attributes.crushable": "UNLOCALIZED: can be Crushed", + "create.item_attributes.crushable.inverted": "UNLOCALIZED: cannot be Crushed", "create.item_attributes.blastable": "è fondibile in un Forno fusorio", + "create.item_attributes.blastable.inverted": "UNLOCALIZED: is not smeltable in Blast Furnace", "create.item_attributes.enchanted": "è incantato", + "create.item_attributes.enchanted.inverted": "UNLOCALIZED: is unenchanted", "create.item_attributes.damaged": "è danneggiato", + "create.item_attributes.damaged.inverted": "UNLOCALIZED: is not damaged", "create.item_attributes.badly_damaged": "è gravemente danneggiato", + "create.item_attributes.badly_damaged.inverted": "UNLOCALIZED: is not heavily damaged", "create.item_attributes.not_stackable": "non impilabile", + "create.item_attributes.not_stackable.inverted": "UNLOCALIZED: can be stacked", "create.item_attributes.equipable": "può essere equipaggiato", + "create.item_attributes.equipable.inverted": "UNLOCALIZED: cannot be equipped", "create.item_attributes.furnace_fuel": "è il combustibile della fornace", + "create.item_attributes.furnace_fuel.inverted": "UNLOCALIZED: is not furnace fuel", "create.item_attributes.in_tag": "è etichettato %1$s", + "create.item_attributes.in_tag.inverted": "UNLOCALIZED: is not tagged %1$s", "create.item_attributes.in_item_group": "appartiene a %1$s", + "create.item_attributes.in_item_group.inverted": "UNLOCALIZED: is not in group '%1$s'", "create.item_attributes.added_by": "è stato aggiunto da %1$s", + "create.item_attributes.added_by.inverted": "UNLOCALIZED: was not added by %1$s", "create.gui.attribute_filter.no_selected_attributes": "Nessun attributo selezionato", "create.gui.attribute_filter.selected_attributes": "Attributi selezionati:", + "create.gui.attribute_filter.add_attribute": "UNLOCALIZED: Add attribute to List", + "create.gui.attribute_filter.add_inverted_attribute": "UNLOCALIZED: Add opposite attribute to List", "create.gui.attribute_filter.whitelist_disjunctive": "Lista Bianca (Qualsiasi)", "create.gui.attribute_filter.whitelist_disjunctive.description": "Gli oggetti passano se hanno uno degli attributi selezionati.", "create.gui.attribute_filter.whitelist_conjunctive": "Lista Bianca (Tutti)", diff --git a/src/generated/resources/assets/create/lang/unfinished/ja_jp.json b/src/generated/resources/assets/create/lang/unfinished/ja_jp.json index a3a287baf..adf7de27a 100644 --- a/src/generated/resources/assets/create/lang/unfinished/ja_jp.json +++ b/src/generated/resources/assets/create/lang/unfinished/ja_jp.json @@ -1,5 +1,5 @@ { - "_": "Missing Localizations: 410", + "_": "Missing Localizations: 440", "_": "->------------------------] Game Elements [------------------------<-", @@ -663,12 +663,9 @@ "create.gui.adjustable_crate.title": "調整可能なクレート", "create.gui.adjustable_crate.storageSpace": "収納スペース", "create.gui.stockpile_switch.title": "在庫スイッチ", - "create.gui.stockpile_switch.lowerLimit": "下限しきい値", - "create.gui.stockpile_switch.upperLimit": "上限しきい値", - "create.gui.stockpile_switch.startAt": "開始信号", - "create.gui.stockpile_switch.startAbove": "以上の開始信号", - "create.gui.stockpile_switch.stopAt": "停止信号", - "create.gui.stockpile_switch.stopBelow": "以下の停止信号", + "create.gui.stockpile_switch.invert_signal": "UNLOCALIZED: Invert Signal", + "create.gui.stockpile_switch.move_to_lower_at": "UNLOCALIZED: Move to lower lane at %1$s%%", + "create.gui.stockpile_switch.move_to_upper_at": "UNLOCALIZED: Move to upper lane at %1$s%%", "create.gui.sequenced_gearshift.title": "シーケンスギアシフト", "create.gui.sequenced_gearshift.instruction": "命令", "create.gui.sequenced_gearshift.instruction.turn_angle": "回転", @@ -689,7 +686,8 @@ "create.schematicAndQuill.secondPos": "2番目の位置セット。", "create.schematicAndQuill.noTarget": "[Ctrl] を押したままで空気ブロックを選択します", "create.schematicAndQuill.abort": "選択を削除しました。", - "create.schematicAndQuill.prompt": "概略図の名前を入力してください:", + "create.schematicAndQuill.title": "UNLOCALIZED: Schematic Name:", + "create.schematicAndQuill.convert": "UNLOCALIZED: Save and Deploy Immediately", "create.schematicAndQuill.fallbackName": "My Schematic", "create.schematicAndQuill.saved": "%1$s として保存しました", @@ -740,24 +738,29 @@ "create.schematics.maxAllowedSize": "最大許容概略図ファイルサイズは:", "create.gui.schematicTable.title": "概略図テーブル", + "create.gui.schematicTable.refresh": "UNLOCALIZED: Refresh Files", + "create.gui.schematicTable.open_folder": "UNLOCALIZED: Open Folder", "create.gui.schematicTable.availableSchematics": "利用可能な概略図", "create.gui.schematicTable.noSchematics": "保存された概略図はありません", "create.gui.schematicTable.uploading": "アップロードしています...", "create.gui.schematicTable.finished": "アップロードが完了しました!", "create.gui.schematicannon.title": "概略図砲", - "create.gui.schematicannon.settingsTitle": "配置設定", "create.gui.schematicannon.listPrinter": "材料リストプリンター", "create.gui.schematicannon.gunpowderLevel": "火薬はあと %1$s%% 残っています", "create.gui.schematicannon.shotsRemaining": "残りのショット数: %1$s", "create.gui.schematicannon.shotsRemainingWithBackup": "バックアップあり: %1$s", "create.gui.schematicannon.optionEnabled": "現在有効", "create.gui.schematicannon.optionDisabled": "現在無効", + "create.gui.schematicannon.showOptions": "UNLOCALIZED: Show Printer Settings", "create.gui.schematicannon.option.dontReplaceSolid": "固体ブロックを置き換えない", "create.gui.schematicannon.option.replaceWithSolid": "固体を固体に置き換える", "create.gui.schematicannon.option.replaceWithAny": "固体を任意のものに置き換える", "create.gui.schematicannon.option.replaceWithEmpty": "空の固体と交換", "create.gui.schematicannon.option.skipMissing": "不足しているブロックをスキップ", "create.gui.schematicannon.option.skipTileEntities": "タイルエンティティを保護する", + "create.gui.schematicannon.slot.gunpowder": "UNLOCALIZED: Add gunpowder to fuel the cannon", + "create.gui.schematicannon.slot.listPrinter": "UNLOCALIZED: Place books here to print a Checklist for your Schematic", + "create.gui.schematicannon.slot.schematic": "UNLOCALIZED: Add your Schematic here. Make sure it is deployed at a specific location.", "create.gui.schematicannon.option.skipMissing.description": "大砲が配置に必要なブロックを見つけられない場合、次の場所に進みます。", "create.gui.schematicannon.option.skipTileEntities.description": "大砲は、チェストなどのデータ保持ブロックの交換を回避します。", "create.gui.schematicannon.option.dontReplaceSolid.description": "大砲は、その作業領域の固体ブロックを置き換えることはなく、非固体と空気のみを置き換えます。", @@ -793,23 +796,42 @@ "create.gui.filter.ignore_data.description": "アイテムは属性に関係なく一致します。", "create.item_attributes.placeable": "設置可能か", + "create.item_attributes.placeable.inverted": "UNLOCALIZED: is not placeable", "create.item_attributes.consumable": "食べられるか", + "create.item_attributes.consumable.inverted": "UNLOCALIZED: cannot be eaten", "create.item_attributes.smeltable": "精錬可能か", + "create.item_attributes.smeltable.inverted": "UNLOCALIZED: cannot be Smelted", "create.item_attributes.washable": "洗えるか", + "create.item_attributes.washable.inverted": "UNLOCALIZED: cannot be Washed", "create.item_attributes.smokable": "燻製可能か", + "create.item_attributes.smokable.inverted": "UNLOCALIZED: cannot be Smoked", + "create.item_attributes.crushable": "UNLOCALIZED: can be Crushed", + "create.item_attributes.crushable.inverted": "UNLOCALIZED: cannot be Crushed", "create.item_attributes.blastable": "高炉で製錬可能か", + "create.item_attributes.blastable.inverted": "UNLOCALIZED: is not smeltable in Blast Furnace", "create.item_attributes.enchanted": "エンチャント済みか", + "create.item_attributes.enchanted.inverted": "UNLOCALIZED: is unenchanted", "create.item_attributes.damaged": "破損してるか", + "create.item_attributes.damaged.inverted": "UNLOCALIZED: is not damaged", "create.item_attributes.badly_damaged": "ひどく損傷してるか", + "create.item_attributes.badly_damaged.inverted": "UNLOCALIZED: is not heavily damaged", "create.item_attributes.not_stackable": "スタック可能か", + "create.item_attributes.not_stackable.inverted": "UNLOCALIZED: can be stacked", "create.item_attributes.equipable": "装備可能か", + "create.item_attributes.equipable.inverted": "UNLOCALIZED: cannot be equipped", "create.item_attributes.furnace_fuel": "かまどの燃料か", + "create.item_attributes.furnace_fuel.inverted": "UNLOCALIZED: is not furnace fuel", "create.item_attributes.in_tag": "%1$s のタグが付けられてるか", + "create.item_attributes.in_tag.inverted": "UNLOCALIZED: is not tagged %1$s", "create.item_attributes.in_item_group": "%1$s に属してるか", + "create.item_attributes.in_item_group.inverted": "UNLOCALIZED: is not in group '%1$s'", "create.item_attributes.added_by": "%1$s によって追加されたか", + "create.item_attributes.added_by.inverted": "UNLOCALIZED: was not added by %1$s", "create.gui.attribute_filter.no_selected_attributes": "属性が選択されていません", "create.gui.attribute_filter.selected_attributes": "選択された属性:", + "create.gui.attribute_filter.add_attribute": "UNLOCALIZED: Add attribute to List", + "create.gui.attribute_filter.add_inverted_attribute": "UNLOCALIZED: Add opposite attribute to List", "create.gui.attribute_filter.whitelist_disjunctive": "ホワイトリスト(どれか)", "create.gui.attribute_filter.whitelist_disjunctive.description": "選択した属性のいずれかを持っている場合、アイテムは通り抜けます。", "create.gui.attribute_filter.whitelist_conjunctive": "ホワイトリスト(全て)", diff --git a/src/generated/resources/assets/create/lang/unfinished/ko_kr.json b/src/generated/resources/assets/create/lang/unfinished/ko_kr.json index 0acc022b0..6d0bdcaef 100644 --- a/src/generated/resources/assets/create/lang/unfinished/ko_kr.json +++ b/src/generated/resources/assets/create/lang/unfinished/ko_kr.json @@ -1,5 +1,5 @@ { - "_": "Missing Localizations: 415", + "_": "Missing Localizations: 445", "_": "->------------------------] Game Elements [------------------------<-", @@ -663,12 +663,9 @@ "create.gui.adjustable_crate.title": "가변 창고 ", "create.gui.adjustable_crate.storageSpace": "저장 공간", "create.gui.stockpile_switch.title": "수량 스위치", - "create.gui.stockpile_switch.lowerLimit": "최소 신호 유지수량", - "create.gui.stockpile_switch.upperLimit": "최초 신호 발동수량", - "create.gui.stockpile_switch.startAt": "다음 수량에 신호 주기", - "create.gui.stockpile_switch.startAbove": "다음 수량이상일떄 신호 주기", - "create.gui.stockpile_switch.stopAt": "다음 수량에 신호 멈추기", - "create.gui.stockpile_switch.stopBelow": "다음 수량이하일때 신호 멈추기", + "create.gui.stockpile_switch.invert_signal": "UNLOCALIZED: Invert Signal", + "create.gui.stockpile_switch.move_to_lower_at": "UNLOCALIZED: Move to lower lane at %1$s%%", + "create.gui.stockpile_switch.move_to_upper_at": "UNLOCALIZED: Move to upper lane at %1$s%%", "create.gui.sequenced_gearshift.title": "순서 기어쉬프트", "create.gui.sequenced_gearshift.instruction": "설명", "create.gui.sequenced_gearshift.instruction.turn_angle": "회전", @@ -689,7 +686,8 @@ "create.schematicAndQuill.secondPos": "두번째 위치 지정됨.", "create.schematicAndQuill.noTarget": "[Ctrl]을 눌러 공기 블럭을 선택하기.", "create.schematicAndQuill.abort": "위치 제거됨.", - "create.schematicAndQuill.prompt": "청사진의 제목을 작성하기:", + "create.schematicAndQuill.title": "UNLOCALIZED: Schematic Name:", + "create.schematicAndQuill.convert": "UNLOCALIZED: Save and Deploy Immediately", "create.schematicAndQuill.fallbackName": "내 청사진", "create.schematicAndQuill.saved": "%1$s로 저장됨", @@ -740,24 +738,29 @@ "create.schematics.maxAllowedSize": "최대 청사진 파일 크기는:", "create.gui.schematicTable.title": "청사진 테이블", + "create.gui.schematicTable.refresh": "UNLOCALIZED: Refresh Files", + "create.gui.schematicTable.open_folder": "UNLOCALIZED: Open Folder", "create.gui.schematicTable.availableSchematics": "이용가능한 청사진", "create.gui.schematicTable.noSchematics": "저장된 청사진 없음", "create.gui.schematicTable.uploading": "업로딩 중...", "create.gui.schematicTable.finished": "업로드 완료!", "create.gui.schematicannon.title": "청사진 대포", - "create.gui.schematicannon.settingsTitle": "설치 설정", "create.gui.schematicannon.listPrinter": "재료 목록 프린터", "create.gui.schematicannon.gunpowderLevel": "화약 용량 %1$s%%", "create.gui.schematicannon.shotsRemaining": "남은 발포 수 : %1$s", "create.gui.schematicannon.shotsRemainingWithBackup": "화약 여분: %1$s", "create.gui.schematicannon.optionEnabled": "현재 활성화 됨", "create.gui.schematicannon.optionDisabled": "현재 비활성화 됨", + "create.gui.schematicannon.showOptions": "UNLOCALIZED: Show Printer Settings", "create.gui.schematicannon.option.dontReplaceSolid": "온전한 블럭을 대체하지 않음", "create.gui.schematicannon.option.replaceWithSolid": "온전한 블럭을 재료로 대체함", "create.gui.schematicannon.option.replaceWithAny": "온전한 블럭을 아무 재료로 대체함", "create.gui.schematicannon.option.replaceWithEmpty": "온전한 블럭을 공기로 채움", "create.gui.schematicannon.option.skipMissing": "부족한 블럭을 무시하고 진행", "create.gui.schematicannon.option.skipTileEntities": "타일 엔티티를 보호", + "create.gui.schematicannon.slot.gunpowder": "UNLOCALIZED: Add gunpowder to fuel the cannon", + "create.gui.schematicannon.slot.listPrinter": "UNLOCALIZED: Place books here to print a Checklist for your Schematic", + "create.gui.schematicannon.slot.schematic": "UNLOCALIZED: Add your Schematic here. Make sure it is deployed at a specific location.", "create.gui.schematicannon.option.skipMissing.description": "만약 대포가 설치에 필요한 블럭을 찾지 못할 경우,건너뛰고 다음 블럭 설치를 진행합니다.", "create.gui.schematicannon.option.skipTileEntities.description": "대포가 상세정보가 든 상자같은 타일 엔티티 설치를 무시합니다.", "create.gui.schematicannon.option.dontReplaceSolid.description": "대포가 작업구역의 온전한 블럭을 대체하지 않습니다.", @@ -793,23 +796,42 @@ "create.gui.filter.ignore_data.description": "상세정보와 상관없이 아이템 종류만 일치한다면 통과시킵니다.", "create.item_attributes.placeable": "설치할 수 있음", + "create.item_attributes.placeable.inverted": "UNLOCALIZED: is not placeable", "create.item_attributes.consumable": "먹을 수 있음", + "create.item_attributes.consumable.inverted": "UNLOCALIZED: cannot be eaten", "create.item_attributes.smeltable": "구워질 수 있음", + "create.item_attributes.smeltable.inverted": "UNLOCALIZED: cannot be Smelted", "create.item_attributes.washable": "세척될 수 있음", + "create.item_attributes.washable.inverted": "UNLOCALIZED: cannot be Washed", "create.item_attributes.smokable": "훈연될 수 있음", + "create.item_attributes.smokable.inverted": "UNLOCALIZED: cannot be Smoked", + "create.item_attributes.crushable": "UNLOCALIZED: can be Crushed", + "create.item_attributes.crushable.inverted": "UNLOCALIZED: cannot be Crushed", "create.item_attributes.blastable": "용광로에 녹일 수 있음", + "create.item_attributes.blastable.inverted": "UNLOCALIZED: is not smeltable in Blast Furnace", "create.item_attributes.enchanted": "마법부여됨", + "create.item_attributes.enchanted.inverted": "UNLOCALIZED: is unenchanted", "create.item_attributes.damaged": "내구도가 닮", + "create.item_attributes.damaged.inverted": "UNLOCALIZED: is not damaged", "create.item_attributes.badly_damaged": "심각하게 내구도가 닮", + "create.item_attributes.badly_damaged.inverted": "UNLOCALIZED: is not heavily damaged", "create.item_attributes.not_stackable": "겹쳐질 수 없음", + "create.item_attributes.not_stackable.inverted": "UNLOCALIZED: can be stacked", "create.item_attributes.equipable": "장착할 수 있음", + "create.item_attributes.equipable.inverted": "UNLOCALIZED: cannot be equipped", "create.item_attributes.furnace_fuel": "화로 연료로 쓸 수 있음", + "create.item_attributes.furnace_fuel.inverted": "UNLOCALIZED: is not furnace fuel", "create.item_attributes.in_tag": "%1$s로 등록됨", + "create.item_attributes.in_tag.inverted": "UNLOCALIZED: is not tagged %1$s", "create.item_attributes.in_item_group": "%1$s탭에 속함", + "create.item_attributes.in_item_group.inverted": "UNLOCALIZED: is not in group '%1$s'", "create.item_attributes.added_by": "%1$s가 추가함", + "create.item_attributes.added_by.inverted": "UNLOCALIZED: was not added by %1$s", "create.gui.attribute_filter.no_selected_attributes": "속성이 선택되지 않음", "create.gui.attribute_filter.selected_attributes": "선택된 속성:", + "create.gui.attribute_filter.add_attribute": "UNLOCALIZED: Add attribute to List", + "create.gui.attribute_filter.add_inverted_attribute": "UNLOCALIZED: Add opposite attribute to List", "create.gui.attribute_filter.whitelist_disjunctive": "화이트리스트 (최소)", "create.gui.attribute_filter.whitelist_disjunctive.description": "아이템이 선택된 속성 중 하나라도 가지고 있다면 통과시킵니다.", "create.gui.attribute_filter.whitelist_conjunctive": "화이트리스트 (모두)", diff --git a/src/generated/resources/assets/create/lang/unfinished/nl_nl.json b/src/generated/resources/assets/create/lang/unfinished/nl_nl.json index 876604dd5..360c1c3cd 100644 --- a/src/generated/resources/assets/create/lang/unfinished/nl_nl.json +++ b/src/generated/resources/assets/create/lang/unfinished/nl_nl.json @@ -1,5 +1,5 @@ { - "_": "Missing Localizations: 745", + "_": "Missing Localizations: 775", "_": "->------------------------] Game Elements [------------------------<-", @@ -663,12 +663,9 @@ "create.gui.adjustable_crate.title": "FlexKrat", "create.gui.adjustable_crate.storageSpace": "Opslagruimte", "create.gui.stockpile_switch.title": "Voorraad Schakelaar", - "create.gui.stockpile_switch.lowerLimit": "Lagere drempel", - "create.gui.stockpile_switch.upperLimit": "Hogere drempel", - "create.gui.stockpile_switch.startAt": "Start Signaal op", - "create.gui.stockpile_switch.startAbove": "Start Signaal boven", - "create.gui.stockpile_switch.stopAt": "Stop Signaal op", - "create.gui.stockpile_switch.stopBelow": "Stop Signaal onder", + "create.gui.stockpile_switch.invert_signal": "UNLOCALIZED: Invert Signal", + "create.gui.stockpile_switch.move_to_lower_at": "UNLOCALIZED: Move to lower lane at %1$s%%", + "create.gui.stockpile_switch.move_to_upper_at": "UNLOCALIZED: Move to upper lane at %1$s%%", "create.gui.sequenced_gearshift.title": "UNLOCALIZED: Sequenced Gearshift", "create.gui.sequenced_gearshift.instruction": "UNLOCALIZED: Instruction", "create.gui.sequenced_gearshift.instruction.turn_angle": "UNLOCALIZED: Turn", @@ -689,7 +686,8 @@ "create.schematicAndQuill.secondPos": "Tweede positie ingesteld.", "create.schematicAndQuill.noTarget": "Houd [Ctrl] ingedrukt om een Lucht block te kiezen.", "create.schematicAndQuill.abort": "Keuze verwijderd.", - "create.schematicAndQuill.prompt": "Vul een naam in voor de bouwtekening:", + "create.schematicAndQuill.title": "UNLOCALIZED: Schematic Name:", + "create.schematicAndQuill.convert": "UNLOCALIZED: Save and Deploy Immediately", "create.schematicAndQuill.fallbackName": "Mijn Bouwtekening", "create.schematicAndQuill.saved": "Opgeslagen als %1$s", @@ -740,24 +738,29 @@ "create.schematics.maxAllowedSize": "De maximum toegestane grote van een Bouwtekings bestand is:", "create.gui.schematicTable.title": "Bouwtekening Tafel", + "create.gui.schematicTable.refresh": "UNLOCALIZED: Refresh Files", + "create.gui.schematicTable.open_folder": "UNLOCALIZED: Open Folder", "create.gui.schematicTable.availableSchematics": "Beschikbare Bouwtekeningen", "create.gui.schematicTable.noSchematics": "Geen Bouwtekeningen opgeslagen", "create.gui.schematicTable.uploading": "Uploaden...", "create.gui.schematicTable.finished": "Upload Klaar!", "create.gui.schematicannon.title": "Bouwtekeningkannon", - "create.gui.schematicannon.settingsTitle": "Plaatsing Instellingen", "create.gui.schematicannon.listPrinter": "Materiaal lijst Printer", "create.gui.schematicannon.gunpowderLevel": "Buskruit op %1$s%%", "create.gui.schematicannon.shotsRemaining": "Schoten over: %1$s", "create.gui.schematicannon.shotsRemainingWithBackup": "Met backup: %1$s", "create.gui.schematicannon.optionEnabled": "Momenteel Ingeschakeld", "create.gui.schematicannon.optionDisabled": "Momenteel Uitgeschakeld", + "create.gui.schematicannon.showOptions": "UNLOCALIZED: Show Printer Settings", "create.gui.schematicannon.option.dontReplaceSolid": "Niet vaste blokken vervangen", "create.gui.schematicannon.option.replaceWithSolid": "Vervang vast met vast", "create.gui.schematicannon.option.replaceWithAny": "Vervang vast met alles", "create.gui.schematicannon.option.replaceWithEmpty": "Vervang vast met leeg", "create.gui.schematicannon.option.skipMissing": "Sla missende blokken over", "create.gui.schematicannon.option.skipTileEntities": "Bescherm Tile Entities", + "create.gui.schematicannon.slot.gunpowder": "UNLOCALIZED: Add gunpowder to fuel the cannon", + "create.gui.schematicannon.slot.listPrinter": "UNLOCALIZED: Place books here to print a Checklist for your Schematic", + "create.gui.schematicannon.slot.schematic": "UNLOCALIZED: Add your Schematic here. Make sure it is deployed at a specific location.", "create.gui.schematicannon.option.skipMissing.description": "Als het Bouwtekeningkannon niet een geschikt blok kan vinden om te plaatsen gaat hij door bij de volgende locatie.", "create.gui.schematicannon.option.skipTileEntities.description": "Het Bouwtekeningkannon probeert blokken met data zoals kisten te vermijden", "create.gui.schematicannon.option.dontReplaceSolid.description": "Het Bouwtekeningkannon zal nooit vaste blokken in zijn gebied vervangen, alleen niet-vaste blokken en lucht", @@ -793,23 +796,42 @@ "create.gui.filter.ignore_data.description": "UNLOCALIZED: Items match regardless of their attributes.", "create.item_attributes.placeable": "UNLOCALIZED: is placeable", + "create.item_attributes.placeable.inverted": "UNLOCALIZED: is not placeable", "create.item_attributes.consumable": "UNLOCALIZED: can be eaten", + "create.item_attributes.consumable.inverted": "UNLOCALIZED: cannot be eaten", "create.item_attributes.smeltable": "UNLOCALIZED: can be Smelted", + "create.item_attributes.smeltable.inverted": "UNLOCALIZED: cannot be Smelted", "create.item_attributes.washable": "UNLOCALIZED: can be Washed", + "create.item_attributes.washable.inverted": "UNLOCALIZED: cannot be Washed", "create.item_attributes.smokable": "UNLOCALIZED: can be Smoked", + "create.item_attributes.smokable.inverted": "UNLOCALIZED: cannot be Smoked", + "create.item_attributes.crushable": "UNLOCALIZED: can be Crushed", + "create.item_attributes.crushable.inverted": "UNLOCALIZED: cannot be Crushed", "create.item_attributes.blastable": "UNLOCALIZED: is smeltable in Blast Furnace", + "create.item_attributes.blastable.inverted": "UNLOCALIZED: is not smeltable in Blast Furnace", "create.item_attributes.enchanted": "UNLOCALIZED: is enchanted", + "create.item_attributes.enchanted.inverted": "UNLOCALIZED: is unenchanted", "create.item_attributes.damaged": "UNLOCALIZED: is damaged", + "create.item_attributes.damaged.inverted": "UNLOCALIZED: is not damaged", "create.item_attributes.badly_damaged": "UNLOCALIZED: is heavily damaged", + "create.item_attributes.badly_damaged.inverted": "UNLOCALIZED: is not heavily damaged", "create.item_attributes.not_stackable": "UNLOCALIZED: cannot stack", + "create.item_attributes.not_stackable.inverted": "UNLOCALIZED: can be stacked", "create.item_attributes.equipable": "UNLOCALIZED: can be equipped", + "create.item_attributes.equipable.inverted": "UNLOCALIZED: cannot be equipped", "create.item_attributes.furnace_fuel": "UNLOCALIZED: is furnace fuel", + "create.item_attributes.furnace_fuel.inverted": "UNLOCALIZED: is not furnace fuel", "create.item_attributes.in_tag": "UNLOCALIZED: is tagged %1$s", - "create.item_attributes.in_item_group": "UNLOCALIZED: belongs to %1$s", + "create.item_attributes.in_tag.inverted": "UNLOCALIZED: is not tagged %1$s", + "create.item_attributes.in_item_group": "UNLOCALIZED: is in group '%1$s'", + "create.item_attributes.in_item_group.inverted": "UNLOCALIZED: is not in group '%1$s'", "create.item_attributes.added_by": "UNLOCALIZED: was added by %1$s", + "create.item_attributes.added_by.inverted": "UNLOCALIZED: was not added by %1$s", "create.gui.attribute_filter.no_selected_attributes": "UNLOCALIZED: No attributes selected", "create.gui.attribute_filter.selected_attributes": "UNLOCALIZED: Selected attributes:", + "create.gui.attribute_filter.add_attribute": "UNLOCALIZED: Add attribute to List", + "create.gui.attribute_filter.add_inverted_attribute": "UNLOCALIZED: Add opposite attribute to List", "create.gui.attribute_filter.whitelist_disjunctive": "UNLOCALIZED: Whitelist (Any)", "create.gui.attribute_filter.whitelist_disjunctive.description": "UNLOCALIZED: Items pass if they have any of the selected attributes.", "create.gui.attribute_filter.whitelist_conjunctive": "UNLOCALIZED: Whitelist (All)", diff --git a/src/generated/resources/assets/create/lang/unfinished/pt_br.json b/src/generated/resources/assets/create/lang/unfinished/pt_br.json index a83331be0..0c27d8261 100644 --- a/src/generated/resources/assets/create/lang/unfinished/pt_br.json +++ b/src/generated/resources/assets/create/lang/unfinished/pt_br.json @@ -1,5 +1,5 @@ { - "_": "Missing Localizations: 814", + "_": "Missing Localizations: 844", "_": "->------------------------] Game Elements [------------------------<-", @@ -663,12 +663,9 @@ "create.gui.adjustable_crate.title": "adjustable_crate", "create.gui.adjustable_crate.storageSpace": "Espaço de Armazenamento", "create.gui.stockpile_switch.title": "Disjuntor de Armazenamento", - "create.gui.stockpile_switch.lowerLimit": "Limite Mínimo", - "create.gui.stockpile_switch.upperLimit": "Limite Máximo", - "create.gui.stockpile_switch.startAt": "Iniciar Sinal em", - "create.gui.stockpile_switch.startAbove": "Iniciar Sinal acima de", - "create.gui.stockpile_switch.stopAt": "Parar Sinal em", - "create.gui.stockpile_switch.stopBelow": "Parar Sinal abaixo de", + "create.gui.stockpile_switch.invert_signal": "UNLOCALIZED: Invert Signal", + "create.gui.stockpile_switch.move_to_lower_at": "UNLOCALIZED: Move to lower lane at %1$s%%", + "create.gui.stockpile_switch.move_to_upper_at": "UNLOCALIZED: Move to upper lane at %1$s%%", "create.gui.sequenced_gearshift.title": "UNLOCALIZED: Sequenced Gearshift", "create.gui.sequenced_gearshift.instruction": "UNLOCALIZED: Instruction", "create.gui.sequenced_gearshift.instruction.turn_angle": "UNLOCALIZED: Turn", @@ -689,7 +686,8 @@ "create.schematicAndQuill.secondPos": "Segunda posição feita.", "create.schematicAndQuill.noTarget": "Seguro [Ctrl] para selecionar Blocos de Ar.", "create.schematicAndQuill.abort": "Seleção removida.", - "create.schematicAndQuill.prompt": "Informe um nome para o Esquema:", + "create.schematicAndQuill.title": "UNLOCALIZED: Schematic Name:", + "create.schematicAndQuill.convert": "UNLOCALIZED: Save and Deploy Immediately", "create.schematicAndQuill.fallbackName": "Meu Esquema", "create.schematicAndQuill.saved": "Salvo como %1$s", @@ -740,24 +738,29 @@ "create.schematics.maxAllowedSize": "O tamanho máximo permitido para o esquema é:", "create.gui.schematicTable.title": "Mesa de Desenho", + "create.gui.schematicTable.refresh": "UNLOCALIZED: Refresh Files", + "create.gui.schematicTable.open_folder": "UNLOCALIZED: Open Folder", "create.gui.schematicTable.availableSchematics": "UNLOCALIZED: Available Schematics", "create.gui.schematicTable.noSchematics": "UNLOCALIZED: No Schematics Saved", "create.gui.schematicTable.uploading": "Importando...", "create.gui.schematicTable.finished": "Envio Concluído!", "create.gui.schematicannon.title": "Esquemaannon", - "create.gui.schematicannon.settingsTitle": "Parâmetros de Posicionamento", "create.gui.schematicannon.listPrinter": "Impressora de Lista de Materiais", "create.gui.schematicannon.gunpowderLevel": "Pólvora em %1$s%%", "create.gui.schematicannon.shotsRemaining": "Disparos faltantes: %1$s", "create.gui.schematicannon.shotsRemainingWithBackup": "Com backup: %1$s", "create.gui.schematicannon.optionEnabled": "Habilitado Atualmente", "create.gui.schematicannon.optionDisabled": "Desabilitado Atualmente", + "create.gui.schematicannon.showOptions": "UNLOCALIZED: Show Printer Settings", "create.gui.schematicannon.option.dontReplaceSolid": "Não Substituir Blocos Sólidos", "create.gui.schematicannon.option.replaceWithSolid": "Substituir Blocos Sólidos", "create.gui.schematicannon.option.replaceWithAny": "Substituir Sólidos com Qualquer", "create.gui.schematicannon.option.replaceWithEmpty": "Substituir Sólidos com Vazio", "create.gui.schematicannon.option.skipMissing": "Pulando Blocos faltantes", "create.gui.schematicannon.option.skipTileEntities": "Proteger Entidades Entalhadas", + "create.gui.schematicannon.slot.gunpowder": "UNLOCALIZED: Add gunpowder to fuel the cannon", + "create.gui.schematicannon.slot.listPrinter": "UNLOCALIZED: Place books here to print a Checklist for your Schematic", + "create.gui.schematicannon.slot.schematic": "UNLOCALIZED: Add your Schematic here. Make sure it is deployed at a specific location.", "create.gui.schematicannon.option.skipMissing.description": "Se o Esquemaannon não encontrar o Bloco para colocar, ele irá continuar para a próx. Posição.", "create.gui.schematicannon.option.skipTileEntities.description": "O Esquemaannon vai evitar substituir blocos que contêm dados como Baus.", "create.gui.schematicannon.option.dontReplaceSolid.description": "O canhão irá nunca substituir Blocos sólidos na área em trabalho, apenas não-Sólidos e Ar.", @@ -793,23 +796,42 @@ "create.gui.filter.ignore_data.description": "UNLOCALIZED: Items match regardless of their attributes.", "create.item_attributes.placeable": "UNLOCALIZED: is placeable", + "create.item_attributes.placeable.inverted": "UNLOCALIZED: is not placeable", "create.item_attributes.consumable": "UNLOCALIZED: can be eaten", + "create.item_attributes.consumable.inverted": "UNLOCALIZED: cannot be eaten", "create.item_attributes.smeltable": "UNLOCALIZED: can be Smelted", + "create.item_attributes.smeltable.inverted": "UNLOCALIZED: cannot be Smelted", "create.item_attributes.washable": "UNLOCALIZED: can be Washed", + "create.item_attributes.washable.inverted": "UNLOCALIZED: cannot be Washed", "create.item_attributes.smokable": "UNLOCALIZED: can be Smoked", + "create.item_attributes.smokable.inverted": "UNLOCALIZED: cannot be Smoked", + "create.item_attributes.crushable": "UNLOCALIZED: can be Crushed", + "create.item_attributes.crushable.inverted": "UNLOCALIZED: cannot be Crushed", "create.item_attributes.blastable": "UNLOCALIZED: is smeltable in Blast Furnace", + "create.item_attributes.blastable.inverted": "UNLOCALIZED: is not smeltable in Blast Furnace", "create.item_attributes.enchanted": "UNLOCALIZED: is enchanted", + "create.item_attributes.enchanted.inverted": "UNLOCALIZED: is unenchanted", "create.item_attributes.damaged": "UNLOCALIZED: is damaged", + "create.item_attributes.damaged.inverted": "UNLOCALIZED: is not damaged", "create.item_attributes.badly_damaged": "UNLOCALIZED: is heavily damaged", + "create.item_attributes.badly_damaged.inverted": "UNLOCALIZED: is not heavily damaged", "create.item_attributes.not_stackable": "UNLOCALIZED: cannot stack", + "create.item_attributes.not_stackable.inverted": "UNLOCALIZED: can be stacked", "create.item_attributes.equipable": "UNLOCALIZED: can be equipped", + "create.item_attributes.equipable.inverted": "UNLOCALIZED: cannot be equipped", "create.item_attributes.furnace_fuel": "UNLOCALIZED: is furnace fuel", + "create.item_attributes.furnace_fuel.inverted": "UNLOCALIZED: is not furnace fuel", "create.item_attributes.in_tag": "UNLOCALIZED: is tagged %1$s", - "create.item_attributes.in_item_group": "UNLOCALIZED: belongs to %1$s", + "create.item_attributes.in_tag.inverted": "UNLOCALIZED: is not tagged %1$s", + "create.item_attributes.in_item_group": "UNLOCALIZED: is in group '%1$s'", + "create.item_attributes.in_item_group.inverted": "UNLOCALIZED: is not in group '%1$s'", "create.item_attributes.added_by": "UNLOCALIZED: was added by %1$s", + "create.item_attributes.added_by.inverted": "UNLOCALIZED: was not added by %1$s", "create.gui.attribute_filter.no_selected_attributes": "UNLOCALIZED: No attributes selected", "create.gui.attribute_filter.selected_attributes": "UNLOCALIZED: Selected attributes:", + "create.gui.attribute_filter.add_attribute": "UNLOCALIZED: Add attribute to List", + "create.gui.attribute_filter.add_inverted_attribute": "UNLOCALIZED: Add opposite attribute to List", "create.gui.attribute_filter.whitelist_disjunctive": "UNLOCALIZED: Whitelist (Any)", "create.gui.attribute_filter.whitelist_disjunctive.description": "UNLOCALIZED: Items pass if they have any of the selected attributes.", "create.gui.attribute_filter.whitelist_conjunctive": "UNLOCALIZED: Whitelist (All)", diff --git a/src/generated/resources/assets/create/lang/unfinished/ru_ru.json b/src/generated/resources/assets/create/lang/unfinished/ru_ru.json index 6844d5fea..f40209113 100644 --- a/src/generated/resources/assets/create/lang/unfinished/ru_ru.json +++ b/src/generated/resources/assets/create/lang/unfinished/ru_ru.json @@ -1,5 +1,5 @@ { - "_": "Missing Localizations: 808", + "_": "Missing Localizations: 838", "_": "->------------------------] Game Elements [------------------------<-", @@ -663,12 +663,9 @@ "create.gui.adjustable_crate.title": "Гибкий ящик", "create.gui.adjustable_crate.storageSpace": "Обьём хранилища", "create.gui.stockpile_switch.title": "Сенсор хранилища", - "create.gui.stockpile_switch.lowerLimit": "Нижний порог", - "create.gui.stockpile_switch.upperLimit": "Верхний порог", - "create.gui.stockpile_switch.startAt": "Включить на", - "create.gui.stockpile_switch.startAbove": "Включить выше", - "create.gui.stockpile_switch.stopAt": "Отключить на", - "create.gui.stockpile_switch.stopBelow": "Отключить ниже", + "create.gui.stockpile_switch.invert_signal": "UNLOCALIZED: Invert Signal", + "create.gui.stockpile_switch.move_to_lower_at": "UNLOCALIZED: Move to lower lane at %1$s%%", + "create.gui.stockpile_switch.move_to_upper_at": "UNLOCALIZED: Move to upper lane at %1$s%%", "create.gui.sequenced_gearshift.title": "UNLOCALIZED: Sequenced Gearshift", "create.gui.sequenced_gearshift.instruction": "UNLOCALIZED: Instruction", "create.gui.sequenced_gearshift.instruction.turn_angle": "UNLOCALIZED: Turn", @@ -689,7 +686,8 @@ "create.schematicAndQuill.secondPos": "Вторая позиция установлена.", "create.schematicAndQuill.noTarget": "Зажмите [Ctrl], чтобы выделять блоки воздуха.", "create.schematicAndQuill.abort": "Выделение удалено.", - "create.schematicAndQuill.prompt": "Введите название для новой схемы:", + "create.schematicAndQuill.title": "UNLOCALIZED: Schematic Name:", + "create.schematicAndQuill.convert": "UNLOCALIZED: Save and Deploy Immediately", "create.schematicAndQuill.fallbackName": "Моя схема", "create.schematicAndQuill.saved": "Сохранено как %1$s", @@ -740,24 +738,29 @@ "create.schematics.maxAllowedSize": "Максимальный размер файла схемы:", "create.gui.schematicTable.title": "Стол для схем", + "create.gui.schematicTable.refresh": "UNLOCALIZED: Refresh Files", + "create.gui.schematicTable.open_folder": "UNLOCALIZED: Open Folder", "create.gui.schematicTable.availableSchematics": "Доступные схемы", "create.gui.schematicTable.noSchematics": "Нет сохранённых схем", "create.gui.schematicTable.uploading": "Загрузка...", "create.gui.schematicTable.finished": "Загрузка завершена!", "create.gui.schematicannon.title": "Схемопушка", - "create.gui.schematicannon.settingsTitle": "Параметры размещения", "create.gui.schematicannon.listPrinter": "Распечатать список материалов", "create.gui.schematicannon.gunpowderLevel": "Порох: %1$s%%", "create.gui.schematicannon.shotsRemaining": "Выстрелов осталось: %1$s", "create.gui.schematicannon.shotsRemainingWithBackup": "C запасом: %1$s", "create.gui.schematicannon.optionEnabled": "Включена", "create.gui.schematicannon.optionDisabled": "Отключена", + "create.gui.schematicannon.showOptions": "UNLOCALIZED: Show Printer Settings", "create.gui.schematicannon.option.dontReplaceSolid": "Не заменять целые блоки", "create.gui.schematicannon.option.replaceWithSolid": "Заменять целые блоки целыми блоками", "create.gui.schematicannon.option.replaceWithAny": "Заменять целые блоки чем угодно", "create.gui.schematicannon.option.replaceWithEmpty": "Заменять целые блоки пустотой", "create.gui.schematicannon.option.skipMissing": "Пропускать отсутствующие блоки", "create.gui.schematicannon.option.skipTileEntities": "Защита от сущностей", + "create.gui.schematicannon.slot.gunpowder": "UNLOCALIZED: Add gunpowder to fuel the cannon", + "create.gui.schematicannon.slot.listPrinter": "UNLOCALIZED: Place books here to print a Checklist for your Schematic", + "create.gui.schematicannon.slot.schematic": "UNLOCALIZED: Add your Schematic here. Make sure it is deployed at a specific location.", "create.gui.schematicannon.option.skipMissing.description": "Если схемопушка не найдёт нужный блок, то она продолжит в следующем месте.", "create.gui.schematicannon.option.skipTileEntities.description": "Схемопушка будет избегать замены блоков с данными, например сундуки.", "create.gui.schematicannon.option.dontReplaceSolid.description": "Схемопушка никогда не заменит целые блоки, только не целые и воздух.", @@ -793,23 +796,42 @@ "create.gui.filter.ignore_data.description": "UNLOCALIZED: Items match regardless of their attributes.", "create.item_attributes.placeable": "UNLOCALIZED: is placeable", + "create.item_attributes.placeable.inverted": "UNLOCALIZED: is not placeable", "create.item_attributes.consumable": "UNLOCALIZED: can be eaten", + "create.item_attributes.consumable.inverted": "UNLOCALIZED: cannot be eaten", "create.item_attributes.smeltable": "UNLOCALIZED: can be Smelted", + "create.item_attributes.smeltable.inverted": "UNLOCALIZED: cannot be Smelted", "create.item_attributes.washable": "UNLOCALIZED: can be Washed", + "create.item_attributes.washable.inverted": "UNLOCALIZED: cannot be Washed", "create.item_attributes.smokable": "UNLOCALIZED: can be Smoked", + "create.item_attributes.smokable.inverted": "UNLOCALIZED: cannot be Smoked", + "create.item_attributes.crushable": "UNLOCALIZED: can be Crushed", + "create.item_attributes.crushable.inverted": "UNLOCALIZED: cannot be Crushed", "create.item_attributes.blastable": "UNLOCALIZED: is smeltable in Blast Furnace", + "create.item_attributes.blastable.inverted": "UNLOCALIZED: is not smeltable in Blast Furnace", "create.item_attributes.enchanted": "UNLOCALIZED: is enchanted", + "create.item_attributes.enchanted.inverted": "UNLOCALIZED: is unenchanted", "create.item_attributes.damaged": "UNLOCALIZED: is damaged", + "create.item_attributes.damaged.inverted": "UNLOCALIZED: is not damaged", "create.item_attributes.badly_damaged": "UNLOCALIZED: is heavily damaged", + "create.item_attributes.badly_damaged.inverted": "UNLOCALIZED: is not heavily damaged", "create.item_attributes.not_stackable": "UNLOCALIZED: cannot stack", + "create.item_attributes.not_stackable.inverted": "UNLOCALIZED: can be stacked", "create.item_attributes.equipable": "UNLOCALIZED: can be equipped", + "create.item_attributes.equipable.inverted": "UNLOCALIZED: cannot be equipped", "create.item_attributes.furnace_fuel": "UNLOCALIZED: is furnace fuel", + "create.item_attributes.furnace_fuel.inverted": "UNLOCALIZED: is not furnace fuel", "create.item_attributes.in_tag": "UNLOCALIZED: is tagged %1$s", - "create.item_attributes.in_item_group": "UNLOCALIZED: belongs to %1$s", + "create.item_attributes.in_tag.inverted": "UNLOCALIZED: is not tagged %1$s", + "create.item_attributes.in_item_group": "UNLOCALIZED: is in group '%1$s'", + "create.item_attributes.in_item_group.inverted": "UNLOCALIZED: is not in group '%1$s'", "create.item_attributes.added_by": "UNLOCALIZED: was added by %1$s", + "create.item_attributes.added_by.inverted": "UNLOCALIZED: was not added by %1$s", "create.gui.attribute_filter.no_selected_attributes": "UNLOCALIZED: No attributes selected", "create.gui.attribute_filter.selected_attributes": "UNLOCALIZED: Selected attributes:", + "create.gui.attribute_filter.add_attribute": "UNLOCALIZED: Add attribute to List", + "create.gui.attribute_filter.add_inverted_attribute": "UNLOCALIZED: Add opposite attribute to List", "create.gui.attribute_filter.whitelist_disjunctive": "UNLOCALIZED: Whitelist (Any)", "create.gui.attribute_filter.whitelist_disjunctive.description": "UNLOCALIZED: Items pass if they have any of the selected attributes.", "create.gui.attribute_filter.whitelist_conjunctive": "UNLOCALIZED: Whitelist (All)", diff --git a/src/generated/resources/assets/create/lang/unfinished/zh_cn.json b/src/generated/resources/assets/create/lang/unfinished/zh_cn.json index 863fb68e4..0a76d10fe 100644 --- a/src/generated/resources/assets/create/lang/unfinished/zh_cn.json +++ b/src/generated/resources/assets/create/lang/unfinished/zh_cn.json @@ -1,5 +1,5 @@ { - "_": "Missing Localizations: 95", + "_": "Missing Localizations: 125", "_": "->------------------------] Game Elements [------------------------<-", @@ -663,12 +663,9 @@ "create.gui.adjustable_crate.title": "板条箱", "create.gui.adjustable_crate.storageSpace": "储存空间", "create.gui.stockpile_switch.title": "储存开关", - "create.gui.stockpile_switch.lowerLimit": "阈值下限", - "create.gui.stockpile_switch.upperLimit": "阈值上限", - "create.gui.stockpile_switch.startAt": "启动信号", - "create.gui.stockpile_switch.startAbove": "给予红石信号当容量大于", - "create.gui.stockpile_switch.stopAt": "停止信号", - "create.gui.stockpile_switch.stopBelow": "停止红石信号当容量小于", + "create.gui.stockpile_switch.invert_signal": "UNLOCALIZED: Invert Signal", + "create.gui.stockpile_switch.move_to_lower_at": "UNLOCALIZED: Move to lower lane at %1$s%%", + "create.gui.stockpile_switch.move_to_upper_at": "UNLOCALIZED: Move to upper lane at %1$s%%", "create.gui.sequenced_gearshift.title": "可编程齿轮箱", "create.gui.sequenced_gearshift.instruction": "指令", "create.gui.sequenced_gearshift.instruction.turn_angle": "旋转", @@ -689,7 +686,8 @@ "create.schematicAndQuill.secondPos": "第二个位置.", "create.schematicAndQuill.noTarget": "按住Ctrl选择空气方块.", "create.schematicAndQuill.abort": "删除选择.", - "create.schematicAndQuill.prompt": "输入蓝图的名称:", + "create.schematicAndQuill.title": "UNLOCALIZED: Schematic Name:", + "create.schematicAndQuill.convert": "UNLOCALIZED: Save and Deploy Immediately", "create.schematicAndQuill.fallbackName": "我的蓝图", "create.schematicAndQuill.saved": "另存为 %1$s", @@ -740,24 +738,29 @@ "create.schematics.maxAllowedSize": "允许的最大蓝图文件大小为:", "create.gui.schematicTable.title": "蓝图桌", + "create.gui.schematicTable.refresh": "UNLOCALIZED: Refresh Files", + "create.gui.schematicTable.open_folder": "UNLOCALIZED: Open Folder", "create.gui.schematicTable.availableSchematics": "可用蓝图", "create.gui.schematicTable.noSchematics": "没有保存的蓝图", "create.gui.schematicTable.uploading": "正在上传...", "create.gui.schematicTable.finished": "上传完成!", "create.gui.schematicannon.title": "蓝图加农炮", - "create.gui.schematicannon.settingsTitle": "放置设置", "create.gui.schematicannon.listPrinter": "物品清单打印机", "create.gui.schematicannon.gunpowderLevel": "火药 %1$s%%", "create.gui.schematicannon.shotsRemaining": "发射进度: %1$s", "create.gui.schematicannon.shotsRemainingWithBackup": "备份: %1$s", "create.gui.schematicannon.optionEnabled": "当前启用", "create.gui.schematicannon.optionDisabled": "当前禁用", + "create.gui.schematicannon.showOptions": "UNLOCALIZED: Show Printer Settings", "create.gui.schematicannon.option.dontReplaceSolid": "不要替换方块", "create.gui.schematicannon.option.replaceWithSolid": "用固体方块替换工作区域内的方块", "create.gui.schematicannon.option.replaceWithAny": "用任何方块替换工作区域内的方块", "create.gui.schematicannon.option.replaceWithEmpty": "用空气替换工作区域内的方块", "create.gui.schematicannon.option.skipMissing": "绕过缺少的方块", "create.gui.schematicannon.option.skipTileEntities": "保护存储方块", + "create.gui.schematicannon.slot.gunpowder": "UNLOCALIZED: Add gunpowder to fuel the cannon", + "create.gui.schematicannon.slot.listPrinter": "UNLOCALIZED: Place books here to print a Checklist for your Schematic", + "create.gui.schematicannon.slot.schematic": "UNLOCALIZED: Add your Schematic here. Make sure it is deployed at a specific location.", "create.gui.schematicannon.option.skipMissing.description": "如果缺失材料, 蓝图大炮将忽略当前缺失材料并且使用其他已有材料继续工作", "create.gui.schematicannon.option.skipTileEntities.description": "蓝图将避免更换存储方块,如箱子.", "create.gui.schematicannon.option.dontReplaceSolid.description": "蓝图加农炮将不会替换工作范围内的任何固体方块.", @@ -793,23 +796,42 @@ "create.gui.filter.ignore_data.description": "匹配时忽视物品的耐久、附魔等其他属性", "create.item_attributes.placeable": "可放置", + "create.item_attributes.placeable.inverted": "UNLOCALIZED: is not placeable", "create.item_attributes.consumable": "可食用", + "create.item_attributes.consumable.inverted": "UNLOCALIZED: cannot be eaten", "create.item_attributes.smeltable": "可被熔炉烧制", + "create.item_attributes.smeltable.inverted": "UNLOCALIZED: cannot be Smelted", "create.item_attributes.washable": "可被筛洗", + "create.item_attributes.washable.inverted": "UNLOCALIZED: cannot be Washed", "create.item_attributes.smokable": "可被烟熏", + "create.item_attributes.smokable.inverted": "UNLOCALIZED: cannot be Smoked", + "create.item_attributes.crushable": "UNLOCALIZED: can be Crushed", + "create.item_attributes.crushable.inverted": "UNLOCALIZED: cannot be Crushed", "create.item_attributes.blastable": "可被高炉冶炼", + "create.item_attributes.blastable.inverted": "UNLOCALIZED: is not smeltable in Blast Furnace", "create.item_attributes.enchanted": "已被附魔", + "create.item_attributes.enchanted.inverted": "UNLOCALIZED: is unenchanted", "create.item_attributes.damaged": "已损坏", + "create.item_attributes.damaged.inverted": "UNLOCALIZED: is not damaged", "create.item_attributes.badly_damaged": "严重受损", + "create.item_attributes.badly_damaged.inverted": "UNLOCALIZED: is not heavily damaged", "create.item_attributes.not_stackable": "无法堆叠", + "create.item_attributes.not_stackable.inverted": "UNLOCALIZED: can be stacked", "create.item_attributes.equipable": "可装备", + "create.item_attributes.equipable.inverted": "UNLOCALIZED: cannot be equipped", "create.item_attributes.furnace_fuel": "是燃料", + "create.item_attributes.furnace_fuel.inverted": "UNLOCALIZED: is not furnace fuel", "create.item_attributes.in_tag": "标签是%1$s", + "create.item_attributes.in_tag.inverted": "UNLOCALIZED: is not tagged %1$s", "create.item_attributes.in_item_group": "属于 %1$s", + "create.item_attributes.in_item_group.inverted": "UNLOCALIZED: is not in group '%1$s'", "create.item_attributes.added_by": "由%1$s添加", + "create.item_attributes.added_by.inverted": "UNLOCALIZED: was not added by %1$s", "create.gui.attribute_filter.no_selected_attributes": "没有标记任何属性", "create.gui.attribute_filter.selected_attributes": "已选择的属性:", + "create.gui.attribute_filter.add_attribute": "UNLOCALIZED: Add attribute to List", + "create.gui.attribute_filter.add_inverted_attribute": "UNLOCALIZED: Add opposite attribute to List", "create.gui.attribute_filter.whitelist_disjunctive": "任意匹配白名单 (任何)", "create.gui.attribute_filter.whitelist_disjunctive.description": "只要有其中一项属性符合,就可以通过", "create.gui.attribute_filter.whitelist_conjunctive": "全匹配白名单 (所有)", diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/fan/AirCurrent.java b/src/main/java/com/simibubi/create/content/contraptions/components/fan/AirCurrent.java index f77d9c5a1..a92bb9181 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/fan/AirCurrent.java +++ b/src/main/java/com/simibubi/create/content/contraptions/components/fan/AirCurrent.java @@ -13,6 +13,7 @@ import com.simibubi.create.content.logistics.InWorldProcessing.Type; import com.simibubi.create.foundation.config.AllConfigs; import com.simibubi.create.foundation.tileEntity.TileEntityBehaviour; import com.simibubi.create.foundation.tileEntity.behaviour.belt.TransportedItemStackHandlerBehaviour; +import com.simibubi.create.foundation.tileEntity.behaviour.belt.TransportedItemStackHandlerBehaviour.TransportedResult; import com.simibubi.create.foundation.utility.Iterate; import com.simibubi.create.foundation.utility.VecHelper; @@ -305,7 +306,7 @@ public class AirCurrent { InWorldProcessing.spawnParticlesForProcessing(world, handler.getWorldPositionOf(transported), processingType); if (world.isRemote) - return null; + return TransportedResult.doNothing(); return InWorldProcessing.applyProcessing(transported, world, processingType); }); } diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/mounted/CartAssemblerTileEntity.java b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/mounted/CartAssemblerTileEntity.java index 2638f75bf..4e98a97be 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/mounted/CartAssemblerTileEntity.java +++ b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/mounted/CartAssemblerTileEntity.java @@ -10,9 +10,12 @@ import com.simibubi.create.foundation.tileEntity.behaviour.ValueBoxTransform; import com.simibubi.create.foundation.tileEntity.behaviour.scrollvalue.INamedIconOptions; import com.simibubi.create.foundation.tileEntity.behaviour.scrollvalue.ScrollOptionBehaviour; import com.simibubi.create.foundation.utility.Lang; +import com.simibubi.create.foundation.utility.VecHelper; +import net.minecraft.state.properties.RailShape; import net.minecraft.tileentity.TileEntityType; -import net.minecraft.util.Direction; +import net.minecraft.util.Direction.Axis; +import net.minecraft.util.math.Vec3d; public class CartAssemblerTileEntity extends SmartTileEntity { private static final int assemblyCooldown = 8; @@ -24,11 +27,11 @@ public class CartAssemblerTileEntity extends SmartTileEntity { super(type); ticksSinceMinecartUpdate = assemblyCooldown; } - + @Override public void tick() { super.tick(); - if(ticksSinceMinecartUpdate < assemblyCooldown) { + if (ticksSinceMinecartUpdate < assemblyCooldown) { ticksSinceMinecartUpdate++; } } @@ -36,15 +39,36 @@ public class CartAssemblerTileEntity extends SmartTileEntity { @Override public void addBehaviours(List behaviours) { movementMode = new ScrollOptionBehaviour<>(CartMovementMode.class, - Lang.translate("contraptions.cart_movement_mode"), this, getMovementModeSlot()); + Lang.translate("contraptions.cart_movement_mode"), this, getMovementModeSlot()); movementMode.requiresWrench(); behaviours.add(movementMode); } protected ValueBoxTransform getMovementModeSlot() { - return new CenteredSideValueBoxTransform((state, d) -> d == Direction.UP); + return new CartAssemblerValueBoxTransform(); } + private class CartAssemblerValueBoxTransform extends CenteredSideValueBoxTransform { + + public CartAssemblerValueBoxTransform() { + super((state, d) -> { + if (d.getAxis() + .isVertical()) + return false; + if (!state.has(CartAssemblerBlock.RAIL_SHAPE)) + return false; + RailShape railShape = state.get(CartAssemblerBlock.RAIL_SHAPE); + return (d.getAxis() == Axis.X) == (railShape == RailShape.NORTH_SOUTH); + }); + } + + @Override + protected Vec3d getSouthLocation() { + return VecHelper.voxelSpace(8, 8, 18); + } + + } + public static enum CartMovementMode implements INamedIconOptions { ROTATE(AllIcons.I_CART_ROTATE), @@ -71,11 +95,11 @@ public class CartAssemblerTileEntity extends SmartTileEntity { return translationKey; } } - + public void resetTicksSinceMinecartUpdate() { ticksSinceMinecartUpdate = 0; } - + public boolean isMinecartUpdateValid() { return ticksSinceMinecartUpdate >= assemblyCooldown; } diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/pulley/PulleyRenderer.java b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/pulley/PulleyRenderer.java index 9994c52ec..6365ac1ae 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/pulley/PulleyRenderer.java +++ b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/pulley/PulleyRenderer.java @@ -26,6 +26,11 @@ public class PulleyRenderer extends KineticTileEntityRenderer { public PulleyRenderer(TileEntityRendererDispatcher dispatcher) { super(dispatcher); } + + @Override + public boolean isGlobalRenderer(KineticTileEntity p_188185_1_) { + return true; + } @Override protected void renderSafe(KineticTileEntity te, float partialTicks, MatrixStack ms, IRenderTypeBuffer buffer, diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/pulley/PulleyTileEntity.java b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/pulley/PulleyTileEntity.java index 04d0e1e81..7e9fd847c 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/pulley/PulleyTileEntity.java +++ b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/pulley/PulleyTileEntity.java @@ -39,7 +39,7 @@ public class PulleyTileEntity extends LinearActuatorTileEntity { public double getMaxRenderDistanceSquared() { return super.getMaxRenderDistanceSquared() + offset * offset; } - + @Override protected void assemble() { if (!(world.getBlockState(pos) diff --git a/src/main/java/com/simibubi/create/content/contraptions/fluids/tank/FluidTankBlock.java b/src/main/java/com/simibubi/create/content/contraptions/fluids/tank/FluidTankBlock.java index 0b209bbbf..f761f9d5a 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/fluids/tank/FluidTankBlock.java +++ b/src/main/java/com/simibubi/create/content/contraptions/fluids/tank/FluidTankBlock.java @@ -100,6 +100,9 @@ public class FluidTankBlock extends Block implements IWrenchable, ITE tankCapability = te.getCapability(CapabilityFluidHandler.FLUID_HANDLER_CAPABILITY, ray.getFace()); diff --git a/src/main/java/com/simibubi/create/content/contraptions/relays/advanced/sequencer/SequencedGearshiftBlock.java b/src/main/java/com/simibubi/create/content/contraptions/relays/advanced/sequencer/SequencedGearshiftBlock.java index 8f6fc42a3..3341651f4 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/relays/advanced/sequencer/SequencedGearshiftBlock.java +++ b/src/main/java/com/simibubi/create/content/contraptions/relays/advanced/sequencer/SequencedGearshiftBlock.java @@ -141,5 +141,15 @@ public class SequencedGearshiftBlock extends HorizontalAxisKineticBlock implemen public Class getTileEntityClass() { return SequencedGearshiftTileEntity.class; } + + @Override + public boolean hasComparatorInputOverride(BlockState p_149740_1_) { + return true; + } + + @Override + public int getComparatorInputOverride(BlockState state, World world, BlockPos pos) { + return state.get(STATE).intValue(); + } } diff --git a/src/main/java/com/simibubi/create/content/contraptions/relays/advanced/sequencer/SequencedGearshiftScreen.java b/src/main/java/com/simibubi/create/content/contraptions/relays/advanced/sequencer/SequencedGearshiftScreen.java index 0932fe187..500240631 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/relays/advanced/sequencer/SequencedGearshiftScreen.java +++ b/src/main/java/com/simibubi/create/content/contraptions/relays/advanced/sequencer/SequencedGearshiftScreen.java @@ -3,11 +3,15 @@ package com.simibubi.create.content.contraptions.relays.advanced.sequencer; import com.simibubi.create.AllBlocks; import com.simibubi.create.foundation.gui.AbstractSimiScreen; import com.simibubi.create.foundation.gui.AllGuiTextures; +import com.simibubi.create.foundation.gui.AllIcons; import com.simibubi.create.foundation.gui.GuiGameElement; +import com.simibubi.create.foundation.gui.widgets.IconButton; import com.simibubi.create.foundation.gui.widgets.ScrollInput; import com.simibubi.create.foundation.gui.widgets.SelectionScrollInput; import com.simibubi.create.foundation.networking.AllPackets; import com.simibubi.create.foundation.utility.Lang; + +import net.minecraft.client.Minecraft; import net.minecraft.item.ItemStack; import net.minecraft.nbt.ListNBT; import net.minecraft.util.math.BlockPos; @@ -18,6 +22,7 @@ public class SequencedGearshiftScreen extends AbstractSimiScreen { private final ItemStack renderedItem = AllBlocks.SEQUENCED_GEARSHIFT.asStack(); private final AllGuiTextures background = AllGuiTextures.SEQUENCER; + private IconButton confirmButton; private final String title = Lang.translate("gui.sequenced_gearshift.title"); private ListNBT compareTag; @@ -47,9 +52,9 @@ public class SequencedGearshiftScreen extends AbstractSimiScreen { } public void initInputsOfRow(int row) { - int x = guiLeft + 28; - int y = guiTop + 29; - int rowHeight = 18; + int x = guiLeft + 30; + int y = guiTop + 18; + int rowHeight = 22; Vector rowInputs = inputs.get(row); rowInputs.forEach(widgets::remove); @@ -58,16 +63,16 @@ public class SequencedGearshiftScreen extends AbstractSimiScreen { Instruction instruction = instructions.get(row); ScrollInput type = - new SelectionScrollInput(x, y + rowHeight * row, 50, 14).forOptions(SequencerInstructions.getOptions()) - .calling(state -> instructionUpdated(index, state)) - .setState(instruction.instruction.ordinal()) - .titled(Lang.translate("gui.sequenced_gearshift.instruction")); + new SelectionScrollInput(x, y + rowHeight * row, 50, 18).forOptions(SequencerInstructions.getOptions()) + .calling(state -> instructionUpdated(index, state)) + .setState(instruction.instruction.ordinal()) + .titled(Lang.translate("gui.sequenced_gearshift.instruction")); ScrollInput value = - new ScrollInput(x + 54, y + rowHeight * row, 30, 14).calling(state -> instruction.value = state); - ScrollInput direction = new SelectionScrollInput(x + 88, y + rowHeight * row, 18, 14) - .forOptions(InstructionSpeedModifiers.getOptions()) - .calling(state -> instruction.speedModifier = InstructionSpeedModifiers.values()[state]) - .titled(Lang.translate("gui.sequenced_gearshift.speed")); + new ScrollInput(x + 58, y + rowHeight * row, 28, 18).calling(state -> instruction.value = state); + ScrollInput direction = new SelectionScrollInput(x + 88, y + rowHeight * row, 28, 18) + .forOptions(InstructionSpeedModifiers.getOptions()) + .calling(state -> instruction.speedModifier = InstructionSpeedModifiers.values()[state]) + .titled(Lang.translate("gui.sequenced_gearshift.speed")); rowInputs.add(type); rowInputs.add(value); @@ -75,6 +80,10 @@ public class SequencedGearshiftScreen extends AbstractSimiScreen { widgets.addAll(rowInputs); updateParamsOfRow(row); + + confirmButton = + new IconButton(guiLeft + background.width - 33, guiTop + background.height - 24, AllIcons.I_CONFIRM); + widgets.add(confirmButton); } public void updateParamsOfRow(int row) { @@ -88,10 +97,10 @@ public class SequencedGearshiftScreen extends AbstractSimiScreen { value.active = value.visible = hasValue; if (hasValue) value.withRange(1, def.maxValue + 1) - .titled(Lang.translate(def.parameterKey)) - .withShiftStep(def.shiftStep) - .setState(instruction.value) - .onChanged(); + .titled(Lang.translate(def.parameterKey)) + .withShiftStep(def.shiftStep) + .setState(instruction.value) + .onChanged(); if (def == SequencerInstructions.WAIT) { value.withStepFunction(context -> { int v = context.currentValue; @@ -112,40 +121,37 @@ public class SequencedGearshiftScreen extends AbstractSimiScreen { @Override protected void renderWindow(int mouseX, int mouseY, float partialTicks) { - int hFontColor = 0xD3CBBE; background.draw(this, guiLeft, guiTop); for (int row = 0; row < instructions.capacity(); row++) { AllGuiTextures toDraw = AllGuiTextures.SEQUENCER_EMPTY; int yOffset = toDraw.height * row; - if (row < instructions.size()) { - Instruction instruction = instructions.get(row); - SequencerInstructions def = instruction.instruction; - def.background.draw(guiLeft + 14, guiTop + 29 + yOffset); - - label(32, 6 + yOffset, Lang.translate(def.translationKey)); - if (def.hasValueParameter) { - String text = def.formatValue(instruction.value); - int stringWidth = font.getStringWidth(text); - label(85 + (12 - stringWidth / 2), 6 + yOffset, text); - } - if (def.hasSpeedParameter) - label(120, 6 + yOffset, instruction.speedModifier.label); - + if (row >= instructions.size()) { + toDraw.draw(guiLeft, guiTop + 14 + yOffset); continue; } - toDraw.draw(guiLeft + 14, guiTop + 29 + yOffset); + Instruction instruction = instructions.get(row); + SequencerInstructions def = instruction.instruction; + def.background.draw(guiLeft, guiTop + 14 + yOffset); + + label(36, yOffset - 3, Lang.translate(def.translationKey)); + if (def.hasValueParameter) { + String text = def.formatValue(instruction.value); + int stringWidth = font.getStringWidth(text); + label(90 + (12 - stringWidth / 2), yOffset - 3, text); + } + if (def.hasSpeedParameter) + label(127, yOffset - 3, instruction.speedModifier.label); } - font.drawStringWithShadow(title, guiLeft - 3 + (background.width - font.getStringWidth(title)) / 2, guiTop + 10, - hFontColor); + font.drawStringWithShadow(title, guiLeft - 3 + (background.width - font.getStringWidth(title)) / 2, guiTop + 3, 0xffffff); GuiGameElement.of(renderedItem) - .at(guiLeft + background.width + 20, guiTop + 50) - .scale(5) - .render(); + .at(guiLeft + background.width + 20, guiTop + 50) + .scale(5) + .render(); } private void label(int x, int y, String text) { @@ -184,4 +190,14 @@ public class SequencedGearshiftScreen extends AbstractSimiScreen { } } + @Override + public boolean mouseClicked(double x, double y, int button) { + if (confirmButton.isHovered()) { + Minecraft.getInstance().player.closeScreen(); + return true; + } + + return super.mouseClicked(x, y, button); + } + } diff --git a/src/main/java/com/simibubi/create/content/contraptions/relays/advanced/sequencer/SequencerInstructions.java b/src/main/java/com/simibubi/create/content/contraptions/relays/advanced/sequencer/SequencerInstructions.java index e4b397bc7..3bb06ba8e 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/relays/advanced/sequencer/SequencerInstructions.java +++ b/src/main/java/com/simibubi/create/content/contraptions/relays/advanced/sequencer/SequencerInstructions.java @@ -9,7 +9,7 @@ import com.simibubi.create.foundation.utility.Lang; public enum SequencerInstructions { TURN_ANGLE("angle", AllGuiTextures.SEQUENCER_INSTRUCTION, true, true, 360, 45, 90), - TURN_DISTANCE("distance", AllGuiTextures.SEQUENCER_INSTRUCTION, true, true, 50, 5, 5), + TURN_DISTANCE("distance", AllGuiTextures.SEQUENCER_INSTRUCTION, true, true, 128, 5, 5), WAIT("duration", AllGuiTextures.SEQUENCER_WAIT, true, false, 600, 20, 10), END("", AllGuiTextures.SEQUENCER_END), diff --git a/src/main/java/com/simibubi/create/content/contraptions/relays/belt/BeltRenderer.java b/src/main/java/com/simibubi/create/content/contraptions/relays/belt/BeltRenderer.java index c5c9cd256..8d4188d50 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/relays/belt/BeltRenderer.java +++ b/src/main/java/com/simibubi/create/content/contraptions/relays/belt/BeltRenderer.java @@ -40,6 +40,11 @@ public class BeltRenderer extends SafeTileEntityRenderer { public BeltRenderer(TileEntityRendererDispatcher dispatcher) { super(dispatcher); } + + @Override + public boolean isGlobalRenderer(BeltTileEntity te) { + return BeltBlock.canTransportObjects(te.getBlockState()); + } @Override protected void renderSafe(BeltTileEntity te, float partialTicks, MatrixStack ms, IRenderTypeBuffer buffer, diff --git a/src/main/java/com/simibubi/create/content/contraptions/relays/belt/BeltTileEntity.java b/src/main/java/com/simibubi/create/content/contraptions/relays/belt/BeltTileEntity.java index 2fb39ce91..bde2e2483 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/relays/belt/BeltTileEntity.java +++ b/src/main/java/com/simibubi/create/content/contraptions/relays/belt/BeltTileEntity.java @@ -76,7 +76,7 @@ public class BeltTileEntity extends KineticTileEntity { casing = CasingType.NONE; color = -1; } - + @Override public void addBehaviours(List behaviours) { super.addBehaviours(behaviours); diff --git a/src/main/java/com/simibubi/create/content/curiosities/symmetry/SymmetryHandler.java b/src/main/java/com/simibubi/create/content/curiosities/symmetry/SymmetryHandler.java index f3efe5f37..76d66499a 100644 --- a/src/main/java/com/simibubi/create/content/curiosities/symmetry/SymmetryHandler.java +++ b/src/main/java/com/simibubi/create/content/curiosities/symmetry/SymmetryHandler.java @@ -13,7 +13,6 @@ import net.minecraft.block.Blocks; import net.minecraft.client.Minecraft; import net.minecraft.client.entity.player.ClientPlayerEntity; import net.minecraft.client.renderer.ActiveRenderInfo; -import net.minecraft.client.renderer.Atlases; import net.minecraft.client.renderer.IRenderTypeBuffer; import net.minecraft.client.renderer.RenderType; import net.minecraft.client.renderer.model.IBakedModel; @@ -103,7 +102,7 @@ public class SymmetryHandler { double speed = 1 / 16d; yShift = MathHelper.sin((float) (AnimationTickHolder.getRenderTick() * speed)) / 5f; - IRenderTypeBuffer buffer = Minecraft.getInstance() + IRenderTypeBuffer.Impl buffer = Minecraft.getInstance() .getBufferBuilders() .getEntityVertexConsumers(); ActiveRenderInfo info = mc.gameRenderer.getActiveRenderInfo(); @@ -117,7 +116,7 @@ public class SymmetryHandler { mirror.applyModelTransform(ms); IBakedModel model = mirror.getModel() .get(); - IVertexBuilder builder = buffer.getBuffer(RenderType.getTranslucent()); + IVertexBuilder builder = buffer.getBuffer(RenderType.getSolid()); mc.getBlockRendererDispatcher() .getBlockModelRenderer() @@ -125,11 +124,7 @@ public class SymmetryHandler { player.world.getRandom(), MathHelper.getPositionRandom(pos), OverlayTexture.DEFAULT_UV, EmptyModelData.INSTANCE); - Minecraft.getInstance() - .getBufferBuilders() - .getEntityVertexConsumers() - .draw(Atlases.getEntityTranslucent()); - + buffer.draw(); ms.pop(); } } diff --git a/src/main/java/com/simibubi/create/content/curiosities/symmetry/SymmetryWandScreen.java b/src/main/java/com/simibubi/create/content/curiosities/symmetry/SymmetryWandScreen.java index cba957ade..cface0dc2 100644 --- a/src/main/java/com/simibubi/create/content/curiosities/symmetry/SymmetryWandScreen.java +++ b/src/main/java/com/simibubi/create/content/curiosities/symmetry/SymmetryWandScreen.java @@ -2,16 +2,24 @@ package com.simibubi.create.content.curiosities.symmetry; import com.mojang.blaze3d.matrix.MatrixStack; import com.mojang.blaze3d.systems.RenderSystem; -import com.simibubi.create.content.curiosities.symmetry.mirror.*; +import com.simibubi.create.content.curiosities.symmetry.mirror.CrossPlaneMirror; +import com.simibubi.create.content.curiosities.symmetry.mirror.EmptyMirror; +import com.simibubi.create.content.curiosities.symmetry.mirror.PlaneMirror; +import com.simibubi.create.content.curiosities.symmetry.mirror.SymmetryMirror; +import com.simibubi.create.content.curiosities.symmetry.mirror.TriplePlaneMirror; import com.simibubi.create.foundation.gui.AbstractSimiScreen; import com.simibubi.create.foundation.gui.AllGuiTextures; +import com.simibubi.create.foundation.gui.AllIcons; import com.simibubi.create.foundation.gui.GuiGameElement; +import com.simibubi.create.foundation.gui.widgets.IconButton; import com.simibubi.create.foundation.gui.widgets.Label; import com.simibubi.create.foundation.gui.widgets.ScrollInput; import com.simibubi.create.foundation.gui.widgets.SelectionScrollInput; import com.simibubi.create.foundation.networking.AllPackets; import com.simibubi.create.foundation.networking.NbtPacket; import com.simibubi.create.foundation.utility.Lang; + +import net.minecraft.client.Minecraft; import net.minecraft.client.renderer.Vector3f; import net.minecraft.item.ItemStack; import net.minecraft.nbt.CompoundNBT; @@ -25,6 +33,7 @@ public class SymmetryWandScreen extends AbstractSimiScreen { private Label labelType; private ScrollInput areaAlign; private Label labelAlign; + private IconButton confirmButton; private final String mirrorType = Lang.translate("gui.symmetryWand.mirrorType"); private final String orientation = Lang.translate("gui.symmetryWand.orientation"); @@ -37,9 +46,9 @@ public class SymmetryWandScreen extends AbstractSimiScreen { super(); currentElement = SymmetryWandItem.getMirror(wand); - if (currentElement instanceof EmptyMirror) { + if (currentElement instanceof EmptyMirror) currentElement = new PlaneMirror(Vec3d.ZERO); - } + this.hand = hand; this.wand = wand; } @@ -47,16 +56,17 @@ public class SymmetryWandScreen extends AbstractSimiScreen { @Override public void init() { super.init(); - this.setWindowSize(AllGuiTextures.WAND_SYMMETRY.width + 50, AllGuiTextures.WAND_SYMMETRY.height + 50); + AllGuiTextures background = AllGuiTextures.WAND_OF_SYMMETRY; + this.setWindowSize(background.width + 50, background.height + 50); - labelType = new Label(guiLeft + 122, guiTop + 15, "").colored(0xFFFFFFFF) + labelType = new Label(guiLeft + 49, guiTop + 26, "").colored(0xFFFFFFFF) .withShadow(); - labelAlign = new Label(guiLeft + 122, guiTop + 35, "").colored(0xFFFFFFFF) + labelAlign = new Label(guiLeft + 49, guiTop + 48, "").colored(0xFFFFFFFF) .withShadow(); int state = currentElement instanceof TriplePlaneMirror ? 2 : currentElement instanceof CrossPlaneMirror ? 1 : 0; - areaType = new SelectionScrollInput(guiLeft + 119, guiTop + 12, 70, 14).forOptions(SymmetryMirror.getMirrors()) + areaType = new SelectionScrollInput(guiLeft + 45, guiTop + 21, 109, 18).forOptions(SymmetryMirror.getMirrors()) .titled(mirrorType) .writingTo(labelType) .setState(state); @@ -85,15 +95,17 @@ public class SymmetryWandScreen extends AbstractSimiScreen { widgets.add(labelAlign); widgets.add(areaType); widgets.add(labelType); + + confirmButton = new IconButton(guiLeft + background.width - 33, guiTop + background.height - 24, AllIcons.I_CONFIRM); + widgets.add(confirmButton); } private void initAlign(SymmetryMirror element) { - if (areaAlign != null) { + if (areaAlign != null) widgets.remove(areaAlign); - } - areaAlign = new SelectionScrollInput(guiLeft + 119, guiTop + 32, 70, 14).forOptions(element.getAlignToolTips()) + areaAlign = new SelectionScrollInput(guiLeft + 45, guiTop + 43, 109, 18).forOptions(element.getAlignToolTips()) .titled(orientation) .writingTo(labelAlign) .setState(element.getOrientationIndex()) @@ -104,30 +116,26 @@ public class SymmetryWandScreen extends AbstractSimiScreen { @Override protected void renderWindow(int mouseX, int mouseY, float partialTicks) { - AllGuiTextures.WAND_SYMMETRY.draw(this, guiLeft, guiTop); + AllGuiTextures.WAND_OF_SYMMETRY.draw(this, guiLeft, guiTop); - int x = guiLeft + 63; - int y = guiTop + 15; - - font.drawString(mirrorType, x - 5, y, AllGuiTextures.FONT_COLOR); - font.drawString(orientation, x - 5, y + 20, AllGuiTextures.FONT_COLOR); + font.drawStringWithShadow(wand.getDisplayName() + .getFormattedText(), guiLeft + 11, guiTop + 3, 0xffffff); renderBlock(); - GuiGameElement.of(wand) - .at(guiLeft + 200, guiTop + 170) - .scale(4) - .rotate(-70, 20, 20) - .render(); + .at(guiLeft + 170, guiTop + 200) + .scale(4) + .rotate(-70, 20, 20) + .render(); } protected void renderBlock() { RenderSystem.pushMatrix(); MatrixStack ms = new MatrixStack(); - ms.translate(guiLeft + 18, guiTop + 11, 20); + ms.translate(guiLeft + 25.5f, guiTop + 21, 20); ms.multiply(new Vector3f(.3f, 1f, 0f).getDegreesQuaternion(-22.5f)); - ms.scale(32, -32, 32); + ms.scale(16, -16, 16); currentElement.applyModelTransform(ms); RenderSystem.multMatrix(ms.peek() .getModel()); @@ -147,5 +155,15 @@ public class SymmetryWandScreen extends AbstractSimiScreen { minecraft.player.setHeldItem(hand, heldItem); super.removed(); } + + @Override + public boolean mouseClicked(double x, double y, int button) { + if (confirmButton.isHovered()) { + Minecraft.getInstance().player.closeScreen(); + return true; + } + + return super.mouseClicked(x, y, button); + } } diff --git a/src/main/java/com/simibubi/create/content/curiosities/zapper/ZapperScreen.java b/src/main/java/com/simibubi/create/content/curiosities/zapper/ZapperScreen.java index 2beb5a4e7..6354da3e4 100644 --- a/src/main/java/com/simibubi/create/content/curiosities/zapper/ZapperScreen.java +++ b/src/main/java/com/simibubi/create/content/curiosities/zapper/ZapperScreen.java @@ -5,6 +5,7 @@ import java.util.Vector; import com.mojang.blaze3d.systems.RenderSystem; import com.simibubi.create.foundation.gui.AbstractSimiScreen; import com.simibubi.create.foundation.gui.AllGuiTextures; +import com.simibubi.create.foundation.gui.AllIcons; import com.simibubi.create.foundation.gui.GuiGameElement; import com.simibubi.create.foundation.gui.widgets.IconButton; import com.simibubi.create.foundation.networking.AllPackets; @@ -14,20 +15,19 @@ import com.simibubi.create.foundation.utility.Lang; import net.minecraft.block.BlockState; import net.minecraft.block.Blocks; import net.minecraft.client.Minecraft; -import net.minecraft.client.renderer.texture.AtlasTexture; import net.minecraft.item.ItemStack; import net.minecraft.nbt.CompoundNBT; import net.minecraft.nbt.NBTUtil; import net.minecraft.util.Hand; -@SuppressWarnings("deprecation") public class ZapperScreen extends AbstractSimiScreen { protected ItemStack zapper; protected boolean offhand; protected float animationProgress; protected AllGuiTextures background; - + private IconButton confirmButton; + protected final String patternSection = Lang.translate("gui.blockzapper.patternSection"); protected String title; @@ -41,7 +41,7 @@ public class ZapperScreen extends AbstractSimiScreen { this.zapper = zapper; this.offhand = offhand; title = ""; - brightColor = 0xCCDDFF; + brightColor = 0xfefefe; fontColor = AllGuiTextures.FONT_COLOR; } @@ -51,6 +51,9 @@ public class ZapperScreen extends AbstractSimiScreen { setWindowSize(background.width + 40, background.height); super.init(); widgets.clear(); + + confirmButton = new IconButton(guiLeft + background.width - 53, guiTop + background.height - 24, AllIcons.I_CONFIRM); + widgets.add(confirmButton); int i = guiLeft - 20; int j = guiTop; @@ -61,7 +64,7 @@ public class ZapperScreen extends AbstractSimiScreen { for (int col = 0; col <= 2; col++) { int id = patternButtons.size(); PlacementPatterns pattern = PlacementPatterns.values()[id]; - patternButtons.add(new IconButton(i + 147 + col * 18, j + 23 + row * 18, pattern.icon)); + patternButtons.add(new IconButton(i + background.width - 76 + col * 18, j + 19 + row * 18, pattern.icon)); patternButtons.get(id) .setToolTip(Lang.translate("gui.blockzapper.pattern." + pattern.translationKey)); } @@ -82,17 +85,12 @@ public class ZapperScreen extends AbstractSimiScreen { background.draw(this, i, j); drawOnBackground(i, j); - minecraft.getTextureManager() - .bindTexture(AtlasTexture.LOCATION_BLOCKS_TEXTURE); - RenderSystem.enableBlend(); - renderBlock(); renderZapper(); } protected void drawOnBackground(int i, int j) { - font.drawStringWithShadow(title, i + 8, j + 10, brightColor); - font.drawString(patternSection, i + 148, j + 11, fontColor); + font.drawStringWithShadow(title, i + 11, j + 3, brightColor); } @Override @@ -122,20 +120,25 @@ public class ZapperScreen extends AbstractSimiScreen { nbt.putString("Pattern", PlacementPatterns.values()[patternButtons.indexOf(patternButton)].name()); } } + + if (confirmButton.isHovered()) { + Minecraft.getInstance().player.closeScreen(); + return true; + } return super.mouseClicked(x, y, button); } protected void renderZapper() { GuiGameElement.of(zapper) - .at((this.width - this.sWidth) / 2 + 210, this.height / 2 - this.sHeight / 4) + .at((this.width - this.sWidth) / 2 + 220, this.height / 2 - this.sHeight / 4 + 30) .scale(4) .render(); } protected void renderBlock() { RenderSystem.pushMatrix(); - RenderSystem.translated(guiLeft + 1.7f, guiTop + 48, 120); + RenderSystem.translated(guiLeft + 7f, guiTop + 43.5f, 120); RenderSystem.rotatef(-30f, .5f, .9f, -.1f); RenderSystem.scaled(20, 20, 20); diff --git a/src/main/java/com/simibubi/create/content/curiosities/zapper/blockzapper/BlockzapperScreen.java b/src/main/java/com/simibubi/create/content/curiosities/zapper/blockzapper/BlockzapperScreen.java index d0e5794f9..ad92257d2 100644 --- a/src/main/java/com/simibubi/create/content/curiosities/zapper/blockzapper/BlockzapperScreen.java +++ b/src/main/java/com/simibubi/create/content/curiosities/zapper/blockzapper/BlockzapperScreen.java @@ -43,26 +43,26 @@ public class BlockzapperScreen extends ZapperScreen { int j = guiTop; CompoundNBT nbt = zapper.getOrCreateTag(); - replaceModeIndicator = new Indicator(i + 51, j + 36, ""); - replaceModeButton = new IconButton(i + 51, j + 41, AllIcons.I_REPLACE_SOLID); + replaceModeIndicator = new Indicator(i + 49, j + 67, ""); + replaceModeButton = new IconButton(i + 49, j + 73, AllIcons.I_REPLACE_SOLID); if (nbt.contains("Replace") && nbt.getBoolean("Replace")) replaceModeIndicator.state = State.ON; replaceModeButton.setToolTip(Lang.translate("gui.blockzapper.replaceMode")); - spreadDiagonallyIndicator = new Indicator(i + 74, j + 36, ""); - spreadDiagonallyButton = new IconButton(i + 74, j + 41, AllIcons.I_FOLLOW_DIAGONAL); + spreadDiagonallyIndicator = new Indicator(i + 8, j + 67, ""); + spreadDiagonallyButton = new IconButton(i + 8, j + 73, AllIcons.I_FOLLOW_DIAGONAL); if (nbt.contains("SearchDiagonal") && nbt.getBoolean("SearchDiagonal")) spreadDiagonallyIndicator.state = State.ON; spreadDiagonallyButton.setToolTip(Lang.translate("gui.blockzapper.searchDiagonal")); - spreadMaterialIndicator = new Indicator(i + 92, j + 36, ""); - spreadMaterialButton = new IconButton(i + 92, j + 41, AllIcons.I_FOLLOW_MATERIAL); + spreadMaterialIndicator = new Indicator(i + 26, j + 67, ""); + spreadMaterialButton = new IconButton(i + 26, j + 73, AllIcons.I_FOLLOW_MATERIAL); if (nbt.contains("SearchFuzzy") && nbt.getBoolean("SearchFuzzy")) spreadMaterialIndicator.state = State.ON; spreadMaterialButton.setToolTip(Lang.translate("gui.blockzapper.searchFuzzy")); - spreadRangeLabel = new Label(i + 119, j + 46, "").withShadow().withSuffix("m"); - spreadRangeInput = new ScrollInput(i + 115, j + 43, 22, 14).withRange(1, BlockzapperItem.getMaxAoe(zapper)) + spreadRangeLabel = new Label(i + 79, j + 78, "").withShadow().withSuffix("m"); + spreadRangeInput = new ScrollInput(i + 73, j + 73, 26, 18).withRange(1, BlockzapperItem.getMaxAoe(zapper)) .setState(1).titled(Lang.translate("gui.blockzapper.range")).writingTo(spreadRangeLabel); if (nbt.contains("SearchDistance")) diff --git a/src/main/java/com/simibubi/create/content/curiosities/zapper/terrainzapper/WorldshaperScreen.java b/src/main/java/com/simibubi/create/content/curiosities/zapper/terrainzapper/WorldshaperScreen.java index f9d6ec474..0e6b7bca4 100644 --- a/src/main/java/com/simibubi/create/content/curiosities/zapper/terrainzapper/WorldshaperScreen.java +++ b/src/main/java/com/simibubi/create/content/curiosities/zapper/terrainzapper/WorldshaperScreen.java @@ -38,8 +38,7 @@ public class WorldshaperScreen extends ZapperScreen { public WorldshaperScreen(ItemStack zapper, boolean offhand) { super(AllGuiTextures.TERRAINZAPPER, zapper, offhand); - brightColor = 0xDFF6FF; - fontColor = 0x436B77; + fontColor = 0x767676; title = Lang.translate("gui.terrainzapper.title"); nbt = zapper.getOrCreateTag(); } @@ -51,8 +50,8 @@ public class WorldshaperScreen extends ZapperScreen { i = guiLeft - 20; j = guiTop; - brushLabel = new Label(i + 58, j + 28, "").withShadow(); - brushInput = new SelectionScrollInput(i + 55, j + 25, 78, 14).forOptions(brushOptions) + brushLabel = new Label(i + 61, j + 23, "").withShadow(); + brushInput = new SelectionScrollInput(i + 56, j + 18, 77, 18).forOptions(brushOptions) .titled(Lang.translate("gui.terrainzapper.brush")) .writingTo(brushLabel) .calling(this::brushChanged); @@ -68,7 +67,7 @@ public class WorldshaperScreen extends ZapperScreen { TerrainTools[] toolValues = TerrainTools.values(); for (int id = 0; id < toolValues.length; id++) { TerrainTools tool = toolValues[id]; - toolButtons.add(new IconButton(i + 8 + id * 18, j + 76, tool.icon)); + toolButtons.add(new IconButton(i + 7 + id * 18, j + 77, tool.icon)); toolButtons.get(id) .setToolTip(Lang.translate("gui.terrainzapper.tool." + tool.translationKey)); } @@ -82,7 +81,7 @@ public class WorldshaperScreen extends ZapperScreen { PlacementOptions[] placementValues = PlacementOptions.values(); for (int id = 0; id < placementValues.length; id++) { PlacementOptions option = placementValues[id]; - placementButtons.add(new IconButton(i + 147 + id * 18, j + 76, option.icon)); + placementButtons.add(new IconButton(i + 136 + id * 18, j + 77, option.icon)); placementButtons.get(id) .setToolTip(Lang.translate("gui.terrainzapper.placement." + option.translationKey)); } @@ -114,15 +113,15 @@ public class WorldshaperScreen extends ZapperScreen { Brush currentBrush = TerrainBrushes.values()[brushInput.getState()].get(); for (int index = 0; index < 3; index++) { - Label label = new Label(i + 62 + 18 * index, j + 46, "").withShadow(); + Label label = new Label(i + 65 + 20 * index, j + 43, "").withShadow(); brushParamLabels.add(label); int indexFinal = index; - ScrollInput input = new ScrollInput(i + 55 + 18 * index, j + 43, 14, 14) + ScrollInput input = new ScrollInput(i + 56 + 20 * index, j + 38, 18, 18) .withRange(currentBrush.getMin(index), currentBrush.getMax(index) + 1) .writingTo(label) .titled(currentBrush.getParamLabel(index)) .calling(state -> { - label.x = i + 62 + 18 * indexFinal - font.getStringWidth(label.text) / 2; + label.x = i + 65 + 20 * indexFinal - font.getStringWidth(label.text) / 2; }); input.setState(params[index]); input.onChanged(); @@ -175,12 +174,11 @@ public class WorldshaperScreen extends ZapperScreen { super.drawOnBackground(i, j); Brush currentBrush = TerrainBrushes.values()[brushInput.getState()].get(); - for (int index = 2; index >= currentBrush.amtParams; index--) { - AllGuiTextures.TERRAINZAPPER_INACTIVE_PARAM.draw(i + 55 + index * 18, j + 43); - } + for (int index = 2; index >= currentBrush.amtParams; index--) + AllGuiTextures.TERRAINZAPPER_INACTIVE_PARAM.draw(i + 56 + 20 * index, j + 38); - font.drawString(toolSection, i + 8, j + 64, fontColor); - font.drawString(placementSection, i + 148, j + 64, fontColor); + font.drawString(toolSection, i + 7, j + 66, fontColor); + font.drawString(placementSection, i + 136, j + 66, fontColor); } @Override diff --git a/src/main/java/com/simibubi/create/content/logistics/block/inventories/AdjustableCrateContainer.java b/src/main/java/com/simibubi/create/content/logistics/block/inventories/AdjustableCrateContainer.java index 68c13d22a..d67062c1f 100644 --- a/src/main/java/com/simibubi/create/content/logistics/block/inventories/AdjustableCrateContainer.java +++ b/src/main/java/com/simibubi/create/content/logistics/block/inventories/AdjustableCrateContainer.java @@ -40,17 +40,17 @@ public class AdjustableCrateContainer extends Container { private void init() { doubleCrate = te.isDoubleCrate(); - int x = doubleCrate ? 52 : 124; + int x = doubleCrate ? 51 : 123; int maxCol = doubleCrate ? 8 : 4; for (int row = 0; row < 4; ++row) { for (int col = 0; col < maxCol; ++col) { - this.addSlot(new SlotItemHandler(te.inventory, col + row * maxCol, x + col * 18, 25 + row * 18)); + this.addSlot(new SlotItemHandler(te.inventory, col + row * maxCol, x + col * 18, 20 + row * 18)); } } // player Slots int xOffset = 58; - int yOffset = 157; + int yOffset = 155; for (int row = 0; row < 3; ++row) { for (int col = 0; col < 9; ++col) { this.addSlot(new Slot(playerInventory, col + row * 9 + 9, xOffset + col * 18, yOffset + row * 18)); diff --git a/src/main/java/com/simibubi/create/content/logistics/block/inventories/AdjustableCrateScreen.java b/src/main/java/com/simibubi/create/content/logistics/block/inventories/AdjustableCrateScreen.java index 2a58b5e08..6a312a59c 100644 --- a/src/main/java/com/simibubi/create/content/logistics/block/inventories/AdjustableCrateScreen.java +++ b/src/main/java/com/simibubi/create/content/logistics/block/inventories/AdjustableCrateScreen.java @@ -1,7 +1,7 @@ package com.simibubi.create.content.logistics.block.inventories; -import static com.simibubi.create.foundation.gui.AllGuiTextures.FLEXCRATE; -import static com.simibubi.create.foundation.gui.AllGuiTextures.FLEXCRATE_DOUBLE; +import static com.simibubi.create.foundation.gui.AllGuiTextures.ADJUSTABLE_CRATE; +import static com.simibubi.create.foundation.gui.AllGuiTextures.ADJUSTABLE_DOUBLE_CRATE; import static com.simibubi.create.foundation.gui.AllGuiTextures.PLAYER_INVENTORY; import java.util.ArrayList; @@ -43,11 +43,11 @@ public class AdjustableCrateScreen extends AbstractSimiContainerScreen(); - extraAreas.add(new Rectangle2d(guiLeft + FLEXCRATE.width + 110, guiTop + 46, 71, 70)); + extraAreas.add(new Rectangle2d(guiLeft + ADJUSTABLE_CRATE.width + 110, guiTop + 46, 71, 70)); } @Override @@ -68,18 +68,17 @@ public class AdjustableCrateScreen extends AbstractSimiContainerScreen slot * 64) continue; int slotsPerRow = (container.doubleCrate ? 8 : 4); - int x = crateLeft + 23 + (slot % slotsPerRow) * 18; - int y = crateTop + 24 + (slot / slotsPerRow) * 18; - AllGuiTextures.FLEXCRATE_LOCKED_SLOT.draw(this, x, y); + int x = crateLeft + 22 + (slot % slotsPerRow) * 18; + int y = crateTop + 19 + (slot / slotsPerRow) * 18; + AllGuiTextures.ADJUSTABLE_CRATE_LOCKED_SLOT.draw(this, x, y); } GuiGameElement.of(renderedItem) - .at(guiLeft + FLEXCRATE.width + 110, guiTop + 40) + .at(guiLeft + ADJUSTABLE_CRATE.width + 110, guiTop + 40) .scale(5) .render(); } diff --git a/src/main/java/com/simibubi/create/content/logistics/block/redstone/StockpileSwitchBlock.java b/src/main/java/com/simibubi/create/content/logistics/block/redstone/StockpileSwitchBlock.java index 1dff71e17..a701a2b07 100644 --- a/src/main/java/com/simibubi/create/content/logistics/block/redstone/StockpileSwitchBlock.java +++ b/src/main/java/com/simibubi/create/content/logistics/block/redstone/StockpileSwitchBlock.java @@ -80,7 +80,7 @@ public class StockpileSwitchBlock extends HorizontalBlock implements ITE { - offBelowLabel.text = state + "%"; - lastModification = 0; - if (onAbove.getState() - 4 <= state) { - onAbove.setState(state + 5); - onAbove.onChanged(); - } - }) - .setState((int) (te.offWhenBelow * 100)); + cursor = LerpedFloat.linear() + .startWithValue(te.getLevelForDisplay()); + cursorLane = LerpedFloat.linear() + .startWithValue(te.getState() ? 1 : 0); - onAboveLabel = new Label(guiLeft + 116, guiTop + 55, "").colored(0xD3CBBE) - .withShadow(); - onAbove = new ScrollInput(guiLeft + 113, guiTop + 52, 33, 14).withRange(5, 101) - .titled(upperLimit) - .calling(state -> { - onAboveLabel.text = state + "%"; - lastModification = 0; - if (offBelow.getState() + 4 >= state) { - offBelow.setState(state - 5); - offBelow.onChanged(); - } - }) - .setState((int) (te.onWhenAbove * 100)); + offBelow = new ScrollInput(guiLeft + 36, guiTop + 40, 102, 18).withRange(0, 100) + .titled("") + .calling(state -> { + lastModification = 0; + offBelow.titled(Lang.translate("gui.stockpile_switch.move_to_upper_at", state)); + if (onAbove.getState() <= state) { + onAbove.setState(state + 1); + onAbove.onChanged(); + } + }) + .setState((int) (te.offWhenBelow * 100)); + + onAbove = new ScrollInput(guiLeft + 36, guiTop + 18, 102, 18).withRange(1, 101) + .titled("") + .calling(state -> { + lastModification = 0; + onAbove.titled(Lang.translate("gui.stockpile_switch.move_to_lower_at", state)); + if (offBelow.getState() >= state) { + offBelow.setState(state - 1); + offBelow.onChanged(); + } + }) + .setState((int) (te.onWhenAbove * 100)); onAbove.onChanged(); offBelow.onChanged(); - widgets.addAll(Arrays.asList(offBelowLabel, offBelow, onAbove, onAboveLabel)); + + widgets.add(onAbove); + widgets.add(offBelow); + + confirmButton = + new IconButton(guiLeft + background.width - 33, guiTop + background.height - 24, AllIcons.I_CONFIRM); + widgets.add(confirmButton); + + flipSignals = new IconButton(guiLeft + 14, guiTop + 40, AllIcons.I_FLIP); + flipSignals.setToolTip(invertSignal); + widgets.add(flipSignals); } @Override protected void renderWindow(int mouseX, int mouseY, float partialTicks) { - int hFontColor = 0xD3CBBE; - int fontColor = 0x4B3A22; STOCKSWITCH.draw(this, guiLeft, guiTop); - font.drawStringWithShadow(title, guiLeft - 3 + (STOCKSWITCH.width - font.getStringWidth(title)) / 2, - guiTop + 10, hFontColor); - font.drawString(onAbove.getState() == 100 ? startAt : startAbove, guiLeft + 13, guiTop + 55, fontColor); - font.drawString(offBelow.getState() == 0 ? stopAt : stopBelow, guiLeft + 13, guiTop + 72, fontColor); + + AllGuiTextures.STOCKSWITCH_POWERED_LANE.draw(this, guiLeft + 36, guiTop + (te.isInverted() ? 18 : 40)); + AllGuiTextures.STOCKSWITCH_UNPOWERED_LANE.draw(this, guiLeft + 36, guiTop + (te.isInverted() ? 40 : 18)); + + font.drawStringWithShadow(title, guiLeft - 3 + (STOCKSWITCH.width - font.getStringWidth(title)) / 2, guiTop + 3, + 0xffffff); AllGuiTextures sprite = AllGuiTextures.STOCKSWITCH_INTERVAL; - float lowerBound = offBelow.getState() / 100f * (sprite.width - 20) + 10; - float upperBound = onAbove.getState() / 100f * (sprite.width - 20) + 10; + float lowerBound = offBelow.getState(); + float upperBound = onAbove.getState(); sprite.bind(); - blit((int) (guiLeft + lowerBound), guiTop + 26, (int) (sprite.startX + lowerBound), sprite.startY, - (int) (upperBound - lowerBound), sprite.height); + blit((int) (guiLeft + upperBound) + 37, guiTop + 18, (int) (sprite.startX + upperBound), sprite.startY, + (int) (sprite.width - upperBound), sprite.height); + blit(guiLeft + 37, guiTop + 40, sprite.startX, sprite.startY, (int) (lowerBound), sprite.height); - sprite = AllGuiTextures.STOCKSWITCH_INTERVAL_END; - sprite.bind(); - blit((int) (guiLeft + upperBound), guiTop + 26, (int) (sprite.startX + upperBound), sprite.startY, - (int) (sprite.width - upperBound), sprite.height); + AllGuiTextures.STOCKSWITCH_ARROW_UP.draw(this, (int) (guiLeft + lowerBound + 36) - 2, guiTop + 35); + AllGuiTextures.STOCKSWITCH_ARROW_DOWN.draw(this, (int) (guiLeft + upperBound + 36) - 3, guiTop + 17); - AllGuiTextures.STOCKSWITCH_BOUND_LEFT.draw(this, (int) (guiLeft + lowerBound) - 1, guiTop + 24); - AllGuiTextures.STOCKSWITCH_BOUND_RIGHT.draw(this, (int) (guiLeft + upperBound) - 5, guiTop + 24); - - AllGuiTextures cursor = - te.powered ? AllGuiTextures.STOCKSWITCH_CURSOR_ON : AllGuiTextures.STOCKSWITCH_CURSOR_OFF; - RenderSystem.pushMatrix(); - RenderSystem.translatef((cursorPos * (sprite.width - 20) + 10), 0, 0); - cursor.draw(this, guiLeft - 4, guiTop + 24); - RenderSystem.popMatrix(); + if (te.currentLevel != -1) { + AllGuiTextures cursor = AllGuiTextures.STOCKSWITCH_CURSOR; + RenderSystem.pushMatrix(); + RenderSystem.translatef(Math.min(99, this.cursor.getValue(partialTicks) * sprite.width), + cursorLane.getValue(partialTicks) * 22, 0); + cursor.draw(this, guiLeft + 34, guiTop + 19); + RenderSystem.popMatrix(); + } RenderSystem.pushMatrix(); GuiGameElement.of(renderedItem) - .at(guiLeft + STOCKSWITCH.width + 15, guiTop + 20) - .scale(5) - .render(); + .at(guiLeft + STOCKSWITCH.width + 15, guiTop + 20) + .scale(5) + .render(); RenderSystem.popMatrix(); } @@ -127,25 +135,39 @@ public class StockpileSwitchScreen extends AbstractSimiScreen { public void tick() { super.tick(); - if (te.currentLevel == -1) - cursorPos = 0; - else - cursorPos += (te.currentLevel - cursorPos) / 4; + cursor.chase(te.getLevelForDisplay(), 1 / 4f, Chaser.EXP); + cursor.tickChaser(); + cursorLane.chase(te.getState() ? 1 : 0, 1 / 4f, Chaser.EXP); + cursorLane.tickChaser(); if (lastModification >= 0) lastModification++; if (lastModification >= 20) { lastModification = -1; - AllPackets.channel.sendToServer( - new ConfigureStockswitchPacket(te.getPos(), offBelow.getState() / 100f, onAbove.getState() / 100f)); + send(te.isInverted()); } } @Override public void removed() { - AllPackets.channel.sendToServer( - new ConfigureStockswitchPacket(te.getPos(), offBelow.getState() / 100f, onAbove.getState() / 100f)); + send(te.isInverted()); + } + + protected void send(boolean invert) { + AllPackets.channel.sendToServer(new ConfigureStockswitchPacket(te.getPos(), offBelow.getState() / 100f, + onAbove.getState() / 100f, invert)); + } + + @Override + public boolean mouseClicked(double x, double y, int button) { + if (flipSignals.isHovered()) + send(!te.isInverted()); + if (confirmButton.isHovered()) { + Minecraft.getInstance().player.closeScreen(); + return true; + } + return super.mouseClicked(x, y, button); } } diff --git a/src/main/java/com/simibubi/create/content/logistics/block/redstone/StockpileSwitchTileEntity.java b/src/main/java/com/simibubi/create/content/logistics/block/redstone/StockpileSwitchTileEntity.java index 863070eb1..4f44d92d8 100644 --- a/src/main/java/com/simibubi/create/content/logistics/block/redstone/StockpileSwitchTileEntity.java +++ b/src/main/java/com/simibubi/create/content/logistics/block/redstone/StockpileSwitchTileEntity.java @@ -20,7 +20,8 @@ public class StockpileSwitchTileEntity extends SmartTileEntity { public float onWhenAbove; public float offWhenBelow; public float currentLevel; - public boolean powered; + private boolean state; + private boolean inverted; private FilteringBehaviour filtering; private InvManipulationBehaviour observedInventory; @@ -30,7 +31,8 @@ public class StockpileSwitchTileEntity extends SmartTileEntity { onWhenAbove = .75f; offWhenBelow = .25f; currentLevel = -1; - powered = false; + state = false; + inverted = false; setLazyTickRate(10); } @@ -39,7 +41,8 @@ public class StockpileSwitchTileEntity extends SmartTileEntity { onWhenAbove = compound.getFloat("OnAbove"); offWhenBelow = compound.getFloat("OffBelow"); currentLevel = compound.getFloat("Current"); - powered = compound.getBoolean("Powered"); + state = compound.getBoolean("Powered"); + inverted = compound.getBoolean("Inverted"); super.read(compound, clientPacket); } @@ -48,7 +51,8 @@ public class StockpileSwitchTileEntity extends SmartTileEntity { compound.putFloat("OnAbove", onWhenAbove); compound.putFloat("OffBelow", offWhenBelow); compound.putFloat("Current", currentLevel); - compound.putBoolean("Powered", powered); + compound.putBoolean("Powered", state); + compound.putBoolean("Inverted", inverted); super.write(compound, clientPacket); } @@ -57,13 +61,15 @@ public class StockpileSwitchTileEntity extends SmartTileEntity { } public void updateCurrentLevel() { + boolean changed = false; if (!observedInventory.hasInventory()) { if (currentLevel == -1) return; world.setBlockState(pos, getBlockState().with(StockpileSwitchBlock.INDICATOR, 0), 3); currentLevel = -1; - powered = false; + state = false; world.notifyNeighbors(pos, getBlockState().getBlock()); + sendData(); return; } @@ -85,15 +91,18 @@ public class StockpileSwitchTileEntity extends SmartTileEntity { occupied += count * (1f / space); } - currentLevel = (float) occupied / totalSpace; + float level = (float) occupied / totalSpace; + if (currentLevel != level) + changed = true; + currentLevel = level; currentLevel = MathHelper.clamp(currentLevel, 0, 1); - boolean previouslyPowered = powered; - if (powered && currentLevel <= offWhenBelow) - powered = false; - else if (!powered && currentLevel >= onWhenAbove) - powered = true; - boolean update = previouslyPowered != powered; + boolean previouslyPowered = state; + if (state && currentLevel <= offWhenBelow) + state = false; + else if (!state && currentLevel >= onWhenAbove) + state = true; + boolean update = previouslyPowered != state; int displayLevel = 0; if (currentLevel > 0) @@ -101,6 +110,8 @@ public class StockpileSwitchTileEntity extends SmartTileEntity { world.setBlockState(pos, getBlockState().with(StockpileSwitchBlock.INDICATOR, displayLevel), update ? 3 : 2); if (update) world.notifyNeighbors(pos, getBlockState().getBlock()); + if (changed || update) + sendData(); } @Override @@ -120,4 +131,27 @@ public class StockpileSwitchTileEntity extends SmartTileEntity { observedInventory = new InvManipulationBehaviour(this, InterfaceProvider.towardBlockFacing()).bypassSidedness(); behaviours.add(observedInventory); } + + public float getLevelForDisplay() { + return currentLevel == -1 ? 0 : currentLevel; + } + + public boolean getState() { + return state; + } + + public boolean isPowered() { + return inverted != state; + } + + public boolean isInverted() { + return inverted; + } + + public void setInverted(boolean inverted) { + if (inverted == this.inverted) + return; + this.inverted = inverted; + world.notifyNeighbors(pos, getBlockState().getBlock()); + } } diff --git a/src/main/java/com/simibubi/create/content/logistics/item/filter/AbstractFilterScreen.java b/src/main/java/com/simibubi/create/content/logistics/item/filter/AbstractFilterScreen.java index 73e532dc4..ae138ce3d 100644 --- a/src/main/java/com/simibubi/create/content/logistics/item/filter/AbstractFilterScreen.java +++ b/src/main/java/com/simibubi/create/content/logistics/item/filter/AbstractFilterScreen.java @@ -41,8 +41,8 @@ public abstract class AbstractFilterScreen ex super.init(); widgets.clear(); - resetButton = new IconButton(guiLeft + 15, guiTop + background.height - 30, AllIcons.I_TRASH); - confirmButton = new IconButton(guiLeft + 159, guiTop + background.height - 30, AllIcons.I_CONFIRM); + resetButton = new IconButton(guiLeft + background.width - 62, guiTop + background.height - 24, AllIcons.I_TRASH); + confirmButton = new IconButton(guiLeft + background.width - 33, guiTop + background.height - 24, AllIcons.I_CONFIRM); widgets.add(resetButton); widgets.add(confirmButton); @@ -59,14 +59,7 @@ public abstract class AbstractFilterScreen ex PLAYER_INVENTORY.draw(this, invX, invY); font.drawString(playerInventory.getDisplayName().getFormattedText(), invX + 7, invY + 6, 0x666666); - font.drawString(I18n.format(container.filterItem.getTranslationKey()), x + 15, y + 9, 0x5B5037); - - /*RenderHelper.enableGuiDepthLighting(); - RenderSystem.pushMatrix(); - RenderSystem.translated(guiLeft + background.width + 0, guiTop + background.height - 60, 0); - RenderSystem.scaled(5, 5, 5); - itemRenderer.renderItemIntoGUI(container.filterItem, 0, 0); - RenderSystem.popMatrix();*/ + font.drawStringWithShadow(I18n.format(container.filterItem.getTranslationKey()), x + 15, y + 3, 0xdedede); GuiGameElement.of(container.filterItem) .at(guiLeft + background.width, guiTop +background.height -60) diff --git a/src/main/java/com/simibubi/create/content/logistics/item/filter/AttributeFilterContainer.java b/src/main/java/com/simibubi/create/content/logistics/item/filter/AttributeFilterContainer.java index 45595fd97..54e945ca9 100644 --- a/src/main/java/com/simibubi/create/content/logistics/item/filter/AttributeFilterContainer.java +++ b/src/main/java/com/simibubi/create/content/logistics/item/filter/AttributeFilterContainer.java @@ -4,6 +4,7 @@ import java.util.ArrayList; import java.util.List; import com.simibubi.create.AllContainerTypes; +import com.simibubi.create.foundation.utility.Pair; import net.minecraft.entity.player.PlayerEntity; import net.minecraft.entity.player.PlayerInventory; @@ -27,7 +28,7 @@ public class AttributeFilterContainer extends AbstractFilterContainer { } WhitelistMode whitelistMode; - List selectedAttributes; + List> selectedAttributes; public AttributeFilterContainer(int id, PlayerInventory inv, PacketBuffer extraData) { super(AllContainerTypes.ATTRIBUTE_FILTER.type, id, inv, extraData); @@ -37,21 +38,21 @@ public class AttributeFilterContainer extends AbstractFilterContainer { super(AllContainerTypes.ATTRIBUTE_FILTER.type, id, inv, stack); } - public void appendSelectedAttribute(ItemAttribute itemAttribute) { - selectedAttributes.add(itemAttribute); + public void appendSelectedAttribute(ItemAttribute itemAttribute, boolean inverted) { + selectedAttributes.add(Pair.of(itemAttribute, inverted)); } @Override protected void clearContents() { selectedAttributes.clear(); } - + @Override protected void init() { super.init(); ItemStack stack = new ItemStack(Items.NAME_TAG); stack.setDisplayName( - new StringTextComponent("Selected Tags").applyTextStyles(TextFormatting.RESET, TextFormatting.BLUE)); + new StringTextComponent("Selected Tags").applyTextStyles(TextFormatting.RESET, TextFormatting.BLUE)); filterInventory.setStackInSlot(1, stack); } @@ -61,8 +62,8 @@ public class AttributeFilterContainer extends AbstractFilterContainer { } protected void addFilterSlots() { - this.addSlot(new SlotItemHandler(filterInventory, 0, 16, 23)); - this.addSlot(new SlotItemHandler(filterInventory, 1, 59, 56) { + this.addSlot(new SlotItemHandler(filterInventory, 0, 16, 22)); + this.addSlot(new SlotItemHandler(filterInventory, 1, 22, 57) { @Override public boolean canTakeStack(PlayerEntity playerIn) { return false; @@ -110,29 +111,37 @@ public class AttributeFilterContainer extends AbstractFilterContainer { @Override protected int getInventoryOffset() { - return 86; + return 83; } @Override protected void readData(ItemStack filterItem) { selectedAttributes = new ArrayList<>(); - whitelistMode = WhitelistMode.values()[filterItem.getOrCreateTag().getInt("WhitelistMode")]; - ListNBT attributes = filterItem.getOrCreateTag().getList("MatchedAttributes", NBT.TAG_COMPOUND); - attributes.forEach(inbt -> selectedAttributes.add(ItemAttribute.fromNBT((CompoundNBT) inbt))); + whitelistMode = WhitelistMode.values()[filterItem.getOrCreateTag() + .getInt("WhitelistMode")]; + ListNBT attributes = filterItem.getOrCreateTag() + .getList("MatchedAttributes", NBT.TAG_COMPOUND); + attributes.forEach(inbt -> { + CompoundNBT compound = (CompoundNBT) inbt; + selectedAttributes.add(Pair.of(ItemAttribute.fromNBT(compound), compound.getBoolean("Inverted"))); + }); } @Override protected void saveData(ItemStack filterItem) { - filterItem.getOrCreateTag().putInt("WhitelistMode", whitelistMode.ordinal()); + filterItem.getOrCreateTag() + .putInt("WhitelistMode", whitelistMode.ordinal()); ListNBT attributes = new ListNBT(); selectedAttributes.forEach(at -> { if (at == null) return; CompoundNBT compoundNBT = new CompoundNBT(); - at.serializeNBT(compoundNBT); + at.getFirst().serializeNBT(compoundNBT); + compoundNBT.putBoolean("Inverted", at.getSecond()); attributes.add(compoundNBT); }); - filterItem.getOrCreateTag().put("MatchedAttributes", attributes); + filterItem.getOrCreateTag() + .put("MatchedAttributes", attributes); } } diff --git a/src/main/java/com/simibubi/create/content/logistics/item/filter/AttributeFilterScreen.java b/src/main/java/com/simibubi/create/content/logistics/item/filter/AttributeFilterScreen.java index d31e29cf9..aec61f789 100644 --- a/src/main/java/com/simibubi/create/content/logistics/item/filter/AttributeFilterScreen.java +++ b/src/main/java/com/simibubi/create/content/logistics/item/filter/AttributeFilterScreen.java @@ -16,6 +16,7 @@ import com.simibubi.create.foundation.gui.widgets.Label; import com.simibubi.create.foundation.gui.widgets.SelectionScrollInput; import com.simibubi.create.foundation.networking.AllPackets; import com.simibubi.create.foundation.utility.Lang; +import com.simibubi.create.foundation.utility.Pair; import net.minecraft.entity.player.PlayerInventory; import net.minecraft.item.ItemStack; @@ -30,6 +31,10 @@ public class AttributeFilterScreen extends AbstractFilterScreen { - }); + attributeSelector.removeCallback(); referenceItemChanged(container.filterInventory.getStackInSlot(0)); widgets.add(attributeSelector); @@ -88,8 +96,9 @@ public class AttributeFilterScreen extends AbstractFilterScreen selectedAttributes.add(TextFormatting.GRAY + "- " + at.format())); + .add(TextFormatting.YELLOW + (container.selectedAttributes.isEmpty() ? noSelectedT : selectedT)); + container.selectedAttributes.forEach(at -> selectedAttributes.add(TextFormatting.GRAY + "- " + at.getFirst() + .format(at.getSecond()))); } @@ -101,17 +110,22 @@ public class AttributeFilterScreen extends AbstractFilterScreen { }); return; } add.active = true; - attributeSelector.titled(stack.getDisplayName().getFormattedText() + "..."); + addInverted.active = true; + attributeSelector.titled(stack.getDisplayName() + .getFormattedText() + "..."); attributesOfItem.clear(); for (ItemAttribute itemAttribute : ItemAttribute.types) attributesOfItem.addAll(itemAttribute.listAttributesOf(stack, this.minecraft.world)); - List options = attributesOfItem.stream().map(ItemAttribute::format).collect(Collectors.toList()); + List options = attributesOfItem.stream() + .map(ia -> ia.format(false)) + .collect(Collectors.toList()); attributeSelector.forOptions(options); attributeSelector.active = true; attributeSelector.visible = true; @@ -119,17 +133,20 @@ public class AttributeFilterScreen extends AbstractFilterScreen { attributeSelectorLabel.setTextAndTrim(options.get(i), true, 112); ItemAttribute selected = attributesOfItem.get(i); - for (ItemAttribute existing : container.selectedAttributes) { + for (Pair existing : container.selectedAttributes) { CompoundNBT testTag = new CompoundNBT(); CompoundNBT testTag2 = new CompoundNBT(); - existing.serializeNBT(testTag); + existing.getFirst() + .serializeNBT(testTag); selected.serializeNBT(testTag2); if (testTag.equals(testTag2)) { add.active = false; + addInverted.active = false; return; } } add.active = true; + addInverted.active = true; }); attributeSelector.onChanged(); } @@ -141,8 +158,8 @@ public class AttributeFilterScreen extends AbstractFilterScreen= attributesOfItem.size()) + return false; + add.active = false; + addInverted.active = false; + CompoundNBT tag = new CompoundNBT(); + ItemAttribute itemAttribute = attributesOfItem.get(index); + itemAttribute.serializeNBT(tag); + AllPackets.channel + .sendToServer(new FilterScreenPacket(inverted ? Option.ADD_INVERTED_TAG : Option.ADD_TAG, tag)); + container.appendSelectedAttribute(itemAttribute, inverted); + if (container.selectedAttributes.size() == 1) + selectedAttributes.set(0, TextFormatting.YELLOW + selectedT); + selectedAttributes.add(TextFormatting.GRAY + "- " + itemAttribute.format(inverted)); + return true; + } + @Override protected void contentsCleared() { selectedAttributes.clear(); selectedAttributes.add(TextFormatting.YELLOW + noSelectedT); - if (!lastItemScanned.isEmpty()) + if (!lastItemScanned.isEmpty()) { add.active = true; + addInverted.active = true; + } } @Override diff --git a/src/main/java/com/simibubi/create/content/logistics/item/filter/FilterContainer.java b/src/main/java/com/simibubi/create/content/logistics/item/filter/FilterContainer.java index 6356878cd..483ac1190 100644 --- a/src/main/java/com/simibubi/create/content/logistics/item/filter/FilterContainer.java +++ b/src/main/java/com/simibubi/create/content/logistics/item/filter/FilterContainer.java @@ -24,8 +24,8 @@ public class FilterContainer extends AbstractFilterContainer { @Override protected void addFilterSlots() { - int x = 16; - int y = 21; + int x = 23; + int y = 20; for (int row = 0; row < 2; ++row) for (int col = 0; col < 9; ++col) @@ -39,7 +39,7 @@ public class FilterContainer extends AbstractFilterContainer { @Override protected int getInventoryOffset() { - return 100; + return 97; } @Override diff --git a/src/main/java/com/simibubi/create/content/logistics/item/filter/FilterItem.java b/src/main/java/com/simibubi/create/content/logistics/item/filter/FilterItem.java index feb43b008..67f6a9ac1 100644 --- a/src/main/java/com/simibubi/create/content/logistics/item/filter/FilterItem.java +++ b/src/main/java/com/simibubi/create/content/logistics/item/filter/FilterItem.java @@ -4,6 +4,8 @@ import java.util.ArrayList; import java.util.Collections; import java.util.List; +import javax.annotation.Nonnull; + import com.simibubi.create.AllItems; import com.simibubi.create.AllKeys; import com.simibubi.create.content.logistics.item.filter.AttributeFilterContainer.WhitelistMode; @@ -36,8 +38,6 @@ import net.minecraftforge.fml.network.NetworkHooks; import net.minecraftforge.items.ItemHandlerHelper; import net.minecraftforge.items.ItemStackHandler; -import javax.annotation.Nonnull; - public class FilterItem extends Item implements INamedContainerProvider { private FilterType type; @@ -121,12 +121,14 @@ public class FilterItem extends Item implements INamedContainerProvider { ListNBT attributes = filter.getOrCreateTag() .getList("MatchedAttributes", NBT.TAG_COMPOUND); for (INBT inbt : attributes) { - ItemAttribute attribute = ItemAttribute.fromNBT((CompoundNBT) inbt); + CompoundNBT compound = (CompoundNBT) inbt; + ItemAttribute attribute = ItemAttribute.fromNBT(compound); + boolean inverted = compound.getBoolean("Inverted"); if (count > 3) { list.add(TextFormatting.DARK_GRAY + "- ..."); break; } - list.add(TextFormatting.GRAY + "- " + attribute.format()); + list.add(TextFormatting.GRAY + "- " + attribute.format(inverted)); count++; } @@ -211,8 +213,9 @@ public class FilterItem extends Item implements INamedContainerProvider { ListNBT attributes = filter.getOrCreateTag() .getList("MatchedAttributes", NBT.TAG_COMPOUND); for (INBT inbt : attributes) { - ItemAttribute attribute = ItemAttribute.fromNBT((CompoundNBT) inbt); - boolean matches = attribute.appliesTo(stack, world); + CompoundNBT compound = (CompoundNBT) inbt; + ItemAttribute attribute = ItemAttribute.fromNBT(compound); + boolean matches = attribute.appliesTo(stack, world) != compound.getBoolean("Inverted"); if (matches) { switch (whitelistMode) { diff --git a/src/main/java/com/simibubi/create/content/logistics/item/filter/FilterScreen.java b/src/main/java/com/simibubi/create/content/logistics/item/filter/FilterScreen.java index 9a1defe51..2144bbda1 100644 --- a/src/main/java/com/simibubi/create/content/logistics/item/filter/FilterScreen.java +++ b/src/main/java/com/simibubi/create/content/logistics/item/filter/FilterScreen.java @@ -42,20 +42,20 @@ public class FilterScreen extends AbstractFilterScreen { int x = guiLeft; int y = guiTop; - blacklist = new IconButton(x + 58, y + 72, AllIcons.I_BLACKLIST); + blacklist = new IconButton(x + 18, y + 73, AllIcons.I_BLACKLIST); blacklist.setToolTip(blacklistN); - whitelist = new IconButton(x + 76, y + 72, AllIcons.I_WHITELIST); + whitelist = new IconButton(x + 36, y + 73, AllIcons.I_WHITELIST); whitelist.setToolTip(whitelistN); - blacklistIndicator = new Indicator(x + 58, y + 67, ""); - whitelistIndicator = new Indicator(x + 76, y + 67, ""); + blacklistIndicator = new Indicator(x + 18, y + 67, ""); + whitelistIndicator = new Indicator(x + 36, y + 67, ""); widgets.addAll(Arrays.asList(blacklist, whitelist, blacklistIndicator, whitelistIndicator)); - respectNBT = new IconButton(x + 98, y + 72, AllIcons.I_RESPECT_NBT); + respectNBT = new IconButton(x + 60, y + 73, AllIcons.I_RESPECT_NBT); respectNBT.setToolTip(respectDataN); - ignoreNBT = new IconButton(x + 116, y + 72, AllIcons.I_IGNORE_NBT); + ignoreNBT = new IconButton(x + 78, y + 73, AllIcons.I_IGNORE_NBT); ignoreNBT.setToolTip(ignoreDataN); - respectNBTIndicator = new Indicator(x + 98, y + 67, ""); - ignoreNBTIndicator = new Indicator(x + 116, y + 67, ""); + respectNBTIndicator = new Indicator(x + 60, y + 67, ""); + ignoreNBTIndicator = new Indicator(x + 78, y + 67, ""); widgets.addAll(Arrays.asList(respectNBT, ignoreNBT, respectNBTIndicator, ignoreNBTIndicator)); handleIndicators(); } diff --git a/src/main/java/com/simibubi/create/content/logistics/item/filter/FilterScreenPacket.java b/src/main/java/com/simibubi/create/content/logistics/item/filter/FilterScreenPacket.java index 8d49abeb4..984f455ec 100644 --- a/src/main/java/com/simibubi/create/content/logistics/item/filter/FilterScreenPacket.java +++ b/src/main/java/com/simibubi/create/content/logistics/item/filter/FilterScreenPacket.java @@ -13,7 +13,7 @@ import net.minecraftforge.fml.network.NetworkEvent.Context; public class FilterScreenPacket extends SimplePacketBase { enum Option { - CLEAR, WHITELIST, WHITELIST2, BLACKLIST, RESPECT_DATA, IGNORE_DATA, ADD_TAG; + CLEAR, WHITELIST, WHITELIST2, BLACKLIST, RESPECT_DATA, IGNORE_DATA, ADD_TAG, ADD_INVERTED_TAG; } private Option option; @@ -75,7 +75,9 @@ public class FilterScreenPacket extends SimplePacketBase { if (option == Option.BLACKLIST) c.whitelistMode = WhitelistMode.BLACKLIST; if (option == Option.ADD_TAG) - c.appendSelectedAttribute(ItemAttribute.fromNBT(data)); + c.appendSelectedAttribute(ItemAttribute.fromNBT(data), false); + if (option == Option.ADD_INVERTED_TAG) + c.appendSelectedAttribute(ItemAttribute.fromNBT(data), true); } }); diff --git a/src/main/java/com/simibubi/create/content/logistics/item/filter/ItemAttribute.java b/src/main/java/com/simibubi/create/content/logistics/item/filter/ItemAttribute.java index 3759744aa..1be6edd4b 100644 --- a/src/main/java/com/simibubi/create/content/logistics/item/filter/ItemAttribute.java +++ b/src/main/java/com/simibubi/create/content/logistics/item/filter/ItemAttribute.java @@ -12,6 +12,7 @@ import java.util.stream.Collectors; import org.apache.commons.lang3.StringUtils; import com.google.common.base.Predicates; +import com.simibubi.create.AllRecipeTypes; import com.simibubi.create.content.logistics.InWorldProcessing; import com.simibubi.create.foundation.utility.Lang; @@ -95,8 +96,9 @@ public interface ItemAttribute { } @OnlyIn(value = Dist.CLIENT) - default String format() { - return Lang.translate("item_attributes." + getTranslationKey(), getTranslationParameters()); + default String format(boolean inverted) { + return Lang.translate("item_attributes." + getTranslationKey() + (inverted ? ".inverted" : ""), + getTranslationParameters()); } public static enum StandardTraits implements ItemAttribute { @@ -111,6 +113,8 @@ public interface ItemAttribute { EQUIPABLE(s -> s.getEquipmentSlot() != null), FURNACE_FUEL(AbstractFurnaceTileEntity::isFuel), WASHABLE(InWorldProcessing::isWashable), + CRUSHABLE((s, w) -> testRecipe(s, w, AllRecipeTypes.CRUSHING.getType()) + || testRecipe(s, w, AllRecipeTypes.MILLING.getType())), SMELTABLE((s, w) -> testRecipe(s, w, IRecipeType.SMELTING)), SMOKABLE((s, w) -> testRecipe(s, w, IRecipeType.SMOKING)), BLASTABLE((s, w) -> testRecipe(s, w, IRecipeType.BLASTING)); @@ -125,9 +129,11 @@ public interface ItemAttribute { private static boolean testRecipe(ItemStack s, World w, IRecipeType> smelting) { RECIPE_WRAPPER.setInventorySlotContents(0, s.copy()); - return w.getRecipeManager().getRecipe(smelting, RECIPE_WRAPPER, w).isPresent(); + return w.getRecipeManager() + .getRecipe(smelting, RECIPE_WRAPPER, w) + .isPresent(); } - + private StandardTraits(BiPredicate test) { this.testWithWorld = test; } @@ -193,12 +199,18 @@ public interface ItemAttribute { @Override public boolean appliesTo(ItemStack stack) { - return stack.getItem().getTags().contains(tagName); + return stack.getItem() + .getTags() + .contains(tagName); } @Override public List listAttributesOf(ItemStack stack) { - return stack.getItem().getTags().stream().map(InTag::new).collect(Collectors.toList()); + return stack.getItem() + .getTags() + .stream() + .map(InTag::new) + .collect(Collectors.toList()); } @Override @@ -240,7 +252,8 @@ public interface ItemAttribute { @Override public List listAttributesOf(ItemStack stack) { - ItemGroup group = stack.getItem().getGroup(); + ItemGroup group = stack.getItem() + .getGroup(); return group == null ? Collections.emptyList() : Arrays.asList(new InItemGroup(group)); } @@ -249,9 +262,11 @@ public interface ItemAttribute { return "in_item_group"; } + @Override @OnlyIn(value = Dist.CLIENT) - public String format() { - return Lang.translate("item_attributes." + getTranslationKey(), I18n.format(group.getTranslationKey())); + public String format(boolean inverted) { + return Lang.translate("item_attributes." + getTranslationKey() + (inverted ? ".inverted" : ""), + I18n.format(group.getTranslationKey())); } @Override @@ -263,7 +278,8 @@ public interface ItemAttribute { public ItemAttribute readNBT(CompoundNBT nbt) { String readPath = nbt.getString("path"); for (ItemGroup group : ItemGroup.GROUPS) - if (group.getPath().equals(readPath)) + if (group.getPath() + .equals(readPath)) return new InItemGroup(group); return null; } @@ -280,12 +296,14 @@ public interface ItemAttribute { @Override public boolean appliesTo(ItemStack stack) { - return modId.equals(stack.getItem().getCreatorModId(stack)); + return modId.equals(stack.getItem() + .getCreatorModId(stack)); } @Override public List listAttributesOf(ItemStack stack) { - String id = stack.getItem().getCreatorModId(stack); + String id = stack.getItem() + .getCreatorModId(stack); return id == null ? Collections.emptyList() : Arrays.asList(new AddedBy(id)); } @@ -296,9 +314,11 @@ public interface ItemAttribute { @Override public Object[] getTranslationParameters() { - Optional modContainerById = ModList.get().getModContainerById(modId); - String name = modContainerById.map(ModContainer::getModInfo).map(IModInfo::getDisplayName) - .orElse(StringUtils.capitalize(modId)); + Optional modContainerById = ModList.get() + .getModContainerById(modId); + String name = modContainerById.map(ModContainer::getModInfo) + .map(IModInfo::getDisplayName) + .orElse(StringUtils.capitalize(modId)); return new Object[] { name }; } diff --git a/src/main/java/com/simibubi/create/content/logistics/packet/ConfigureStockswitchPacket.java b/src/main/java/com/simibubi/create/content/logistics/packet/ConfigureStockswitchPacket.java index 3f6febd1f..7822cc9f9 100644 --- a/src/main/java/com/simibubi/create/content/logistics/packet/ConfigureStockswitchPacket.java +++ b/src/main/java/com/simibubi/create/content/logistics/packet/ConfigureStockswitchPacket.java @@ -10,11 +10,13 @@ public class ConfigureStockswitchPacket extends TileEntityConfigurationPacket maxSize * 1000) { - Minecraft.getInstance().player.sendMessage(new StringTextComponent( - Lang.translate("schematics.uploadTooLarge") + " (" + size / 1000 + " KB).")); - Minecraft.getInstance().player.sendMessage( - new StringTextComponent(Lang.translate("schematics.maxAllowedSize") + " " + maxSize + " KB")); + if (!validateSizeLimitation(size)) return; - } in = Files.newInputStream(path, StandardOpenOption.READ); activeUploads.put(schematic, in); @@ -83,6 +77,20 @@ public class ClientSchematicLoader { } } + public static boolean validateSizeLimitation(long size) { + if (Minecraft.getInstance().isSingleplayer()) + return true; + Integer maxSize = AllConfigs.SERVER.schematics.maxTotalSchematicSize.get(); + if (size > maxSize * 1000) { + Minecraft.getInstance().player.sendMessage(new StringTextComponent( + Lang.translate("schematics.uploadTooLarge") + " (" + size / 1000 + " KB).")); + Minecraft.getInstance().player.sendMessage( + new StringTextComponent(Lang.translate("schematics.maxAllowedSize") + " " + maxSize + " KB")); + return false; + } + return true; + } + private void continueUpload(String schematic) { if (activeUploads.containsKey(schematic)) { Integer maxPacketSize = AllConfigs.SERVER.schematics.maxSchematicPacketSize.get(); diff --git a/src/main/java/com/simibubi/create/content/schematics/ServerSchematicLoader.java b/src/main/java/com/simibubi/create/content/schematics/ServerSchematicLoader.java index 3755dff63..8c8e117fa 100644 --- a/src/main/java/com/simibubi/create/content/schematics/ServerSchematicLoader.java +++ b/src/main/java/com/simibubi/create/content/schematics/ServerSchematicLoader.java @@ -14,7 +14,10 @@ import java.util.Optional; import java.util.Set; import java.util.stream.Stream; +import org.apache.commons.io.IOUtils; + import com.simibubi.create.AllBlocks; +import com.simibubi.create.AllItems; import com.simibubi.create.Create; import com.simibubi.create.content.schematics.block.SchematicTableTileEntity; import com.simibubi.create.content.schematics.item.SchematicItem; @@ -23,12 +26,17 @@ import com.simibubi.create.foundation.config.CSchematics; import com.simibubi.create.foundation.utility.FilesHelper; import net.minecraft.block.BlockState; +import net.minecraft.block.Blocks; import net.minecraft.entity.player.ServerPlayerEntity; +import net.minecraft.nbt.CompoundNBT; +import net.minecraft.nbt.CompressedStreamTools; import net.minecraft.tileentity.TileEntity; +import net.minecraft.util.Hand; import net.minecraft.util.math.BlockPos; import net.minecraft.util.text.StringTextComponent; import net.minecraft.util.text.TranslationTextComponent; import net.minecraft.world.World; +import net.minecraft.world.gen.feature.template.Template; public class ServerSchematicLoader { @@ -92,17 +100,12 @@ public class ServerSchematicLoader { // Unsupported Format if (!schematic.endsWith(".nbt")) { Create.logger.warn("Attempted Schematic Upload with non-supported Format: " + playerSchematicId); + return; } // Too big - Integer maxFileSize = getConfig().maxTotalSchematicSize.get(); - if (size > maxFileSize * 1000) { - player.sendMessage(new TranslationTextComponent("create.schematics.uploadTooLarge") - .appendSibling(new StringTextComponent(" (" + size / 1000 + " KB)."))); - player.sendMessage(new TranslationTextComponent("create.schematics.maxAllowedSize") - .appendSibling(new StringTextComponent(" " + maxFileSize + " KB"))); + if (!validateSchematicSizeOnServer(player, size)) return; - } // Skip existing Uploads if (activeUploads.containsKey(playerSchematicId)) @@ -134,8 +137,7 @@ public class ServerSchematicLoader { // Open Stream OutputStream writer = Files.newOutputStream(Paths.get(getSchematicPath(), playerSchematicId), StandardOpenOption.CREATE_NEW); - activeUploads.put(playerSchematicId, - new SchematicUploadEntry(writer, size, player.getServerWorld(), pos)); + activeUploads.put(playerSchematicId, new SchematicUploadEntry(writer, size, player.getServerWorld(), pos)); // Notify Tile Entity table.startUpload(schematic); @@ -146,6 +148,18 @@ public class ServerSchematicLoader { } } + protected boolean validateSchematicSizeOnServer(ServerPlayerEntity player, long size) { + Integer maxFileSize = getConfig().maxTotalSchematicSize.get(); + if (size > maxFileSize * 1000) { + player.sendMessage(new TranslationTextComponent("create.schematics.uploadTooLarge") + .appendSibling(new StringTextComponent(" (" + size / 1000 + " KB)."))); + player.sendMessage(new TranslationTextComponent("create.schematics.maxAllowedSize") + .appendSibling(new StringTextComponent(" " + maxFileSize + " KB"))); + return false; + } + return true; + } + public CSchematics getConfig() { return AllConfigs.SERVER.schematics; } @@ -231,7 +245,7 @@ public class ServerSchematicLoader { SchematicUploadEntry removed = activeUploads.remove(playerSchematicId); World world = removed.world; BlockPos pos = removed.tablePos; - + Create.logger.info("New Schematic Uploaded: " + playerSchematicId); if (pos == null) return; @@ -252,6 +266,65 @@ public class ServerSchematicLoader { e.printStackTrace(); } } - } + + public void handleInstantSchematic(ServerPlayerEntity player, String schematic, World world, BlockPos pos, + BlockPos bounds) { + String playerPath = getSchematicPath() + "/" + player.getName() + .getFormattedText(); + String playerSchematicId = player.getName() + .getFormattedText() + "/" + schematic; + FilesHelper.createFolderIfMissing(playerPath); + + // Unsupported Format + if (!schematic.endsWith(".nbt")) { + Create.logger.warn("Attempted Schematic Upload with non-supported Format: " + playerSchematicId); + return; + } + + // Not holding S&Q + if (!AllItems.SCHEMATIC_AND_QUILL.isIn(player.getHeldItemMainhand())) + return; + + try { + // Delete schematic with same name + Path path = Paths.get(getSchematicPath(), playerSchematicId); + Files.deleteIfExists(path); + + // Too many Schematics + Stream list = Files.list(Paths.get(playerPath)); + if (list.count() >= getConfig().maxSchematics.get()) { + Stream list2 = Files.list(Paths.get(playerPath)); + Optional lastFilePath = list2.filter(f -> !Files.isDirectory(f)) + .min(Comparator.comparingLong(f -> f.toFile() + .lastModified())); + list2.close(); + if (lastFilePath.isPresent()) + Files.deleteIfExists(lastFilePath.get()); + } + list.close(); + + Template t = new Template(); + t.takeBlocksFromWorld(world, pos, bounds, true, Blocks.AIR); + + OutputStream outputStream = null; + try { + outputStream = Files.newOutputStream(path, StandardOpenOption.CREATE); + CompoundNBT nbttagcompound = t.writeToNBT(new CompoundNBT()); + CompressedStreamTools.writeCompressed(nbttagcompound, outputStream); + player.setHeldItem(Hand.MAIN_HAND, SchematicItem.create(schematic, player.getName() + .getFormattedText())); + + } catch (IOException e) { + e.printStackTrace(); + } finally { + if (outputStream != null) + IOUtils.closeQuietly(outputStream); + } + } catch (IOException e) { + Create.logger.error("Exception Thrown in direct Schematic Upload: " + playerSchematicId); + e.printStackTrace(); + } + } + } diff --git a/src/main/java/com/simibubi/create/content/schematics/block/SchematicTableContainer.java b/src/main/java/com/simibubi/create/content/schematics/block/SchematicTableContainer.java index 00192180d..b1ae26663 100644 --- a/src/main/java/com/simibubi/create/content/schematics/block/SchematicTableContainer.java +++ b/src/main/java/com/simibubi/create/content/schematics/block/SchematicTableContainer.java @@ -41,7 +41,7 @@ public class SchematicTableContainer extends Container { } protected void init() { - inputSlot = new SlotItemHandler(te.inventory, 0, -9, 40) { + inputSlot = new SlotItemHandler(te.inventory, 0, -35, 41) { @Override public boolean isItemValid(ItemStack stack) { return AllItems.EMPTY_SCHEMATIC.isIn(stack) || AllItems.SCHEMATIC_AND_QUILL.isIn(stack) @@ -49,7 +49,7 @@ public class SchematicTableContainer extends Container { } }; - outputSlot = new SlotItemHandler(te.inventory, 1, 75, 40) { + outputSlot = new SlotItemHandler(te.inventory, 1, 110, 41) { @Override public boolean isItemValid(ItemStack stack) { return false; diff --git a/src/main/java/com/simibubi/create/content/schematics/block/SchematicTableScreen.java b/src/main/java/com/simibubi/create/content/schematics/block/SchematicTableScreen.java index b063dfc60..14a8052f9 100644 --- a/src/main/java/com/simibubi/create/content/schematics/block/SchematicTableScreen.java +++ b/src/main/java/com/simibubi/create/content/schematics/block/SchematicTableScreen.java @@ -38,6 +38,8 @@ public class SchematicTableScreen extends AbstractSimiContainerScreen availableSchematics = CreateClient.schematicSender.getAvailableSchematics(); - schematicsLabel = new Label(mainLeft + 36, mainTop + 26, "").withShadow(); + schematicsLabel = new Label(mainLeft + 49, mainTop + 26, "").withShadow(); schematicsLabel.text = ""; if (!availableSchematics.isEmpty()) { schematicsArea = - new SelectionScrollInput(mainLeft + 33, mainTop + 23, 134, 14).forOptions(availableSchematics) + new SelectionScrollInput(mainLeft + 45, mainTop + 21, 139, 18).forOptions(availableSchematics) .titled(availableSchematicsTitle) .writingTo(schematicsLabel); widgets.add(schematicsArea); widgets.add(schematicsLabel); } - confirmButton = new IconButton(mainLeft + 69, mainTop + 55, AllIcons.I_CONFIRM); - folderButton = new IconButton(mainLeft + 204, mainTop + 6, AllIcons.I_OPEN_FOLDER); - refreshButton = new IconButton(mainLeft + 204, mainTop + 26, AllIcons.I_REFRESH); + confirmButton = new IconButton(mainLeft + 44, mainTop + 56, AllIcons.I_CONFIRM); + + folderButton = new IconButton(mainLeft + 21, mainTop + 21, AllIcons.I_OPEN_FOLDER); + folderButton.setToolTip(folder); + refreshButton = new IconButton(mainLeft + 207, mainTop + 21, AllIcons.I_REFRESH); + refreshButton.setToolTip(refresh); + widgets.add(confirmButton); widgets.add(folderButton); widgets.add(refreshButton); @@ -104,13 +110,13 @@ public class SchematicTableScreen extends AbstractSimiContainerScreen { public SchematicannonRenderer(TileEntityRendererDispatcher dispatcher) { super(dispatcher); } + + @Override + public boolean isGlobalRenderer(SchematicannonTileEntity p_188185_1_) { + return true; + } @Override protected void renderSafe(SchematicannonTileEntity tileEntityIn, float partialTicks, MatrixStack ms, IRenderTypeBuffer buffer, int light, int overlay) { - Minecraft.getInstance().getTextureManager().bindTexture(AtlasTexture.LOCATION_BLOCKS_TEXTURE); - double yaw = 0; double pitch = 40; double recoil = 0; @@ -96,8 +96,8 @@ public class SchematicannonRenderer extends SafeTileEntityRenderer launched.totalTicks - 10) { + if ((launched.ticksRemaining + 1 - partialTicks) > launched.totalTicks - 10) recoil = Math.max(recoil, (launched.ticksRemaining + 1 - partialTicks) - launched.totalTicks + 10); - } // Render particles for launch if (launched.ticksRemaining == launched.totalTicks && tileEntityIn.firstRenderTick) { diff --git a/src/main/java/com/simibubi/create/content/schematics/block/SchematicannonScreen.java b/src/main/java/com/simibubi/create/content/schematics/block/SchematicannonScreen.java index 42fabac2a..ddcad6026 100644 --- a/src/main/java/com/simibubi/create/content/schematics/block/SchematicannonScreen.java +++ b/src/main/java/com/simibubi/create/content/schematics/block/SchematicannonScreen.java @@ -15,12 +15,15 @@ import com.simibubi.create.foundation.item.ItemDescription.Palette; import com.simibubi.create.foundation.item.TooltipHelper; import com.simibubi.create.foundation.networking.AllPackets; import com.simibubi.create.foundation.utility.Lang; + +import net.minecraft.client.Minecraft; import net.minecraft.client.gui.widget.Widget; import net.minecraft.client.renderer.Rectangle2d; import net.minecraft.entity.player.PlayerInventory; import net.minecraft.item.ItemStack; import net.minecraft.util.text.ITextComponent; import net.minecraft.util.text.TextFormatting; +import net.minecraft.util.text.TranslationTextComponent; import java.util.ArrayList; import java.util.Collections; @@ -31,6 +34,9 @@ import static net.minecraft.util.text.TextFormatting.GRAY; public class SchematicannonScreen extends AbstractSimiContainerScreen { + private static final AllGuiTextures BG_BOTTOM = AllGuiTextures.SCHEMATICANNON_BOTTOM; + private static final AllGuiTextures BG_TOP = AllGuiTextures.SCHEMATICANNON_TOP; + protected Vector replaceLevelIndicators; protected Vector replaceLevelButtons; @@ -47,27 +53,37 @@ public class SchematicannonScreen extends AbstractSimiContainerScreen extraAreas; + protected List placementSettingWidgets; private final String title = Lang.translate("gui.schematicannon.title"); - private final String settingsTitle = Lang.translate("gui.schematicannon.settingsTitle"); private final String listPrinter = Lang.translate("gui.schematicannon.listPrinter"); private final String _gunpowderLevel = "gui.schematicannon.gunpowderLevel"; private final String _shotsRemaining = "gui.schematicannon.shotsRemaining"; + private final String _showSettings = "gui.schematicannon.showOptions"; private final String _shotsRemainingWithBackup = "gui.schematicannon.shotsRemainingWithBackup"; + private final String _slotGunpowder = "gui.schematicannon.slot.gunpowder"; + private final String _slotListPrinter = "gui.schematicannon.slot.listPrinter"; + private final String _slotSchematic = "gui.schematicannon.slot.schematic"; + private final String optionEnabled = Lang.translate("gui.schematicannon.optionEnabled"); private final String optionDisabled = Lang.translate("gui.schematicannon.optionDisabled"); private final ItemStack renderedItem = AllBlocks.SCHEMATICANNON.asStack(); + private IconButton confirmButton; + private IconButton showSettingsButton; + private Indicator showSettingsIndicator; + public SchematicannonScreen(SchematicannonContainer container, PlayerInventory inventory, - ITextComponent p_i51105_3_) { + ITextComponent p_i51105_3_) { super(container, inventory, p_i51105_3_); + placementSettingWidgets = new ArrayList<>(); } @Override protected void init() { - setWindowSize(AllGuiTextures.SCHEMATICANNON_BG.width + 50, AllGuiTextures.SCHEMATICANNON_BG.height + 80); + setWindowSize(BG_TOP.width + 50, BG_BOTTOM.height + BG_TOP.height + 80); super.init(); int x = guiLeft + 20; @@ -76,63 +92,87 @@ public class SchematicannonScreen extends AbstractSimiContainerScreen(4); - replaceLevelIndicators = new Vector<>(4); - List icons = ImmutableList - .of(AllIcons.I_DONT_REPLACE, AllIcons.I_REPLACE_SOLID, AllIcons.I_REPLACE_ANY, - AllIcons.I_REPLACE_EMPTY); - List toolTips = ImmutableList - .of(Lang.translate("gui.schematicannon.option.dontReplaceSolid"), - Lang.translate("gui.schematicannon.option.replaceWithSolid"), - Lang.translate("gui.schematicannon.option.replaceWithAny"), - Lang.translate("gui.schematicannon.option.replaceWithEmpty")); - - for (int i = 0; i < 4; i++) { - replaceLevelIndicators.add(new Indicator(x + 16 + i * 18, y + 96, "")); - replaceLevelButtons.add(new IconButton(x + 16 + i * 18, y + 101, icons.get(i))); - replaceLevelButtons.get(i).setToolTip(toolTips.get(i)); - } - widgets.addAll(replaceLevelButtons); - widgets.addAll(replaceLevelIndicators); - - // Other Settings - skipMissingButton = new IconButton(x + 106, y + 101, AllIcons.I_SKIP_MISSING); - skipMissingButton.setToolTip(Lang.translate("gui.schematicannon.option.skipMissing")); - skipMissingIndicator = new Indicator(x + 106, y + 96, ""); - Collections.addAll(widgets, skipMissingButton, skipMissingIndicator); - - skipTilesButton = new IconButton(x + 124, y + 101, AllIcons.I_SKIP_TILES); - skipTilesButton.setToolTip(Lang.translate("gui.schematicannon.option.skipTileEntities")); - skipTilesIndicator = new Indicator(x + 124, y + 96, ""); - Collections.addAll(widgets, skipTilesButton, skipTilesIndicator); + Collections.addAll(widgets, playButton, playIndicator, pauseButton, pauseIndicator, resetButton, + resetIndicator); extraAreas = new ArrayList<>(); extraAreas.add(new Rectangle2d(guiLeft + 240, guiTop + 88, 84, 113)); + confirmButton = new IconButton(x + 180, guiTop + 117, AllIcons.I_CONFIRM); + widgets.add(confirmButton); + showSettingsButton = new IconButton(guiLeft + 29, guiTop + 117, AllIcons.I_PLACEMENT_SETTINGS); + showSettingsButton.setToolTip(Lang.translate(_showSettings)); + widgets.add(showSettingsButton); + showSettingsIndicator = new Indicator(guiLeft + 29, guiTop + 111, ""); + widgets.add(showSettingsIndicator); + tick(); } + private void initPlacementSettings() { + widgets.removeAll(placementSettingWidgets); + placementSettingWidgets.clear(); + + if (placementSettingsHidden()) + return; + + int x = guiLeft + 20; + int y = guiTop; + + // Replace settings + replaceLevelButtons = new Vector<>(4); + replaceLevelIndicators = new Vector<>(4); + List icons = ImmutableList.of(AllIcons.I_DONT_REPLACE, AllIcons.I_REPLACE_SOLID, + AllIcons.I_REPLACE_ANY, AllIcons.I_REPLACE_EMPTY); + List toolTips = ImmutableList.of(Lang.translate("gui.schematicannon.option.dontReplaceSolid"), + Lang.translate("gui.schematicannon.option.replaceWithSolid"), + Lang.translate("gui.schematicannon.option.replaceWithAny"), + Lang.translate("gui.schematicannon.option.replaceWithEmpty")); + + for (int i = 0; i < 4; i++) { + replaceLevelIndicators.add(new Indicator(x + 33 + i * 18, y + 111, "")); + replaceLevelButtons.add(new IconButton(x + 33 + i * 18, y + 117, icons.get(i))); + replaceLevelButtons.get(i) + .setToolTip(toolTips.get(i)); + } + placementSettingWidgets.addAll(replaceLevelButtons); + placementSettingWidgets.addAll(replaceLevelIndicators); + + // Other Settings + skipMissingButton = new IconButton(x + 111, y + 117, AllIcons.I_SKIP_MISSING); + skipMissingButton.setToolTip(Lang.translate("gui.schematicannon.option.skipMissing")); + skipMissingIndicator = new Indicator(x + 111, y + 111, ""); + Collections.addAll(placementSettingWidgets, skipMissingButton, skipMissingIndicator); + + skipTilesButton = new IconButton(x + 129, y + 117, AllIcons.I_SKIP_TILES); + skipTilesButton.setToolTip(Lang.translate("gui.schematicannon.option.skipTileEntities")); + skipTilesIndicator = new Indicator(x + 129, y + 111, ""); + Collections.addAll(placementSettingWidgets, skipTilesButton, skipTilesIndicator); + + widgets.addAll(placementSettingWidgets); + } + + protected boolean placementSettingsHidden() { + return showSettingsIndicator.state == State.OFF; + } + @Override public void tick() { - SchematicannonTileEntity te = container.getTileEntity(); - replaceLevelIndicators.get(0).state = te.replaceMode == 0 ? State.ON : State.OFF; - for (int replaceMode = 1; replaceMode < replaceLevelButtons.size(); replaceMode++) - replaceLevelIndicators.get(replaceMode).state = replaceMode <= te.replaceMode ? State.ON : State.OFF; - skipMissingIndicator.state = te.skipMissing ? State.ON : State.OFF; - skipTilesIndicator.state = !te.replaceTileEntities ? State.ON : State.OFF; + if (!placementSettingsHidden()) { + for (int replaceMode = 0; replaceMode < replaceLevelButtons.size(); replaceMode++) + replaceLevelIndicators.get(replaceMode).state = replaceMode == te.replaceMode ? State.ON : State.OFF; + skipMissingIndicator.state = te.skipMissing ? State.ON : State.OFF; + skipTilesIndicator.state = !te.replaceTileEntities ? State.ON : State.OFF; + } playIndicator.state = State.OFF; pauseIndicator.state = State.OFF; @@ -167,12 +207,18 @@ public class SchematicannonScreen extends AbstractSimiContainerScreen tip = button.getToolTip(); tip.add(TextFormatting.BLUE + (enabled ? optionEnabled : optionDisabled)); - tip - .addAll(TooltipHelper - .cutString(Lang.translate("gui.schematicannon.option." + tooltipKey + ".description"), GRAY, - GRAY)); + tip.addAll(TooltipHelper.cutString(Lang.translate("gui.schematicannon.option." + tooltipKey + ".description"), + GRAY, GRAY)); } @Override protected void renderWindow(int mouseX, int mouseY, float partialTicks) { AllGuiTextures.PLAYER_INVENTORY.draw(this, guiLeft - 10, guiTop + 145); - AllGuiTextures.SCHEMATICANNON_BG.draw(this, guiLeft + 20, guiTop); + BG_TOP.draw(this, guiLeft + 20, guiTop); + BG_BOTTOM.draw(this, guiLeft + 20, guiTop + BG_TOP.height); SchematicannonTileEntity te = container.getTileEntity(); renderPrintingProgress(te.schematicProgress); renderFuelBar(te.fuelLevel); renderChecklistPrinterProgress(te.bookPrintingProgress); - if (!te.inventory.getStackInSlot(0).isEmpty()) + if (!te.inventory.getStackInSlot(0) + .isEmpty()) renderBlueprintHighlight(); GuiGameElement.of(renderedItem) - .at(guiLeft + 240, guiTop + 120) - .scale(5) - .render(); + .at(guiLeft + 230, guiTop + 110) + .scale(5) + .render(); - - font.drawString(title, guiLeft + 80, guiTop + 10, AllGuiTextures.FONT_COLOR); + font.drawStringWithShadow(title, guiLeft + 80, guiTop + 3, 0xfefefe); String msg = Lang.translate("schematicannon.status." + te.statusMsg); int stringWidth = font.getStringWidth(msg); if (te.missingItem != null) { stringWidth += 15; - itemRenderer.renderItemIntoGUI(te.missingItem, guiLeft + 145, guiTop + 25); + itemRenderer.renderItemIntoGUI(te.missingItem, guiLeft + 150, guiTop + 46); } - font.drawStringWithShadow(msg, guiLeft + 20 + 96 - stringWidth / 2, guiTop + 30, 0xCCDDFF); - - font.drawString(settingsTitle, guiLeft + 20 + 13, guiTop + 84, AllGuiTextures.FONT_COLOR); - font - .drawString(playerInventory.getDisplayName().getFormattedText(), guiLeft - 10 + 7, guiTop + 145 + 6, - 0x666666); + font.drawStringWithShadow(msg, guiLeft + 20 + 102 - stringWidth / 2, guiTop + 50, 0xCCDDFF); + font.drawString(playerInventory.getDisplayName() + .getFormattedText(), guiLeft - 10 + 7, guiTop + 145 + 6, 0x666666); // to see or debug the bounds of the extra area uncomment the following lines // Rectangle2d r = extraAreas.get(0); @@ -241,92 +283,128 @@ public class SchematicannonScreen extends AbstractSimiContainerScreen= fuelX && mouseY >= fuelY && mouseX <= fuelX + AllGuiTextures.SCHEMATICANNON_FUEL.width - && mouseY <= fuelY + AllGuiTextures.SCHEMATICANNON_FUEL.height) { - container.getTileEntity(); - - double fuelUsageRate = te.getFuelUsageRate(); - int shotsLeft = (int) (te.fuelLevel / fuelUsageRate); - int shotsLeftWithItems = (int) (shotsLeft - + te.inventory.getStackInSlot(4).getCount() * (te.getFuelAddedByGunPowder() / fuelUsageRate)); - - List tooltip = new ArrayList<>(); - float f = te.hasCreativeCrate ? 100 : te.fuelLevel * 100; - tooltip.add(Lang.translate(_gunpowderLevel, "" + (int) f)); - if (!te.hasCreativeCrate) - tooltip.add(GRAY + Lang.translate(_shotsRemaining, "" + TextFormatting.BLUE + shotsLeft)); - if (shotsLeftWithItems != shotsLeft) - tooltip - .add(GRAY + Lang - .translate(_shotsRemainingWithBackup, "" + TextFormatting.BLUE + shotsLeftWithItems)); - + && mouseY <= fuelY + AllGuiTextures.SCHEMATICANNON_FUEL.height) { + List tooltip = getFuelLevelTooltip(te); renderTooltip(tooltip, mouseX, mouseY); } + if (hoveredSlot != null && !hoveredSlot.getHasStack()) { + if (hoveredSlot.getSlotIndex() == 0) + renderTooltip( + TooltipHelper.cutString(Lang.translate(_slotSchematic), TextFormatting.GRAY, TextFormatting.BLUE), + mouseX, mouseY); + if (hoveredSlot.getSlotIndex() == 2) + renderTooltip( + TooltipHelper.cutString(Lang.translate(_slotListPrinter), TextFormatting.GRAY, TextFormatting.BLUE), + mouseX, mouseY); + if (hoveredSlot.getSlotIndex() == 4) + renderTooltip( + TooltipHelper.cutString(Lang.translate(_slotGunpowder), TextFormatting.GRAY, TextFormatting.BLUE), + mouseX, mouseY); + } + if (te.missingItem != null) { - int missingBlockX = guiLeft + 145, missingBlockY = guiTop + 25; + int missingBlockX = guiLeft + 150, missingBlockY = guiTop + 46; if (mouseX >= missingBlockX && mouseY >= missingBlockY && mouseX <= missingBlockX + 16 - && mouseY <= missingBlockY + 16) { + && mouseY <= missingBlockY + 16) { renderTooltip(te.missingItem, mouseX, mouseY); } } - int paperX = guiLeft + 20 + 202, paperY = guiTop + 20; - if (mouseX >= paperX && mouseY >= paperY && mouseX <= paperX + 16 && mouseY <= paperY + 16) { + int paperX = guiLeft + 132, paperY = guiTop + 19; + if (mouseX >= paperX && mouseY >= paperY && mouseX <= paperX + 16 && mouseY <= paperY + 16) renderTooltip(listPrinter, mouseX, mouseY); - } super.renderWindowForeground(mouseX, mouseY, partialTicks); } - @Override - public boolean mouseClicked(double x, double y, int button) { + protected List getFuelLevelTooltip(SchematicannonTileEntity te) { + double fuelUsageRate = te.getFuelUsageRate(); + int shotsLeft = (int) (te.fuelLevel / fuelUsageRate); + int shotsLeftWithItems = (int) (shotsLeft + te.inventory.getStackInSlot(4) + .getCount() * (te.getFuelAddedByGunPowder() / fuelUsageRate)); + List tooltip = new ArrayList<>(); - for (int replaceMode = 0; replaceMode < replaceLevelButtons.size(); replaceMode++) { - if (!replaceLevelButtons.get(replaceMode).isHovered()) - continue; - if (container.getTileEntity().replaceMode == replaceMode) - continue; - sendOptionUpdate(Option.values()[replaceMode], true); + if (te.hasCreativeCrate) { + tooltip.add(Lang.translate(_gunpowderLevel, "" + 100)); + tooltip.add(TextFormatting.DARK_PURPLE + "(" + new TranslationTextComponent(AllBlocks.CREATIVE_CRATE.get() + .getTranslationKey()).getFormattedText() + ")"); + return tooltip; } - if (skipMissingButton.isHovered()) - sendOptionUpdate(Option.SKIP_MISSING, !container.getTileEntity().skipMissing); - if (skipTilesButton.isHovered()) - sendOptionUpdate(Option.SKIP_TILES, !container.getTileEntity().replaceTileEntities); + float f = te.fuelLevel * 100; + tooltip.add(Lang.translate(_gunpowderLevel, "" + (int) f)); + tooltip.add(GRAY + Lang.translate(_shotsRemaining, "" + TextFormatting.BLUE + shotsLeft)); + if (shotsLeftWithItems != shotsLeft) + tooltip + .add(GRAY + Lang.translate(_shotsRemainingWithBackup, "" + TextFormatting.BLUE + shotsLeftWithItems)); + return tooltip; + } + + @Override + public boolean mouseClicked(double x, double y, int button) { + if (showSettingsButton.isHovered()) { + showSettingsIndicator.state = placementSettingsHidden() ? State.GREEN : State.OFF; + initPlacementSettings(); + } + + if (confirmButton.isHovered()) { + Minecraft.getInstance().player.closeScreen(); + return true; + } + + if (!placementSettingsHidden()) { + for (int replaceMode = 0; replaceMode < replaceLevelButtons.size(); replaceMode++) { + if (!replaceLevelButtons.get(replaceMode) + .isHovered()) + continue; + if (container.getTileEntity().replaceMode == replaceMode) + continue; + sendOptionUpdate(Option.values()[replaceMode], true); + } + if (skipMissingButton.isHovered()) + sendOptionUpdate(Option.SKIP_MISSING, !container.getTileEntity().skipMissing); + if (skipTilesButton.isHovered()) + sendOptionUpdate(Option.SKIP_TILES, !container.getTileEntity().replaceTileEntities); + } if (playButton.isHovered() && playButton.active) sendOptionUpdate(Option.PLAY, true); @@ -344,8 +422,8 @@ public class SchematicannonScreen extends AbstractSimiContainerScreen { - }); - guiScreenIn.setTitle(Lang.translate("schematicAndQuill.prompt")); - guiScreenIn.setButtonTextConfirm(Lang.translate("action.saveToFile")); - guiScreenIn.setButtonTextAbort(Lang.translate("action.discard")); - ScreenOpener.open(guiScreenIn); + ScreenOpener.open(new SchematicPromptScreen()); return; } @@ -128,6 +125,13 @@ public class SchematicAndQuillHandler { firstPos = selectedPos; Lang.sendStatus(player, "schematicAndQuill.firstPos"); } + + public void discard() { + ClientPlayerEntity player = Minecraft.getInstance().player; + firstPos = null; + secondPos = null; + Lang.sendStatus(player, "schematicAndQuill.abort"); + } public void tick() { if (!isActive()) @@ -200,11 +204,13 @@ public class SchematicAndQuillHandler { && Minecraft.getInstance().currentScreen == null; } - public void saveSchematic(String string) { + public void saveSchematic(String string, boolean convertImmediately) { Template t = new Template(); MutableBoundingBox bb = new MutableBoundingBox(firstPos, secondPos); - t.takeBlocksFromWorld(Minecraft.getInstance().world, new BlockPos(bb.minX, bb.minY, bb.minZ), - new BlockPos(bb.getXSize(), bb.getYSize(), bb.getZSize()), true, Blocks.AIR); + BlockPos origin = new BlockPos(bb.minX, bb.minY, bb.minZ); + BlockPos bounds = new BlockPos(bb.getXSize(), bb.getYSize(), bb.getZSize()); + + t.takeBlocksFromWorld(Minecraft.getInstance().world, origin, bounds, true, Blocks.AIR); if (string.isEmpty()) string = Lang.translate("schematicAndQuill.fallbackName"); @@ -214,9 +220,10 @@ public class SchematicAndQuillHandler { String filename = FilesHelper.findFirstValidFilename(string, folderPath, "nbt"); String filepath = folderPath + "/" + filename; + Path path = Paths.get(filepath); OutputStream outputStream = null; try { - outputStream = Files.newOutputStream(Paths.get(filepath), StandardOpenOption.CREATE); + outputStream = Files.newOutputStream(path, StandardOpenOption.CREATE); CompoundNBT nbttagcompound = t.writeToNBT(new CompoundNBT()); CompressedStreamTools.writeCompressed(nbttagcompound, outputStream); } catch (IOException e) { @@ -228,6 +235,23 @@ public class SchematicAndQuillHandler { firstPos = null; secondPos = null; Lang.sendStatus(Minecraft.getInstance().player, "schematicAndQuill.saved", filepath); + + if (!convertImmediately) + return; + if (!Files.exists(path)) { + Create.logger.fatal("Missing Schematic file: " + path.toString()); + return; + } + try { + if (!ClientSchematicLoader.validateSizeLimitation(Files.size(path))) + return; + AllPackets.channel.sendToServer(new InstantSchematicPacket(filename, origin, bounds)); + + } catch (IOException e) { + Create.logger.fatal("Error finding Schematic file: " + path.toString()); + e.printStackTrace(); + return; + } } private Outliner outliner() { diff --git a/src/main/java/com/simibubi/create/content/schematics/client/SchematicEditScreen.java b/src/main/java/com/simibubi/create/content/schematics/client/SchematicEditScreen.java index 1f1c91ea4..401aff0c9 100644 --- a/src/main/java/com/simibubi/create/content/schematics/client/SchematicEditScreen.java +++ b/src/main/java/com/simibubi/create/content/schematics/client/SchematicEditScreen.java @@ -8,11 +8,14 @@ import com.simibubi.create.AllItems; import com.simibubi.create.CreateClient; import com.simibubi.create.foundation.gui.AbstractSimiScreen; import com.simibubi.create.foundation.gui.AllGuiTextures; +import com.simibubi.create.foundation.gui.AllIcons; +import com.simibubi.create.foundation.gui.widgets.IconButton; import com.simibubi.create.foundation.gui.widgets.Label; import com.simibubi.create.foundation.gui.widgets.ScrollInput; import com.simibubi.create.foundation.gui.widgets.SelectionScrollInput; import com.simibubi.create.foundation.utility.Lang; +import net.minecraft.client.Minecraft; import net.minecraft.client.gui.widget.TextFieldWidget; import net.minecraft.item.ItemStack; import net.minecraft.nbt.NBTUtil; @@ -26,12 +29,12 @@ public class SchematicEditScreen extends AbstractSimiScreen { private TextFieldWidget xInput; private TextFieldWidget yInput; private TextFieldWidget zInput; + private IconButton confirmButton; private final List rotationOptions = Lang.translatedOptions("schematic.rotation", "none", "cw90", "cw180", "cw270"); private final List mirrorOptions = Lang.translatedOptions("schematic.mirror", "none", "leftRight", "frontBack"); - private final String positionLabel = Lang.translate("schematic.position"); private final String rotationLabel = Lang.translate("schematic.rotation"); private final String mirrorLabel = Lang.translate("schematic.mirror"); @@ -41,16 +44,18 @@ public class SchematicEditScreen extends AbstractSimiScreen { @Override protected void init() { - setWindowSize(AllGuiTextures.SCHEMATIC.width + 50, AllGuiTextures.SCHEMATIC.height); + AllGuiTextures background = AllGuiTextures.SCHEMATIC; + setWindowSize(background.width + 50, background.height); int x = guiLeft; int y = guiTop; handler = CreateClient.schematicHandler; - xInput = new TextFieldWidget(font, x + 75, y + 32, 32, 10, ""); - yInput = new TextFieldWidget(font, x + 115, y + 32, 32, 10, ""); - zInput = new TextFieldWidget(font, x + 155, y + 32, 32, 10, ""); + xInput = new TextFieldWidget(font, x + 50, y + 26, 34, 10, ""); + yInput = new TextFieldWidget(font, x + 90, y + 26, 34, 10, ""); + zInput = new TextFieldWidget(font, x + 130, y + 26, 34, 10, ""); - BlockPos anchor = handler.getTransformation().getAnchor(); + BlockPos anchor = handler.getTransformation() + .getAnchor(); if (handler.isDeployed()) { xInput.setText("" + anchor.getX()); yInput.setText("" + anchor.getY()); @@ -80,18 +85,29 @@ public class SchematicEditScreen extends AbstractSimiScreen { }); } - PlacementSettings settings = handler.getTransformation().toSettings(); - Label labelR = new Label(x + 99, y + 52, "").withShadow(); - rotationArea = new SelectionScrollInput(x + 96, y + 49, 94, 14).forOptions(rotationOptions).titled("Rotation") - .setState(settings.getRotation().ordinal()).writingTo(labelR); + PlacementSettings settings = handler.getTransformation() + .toSettings(); + Label labelR = new Label(x + 50, y + 48, "").withShadow(); + rotationArea = new SelectionScrollInput(x + 45, y + 43, 118, 18).forOptions(rotationOptions) + .titled(rotationLabel) + .setState(settings.getRotation() + .ordinal()) + .writingTo(labelR); - Label labelM = new Label(x + 99, y + 72, "").withShadow(); - mirrorArea = new SelectionScrollInput(x + 96, y + 69, 94, 14).forOptions(mirrorOptions).titled("Mirror") - .setState(settings.getMirror().ordinal()).writingTo(labelM); + Label labelM = new Label(x + 50, y + 70, "").withShadow(); + mirrorArea = new SelectionScrollInput(x + 45, y + 65, 118, 18).forOptions(mirrorOptions) + .titled(mirrorLabel) + .setState(settings.getMirror() + .ordinal()) + .writingTo(labelM); Collections.addAll(widgets, xInput, yInput, zInput); Collections.addAll(widgets, labelR, labelM, rotationArea, mirrorArea); + confirmButton = + new IconButton(guiLeft + background.width - 33, guiTop + background.height - 24, AllIcons.I_CONFIRM); + widgets.add(confirmButton); + super.init(); } @@ -132,14 +148,10 @@ public class SchematicEditScreen extends AbstractSimiScreen { AllGuiTextures.SCHEMATIC.draw(this, x, y); font.drawStringWithShadow(handler.getCurrentSchematicName(), - x + 103 - font.getStringWidth(handler.getCurrentSchematicName()) / 2, y + 10, 0xDDEEFF); - - font.drawString(positionLabel, x + 10, y + 32, AllGuiTextures.FONT_COLOR); - font.drawString(rotationLabel, x + 10, y + 52, AllGuiTextures.FONT_COLOR); - font.drawString(mirrorLabel, x + 10, y + 72, AllGuiTextures.FONT_COLOR); + x + 93 - font.getStringWidth(handler.getCurrentSchematicName()) / 2, y + 3, 0xffffff); RenderSystem.pushMatrix(); - RenderSystem.translated(guiLeft + 220, guiTop + 20, 0); + RenderSystem.translated(guiLeft + 200, guiTop + 80, 0); RenderSystem.scaled(3, 3, 3); itemRenderer.renderItemIntoGUI(new ItemStack(AllItems.SCHEMATIC.get()), 0, 0); RenderSystem.popMatrix(); @@ -151,7 +163,7 @@ public class SchematicEditScreen extends AbstractSimiScreen { BlockPos newLocation = null; try { newLocation = new BlockPos(Integer.parseInt(xInput.getText()), Integer.parseInt(yInput.getText()), - Integer.parseInt(zInput.getText())); + Integer.parseInt(zInput.getText())); } catch (NumberFormatException e) { validCoords = false; } @@ -159,19 +171,31 @@ public class SchematicEditScreen extends AbstractSimiScreen { PlacementSettings settings = new PlacementSettings(); settings.setRotation(Rotation.values()[rotationArea.getState()]); settings.setMirror(Mirror.values()[mirrorArea.getState()]); - + if (validCoords && newLocation != null) { ItemStack item = handler.getActiveSchematicItem(); if (item != null) { - item.getTag().putBoolean("Deployed", true); - item.getTag().put("Anchor", NBTUtil.writeBlockPos(newLocation)); + item.getTag() + .putBoolean("Deployed", true); + item.getTag() + .put("Anchor", NBTUtil.writeBlockPos(newLocation)); } - handler.getTransformation().init(newLocation, settings, handler.getBounds()); + handler.getTransformation() + .init(newLocation, settings, handler.getBounds()); handler.markDirty(); handler.deploy(); } + } + @Override + public boolean mouseClicked(double x, double y, int button) { + if (confirmButton.isHovered()) { + Minecraft.getInstance().player.closeScreen(); + return true; + } + + return super.mouseClicked(x, y, button); } } diff --git a/src/main/java/com/simibubi/create/content/schematics/client/SchematicHotbarSlotOverlay.java b/src/main/java/com/simibubi/create/content/schematics/client/SchematicHotbarSlotOverlay.java index 0190de43a..e303daf14 100644 --- a/src/main/java/com/simibubi/create/content/schematics/client/SchematicHotbarSlotOverlay.java +++ b/src/main/java/com/simibubi/create/content/schematics/client/SchematicHotbarSlotOverlay.java @@ -11,10 +11,10 @@ public class SchematicHotbarSlotOverlay extends AbstractGui { public void renderOn(int slot) { MainWindow mainWindow = Minecraft.getInstance().getWindow(); - int x = mainWindow.getScaledWidth() / 2 - 92; - int y = mainWindow.getScaledHeight() - 23; + int x = mainWindow.getScaledWidth() / 2 - 88; + int y = mainWindow.getScaledHeight() - 19; RenderSystem.enableAlphaTest(); - AllGuiTextures.BLUEPRINT_SLOT.draw(this, x + 20 * slot, y); + AllGuiTextures.SCHEMATIC_SLOT.draw(this, x + 20 * slot, y); RenderSystem.disableAlphaTest(); } diff --git a/src/main/java/com/simibubi/create/content/schematics/client/SchematicPromptScreen.java b/src/main/java/com/simibubi/create/content/schematics/client/SchematicPromptScreen.java new file mode 100644 index 000000000..df3617635 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/schematics/client/SchematicPromptScreen.java @@ -0,0 +1,103 @@ +package com.simibubi.create.content.schematics.client; + +import org.lwjgl.glfw.GLFW; + +import com.simibubi.create.AllItems; +import com.simibubi.create.CreateClient; +import com.simibubi.create.foundation.gui.AbstractSimiScreen; +import com.simibubi.create.foundation.gui.AllGuiTextures; +import com.simibubi.create.foundation.gui.AllIcons; +import com.simibubi.create.foundation.gui.widgets.IconButton; +import com.simibubi.create.foundation.utility.Lang; + +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.widget.TextFieldWidget; + +public class SchematicPromptScreen extends AbstractSimiScreen { + + private final String title = Lang.translate("schematicAndQuill.title"); + private final String convertLabel = Lang.translate("schematicAndQuill.convert"); + private final String abortLabel = Lang.translate("action.discard"); + private final String confirmLabel = Lang.translate("action.saveToFile"); + + private TextFieldWidget nameField; + private IconButton confirm; + private IconButton abort; + private IconButton convert; + + @Override + public void init() { + super.init(); + AllGuiTextures background = AllGuiTextures.SCHEMATIC_PROMPT; + setWindowSize(background.width, background.height + 30); + + nameField = new TextFieldWidget(font, guiLeft + 49, guiTop + 26, 131, 10, ""); + nameField.setTextColor(-1); + nameField.setDisabledTextColour(-1); + nameField.setEnableBackgroundDrawing(false); + nameField.setMaxStringLength(35); + nameField.changeFocus(true); + + abort = new IconButton(guiLeft + 7, guiTop + 53, AllIcons.I_TRASH); + abort.setToolTip(abortLabel); + widgets.add(abort); + + confirm = new IconButton(guiLeft + 158, guiTop + 53, AllIcons.I_CONFIRM); + confirm.setToolTip(confirmLabel); + widgets.add(confirm); + + convert = new IconButton(guiLeft + 180, guiTop + 53, AllIcons.I_SCHEMATIC); + convert.setToolTip(convertLabel); + widgets.add(convert); + + widgets.add(confirm); + widgets.add(convert); + widgets.add(abort); + widgets.add(nameField); + } + + @Override + public void renderWindow(int mouseX, int mouseY, float partialTicks) { + AllGuiTextures.SCHEMATIC_PROMPT.draw(this, guiLeft, guiTop); + font.drawStringWithShadow(title, guiLeft + (sWidth / 2) - (font.getStringWidth(title) / 2), guiTop + 3, + 0xffffff); + itemRenderer.renderItemIntoGUI(AllItems.SCHEMATIC.asStack(), guiLeft + 22, guiTop + 23); + } + + @Override + public boolean keyPressed(int keyCode, int p_keyPressed_2_, int p_keyPressed_3_) { + if (keyCode == GLFW.GLFW_KEY_ENTER) { + confirm(false); + return true; + } + if (keyCode == 256 && this.shouldCloseOnEsc()) { + this.onClose(); + return true; + } + return nameField.keyPressed(keyCode, p_keyPressed_2_, p_keyPressed_3_); + } + + @Override + public boolean mouseClicked(double x, double y, int button) { + if (confirm.isHovered()) { + confirm(false); + return true; + } + if (abort.isHovered()) { + CreateClient.schematicAndQuillHandler.discard(); + Minecraft.getInstance().player.closeScreen(); + return true; + } + if (convert.isHovered()) { + confirm(true); + return true; + } + return super.mouseClicked(x, y, button); + } + + private void confirm(boolean convertImmediately) { + CreateClient.schematicAndQuillHandler.saveSchematic(nameField.getText(), convertImmediately); + Minecraft.getInstance().player.closeScreen(); + } + +} diff --git a/src/main/java/com/simibubi/create/content/schematics/packet/InstantSchematicPacket.java b/src/main/java/com/simibubi/create/content/schematics/packet/InstantSchematicPacket.java new file mode 100644 index 000000000..30a4fdcba --- /dev/null +++ b/src/main/java/com/simibubi/create/content/schematics/packet/InstantSchematicPacket.java @@ -0,0 +1,52 @@ +package com.simibubi.create.content.schematics.packet; + +import java.util.function.Supplier; + +import com.simibubi.create.Create; +import com.simibubi.create.foundation.networking.SimplePacketBase; + +import net.minecraft.entity.player.ServerPlayerEntity; +import net.minecraft.network.PacketBuffer; +import net.minecraft.util.math.BlockPos; +import net.minecraftforge.fml.network.NetworkEvent.Context; + +public class InstantSchematicPacket extends SimplePacketBase { + + private String name; + private BlockPos origin; + private BlockPos bounds; + + public InstantSchematicPacket(String name, BlockPos origin, BlockPos bounds) { + this.name = name; + this.origin = origin; + this.bounds = bounds; + } + + public InstantSchematicPacket(PacketBuffer buffer) { + name = buffer.readString(32767); + origin = buffer.readBlockPos(); + bounds = buffer.readBlockPos(); + } + + @Override + public void write(PacketBuffer buffer) { + buffer.writeString(name); + buffer.writeBlockPos(origin); + buffer.writeBlockPos(bounds); + } + + @Override + public void handle(Supplier context) { + context.get() + .enqueueWork(() -> { + ServerPlayerEntity player = context.get() + .getSender(); + if (player == null) + return; + Create.schematicReceiver.handleInstantSchematic(player, name, player.world, origin, bounds); + }); + context.get() + .setPacketHandled(true); + } + +} diff --git a/src/main/java/com/simibubi/create/foundation/gui/AllGuiTextures.java b/src/main/java/com/simibubi/create/foundation/gui/AllGuiTextures.java index 49d7882b6..dc0ddd181 100644 --- a/src/main/java/com/simibubi/create/foundation/gui/AllGuiTextures.java +++ b/src/main/java/com/simibubi/create/foundation/gui/AllGuiTextures.java @@ -13,43 +13,47 @@ public enum AllGuiTextures { // Inventories PLAYER_INVENTORY("player_inventory.png", 176, 108), - WAND_SYMMETRY("wand_symmetry.png", 207, 58), - BLOCKZAPPER("zapper.png", 217, 70), - TERRAINZAPPER("zapper.png", 0, 70, 217, 105), - TERRAINZAPPER_INACTIVE_PARAM("zapper.png", 0, 175, 14, 14), + WAND_OF_SYMMETRY("curiosities.png", 188, 99), + BLOCKZAPPER("curiosities.png", 0, 99, 214, 97), + TERRAINZAPPER("curiosities_2.png", 0, 0, 234, 101), + TERRAINZAPPER_INACTIVE_PARAM("curiosities_2.png", 238, 0, 18, 18), - SCHEMATIC_TABLE("schematic_table.png", 207, 89), - SCHEMATIC_TABLE_PROGRESS("schematic_table.png", 209, 0, 24, 17), - SCHEMATIC("schematic.png", 207, 95), + SCHEMATIC("schematics.png", 192, 121), + SCHEMATIC_SLOT("widgets.png", 54, 0, 16, 16), + SCHEMATIC_PROMPT("schematics_2.png", 213, 77), + HUD_BACKGROUND("overlay.png", 0, 0, 16, 16), - SCHEMATICANNON_BG("schematicannon.png", 247, 161), - SCHEMATICANNON_BG_FUEL("schematicannon.png", 247, 161), - SCHEMATICANNON_PROGRESS("schematicannon.png", 0, 161, 121, 16), - SCHEMATICANNON_PROGRESS_2("schematicannon.png", 122, 161, 16, 15), - SCHEMATICANNON_HIGHLIGHT("schematicannon.png", 0, 182, 28, 28), - SCHEMATICANNON_FUEL("schematicannon.png", 0, 215, 82, 4), - SCHEMATICANNON_FUEL_CREATIVE("schematicannon.png", 0, 219, 82, 4), + SCHEMATIC_TABLE("schematics.png", 0, 121, 214, 83), + SCHEMATIC_TABLE_PROGRESS("schematics.png", 0, 204, 84, 16), - FLEXCRATE("flex_crate_and_stockpile_switch.png", 125, 129), - FLEXCRATE_DOUBLE("double_flexcrate.png", 197, 129), - FLEXCRATE_LOCKED_SLOT("flex_crate_and_stockpile_switch.png", 138, 0, 18, 18), + SCHEMATICANNON_TOP("schematics_2.png", 0, 77, 213, 42), + SCHEMATICANNON_BOTTOM("schematics_2.png", 0, 119, 213, 99), + SCHEMATICANNON_PROGRESS("schematics_2.png", 76, 239, 114, 16), + SCHEMATICANNON_CHECKLIST_PROGRESS("schematics_2.png", 191, 240, 16, 14), + SCHEMATICANNON_HIGHLIGHT("schematics_2.png", 1, 229, 26, 26), + SCHEMATICANNON_FUEL("schematics_2.png", 28, 222, 47, 16), + SCHEMATICANNON_FUEL_CREATIVE("schematics_2.png", 28, 239, 47, 16), - STOCKSWITCH("flex_crate_and_stockpile_switch.png", 0, 129, 205, 93), - STOCKSWITCH_INTERVAL("flex_crate_and_stockpile_switch.png", 0, 222, 198, 17), - STOCKSWITCH_INTERVAL_END("flex_crate_and_stockpile_switch.png", 0, 239, 198, 17), - STOCKSWITCH_CURSOR_ON("flex_crate_and_stockpile_switch.png", 218, 129, 8, 21), - STOCKSWITCH_CURSOR_OFF("flex_crate_and_stockpile_switch.png", 226, 129, 8, 21), - STOCKSWITCH_BOUND_LEFT("flex_crate_and_stockpile_switch.png", 234, 129, 7, 21), - STOCKSWITCH_BOUND_RIGHT("flex_crate_and_stockpile_switch.png", 241, 129, 7, 21), + STOCKSWITCH("logistics.png", 182, 93), + STOCKSWITCH_ARROW_UP("logistics.png", 191, 0, 7, 24), + STOCKSWITCH_ARROW_DOWN("logistics.png", 198, 0, 7, 24), + STOCKSWITCH_CURSOR("logistics.png", 206, 0, 7, 16), + STOCKSWITCH_INTERVAL("logistics.png", 0, 93, 100, 18), + STOCKSWITCH_UNPOWERED_LANE("logistics.png", 36, 18, 102, 18), + STOCKSWITCH_POWERED_LANE("logistics.png", 36, 40, 102, 18), - FILTER("filter.png", 200, 100), - ATTRIBUTE_FILTER("filter.png", 0, 100, 200, 86), + ADJUSTABLE_CRATE("logistics_2.png", 124, 127), + ADJUSTABLE_DOUBLE_CRATE("logistics_2.png", 0, 127, 196, 127), + ADJUSTABLE_CRATE_LOCKED_SLOT("logistics_2.png", 125, 109, 18, 18), - SEQUENCER("sequencer.png", 156, 128), - SEQUENCER_INSTRUCTION("sequencer.png", 14, 47, 131, 18), - SEQUENCER_WAIT("sequencer.png", 14, 65, 131, 18), - SEQUENCER_END("sequencer.png", 14, 83, 131, 18), - SEQUENCER_EMPTY("sequencer.png", 14, 101, 131, 18), + FILTER("filters.png", 214, 97), + ATTRIBUTE_FILTER("filters.png", 0, 97, 241, 83), + + SEQUENCER("sequencer.png", 173, 159), + SEQUENCER_INSTRUCTION("sequencer.png", 0, 14, 162, 22), + SEQUENCER_WAIT("sequencer.png", 0, 58, 162, 22), + SEQUENCER_END("sequencer.png", 0, 80, 162, 22), + SEQUENCER_EMPTY("sequencer.png", 0, 102, 162, 22), // JEI JEI_SLOT("jei/widgets.png", 18, 18), @@ -64,19 +68,14 @@ public enum AllGuiTextures { BLOCKZAPPER_UPGRADE_RECIPE("jei/widgets.png", 0, 75, 144, 66), // Widgets - PALETTE_BUTTON("palette_picker.png", 0, 236, 20, 20), - TEXT_INPUT("widgets.png", 0, 28, 194, 47), BUTTON("widgets.png", 18, 18), BUTTON_HOVER("widgets.png", 18, 0, 18, 18), BUTTON_DOWN("widgets.png", 36, 0, 18, 18), - INDICATOR("widgets.png", 0, 18, 18, 5), - INDICATOR_WHITE("widgets.png", 18, 18, 18, 5), - INDICATOR_GREEN("widgets.png", 0, 23, 18, 5), - INDICATOR_YELLOW("widgets.png", 18, 23, 18, 5), - INDICATOR_RED("widgets.png", 36, 23, 18, 5), - GRAY("background.png", 0, 0, 16, 16), - - BLUEPRINT_SLOT("widgets.png", 90, 0, 24, 24), + INDICATOR("widgets.png", 0, 18, 18, 6), + INDICATOR_WHITE("widgets.png", 18, 18, 18, 6), + INDICATOR_GREEN("widgets.png", 36, 18, 18, 6), + INDICATOR_YELLOW("widgets.png", 54, 18, 18, 6), + INDICATOR_RED("widgets.png", 72, 18, 18, 6), ; diff --git a/src/main/java/com/simibubi/create/foundation/gui/AllIcons.java b/src/main/java/com/simibubi/create/foundation/gui/AllIcons.java index af547236b..d542bfb31 100644 --- a/src/main/java/com/simibubi/create/foundation/gui/AllIcons.java +++ b/src/main/java/com/simibubi/create/foundation/gui/AllIcons.java @@ -92,10 +92,14 @@ public class AllIcons { I_ARM_ROUND_ROBIN = next(), I_ARM_FORCED_ROUND_ROBIN = next(), I_ARM_PREFER_FIRST = next(), + + I_ADD_INVERTED_ATTRIBUTE = next(), + I_FLIP = next(), I_PLAY = newRow(), I_PAUSE = next(), I_STOP = next(), + I_PLACEMENT_SETTINGS = next(), I_PATTERN_SOLID = newRow(), I_PATTERN_CHECKERED = next(), @@ -105,7 +109,9 @@ public class AllIcons { I_PATTERN_CHANCE_50 = newRow(), I_PATTERN_CHANCE_75 = next(), I_FOLLOW_DIAGONAL = next(), - I_FOLLOW_MATERIAL = next(); + I_FOLLOW_MATERIAL = next(), + + I_SCHEMATIC = newRow(); public AllIcons(int x, int y) { iconX = x * 16; diff --git a/src/main/java/com/simibubi/create/foundation/gui/TextInputPromptScreen.java b/src/main/java/com/simibubi/create/foundation/gui/TextInputPromptScreen.java deleted file mode 100644 index 27a52be14..000000000 --- a/src/main/java/com/simibubi/create/foundation/gui/TextInputPromptScreen.java +++ /dev/null @@ -1,106 +0,0 @@ -package com.simibubi.create.foundation.gui; - -import java.util.function.Consumer; - -import org.lwjgl.glfw.GLFW; - -import com.simibubi.create.foundation.utility.Lang; - -import net.minecraft.client.gui.widget.TextFieldWidget; -import net.minecraft.client.gui.widget.button.Button; - -public class TextInputPromptScreen extends AbstractSimiScreen { - - private final String defaultConfirm = Lang.translate("action.confirm"); - private final String defaultAbort = Lang.translate("action.abort"); - - private Consumer callback; - private Consumer abortCallback; - - private TextFieldWidget nameField; - private Button confirm; - private Button abort; - - private String buttonTextConfirm; - private String buttonTextAbort; - private String title; - - private boolean confirmed; - - public TextInputPromptScreen(Consumer callBack, Consumer abortCallback) { - super(); - this.callback = callBack; - this.abortCallback = abortCallback; - - buttonTextConfirm = defaultConfirm; - buttonTextAbort = defaultAbort; - confirmed = false; - } - - @Override - public void init() { - super.init(); - setWindowSize(AllGuiTextures.TEXT_INPUT.width, AllGuiTextures.TEXT_INPUT.height + 30); - - this.nameField = new TextFieldWidget(font, guiLeft + 33, guiTop + 26, 128, 8, ""); - this.nameField.setTextColor(-1); - this.nameField.setDisabledTextColour(-1); - this.nameField.setEnableBackgroundDrawing(false); - this.nameField.setMaxStringLength(35); - this.nameField.changeFocus(true); - - confirm = new Button(guiLeft - 5, guiTop + 50, 100, 20, buttonTextConfirm, button -> { - callback.accept(nameField.getText()); - confirmed = true; - minecraft.displayGuiScreen(null); - }); - - abort = new Button(guiLeft + 100, guiTop + 50, 100, 20, buttonTextAbort, button -> { - minecraft.displayGuiScreen(null); - }); - - widgets.add(confirm); - widgets.add(abort); - widgets.add(nameField); - } - - @Override - public void renderWindow(int mouseX, int mouseY, float partialTicks) { - AllGuiTextures.TEXT_INPUT.draw(this, guiLeft, guiTop); - font.drawString(title, guiLeft + (sWidth / 2) - (font.getStringWidth(title) / 2), guiTop + 11, - AllGuiTextures.FONT_COLOR); - } - - @Override - public void removed() { - if (!confirmed) - abortCallback.accept(nameField.getText()); - super.removed(); - } - - public void setButtonTextConfirm(String buttonTextConfirm) { - this.buttonTextConfirm = buttonTextConfirm; - } - - public void setButtonTextAbort(String buttonTextAbort) { - this.buttonTextAbort = buttonTextAbort; - } - - public void setTitle(String title) { - this.title = title; - } - - @Override - public boolean keyPressed(int keyCode, int p_keyPressed_2_, int p_keyPressed_3_) { - if (keyCode == GLFW.GLFW_KEY_ENTER) { - confirm.onPress(); - return true; - } - if (keyCode == 256 && this.shouldCloseOnEsc()) { - this.onClose(); - return true; - } - return nameField.keyPressed(keyCode, p_keyPressed_2_, p_keyPressed_3_); - } - -} diff --git a/src/main/java/com/simibubi/create/foundation/gui/ToolSelectionScreen.java b/src/main/java/com/simibubi/create/foundation/gui/ToolSelectionScreen.java index 8ec08b02c..d49a94861 100644 --- a/src/main/java/com/simibubi/create/foundation/gui/ToolSelectionScreen.java +++ b/src/main/java/com/simibubi/create/foundation/gui/ToolSelectionScreen.java @@ -63,7 +63,7 @@ public class ToolSelectionScreen extends Screen { RenderSystem.pushMatrix(); RenderSystem.translatef(0, -yOffset, focused ? 100 : 0); - AllGuiTextures gray = AllGuiTextures.GRAY; + AllGuiTextures gray = AllGuiTextures.HUD_BACKGROUND; RenderSystem.enableBlend(); RenderSystem.color4f(1, 1, 1, focused ? 7 / 8f : 1 / 2f); diff --git a/src/main/java/com/simibubi/create/foundation/gui/widgets/ScrollInput.java b/src/main/java/com/simibubi/create/foundation/gui/widgets/ScrollInput.java index 415fae287..69fda4a82 100644 --- a/src/main/java/com/simibubi/create/foundation/gui/widgets/ScrollInput.java +++ b/src/main/java/com/simibubi/create/foundation/gui/widgets/ScrollInput.java @@ -45,6 +45,11 @@ public class ScrollInput extends AbstractSimiWidget { this.onScroll = onScroll; return this; } + + public ScrollInput removeCallback() { + this.onScroll = null; + return this; + } public ScrollInput titled(String title) { this.title = title; diff --git a/src/main/java/com/simibubi/create/foundation/networking/AllPackets.java b/src/main/java/com/simibubi/create/foundation/networking/AllPackets.java index 5200f3255..ed8de400c 100644 --- a/src/main/java/com/simibubi/create/foundation/networking/AllPackets.java +++ b/src/main/java/com/simibubi/create/foundation/networking/AllPackets.java @@ -23,6 +23,7 @@ import com.simibubi.create.content.logistics.item.filter.FilterScreenPacket; import com.simibubi.create.content.logistics.packet.ConfigureFlexcratePacket; import com.simibubi.create.content.logistics.packet.ConfigureStockswitchPacket; import com.simibubi.create.content.schematics.packet.ConfigureSchematicannonPacket; +import com.simibubi.create.content.schematics.packet.InstantSchematicPacket; import com.simibubi.create.content.schematics.packet.SchematicPlacePacket; import com.simibubi.create.content.schematics.packet.SchematicUploadPacket; import com.simibubi.create.foundation.command.ConfigureConfigPacket; @@ -55,6 +56,7 @@ public enum AllPackets { PLACE_ARM(ArmPlacementPacket.class, ArmPlacementPacket::new), MINECART_COUPLING_CREATION(MinecartCouplingCreationPacket.class, MinecartCouplingCreationPacket::new), PERSISTANT_DATA_REQUEST(PersistantDataPacketRequest.class, PersistantDataPacketRequest::new), + INSTANT_SCHEMATIC(InstantSchematicPacket.class, InstantSchematicPacket::new), // Server to Client SYMMETRY_EFFECT(SymmetryEffectPacket.class, SymmetryEffectPacket::new), diff --git a/src/main/resources/assets/create/lang/default/messages.json b/src/main/resources/assets/create/lang/default/messages.json index 0c2536fc2..7ef4f7db8 100644 --- a/src/main/resources/assets/create/lang/default/messages.json +++ b/src/main/resources/assets/create/lang/default/messages.json @@ -158,13 +158,10 @@ "create.gui.adjustable_crate.storageSpace": "Storage Space", "create.gui.stockpile_switch.title": "Stockpile Switch", - "create.gui.stockpile_switch.lowerLimit": "Lower Threshold", - "create.gui.stockpile_switch.upperLimit": "Upper Threshold", - "create.gui.stockpile_switch.startAt": "Start Signal at", - "create.gui.stockpile_switch.startAbove": "Start Signal above", - "create.gui.stockpile_switch.stopAt": "Stop Signal at", - "create.gui.stockpile_switch.stopBelow": "Stop Signal below", - + "create.gui.stockpile_switch.invert_signal": "Invert Signal", + "create.gui.stockpile_switch.move_to_lower_at": "Move to lower lane at %1$s%%", + "create.gui.stockpile_switch.move_to_upper_at": "Move to upper lane at %1$s%%", + "create.gui.sequenced_gearshift.title": "Sequenced Gearshift", "create.gui.sequenced_gearshift.instruction": "Instruction", "create.gui.sequenced_gearshift.instruction.turn_angle": "Turn", @@ -185,7 +182,8 @@ "create.schematicAndQuill.secondPos": "Second position set.", "create.schematicAndQuill.noTarget": "Hold [Ctrl] to select Air blocks.", "create.schematicAndQuill.abort": "Removed selection.", - "create.schematicAndQuill.prompt": "Enter a name for the Schematic:", + "create.schematicAndQuill.title": "Schematic Name:", + "create.schematicAndQuill.convert": "Save and Deploy Immediately", "create.schematicAndQuill.fallbackName": "My Schematic", "create.schematicAndQuill.saved": "Saved as %1$s", @@ -234,9 +232,12 @@ "create.schematic.tool.flip.description.3": "", "create.schematics.synchronizing": "Syncing...", - "create.schematics.uploadTooLarge": "Your schematic is too big.", + "create.schematics.uploadTooLarge": "Your schematic exceeds limitations specified by the server.", "create.schematics.maxAllowedSize": "The maximum allowed schematic file size is:", + "create.gui.schematicTable.title": "Schematic Table", + "create.gui.schematicTable.refresh": "Refresh Files", + "create.gui.schematicTable.open_folder": "Open Folder", "create.gui.schematicTable.title": "Schematic Table", "create.gui.schematicTable.availableSchematics": "Available Schematics", "create.gui.schematicTable.noSchematics": "No Schematics Saved", @@ -244,19 +245,23 @@ "create.gui.schematicTable.finished": "Upload Finished!", "create.gui.schematicannon.title": "Schematicannon", - "create.gui.schematicannon.settingsTitle": "Placement Settings", - "create.gui.schematicannon.listPrinter": "Material List Printer", + "create.gui.schematicannon.listPrinter": "Checklist Printer", "create.gui.schematicannon.gunpowderLevel": "Gunpowder at %1$s%%", "create.gui.schematicannon.shotsRemaining": "Shots left: %1$s", "create.gui.schematicannon.shotsRemainingWithBackup": "With backup: %1$s", "create.gui.schematicannon.optionEnabled": "Currently Enabled", "create.gui.schematicannon.optionDisabled": "Currently Disabled", + "create.gui.schematicannon.showOptions": "Show Printer Settings", "create.gui.schematicannon.option.dontReplaceSolid": "Don't Replace Solid Blocks", "create.gui.schematicannon.option.replaceWithSolid": "Replace Solid with Solid", "create.gui.schematicannon.option.replaceWithAny": "Replace Solid with Any", "create.gui.schematicannon.option.replaceWithEmpty": "Replace Solid with Empty", "create.gui.schematicannon.option.skipMissing": "Skip missing Blocks", "create.gui.schematicannon.option.skipTileEntities": "Protect Tile Entities", + + "create.gui.schematicannon.slot.gunpowder": "Add gunpowder to fuel the cannon", + "create.gui.schematicannon.slot.listPrinter": "Place books here to print a Checklist for your Schematic", + "create.gui.schematicannon.slot.schematic": "Add your Schematic here. Make sure it is deployed at a specific location.", "create.gui.schematicannon.option.skipMissing.description": "If the cannon cannot find a required Block for placement, it will continue at the next Location.", "create.gui.schematicannon.option.skipTileEntities.description": "The cannon will avoid replacing data holding blocks such as Chests.", @@ -293,23 +298,42 @@ "create.gui.filter.ignore_data.description": "Items match regardless of their attributes.", "create.item_attributes.placeable": "is placeable", + "create.item_attributes.placeable.inverted": "is not placeable", "create.item_attributes.consumable": "can be eaten", + "create.item_attributes.consumable.inverted": "cannot be eaten", "create.item_attributes.smeltable": "can be Smelted", + "create.item_attributes.smeltable.inverted": "cannot be Smelted", "create.item_attributes.washable": "can be Washed", + "create.item_attributes.washable.inverted": "cannot be Washed", "create.item_attributes.smokable": "can be Smoked", + "create.item_attributes.smokable.inverted": "cannot be Smoked", + "create.item_attributes.crushable": "can be Crushed", + "create.item_attributes.crushable.inverted": "cannot be Crushed", "create.item_attributes.blastable": "is smeltable in Blast Furnace", + "create.item_attributes.blastable.inverted": "is not smeltable in Blast Furnace", "create.item_attributes.enchanted": "is enchanted", + "create.item_attributes.enchanted.inverted": "is unenchanted", "create.item_attributes.damaged": "is damaged", + "create.item_attributes.damaged.inverted": "is not damaged", "create.item_attributes.badly_damaged": "is heavily damaged", + "create.item_attributes.badly_damaged.inverted": "is not heavily damaged", "create.item_attributes.not_stackable": "cannot stack", + "create.item_attributes.not_stackable.inverted": "can be stacked", "create.item_attributes.equipable": "can be equipped", + "create.item_attributes.equipable.inverted": "cannot be equipped", "create.item_attributes.furnace_fuel": "is furnace fuel", + "create.item_attributes.furnace_fuel.inverted": "is not furnace fuel", "create.item_attributes.in_tag": "is tagged %1$s", - "create.item_attributes.in_item_group": "belongs to %1$s", + "create.item_attributes.in_tag.inverted": "is not tagged %1$s", + "create.item_attributes.in_item_group": "is in group '%1$s'", + "create.item_attributes.in_item_group.inverted": "is not in group '%1$s'", "create.item_attributes.added_by": "was added by %1$s", + "create.item_attributes.added_by.inverted": "was not added by %1$s", "create.gui.attribute_filter.no_selected_attributes": "No attributes selected", "create.gui.attribute_filter.selected_attributes": "Selected attributes:", + "create.gui.attribute_filter.add_attribute": "Add attribute to List", + "create.gui.attribute_filter.add_inverted_attribute": "Add opposite attribute to List", "create.gui.attribute_filter.whitelist_disjunctive": "Whitelist (Any)", "create.gui.attribute_filter.whitelist_disjunctive.description": "Items pass if they have any of the selected attributes.", "create.gui.attribute_filter.whitelist_conjunctive": "Whitelist (All)", diff --git a/src/main/resources/assets/create/models/block/symmetry_effect/crossplane.json b/src/main/resources/assets/create/models/block/symmetry_effect/crossplane.json index fede15ab1..0fdbb9668 100644 --- a/src/main/resources/assets/create/models/block/symmetry_effect/crossplane.json +++ b/src/main/resources/assets/create/models/block/symmetry_effect/crossplane.json @@ -1,144 +1,143 @@ { - "__comment": "Model generated using MrCrayfish's Model Creator (http://mrcrayfish.com/modelcreator/)", - "textures": { - "0": "block/white_stained_glass", - "1": "block/obsidian", - "2": "block/packed_ice" - }, - "elements": [ - { - "name": "Mirror", - "from": [ 4.0, 1.0, 7.500000007450581 ], - "to": [ 7.0, 12.0, 8.50000000745058 ], - "faces": { - "north": { "texture": "#0", "uv": [ 4.0, 1.0, 7.0, 12.0 ] }, - "east": { "texture": "#0", "uv": [ 3.0, 1.0, 4.0, 12.0 ] }, - "south": { "texture": "#0", "uv": [ 4.0, 1.0, 7.0, 12.0 ] }, - "west": { "texture": "#0", "uv": [ 12.0, 1.0, 13.0, 12.0 ] }, - "up": { "texture": "#0", "uv": [ 4.0, 1.0, 7.0, 2.0 ] }, - "down": { "texture": "#0", "uv": [ 4.0, 14.0, 7.0, 15.0 ] } - } - }, - { - "name": "rod_left_bottom", - "from": [ 1.2000000029802322, 3.0, 7.0 ], - "to": [ 3.2000000029802322, 4.0, 9.0 ], - "rotation": { "origin": [ 8.0, 8.0, 8.0 ], "axis": "y", "angle": -22.5 }, - "faces": { - "north": { "texture": "#1", "uv": [ 0.0, 0.0, 2.0, 1.0 ] }, - "east": { "texture": "#1", "uv": [ 0.0, 0.0, 2.0, 1.0 ] }, - "south": { "texture": "#1", "uv": [ 0.0, 0.0, 2.0, 1.0 ] }, - "west": { "texture": "#1", "uv": [ 0.0, 0.0, 2.0, 1.0 ] }, - "up": { "texture": "#1", "uv": [ 0.0, 0.0, 2.0, 2.0 ] }, - "down": { "texture": "#1", "uv": [ 0.0, 0.0, 2.0, 2.0 ] } - } - }, - { - "name": "rod_left_top", - "from": [ 1.2000000029802322, 12.0, 7.0 ], - "to": [ 3.2000000029802322, 13.0, 9.0 ], - "rotation": { "origin": [ 8.0, 8.0, 8.0 ], "axis": "y", "angle": -22.5 }, - "faces": { - "north": { "texture": "#1", "uv": [ 0.0, 0.0, 2.0, 1.0 ] }, - "east": { "texture": "#1", "uv": [ 0.0, 0.0, 2.0, 1.0 ] }, - "south": { "texture": "#1", "uv": [ 0.0, 0.0, 2.0, 1.0 ] }, - "west": { "texture": "#1", "uv": [ 0.0, 0.0, 2.0, 1.0 ] }, - "up": { "texture": "#1", "uv": [ 0.0, 0.0, 2.0, 2.0 ] }, - "down": { "texture": "#1", "uv": [ 0.0, 0.0, 2.0, 2.0 ] } - } - }, - { - "name": "rod_left", - "from": [ 2.0, 4.0, 7.499999992549419 ], - "to": [ 3.0, 12.0, 8.49999999254942 ], - "shade": false, - "rotation": { "origin": [ 8.0, 8.0, 8.0 ], "axis": "y", "angle": -22.5 }, - "faces": { - "north": { "texture": "#2", "uv": [ 3.0, 1.0, 4.0, 9.0 ] }, - "east": { "texture": "#2", "uv": [ 3.0, 0.0, 4.0, 8.0 ] }, - "south": { "texture": "#2", "uv": [ 3.0, 1.0, 4.0, 9.0 ] }, - "west": { "texture": "#2", "uv": [ 5.0, 1.0, 6.0, 9.0 ] } - } - }, - { - "name": "rod_right_bottom", - "from": [ 12.799999997019768, 3.0, 7.0 ], - "to": [ 14.799999997019768, 4.0, 9.0 ], - "rotation": { "origin": [ 8.0, 8.0, 8.0 ], "axis": "y", "angle": -22.5 }, - "faces": { - "north": { "texture": "#1", "uv": [ 0.0, 0.0, 2.0, 1.0 ] }, - "east": { "texture": "#1", "uv": [ 0.0, 0.0, 2.0, 1.0 ] }, - "south": { "texture": "#1", "uv": [ 0.0, 0.0, 2.0, 1.0 ] }, - "west": { "texture": "#1", "uv": [ 0.0, 0.0, 2.0, 1.0 ] }, - "up": { "texture": "#1", "uv": [ 0.0, 0.0, 2.0, 2.0 ] }, - "down": { "texture": "#1", "uv": [ 0.0, 0.0, 2.0, 2.0 ] } - } - }, - { - "name": "rod_right", - "from": [ 13.0, 4.0, 7.499999992549419 ], - "to": [ 14.0, 12.0, 8.49999999254942 ], - "shade": false, - "rotation": { "origin": [ 8.0, 8.0, 8.0 ], "axis": "y", "angle": -22.5 }, - "faces": { - "north": { "texture": "#2", "uv": [ 3.0, 2.0, 4.0, 10.0 ] }, - "east": { "texture": "#2", "uv": [ 3.0, 3.0, 4.0, 11.0 ] }, - "south": { "texture": "#2", "uv": [ 4.0, 3.0, 5.0, 11.0 ] }, - "west": { "texture": "#2", "uv": [ 5.0, 0.0, 6.0, 8.0 ] } - } - }, - { - "name": "rod_right_top", - "from": [ 12.799999997019768, 12.0, 7.0 ], - "to": [ 14.799999997019768, 13.0, 9.0 ], - "rotation": { "origin": [ 8.0, 8.0, 8.0 ], "axis": "y", "angle": -22.5 }, - "faces": { - "north": { "texture": "#1", "uv": [ 0.0, 0.0, 2.0, 1.0 ] }, - "east": { "texture": "#1", "uv": [ 0.0, 0.0, 2.0, 1.0 ] }, - "south": { "texture": "#1", "uv": [ 0.0, 0.0, 2.0, 1.0 ] }, - "west": { "texture": "#1", "uv": [ 0.0, 0.0, 2.0, 1.0 ] }, - "up": { "texture": "#1", "uv": [ 0.0, 0.0, 2.0, 2.0 ] }, - "down": { "texture": "#1", "uv": [ 0.0, 0.0, 2.0, 2.0 ] } - } - }, - { - "name": "CrossMirror", - "from": [ 7.499999992549419, 4.0, 9.50000000745058 ], - "to": [ 8.49999999254942, 15.0, 12.50000000745058 ], - "faces": { - "north": { "texture": "#0", "uv": [ 4.0, 1.0, 5.0, 12.0 ] }, - "east": { "texture": "#0", "uv": [ 3.0, 1.0, 6.0, 12.0 ] }, - "south": { "texture": "#0", "uv": [ 4.0, 1.0, 5.0, 12.0 ] }, - "west": { "texture": "#0", "uv": [ 9.0, 1.0, 12.0, 12.0 ] }, - "up": { "texture": "#0", "uv": [ 3.0, 3.0, 4.0, 6.0 ] }, - "down": { "texture": "#0", "uv": [ 5.0, 9.0, 6.0, 12.0 ] } - } - }, - { - "name": "Mirror II", - "from": [ 9.0, 3.0, 7.500000007450581 ], - "to": [ 12.0, 14.0, 8.50000000745058 ], - "faces": { - "north": { "texture": "#0", "uv": [ 4.0, 1.0, 7.0, 12.0 ] }, - "east": { "texture": "#0", "uv": [ 3.0, 1.0, 4.0, 12.0 ] }, - "south": { "texture": "#0", "uv": [ 4.0, 1.0, 7.0, 12.0 ] }, - "west": { "texture": "#0", "uv": [ 12.0, 1.0, 13.0, 12.0 ] }, - "up": { "texture": "#0", "uv": [ 4.0, 1.0, 7.0, 2.0 ] }, - "down": { "texture": "#0", "uv": [ 4.0, 14.0, 7.0, 15.0 ] } - } - }, - { - "name": "CrossMirror II", - "from": [ 7.499999992549419, 2.0, 3.5000000074505806 ], - "to": [ 8.49999999254942, 13.0, 6.500000007450581 ], - "faces": { - "north": { "texture": "#0", "uv": [ 4.0, 1.0, 5.0, 12.0 ] }, - "east": { "texture": "#0", "uv": [ 3.0, 1.0, 6.0, 12.0 ] }, - "south": { "texture": "#0", "uv": [ 4.0, 3.0, 5.0, 14.0 ] }, - "west": { "texture": "#0", "uv": [ 9.0, 2.0, 12.0, 13.0 ] }, - "up": { "texture": "#0", "uv": [ 4.0, 3.0, 5.0, 6.0 ] }, - "down": { "texture": "#0", "uv": [ 4.0, 8.0, 5.0, 11.0 ] } - } - } - ] + "credit": "Made with Blockbench", + "textures": { + "0": "create:block/symmetry_mirror", + "2": "create:block/brass_block" + }, + "elements": [ + { + "name": "Mirror", + "from": [4, 1, 7.5], + "to": [7, 12, 8.5], + "faces": { + "north": {"uv": [4, 1, 7, 12], "texture": "#0"}, + "east": {"uv": [3, 1, 4, 12], "texture": "#0"}, + "south": {"uv": [4, 1, 7, 12], "texture": "#0"}, + "west": {"uv": [12, 1, 13, 12], "texture": "#0"}, + "up": {"uv": [4, 1, 7, 2], "texture": "#0"}, + "down": {"uv": [4, 14, 7, 15], "texture": "#0"} + } + }, + { + "name": "rod_left_bottom", + "from": [1, 3, 7], + "to": [3, 4, 9], + "rotation": {"angle": -22.5, "axis": "y", "origin": [8, 8, 8]}, + "faces": { + "north": {"uv": [0, 0, 2, 1], "texture": "#2"}, + "east": {"uv": [0, 0, 2, 1], "texture": "#2"}, + "south": {"uv": [0, 0, 2, 1], "texture": "#2"}, + "west": {"uv": [0, 0, 2, 1], "texture": "#2"}, + "up": {"uv": [13, 13, 15, 15], "texture": "#2"}, + "down": {"uv": [13, 13, 15, 15], "texture": "#2"} + } + }, + { + "name": "rod_left_bottom", + "from": [13, 3, 7], + "to": [15, 4, 9], + "rotation": {"angle": -22.5, "axis": "y", "origin": [8, 8, 8]}, + "faces": { + "north": {"uv": [0, 0, 2, 1], "texture": "#2"}, + "east": {"uv": [0, 0, 2, 1], "texture": "#2"}, + "south": {"uv": [0, 0, 2, 1], "texture": "#2"}, + "west": {"uv": [0, 0, 2, 1], "texture": "#2"}, + "up": {"uv": [13, 13, 15, 15], "rotation": 180, "texture": "#2"}, + "down": {"uv": [13, 13, 15, 15], "rotation": 180, "texture": "#2"} + } + }, + { + "name": "rod_left_top", + "from": [1, 12, 7], + "to": [3, 13, 9], + "rotation": {"angle": -22.5, "axis": "y", "origin": [8, 8, 8]}, + "faces": { + "north": {"uv": [0, 0, 2, 1], "texture": "#2"}, + "east": {"uv": [0, 0, 2, 1], "texture": "#2"}, + "south": {"uv": [0, 0, 2, 1], "texture": "#2"}, + "west": {"uv": [0, 0, 2, 1], "texture": "#2"}, + "up": {"uv": [13, 13, 15, 15], "texture": "#2"}, + "down": {"uv": [13, 13, 15, 15], "texture": "#2"} + } + }, + { + "name": "rod_left_top", + "from": [13, 12, 7], + "to": [15, 13, 9], + "rotation": {"angle": -22.5, "axis": "y", "origin": [8, 8, 8]}, + "faces": { + "north": {"uv": [0, 0, 2, 1], "texture": "#2"}, + "east": {"uv": [0, 0, 2, 1], "texture": "#2"}, + "south": {"uv": [0, 0, 2, 1], "texture": "#2"}, + "west": {"uv": [0, 0, 2, 1], "texture": "#2"}, + "up": {"uv": [13, 13, 15, 15], "rotation": 180, "texture": "#2"}, + "down": {"uv": [13, 13, 15, 15], "rotation": 180, "texture": "#2"} + } + }, + { + "name": "rod_left", + "from": [1, 4, 7.5], + "to": [3, 12, 8.5], + "shade": false, + "rotation": {"angle": -22.5, "axis": "y", "origin": [8, 8, 8]}, + "faces": { + "north": {"uv": [3, 5, 1, 13], "texture": "#2"}, + "east": {"uv": [8, 4, 9, 12], "texture": "#2"}, + "south": {"uv": [1, 3, 3, 11], "texture": "#2"}, + "west": {"uv": [1, 6, 2, 14], "texture": "#2"} + } + }, + { + "name": "rod_left", + "from": [13, 4, 7.5], + "to": [15, 12, 8.5], + "shade": false, + "rotation": {"angle": -22.5, "axis": "y", "origin": [8, 8, 8]}, + "faces": { + "north": {"uv": [1, 3, 3, 11], "texture": "#2"}, + "east": {"uv": [1, 6, 2, 14], "texture": "#2"}, + "south": {"uv": [3, 5, 1, 13], "texture": "#2"}, + "west": {"uv": [8, 4, 9, 12], "texture": "#2"} + } + }, + { + "name": "CrossMirror", + "from": [7.5, 4, 9.5], + "to": [8.5, 15, 12.5], + "faces": { + "north": {"uv": [4, 1, 5, 12], "texture": "#0"}, + "east": {"uv": [3, 1, 6, 12], "texture": "#0"}, + "south": {"uv": [4, 1, 5, 12], "texture": "#0"}, + "west": {"uv": [9, 1, 12, 12], "texture": "#0"}, + "up": {"uv": [3, 3, 4, 6], "texture": "#0"}, + "down": {"uv": [5, 9, 6, 12], "texture": "#0"} + } + }, + { + "name": "Mirror II", + "from": [9, 3, 7.5], + "to": [12, 14, 8.5], + "faces": { + "north": {"uv": [4, 1, 7, 12], "texture": "#0"}, + "east": {"uv": [3, 1, 4, 12], "texture": "#0"}, + "south": {"uv": [4, 1, 7, 12], "texture": "#0"}, + "west": {"uv": [12, 1, 13, 12], "texture": "#0"}, + "up": {"uv": [4, 1, 7, 2], "texture": "#0"}, + "down": {"uv": [4, 14, 7, 15], "texture": "#0"} + } + }, + { + "name": "CrossMirror II", + "from": [7.5, 2, 3.5], + "to": [8.5, 13, 6.5], + "faces": { + "north": {"uv": [4, 1, 5, 12], "texture": "#0"}, + "east": {"uv": [3, 1, 6, 12], "texture": "#0"}, + "south": {"uv": [4, 3, 5, 14], "texture": "#0"}, + "west": {"uv": [9, 2, 12, 13], "texture": "#0"}, + "up": {"uv": [4, 3, 5, 6], "texture": "#0"}, + "down": {"uv": [4, 8, 5, 11], "texture": "#0"} + } + } + ] } \ No newline at end of file diff --git a/src/main/resources/assets/create/models/block/symmetry_effect/plane.json b/src/main/resources/assets/create/models/block/symmetry_effect/plane.json index 5d36206de..5717ed96f 100644 --- a/src/main/resources/assets/create/models/block/symmetry_effect/plane.json +++ b/src/main/resources/assets/create/models/block/symmetry_effect/plane.json @@ -1,99 +1,105 @@ { - "__comment": "Model generated using MrCrayfish's Model Creator (http://mrcrayfish.com/modelcreator/)", - "textures": { - "0": "block/white_stained_glass", - "1": "block/obsidian", - "2": "block/packed_ice" - }, - "elements": [ - { - "name": "Mirror", - "from": [ 4.0, 1.0, 7.500000007450581 ], - "to": [ 12.0, 15.0, 8.50000000745058 ], - "faces": { - "north": { "texture": "#0", "uv": [ 4.0, 1.0, 12.0, 15.0 ] }, - "east": { "texture": "#0", "uv": [ 3.0, 1.0, 4.0, 15.0 ] }, - "south": { "texture": "#0", "uv": [ 4.0, 1.0, 12.0, 15.0 ] }, - "west": { "texture": "#0", "uv": [ 12.0, 1.0, 13.0, 15.0 ] }, - "up": { "texture": "#0", "uv": [ 4.0, 1.0, 12.0, 2.0 ] }, - "down": { "texture": "#0", "uv": [ 4.0, 14.0, 12.0, 15.0 ] } - } - }, - { - "name": "rod_left_bottom", - "from": [ 1.2000000029802322, 3.0, 7.0 ], - "to": [ 3.2000000029802322, 4.0, 9.0 ], - "faces": { - "north": { "texture": "#1", "uv": [ 0.0, 0.0, 2.0, 1.0 ] }, - "east": { "texture": "#1", "uv": [ 0.0, 0.0, 2.0, 1.0 ] }, - "south": { "texture": "#1", "uv": [ 0.0, 0.0, 2.0, 1.0 ] }, - "west": { "texture": "#1", "uv": [ 0.0, 0.0, 2.0, 1.0 ] }, - "up": { "texture": "#1", "uv": [ 0.0, 0.0, 2.0, 2.0 ] }, - "down": { "texture": "#1", "uv": [ 0.0, 0.0, 2.0, 2.0 ] } - } - }, - { - "name": "rod_left_top", - "from": [ 1.2000000029802322, 12.0, 7.0 ], - "to": [ 3.2000000029802322, 13.0, 9.0 ], - "faces": { - "north": { "texture": "#1", "uv": [ 0.0, 0.0, 2.0, 1.0 ] }, - "east": { "texture": "#1", "uv": [ 0.0, 0.0, 2.0, 1.0 ] }, - "south": { "texture": "#1", "uv": [ 0.0, 0.0, 2.0, 1.0 ] }, - "west": { "texture": "#1", "uv": [ 0.0, 0.0, 2.0, 1.0 ] }, - "up": { "texture": "#1", "uv": [ 0.0, 0.0, 2.0, 2.0 ] }, - "down": { "texture": "#1", "uv": [ 0.0, 0.0, 2.0, 2.0 ] } - } - }, - { - "name": "rod_left", - "from": [ 2.0, 4.0, 7.499999992549419 ], - "to": [ 3.0, 12.0, 8.49999999254942 ], - "shade": false, - "faces": { - "north": { "texture": "#2", "uv": [ 3.0, 1.0, 4.0, 9.0 ] }, - "east": { "texture": "#2", "uv": [ 3.0, 0.0, 4.0, 8.0 ] }, - "south": { "texture": "#2", "uv": [ 3.0, 1.0, 4.0, 9.0 ] }, - "west": { "texture": "#2", "uv": [ 5.0, 1.0, 6.0, 9.0 ] } - } - }, - { - "name": "rod_right_bottom", - "from": [ 12.799999997019768, 3.0, 7.0 ], - "to": [ 14.799999997019768, 4.0, 9.0 ], - "faces": { - "north": { "texture": "#1", "uv": [ 0.0, 0.0, 2.0, 1.0 ] }, - "east": { "texture": "#1", "uv": [ 0.0, 0.0, 2.0, 1.0 ] }, - "south": { "texture": "#1", "uv": [ 0.0, 0.0, 2.0, 1.0 ] }, - "west": { "texture": "#1", "uv": [ 0.0, 0.0, 2.0, 1.0 ] }, - "up": { "texture": "#1", "uv": [ 0.0, 0.0, 2.0, 2.0 ] }, - "down": { "texture": "#1", "uv": [ 0.0, 0.0, 2.0, 2.0 ] } - } - }, - { - "name": "rod_right", - "from": [ 13.0, 4.0, 7.499999992549419 ], - "to": [ 14.0, 12.0, 8.49999999254942 ], - "shade": false, - "faces": { - "north": { "texture": "#2", "uv": [ 3.0, 2.0, 4.0, 10.0 ] }, - "east": { "texture": "#2", "uv": [ 3.0, 3.0, 4.0, 11.0 ] }, - "south": { "texture": "#2", "uv": [ 4.0, 3.0, 5.0, 11.0 ] }, - "west": { "texture": "#2", "uv": [ 5.0, 0.0, 6.0, 8.0 ] } - } - }, - { - "name": "rod_right_top", - "from": [ 12.799999997019768, 12.0, 7.0 ], - "to": [ 14.799999997019768, 13.0, 9.0 ], - "faces": { - "north": { "texture": "#1", "uv": [ 0.0, 0.0, 2.0, 1.0 ] }, - "east": { "texture": "#1", "uv": [ 0.0, 0.0, 2.0, 1.0 ] }, - "south": { "texture": "#1", "uv": [ 0.0, 0.0, 2.0, 1.0 ] }, - "west": { "texture": "#1", "uv": [ 0.0, 0.0, 2.0, 1.0 ] }, - "up": { "texture": "#1", "uv": [ 0.0, 0.0, 2.0, 2.0 ] }, - "down": { "texture": "#1", "uv": [ 0.0, 0.0, 2.0, 2.0 ] } - } - } - ] + "credit": "Made with Blockbench", + "textures": { + "0": "create:block/symmetry_mirror", + "1_2": "create:block/brass_block" + }, + "elements": [ + { + "name": "Mirror", + "from": [4, 1, 7.5], + "to": [12, 15, 8.5], + "faces": { + "north": {"uv": [4, 1, 12, 15], "texture": "#0"}, + "east": {"uv": [3, 1, 4, 15], "texture": "#0"}, + "south": {"uv": [4, 1, 12, 15], "texture": "#0"}, + "west": {"uv": [12, 1, 13, 15], "texture": "#0"}, + "up": {"uv": [4, 1, 12, 2], "texture": "#0"}, + "down": {"uv": [4, 14, 12, 15], "texture": "#0"} + } + }, + { + "name": "rod_left_bottom", + "from": [1, 3, 7], + "to": [3, 4, 9], + "faces": { + "north": {"uv": [0, 0, 2, 1], "texture": "#1_2"}, + "east": {"uv": [0, 0, 2, 1], "texture": "#1_2"}, + "south": {"uv": [0, 0, 2, 1], "texture": "#1_2"}, + "west": {"uv": [0, 0, 2, 1], "texture": "#1_2"}, + "up": {"uv": [13, 13, 15, 15], "texture": "#1_2"}, + "down": {"uv": [13, 13, 15, 15], "texture": "#1_2"} + } + }, + { + "name": "rod_left_bottom", + "from": [13, 3, 7], + "to": [15, 4, 9], + "faces": { + "north": {"uv": [0, 0, 2, 1], "texture": "#1_2"}, + "east": {"uv": [0, 0, 2, 1], "texture": "#1_2"}, + "south": {"uv": [0, 0, 2, 1], "texture": "#1_2"}, + "west": {"uv": [0, 0, 2, 1], "texture": "#1_2"}, + "up": {"uv": [13, 13, 15, 15], "rotation": 180, "texture": "#1_2"}, + "down": {"uv": [13, 13, 15, 15], "rotation": 180, "texture": "#1_2"} + } + }, + { + "name": "rod_left_top", + "from": [1, 12, 7], + "to": [3, 13, 9], + "faces": { + "north": {"uv": [0, 0, 2, 1], "texture": "#1_2"}, + "east": {"uv": [0, 0, 2, 1], "texture": "#1_2"}, + "south": {"uv": [0, 0, 2, 1], "texture": "#1_2"}, + "west": {"uv": [0, 0, 2, 1], "texture": "#1_2"}, + "up": {"uv": [13, 13, 15, 15], "texture": "#1_2"}, + "down": {"uv": [13, 13, 15, 15], "texture": "#1_2"} + } + }, + { + "name": "rod_left_top", + "from": [13, 12, 7], + "to": [15, 13, 9], + "faces": { + "north": {"uv": [0, 0, 2, 1], "texture": "#1_2"}, + "east": {"uv": [0, 0, 2, 1], "texture": "#1_2"}, + "south": {"uv": [0, 0, 2, 1], "texture": "#1_2"}, + "west": {"uv": [0, 0, 2, 1], "texture": "#1_2"}, + "up": {"uv": [13, 13, 15, 15], "rotation": 180, "texture": "#1_2"}, + "down": {"uv": [13, 13, 15, 15], "rotation": 180, "texture": "#1_2"} + } + }, + { + "name": "rod_left", + "from": [1, 4, 7.5], + "to": [3, 12, 8.5], + "shade": false, + "faces": { + "north": {"uv": [3, 5, 1, 13], "texture": "#1_2"}, + "east": {"uv": [8, 4, 9, 12], "texture": "#1_2"}, + "south": {"uv": [1, 3, 3, 11], "texture": "#1_2"}, + "west": {"uv": [1, 6, 2, 14], "texture": "#1_2"} + } + }, + { + "name": "rod_left", + "from": [13, 4, 7.5], + "to": [15, 12, 8.5], + "shade": false, + "faces": { + "north": {"uv": [1, 3, 3, 11], "texture": "#1_2"}, + "east": {"uv": [1, 6, 2, 14], "texture": "#1_2"}, + "south": {"uv": [3, 5, 1, 13], "texture": "#1_2"}, + "west": {"uv": [8, 4, 9, 12], "texture": "#1_2"} + } + } + ], + "groups": [0, + { + "name": "crossplane", + "origin": [8, 8, 8], + "children": [1, 2, 3, 4, 5, 6] + } + ] } \ No newline at end of file diff --git a/src/main/resources/assets/create/models/block/symmetry_effect/tripleplane.json b/src/main/resources/assets/create/models/block/symmetry_effect/tripleplane.json index 2af7a097f..99450d7ca 100644 --- a/src/main/resources/assets/create/models/block/symmetry_effect/tripleplane.json +++ b/src/main/resources/assets/create/models/block/symmetry_effect/tripleplane.json @@ -1,172 +1,178 @@ { - "__comment": "Model generated using MrCrayfish's Model Creator (http://mrcrayfish.com/modelcreator/)", - "textures": { - "0": "block/white_stained_glass", - "1": "block/obsidian", - "2": "block/packed_ice" - }, - "elements": [ - { - "name": "Mirror", - "from": [ 6.499999992549419, 1.0, 10.50000000745058 ], - "to": [ 9.49999999254942, 12.0, 11.50000000745058 ], - "faces": { - "north": { "texture": "#0", "uv": [ 4.0, 1.0, 7.0, 12.0 ] }, - "east": { "texture": "#0", "uv": [ 3.0, 1.0, 4.0, 12.0 ] }, - "south": { "texture": "#0", "uv": [ 4.0, 1.0, 7.0, 12.0 ] }, - "west": { "texture": "#0", "uv": [ 12.0, 1.0, 13.0, 12.0 ] }, - "up": { "texture": "#0", "uv": [ 4.0, 1.0, 7.0, 2.0 ] }, - "down": { "texture": "#0", "uv": [ 4.0, 14.0, 7.0, 15.0 ] } - } - }, - { - "name": "rod_left_bottom", - "from": [ 1.2000000029802322, 3.0, 7.0 ], - "to": [ 3.2000000029802322, 4.0, 9.0 ], - "rotation": { "origin": [ 8.0, 8.0, 8.0 ], "axis": "y", "angle": -45.0 }, - "faces": { - "north": { "texture": "#1", "uv": [ 0.0, 0.0, 2.0, 1.0 ] }, - "east": { "texture": "#1", "uv": [ 0.0, 0.0, 2.0, 1.0 ] }, - "south": { "texture": "#1", "uv": [ 0.0, 0.0, 2.0, 1.0 ] }, - "west": { "texture": "#1", "uv": [ 0.0, 0.0, 2.0, 1.0 ] }, - "up": { "texture": "#1", "uv": [ 0.0, 0.0, 2.0, 2.0 ] }, - "down": { "texture": "#1", "uv": [ 0.0, 0.0, 2.0, 2.0 ] } - } - }, - { - "name": "rod_left_top", - "from": [ 1.2000000029802322, 12.0, 7.0 ], - "to": [ 3.2000000029802322, 13.0, 9.0 ], - "rotation": { "origin": [ 8.0, 8.0, 8.0 ], "axis": "y", "angle": -45.0 }, - "faces": { - "north": { "texture": "#1", "uv": [ 0.0, 0.0, 2.0, 1.0 ] }, - "east": { "texture": "#1", "uv": [ 0.0, 0.0, 2.0, 1.0 ] }, - "south": { "texture": "#1", "uv": [ 0.0, 0.0, 2.0, 1.0 ] }, - "west": { "texture": "#1", "uv": [ 0.0, 0.0, 2.0, 1.0 ] }, - "up": { "texture": "#1", "uv": [ 0.0, 0.0, 2.0, 2.0 ] }, - "down": { "texture": "#1", "uv": [ 0.0, 0.0, 2.0, 2.0 ] } - } - }, - { - "name": "rod_left", - "from": [ 2.0, 4.0, 7.499999992549419 ], - "to": [ 3.0, 12.0, 8.49999999254942 ], - "shade": false, - "rotation": { "origin": [ 8.0, 8.0, 8.0 ], "axis": "y", "angle": -45.0 }, - "faces": { - "north": { "texture": "#2", "uv": [ 3.0, 1.0, 4.0, 9.0 ] }, - "east": { "texture": "#2", "uv": [ 3.0, 0.0, 4.0, 8.0 ] }, - "south": { "texture": "#2", "uv": [ 3.0, 1.0, 4.0, 9.0 ] }, - "west": { "texture": "#2", "uv": [ 5.0, 1.0, 6.0, 9.0 ] } - } - }, - { - "name": "rod_right_bottom", - "from": [ 12.799999997019768, 3.0, 7.0 ], - "to": [ 14.799999997019768, 4.0, 9.0 ], - "rotation": { "origin": [ 8.0, 8.0, 8.0 ], "axis": "y", "angle": -45.0 }, - "faces": { - "north": { "texture": "#1", "uv": [ 0.0, 0.0, 2.0, 1.0 ] }, - "east": { "texture": "#1", "uv": [ 0.0, 0.0, 2.0, 1.0 ] }, - "south": { "texture": "#1", "uv": [ 0.0, 0.0, 2.0, 1.0 ] }, - "west": { "texture": "#1", "uv": [ 0.0, 0.0, 2.0, 1.0 ] }, - "up": { "texture": "#1", "uv": [ 0.0, 0.0, 2.0, 2.0 ] }, - "down": { "texture": "#1", "uv": [ 0.0, 0.0, 2.0, 2.0 ] } - } - }, - { - "name": "rod_right", - "from": [ 13.0, 4.0, 7.499999992549419 ], - "to": [ 14.0, 12.0, 8.49999999254942 ], - "shade": false, - "rotation": { "origin": [ 8.0, 8.0, 8.0 ], "axis": "y", "angle": -45.0 }, - "faces": { - "north": { "texture": "#2", "uv": [ 3.0, 2.0, 4.0, 10.0 ] }, - "east": { "texture": "#2", "uv": [ 3.0, 3.0, 4.0, 11.0 ] }, - "south": { "texture": "#2", "uv": [ 4.0, 3.0, 5.0, 11.0 ] }, - "west": { "texture": "#2", "uv": [ 5.0, 0.0, 6.0, 8.0 ] } - } - }, - { - "name": "rod_right_top", - "from": [ 12.799999997019768, 12.0, 7.0 ], - "to": [ 14.799999997019768, 13.0, 9.0 ], - "rotation": { "origin": [ 8.0, 8.0, 8.0 ], "axis": "y", "angle": -45.0 }, - "faces": { - "north": { "texture": "#1", "uv": [ 0.0, 0.0, 2.0, 1.0 ] }, - "east": { "texture": "#1", "uv": [ 0.0, 0.0, 2.0, 1.0 ] }, - "south": { "texture": "#1", "uv": [ 0.0, 0.0, 2.0, 1.0 ] }, - "west": { "texture": "#1", "uv": [ 0.0, 0.0, 2.0, 1.0 ] }, - "up": { "texture": "#1", "uv": [ 0.0, 0.0, 2.0, 2.0 ] }, - "down": { "texture": "#1", "uv": [ 0.0, 0.0, 2.0, 2.0 ] } - } - }, - { - "name": "CrossMirror", - "from": [ 4.499999977648258, 2.0, 6.500000007450581 ], - "to": [ 5.499999977648258, 13.0, 9.50000000745058 ], - "faces": { - "north": { "texture": "#0", "uv": [ 4.0, 1.0, 5.0, 12.0 ] }, - "east": { "texture": "#0", "uv": [ 3.0, 1.0, 6.0, 12.0 ] }, - "south": { "texture": "#0", "uv": [ 4.0, 1.0, 5.0, 12.0 ] }, - "west": { "texture": "#0", "uv": [ 9.0, 1.0, 12.0, 12.0 ] }, - "up": { "texture": "#0", "uv": [ 3.0, 3.0, 4.0, 6.0 ] }, - "down": { "texture": "#0", "uv": [ 5.0, 9.0, 6.0, 12.0 ] } - } - }, - { - "name": "Mirror II", - "from": [ 6.499999992549419, 3.0, 4.500000007450581 ], - "to": [ 9.49999999254942, 14.0, 5.500000007450581 ], - "faces": { - "north": { "texture": "#0", "uv": [ 4.0, 1.0, 7.0, 12.0 ] }, - "east": { "texture": "#0", "uv": [ 3.0, 1.0, 4.0, 12.0 ] }, - "south": { "texture": "#0", "uv": [ 4.0, 1.0, 7.0, 12.0 ] }, - "west": { "texture": "#0", "uv": [ 12.0, 1.0, 13.0, 12.0 ] }, - "up": { "texture": "#0", "uv": [ 4.0, 1.0, 7.0, 2.0 ] }, - "down": { "texture": "#0", "uv": [ 4.0, 14.0, 7.0, 15.0 ] } - } - }, - { - "name": "CrossMirror II", - "from": [ 10.50000000745058, 4.0, 6.500000007450581 ], - "to": [ 11.50000000745058, 15.0, 9.50000000745058 ], - "faces": { - "north": { "texture": "#0", "uv": [ 4.0, 1.0, 5.0, 12.0 ] }, - "east": { "texture": "#0", "uv": [ 3.0, 1.0, 6.0, 12.0 ] }, - "south": { "texture": "#0", "uv": [ 4.0, 3.0, 5.0, 14.0 ] }, - "west": { "texture": "#0", "uv": [ 9.0, 2.0, 12.0, 13.0 ] }, - "up": { "texture": "#0", "uv": [ 4.0, 3.0, 5.0, 6.0 ] }, - "down": { "texture": "#0", "uv": [ 4.0, 8.0, 5.0, 11.0 ] } - } - }, - { - "name": "Cube", - "from": [ 7.499999992549419, 6.0, -0.4999999925494194 ], - "to": [ 8.49999999254942, 10.0, 3.5000000074505806 ], - "rotation": { "origin": [ 8.0, 8.0, 8.0 ], "axis": "y", "angle": -45.0 }, - "faces": { - "north": { "texture": "#0", "uv": [ 4.0, 1.0, 5.0, 5.0 ] }, - "east": { "texture": "#0", "uv": [ 3.0, 1.0, 7.0, 5.0 ] }, - "south": { "texture": "#0", "uv": [ 4.0, 3.0, 5.0, 7.0 ] }, - "west": { "texture": "#0", "uv": [ 9.0, 2.0, 13.0, 6.0 ] }, - "up": { "texture": "#0", "uv": [ 4.0, 3.0, 5.0, 7.0 ] }, - "down": { "texture": "#0", "uv": [ 4.0, 8.0, 5.0, 12.0 ] } - } - }, - { - "name": "Cube", - "from": [ 7.499999992549419, 6.0, 12.50000000745058 ], - "to": [ 8.49999999254942, 10.0, 16.50000000745058 ], - "rotation": { "origin": [ 8.0, 8.0, 8.0 ], "axis": "y", "angle": -45.0 }, - "faces": { - "north": { "texture": "#0", "uv": [ 4.0, 1.0, 5.0, 5.0 ] }, - "east": { "texture": "#0", "uv": [ 3.0, 1.0, 7.0, 5.0 ] }, - "south": { "texture": "#0", "uv": [ 4.0, 3.0, 5.0, 7.0 ] }, - "west": { "texture": "#0", "uv": [ 9.0, 2.0, 13.0, 6.0 ] }, - "up": { "texture": "#0", "uv": [ 4.0, 3.0, 5.0, 7.0 ] }, - "down": { "texture": "#0", "uv": [ 4.0, 8.0, 5.0, 12.0 ] } - } - } - ] + "credit": "Made with Blockbench", + "textures": { + "0": "create:block/symmetry_mirror", + "2": "create:block/brass_block" + }, + "elements": [ + { + "name": "Mirror", + "from": [6.5, 1, 10.5], + "to": [9.5, 12, 11.5], + "faces": { + "north": {"uv": [4, 1, 7, 12], "texture": "#0"}, + "east": {"uv": [3, 1, 4, 12], "texture": "#0"}, + "south": {"uv": [4, 1, 7, 12], "texture": "#0"}, + "west": {"uv": [12, 1, 13, 12], "texture": "#0"}, + "up": {"uv": [4, 1, 7, 2], "texture": "#0"}, + "down": {"uv": [4, 14, 7, 15], "texture": "#0"} + } + }, + { + "name": "CrossMirror", + "from": [4.5, 2, 6.5], + "to": [5.5, 13, 9.5], + "faces": { + "north": {"uv": [4, 1, 5, 12], "texture": "#0"}, + "east": {"uv": [3, 1, 6, 12], "texture": "#0"}, + "south": {"uv": [4, 1, 5, 12], "texture": "#0"}, + "west": {"uv": [9, 1, 12, 12], "texture": "#0"}, + "up": {"uv": [3, 3, 4, 6], "texture": "#0"}, + "down": {"uv": [5, 9, 6, 12], "texture": "#0"} + } + }, + { + "name": "Mirror II", + "from": [6.5, 3, 4.5], + "to": [9.5, 14, 5.5], + "faces": { + "north": {"uv": [4, 1, 7, 12], "texture": "#0"}, + "east": {"uv": [3, 1, 4, 12], "texture": "#0"}, + "south": {"uv": [4, 1, 7, 12], "texture": "#0"}, + "west": {"uv": [12, 1, 13, 12], "texture": "#0"}, + "up": {"uv": [4, 1, 7, 2], "texture": "#0"}, + "down": {"uv": [4, 14, 7, 15], "texture": "#0"} + } + }, + { + "name": "CrossMirror II", + "from": [10.5, 4, 6.5], + "to": [11.5, 15, 9.5], + "faces": { + "north": {"uv": [4, 1, 5, 12], "texture": "#0"}, + "east": {"uv": [3, 1, 6, 12], "texture": "#0"}, + "south": {"uv": [4, 3, 5, 14], "texture": "#0"}, + "west": {"uv": [9, 2, 12, 13], "texture": "#0"}, + "up": {"uv": [4, 3, 5, 6], "texture": "#0"}, + "down": {"uv": [4, 8, 5, 11], "texture": "#0"} + } + }, + { + "name": "Cube", + "from": [7.5, 6, -0.5], + "to": [8.5, 10, 3.5], + "rotation": {"angle": -45, "axis": "y", "origin": [8, 8, 8]}, + "faces": { + "north": {"uv": [4, 1, 5, 5], "texture": "#0"}, + "east": {"uv": [3, 1, 7, 5], "texture": "#0"}, + "south": {"uv": [4, 3, 5, 7], "texture": "#0"}, + "west": {"uv": [9, 2, 13, 6], "texture": "#0"}, + "up": {"uv": [4, 3, 5, 7], "texture": "#0"}, + "down": {"uv": [4, 8, 5, 12], "texture": "#0"} + } + }, + { + "name": "Cube", + "from": [7.5, 6, 12.5], + "to": [8.5, 10, 16.5], + "rotation": {"angle": -45, "axis": "y", "origin": [8, 8, 8]}, + "faces": { + "north": {"uv": [4, 1, 5, 5], "texture": "#0"}, + "east": {"uv": [3, 1, 7, 5], "texture": "#0"}, + "south": {"uv": [4, 3, 5, 7], "texture": "#0"}, + "west": {"uv": [9, 2, 13, 6], "texture": "#0"}, + "up": {"uv": [4, 3, 5, 7], "texture": "#0"}, + "down": {"uv": [4, 8, 5, 12], "texture": "#0"} + } + }, + { + "name": "rod_left_bottom", + "from": [1, 3, 7], + "to": [3, 4, 9], + "rotation": {"angle": -22.5, "axis": "y", "origin": [8, 8, 8]}, + "faces": { + "north": {"uv": [0, 0, 2, 1], "texture": "#2"}, + "east": {"uv": [0, 0, 2, 1], "texture": "#2"}, + "south": {"uv": [0, 0, 2, 1], "texture": "#2"}, + "west": {"uv": [0, 0, 2, 1], "texture": "#2"}, + "up": {"uv": [13, 13, 15, 15], "texture": "#2"}, + "down": {"uv": [13, 13, 15, 15], "texture": "#2"} + } + }, + { + "name": "rod_left_bottom", + "from": [13, 3, 7], + "to": [15, 4, 9], + "rotation": {"angle": -22.5, "axis": "y", "origin": [8, 8, 8]}, + "faces": { + "north": {"uv": [0, 0, 2, 1], "texture": "#2"}, + "east": {"uv": [0, 0, 2, 1], "texture": "#2"}, + "south": {"uv": [0, 0, 2, 1], "texture": "#2"}, + "west": {"uv": [0, 0, 2, 1], "texture": "#2"}, + "up": {"uv": [13, 13, 15, 15], "rotation": 180, "texture": "#2"}, + "down": {"uv": [13, 13, 15, 15], "rotation": 180, "texture": "#2"} + } + }, + { + "name": "rod_left_top", + "from": [1, 12, 7], + "to": [3, 13, 9], + "rotation": {"angle": -22.5, "axis": "y", "origin": [8, 8, 8]}, + "faces": { + "north": {"uv": [0, 0, 2, 1], "texture": "#2"}, + "east": {"uv": [0, 0, 2, 1], "texture": "#2"}, + "south": {"uv": [0, 0, 2, 1], "texture": "#2"}, + "west": {"uv": [0, 0, 2, 1], "texture": "#2"}, + "up": {"uv": [13, 13, 15, 15], "texture": "#2"}, + "down": {"uv": [13, 13, 15, 15], "texture": "#2"} + } + }, + { + "name": "rod_left_top", + "from": [13, 12, 7], + "to": [15, 13, 9], + "rotation": {"angle": -22.5, "axis": "y", "origin": [8, 8, 8]}, + "faces": { + "north": {"uv": [0, 0, 2, 1], "texture": "#2"}, + "east": {"uv": [0, 0, 2, 1], "texture": "#2"}, + "south": {"uv": [0, 0, 2, 1], "texture": "#2"}, + "west": {"uv": [0, 0, 2, 1], "texture": "#2"}, + "up": {"uv": [13, 13, 15, 15], "rotation": 180, "texture": "#2"}, + "down": {"uv": [13, 13, 15, 15], "rotation": 180, "texture": "#2"} + } + }, + { + "name": "rod_left", + "from": [1, 4, 7.5], + "to": [3, 12, 8.5], + "shade": false, + "rotation": {"angle": -22.5, "axis": "y", "origin": [8, 8, 8]}, + "faces": { + "north": {"uv": [3, 5, 1, 13], "texture": "#2"}, + "east": {"uv": [8, 4, 9, 12], "texture": "#2"}, + "south": {"uv": [1, 3, 3, 11], "texture": "#2"}, + "west": {"uv": [1, 6, 2, 14], "texture": "#2"} + } + }, + { + "name": "rod_left", + "from": [13, 4, 7.5], + "to": [15, 12, 8.5], + "shade": false, + "rotation": {"angle": -22.5, "axis": "y", "origin": [8, 8, 8]}, + "faces": { + "north": {"uv": [1, 3, 3, 11], "texture": "#2"}, + "east": {"uv": [1, 6, 2, 14], "texture": "#2"}, + "south": {"uv": [3, 5, 1, 13], "texture": "#2"}, + "west": {"uv": [8, 4, 9, 12], "texture": "#2"} + } + } + ], + "groups": [0, 1, 2, 3, 4, 5, + { + "name": "crossplane", + "origin": [8, 8, 8], + "children": [6, 7, 8, 9, 10, 11] + } + ] } \ No newline at end of file diff --git a/src/main/resources/assets/create/textures/block/symmetry_mirror.png b/src/main/resources/assets/create/textures/block/symmetry_mirror.png new file mode 100644 index 0000000000000000000000000000000000000000..b29da0866f05c8512c1d5f225241aa26b55a4e1e GIT binary patch literal 262 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 D8wHPm literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/create/textures/gui/double_flexcrate.png b/src/main/resources/assets/create/textures/gui/double_flexcrate.png deleted file mode 100644 index 57df53fe6ad2427d51b17be05ba2c5dde23124d9..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2133 zcmeAS@N?(olHy`uVBq!ia0y~yU<5K58911MRQ8&P5D>38$lZxy-8q?;Kn_c~qpu?a z!^VE@KZ&di49pAxJ|V6^aXoESb93`(FQd=^bsu+!=n&78Fqf=&|Gdax7fs+9Jo z>hA9DTi3V0diCo6|NlTOqhK@yhDQi|sM>uIlxs?Y{DOgLdn5yf;P33Jz*yxh@Q5sC zVBk9p!i>lBSEK+7i%Xs^jv*CsZ|AUQ*33Xw!>kpIAZl;JeaR?i=OLb$5b+XQCDBo`dU%Y zHa+fc$=cn_NvUF7*PWHB&TVp2Ymhy_vZ7P!2BQyybpvMt`}WR=f0B{L8k24^)iWl1M{^zj2n%(A@)Qn3m@Q1 zV7lVM`-TB*#RleQam%}91++H@>;SoTnyC>ZP|Csg%7+a0Blm8L+#6pM&=ug+3y-6X0{&sI-vt-@kF2-WuzruR51A+FJ@+zecy0+VQb?&^#vz+ zO7<`x+kMaBzVL+vwq5raAID}d_|CavUgNp)0|oY1|2D7q&AH;u{@=0zx9i^v2i*OC zSXQ7qKe%G@;yr>k>5-2Mu7Ceu!Bn&;zvv6lCgb(*UT0mXziz$2^}p@=2DQKT$lgny z{O|X?1~;Y(^$dH)Hw``qG6vy*TZ|jOo4v06 zw7>ko>wmiq*XQlJ#ra_WB`LO5&NCQT6o8@7z`#-?&v^cP{XXMuDi7ZN+I;29pK~`R zG;H6vJLvS!T6QKg(#YIgl7Uc^p*uu)_6+Ij&lcz;Ld4Jh` VX?JJ6vld%F6$taD0e0sx%2<7)r_ diff --git a/src/main/resources/assets/create/textures/gui/filter.png b/src/main/resources/assets/create/textures/gui/filter.png deleted file mode 100644 index 00a65a06f9c0295584f25c41a42357272fd79ac3..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 15775 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 E2NTHBpa1{> diff --git a/src/main/resources/assets/create/textures/gui/filters.png b/src/main/resources/assets/create/textures/gui/filters.png new file mode 100644 index 0000000000000000000000000000000000000000..e1f39a915619a2a1c47702fe3a5326541b5e7090 GIT binary patch literal 1855 zcmcgsX;hO}8veeIBoHFV))^y=B9ascIw)YQ2t;JH5mSsTMQKncQ4pmPmCBN@wM8v- z0wX&}Ly1MACjpUVnAn6xpfVbkVxnP71VLmGL=rFC>FT-g`WHLEBJKJb9c6N3i zIdX)_WUAF_Hk++bJX0tXa=Dz(=cCbR2!a+{lkVRLjB*7erGarf!K$h%I-O1;kro#h zwOXxCr(0TDnwgntY;3HotgNZ25s5@%vACzFM=F(ecX#*o^^J~>PEAcMFE0-a3_N=D zXmD^)rBWFT2BlKj(b0i;OPfqTfCwLUMEGIErT=jOl^s5t5E^W9XiN$KShlVmusJVr z768z_VS)STsd2M6ak0u^tDq(?%Fs6!s=TZSn||W%^^4PGMq|6%>FxdZK6i}^5{NxD zGgrIr{^iq@^Ld76_tfk!i*iy%YvNff9z0(_0qrQ@lpAQy1CTxBpO$5==xcWb=kmlk z7ypq~B3GLpBaF=rt)3vvte=wD)oN8Ce>$;)4r?~Va9bg9SNCNP@CCu~ib4I0c8Z!U#z*Km-onT2u6)9JcRoOkz%>zNKnMEEC#;J%>!!p0E7d1fdx7#b9hb zhO@Zd|DC&-6XJ693SU24u;Vzi=&+UOC~HN?Pq}>;057ypT=-gOlWZxw(tQD7b7 z8=IC+{m+!(Two}f0HGDuZ=A>ZzAPdS|&DCq44V+Gu?nlfUVY9K=qE3(TUE0(^%h0ggWf}5;zM(aGo(hqW3~qOiL)OQ-8J^fpIO@B!UOdpQ*M6f2c)=V_8 z&YlxB2exl{a!kP^Ih@s~)hxr&xMi$1$lm}l!aP3|g{QJ2O4Fh5{}@oqFX`zy=H(D! z*4)zK-t5*Jc_(r3oG&(&Kj|N>xRIE-O{i)L2fzPiNB@3JQJ7c8X#tDPxfwc8^z-Fl z3BU=v^`Y43a6}lJS`3tnYE`u-GKt|QeeP84PfwO!GcC-o`wDtqoiJ7Wur$b!?UkO55aqfi|i!%(0GeJrwk?t z&w+7}Ad@tQwrhz0EknAzVM=LwZQXl38H_#2sK}t4$t3D*Xim@ps>IR-?*pc~?ji4k z5)!~4Y+@oh&9G9;KM&@@rD>qWu4T~M8obBPd2HM3ml7}6Q@bxVatqJOy8pIw*CDtc z2{PXjNdiT(4e4+g>yZh6i|xo?orOg@Q}Vn{9JRPL7sn8h}RH_*nICGnKLM zM@XjSV!R75=xzrm{K1^!jYIQFzk_Ix1HjwNN`PKZ0|YVuZ}st`(&1rFI_8tP`Cp%3 QLk2z&78D*R3}AfoJCr+aivR!s literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/create/textures/gui/flex_crate_and_stockpile_switch.png b/src/main/resources/assets/create/textures/gui/flex_crate_and_stockpile_switch.png deleted file mode 100644 index b6da1409e1eff6617cd2af4a32252846d85f836c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 13655 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 YQwwh!z_&IyfbrAUG1M;Bw0ZUa0Pf@Dl(u73`6O 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 literal 4434 zcmdTni8tG6*FQC_n!aVayi^sPE_7=9lnN@+mA1CFT1!H-cB0ZK6-DTDI(8Y1B}H_q zwg#ysC|R^`$W%&diM0|43UP{`9qe@nVIm){DpMLMi zQ8Br2G&oA|l30SmCEnV)h}bUB zW#@0U_yq~qmjcPd@tX=u@APj5iEA56LaWM6;S03{Ysp&7%FCg!aoO0J!z_w;_!V`c zZ3Fk#oL}|$Wt3ldxmxe5TekmZHuc6q1wnk{{F2ON-llXMNeifkE5MbO6Vu%Mn$R>b zsuaQ+{Hw?D+I=BO-^Z5OU-9DcHWc> zs!ag8&$t1uoI=okCi}p>imbdVoX9XYm6mg)q}nu6xlL4Q+hSpq?->1h_Rs8nZXY(M zoKKWJ@*90#S1@o}WATu$h~1a2nR&sKs=<^lAf~DwpPA_X{H-t3?&*3aUhCJgY2z3t+I9IX1D)D+ z^DsC6#pYm6GPK73tX*?^ze+)#aYA#MFf`WfUU*IAaQ0AA=R+M>bCOb8@iCJJ$ zY=rDj%sE)HoLIJSu44IFZuk-`VaqIUE`r?M*-R&j6i$YmwR%0A5yz~T2hpr3qUKs#5cLYqV@Vqw;G%8a2SO=65i7; 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 K<+_V^fBj$EwD#}- diff --git a/src/main/resources/assets/create/textures/gui/logistics.png b/src/main/resources/assets/create/textures/gui/logistics.png new file mode 100644 index 0000000000000000000000000000000000000000..9aeee18e924afcf47ae7b696eea52248368e71e9 GIT binary patch literal 4761 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 literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/create/textures/gui/background.png b/src/main/resources/assets/create/textures/gui/overlay.png similarity index 100% rename from src/main/resources/assets/create/textures/gui/background.png rename to src/main/resources/assets/create/textures/gui/overlay.png diff --git a/src/main/resources/assets/create/textures/gui/schematic.png b/src/main/resources/assets/create/textures/gui/schematic.png deleted file mode 100644 index a46e2686bb2c49a4bb6a7660d4802b5785104d8a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1809 zcmeAS@N?(olHy`uVBq!ia0y~yU<5K58911MRQ8&P5Fo{p?&#~tz_78O`%fY(0|PTd zfKP}kP~6%vC^R%Qt8zv6%p;rk-Z*yb*#H0kf#RcJGz5ly2;8zd`~{RzN`m}?fysU( z1BT%5?5e;B=PdAuEM{QfI|Ravq8eTeKtYKT*NBqf{Irtt#G+J&g2c?c61}|C5(N`I zLp`&+PvnwdHdC0)ZJ(O@cI+$2JQ!T&ejZSou6~wecNLzXD|N#b@q=xj4T2U42&!X zUdL=>VB%-O3wpS2p+IWWkiSI0Io>|$apVZEnc?3bPY>%{ZWaD|3`HjDjm=liio{QhC} zs#5%bI`f*nZ38$lZxy-8q?;Kn_c~qpu?a z!^VE@KZ&di49pAxJ|V6^adUHXYsa9_(9o>P72QBE^T_7CH;x@U_W%EXpzJ6Z4S``C z0!#UXmVanMprAyFYeY$Kep*R+ zVo@qXL1JcJiC$i6iGqoqp`O`aKh77x0!72q#WAEJ?(LmkzuN{3t`FBaSl|2KxI53X z@#^2eTpy>J^AlHfPvLvmzwFYCV|i2jirY`$yU9HLblL9jj8&C8`3<-WcD~U+@c!&~ z0R~3B>Ad^}b69u8l(AJvF8sZ|A+q6g>Ymmd`*X#Q#TAA9V0kBO;9|3JS#P~!uOubc`8-c|f#iGJU`zF}?o2Qh($$5+%F7??OV zC>>Z|z4v3w@>@m+ZqNOZFLz$GfuWnRpuH}vbbZ`*TZVo6`d96{@VbgoW;W|I)*ZiI zrpY%P{;BV>mWi8r3e#MMeF_^)9275bFNjSjZ18T(V>runnmLB!3v-5O1mlDH#y*B# zru)1GvO7DnpI0$$;atP?LGyy>f|u=!nfEf?snKS+#Z+y!5 zqhOV^!)Nvr-Ki^RL|tgvIz zC%!$lxoZ0VV4zS#uP=j{8RLx`ED6cNBb;-=Z@K+%KAuJQv+Y5djlt8^&t;ucLK6TD COq5dq diff --git a/src/main/resources/assets/create/textures/gui/schematicannon.png b/src/main/resources/assets/create/textures/gui/schematicannon.png deleted file mode 100644 index cb838679c815ea20f8dff3b09b71d1d340a2452f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 13735 zcmd6OWmuHk-uDa*QZgVNDk(@v=YWdHrbI+QfuSS>0ZGXjLXbvLLShtDK#=Yn8l<}$ zrMqF6dGA5@KKqf*lFfBo05)|!xenkp1zOk^Msh(h)5?fW1Q71JwP`D7vpEGkXW}B;AC=Ee%N=|n?qqe&-Z0Jl;nkWoj86DOHJcI=l#{z8rFAk_10<-7B!i+NmsZSBiBS;}lFZ=)!NZEz z6SE|i&GS<>C_5wDX^R|f&nmFTq7%Mb&F*Psr2-gNjufyREyKnj%AHQQa!%!I(l=`k z{%coxVB*9VzNiQe^%vqbNO9{h@L@hV(1?KT$e;8SzN6q!9$6XE?Uj6L5=WPr=2OH^ z6JsRqshlJ%|0Z7aRA!#sozSW6alqVksRMG{?Up)-SxJ0pQeRT}{vfE*kfF#%z4|-v zUDn>Nb}n64z4sdSQ0^~eU)uPZ9c6@HPA_qn*fbL44ZWRBAueV90infe#-i6QQJ@NM zM$FWL~uBokrg)iICqPhU6wC~RAAX?##8Cf&rKNo-C?IoVi(2c3IdyuQ;ewD|0P zA0+TdWM=Fhg}vl=o9K)muC6wqb&ED3T8cdj=Rp}CF`$%YH+8>!NM`O=VvhNFGJRxV zzip06w66$R*R97eiE5CHD_jnzLyaLW3Z%s!HgPrDxGEWrMO}ir8N8Nx@7RWHFZ_c& zEM#;z!48qc_rV-Dif01L8W!szbf`xh_>xpG$;i&UoMy>NUUHoyMHdND2#3?QSGlTt z)4;-kx!Knl=F76l_gVS9^PUJS7r+l4&@83;;57@rYCH7`yjP?qKQf8jB~V?VwVj=J zzFtnX{=lQ9hyIpA2l;yAWj>xz@* z2&Lr{t&vu@ZNHsF+00F-m>Tw;Qx^Pz+x~RVr$JfBW9pBhO^-!*n-B8Sk&+y~zUud_ zC+*}WQa(n8a(tF*%qWcm4TQeSb{fzN(NH3t8BJmxS}2paXbkP-jpBZ42X|kU1BVJqb(K#ZN)P4@G#0 zUPe*8#OlJ_i0GkGjw|_V=^>`0A*3dJuP=tkKOP0$4>XW`D>g>YBmOiVR2Kjz(mHl# zi4cuQv*>5sAX~W9y=-E4AH*4J?e-@9)yw{)Id@HNpOrLLezdHDN8os1GQryReyGW% zPrF(GQm6$}YED50LF=n4JJw$`%vW^pC=o%|s|@e!x_=%8x;Qn<gu`%|FY2zmSljUYp|7xo02_t3HiJB5$MK;7TV%xa!e zUQ&-TRCl5Cz8dtrAc2A3Q78YIdVOlvWzDCruDsXbyK}ElHM4BB&Ie65qb%g9okFm6 zwf45r(IOI#aa>Gxr^N1GcVO{7pnzo>w5zCtylyhu+nL63@zp;p%?Yj1#;?q7ooRV9 zZO!5Jw5)G0lcoK+Sl8NWxab63E0-33|1xUnnSc$GIBC-Wd7y@&3*CSi8RO{Fvb9re z%T|lKf(&}x0saKIs;f!%RxZZRfi1^pwRRz7-uzJEvz38DNit{yKBF{6vwJYi&S>E= zQ!Zi^+PKU|?=_~b?qW-8A=m#8EYx#zb%lEf;dtZg9gUl!p&uBOG~)W$W{!wqSh`77 zlgj!Qk&)PUd!J0&rwP;vJ)51W9AzEg@_hILk9`SnB#hWFImiBm<3xoth|z3<+&CkgKNSa-mqIrXf)X)M}H0J1b%7(ZTBF2873 zetJbS>w@%Cvr&r%0+O0VFO2)4(H9eK2%P>#qcnQ=EPf=r_ zDQrj+j|z(6TpX__HgAe@dss_`mfghiyBnWwf~g@IAczkkh*$k_((cx9%#E^9r^DNS zd>d?f$9y+2BtNs@0`+5ns=juAJ?dScHJ4(I$8(p-2!;2Stv*a%q7!;V>wY4Gs4rFX z@zxyyKGPLykmQ~kjIg1Jr(Zo?hEZ%hE!uZ=)n*uc19MqZl#tS0At6#D@8IP5!tX0} z?dT5qyoIR9!)|P91CS582Q}OUl>oZ?MH*$=sl*EHnM7!~Uv^ z+Z3-cHEcRCLWfR4n9z5#nu@#|j&UBfD&g~8sx8kTouTg+Mf4>qtAiREBzO1S+Xc80 ztn&CHr0Gdcp^swn*^ro>pvBV3YOE~3uUM)%aY0?ClY?nqBTC(=Fa1{uS|eox?$Jrz z*eGB0?ak6B!mA%Opk120lAE4%P;6K=vc=JDuZrYUxbSm_oP!SgDF(FyKUpQwJe{MN zE2`iST+f=bdUWflbv5W%BYQ z5ZteW?h8mZ7`aat&#Rj3x8Bkdko@}T?js|^!?&>c35#ihSB7Y1vx2N3{!Z>vc8JbP z<4}=>s5;u3etuz6Dc(`m^1-?=lZ6u-gD8pX+1gs8XPHq&-B{+#V_JIE=2g%5h}TR8;6Tb) zbdKUX89M25x$!+3e8EoXQHyY*tBD`3IR^JScaXPMZdSuw#}Yri$yYo|T`oRmQ@`)h zKA?#obeZ9dPtgHy>5O*9RDNx(P;>S(w#K|RkjMYM3ft@3r#c|RG)b_)d?+g1+@Gkc zHRGGr%v|L12L;&kmDR22Z(_m{yJ3cAa}O0Vc0&`|hKE$`iiE0m{nlRl{@m@RjyViT zYbdVWNxN{&htfK$KkX=PI!RuIhdh>3Wk1zGd6d+i2E)6CiDNLvN>3Mep!gaEaxLkn zy;f|N%uVnv=|z_?_V8~6vH2smXni(*-=)FmF8kh(9@PrS?&7Uueu{8<=pIeXd<4>M zlzOHAW6xyqs8|hN+~*a7QJu4tDjHCpH>T=!Rs>9vj{fd-M9P>)BcxK^m&R?M9MoiY zK}G}5{L>=dKBsUSXJOn{e7E^+B6abScMlI+NEK9)PSB&@WxTH|1}qfGAO;rPBjZ?k z^G{sLB!W8^{}>`473V=TrMQq>+VwU9TffcBm4%_3E_tp0FiFh??Gr@T;ISxp$3xe( zM_PIxI1L*S^Le_AxOXh0bwMV|pf2xO>GxMLQP`uXN*DoNwe7n6jcYq2jsbyciWx*& z&)aT@ARX`ss8C!lzQYbeGXb3tAuhvlar&_7VDWA{*5%XnnpIy{5g2%C=K?zD^ zbw4H(E`Igk{YwUQ|wO9>@y!Cs#bT2?|+rDlt0Yvo0Ur^$u!egH6SC*bv3K+na<=K5LhT zFFtORH65F89&y7PvG=g&@oSV`OiHe$GlV{t_PP$?!^Z64efMHXg{$sf1k=b9 zWuj^FShRFxbAnIu^Poz+@&%hGGOXdtpkS^vDe{i{=pvPoMrHSUf8pV5!Kf>0%Cfm` zeX0P^JX}l+dd7oLja#�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 C)vJX7 diff --git a/src/main/resources/assets/create/textures/gui/schematics.png b/src/main/resources/assets/create/textures/gui/schematics.png new file mode 100644 index 0000000000000000000000000000000000000000..a3cc2615a770e7a881f49dff52dc02371977d037 GIT binary patch literal 1987 zcma)7eK?e97eCMQ3^NToJ~EcDCaGAGR6eU6-l@@wEF!XuZ3wMpv24EPLAGfn6iMFJ zgp!ZOR9il4CM)YBTkRG@so4+_6)naZ^FG@5&-ah_zOMWFopasi-1j-ZbME^-?&-n) zh`Ndj03YpkWqAQ0gopqIBj9lDexGG6&Wr5=!ru&E5en&$v%53E)m*j35EVjq^W5XJ zlfc~ETmu7xLx&EvwzgJRSC5a6bEA&3-Gl7x?Be6&v$M06N@aO@`HL4X+S}Xr?b{a? z7ABSUOQq7jzP^fzitD$ePR_*XaH?VZY6A4*y*#`Lm;X5c*+Q)+j8??B`o{s#?krEF zA^-3sfa=rTEN7qZgC@`C_zs(CW^EQu)DAQcF5NrvMpe@vc94DpRj& zqn+s;{%N07t%!4Jlt;f{=D4_RH(~}V_>%D%)Dx&ogj1KnQj z_S;X5M8h`4B0FH)LzF*jY05`f$-3I(@EtVq0tsMtAteVg*?!6v_Qv;dpBBK z=$V+F9$J5k{Q@8F+hMQ@Ayx`!{h$r7VGQj$V(@dFeCDv+g-Dfj$e+=9tQN_0F z<1gRPt3#Ja51yZ;x*YlC0*h5Cv9o`5hHxZV1dImX-n0Kgb7(31QJ1w&OS?+xIBeV z9_81RlBbM_L{5&=#m$3(mq0gOU4{EJ%wDnNEYij<6rzKko8=RaYk2kNZ z&@I9iGdZ(=Fs^!xswL6Oaxg=f>%Z}5r?O@3gI+`zuNvv%xe1PAFWc5Y+=gy=o3x3# zJ#Lu?MF+AiuB>zPjxS9VU?_2cO3Ck=KfclqMdCy-PXBIcQi%G78AP46${gFrUq^dO zdcAHybRu)XQkG0F%g0QP5Olj=ypP`YTV3rWlM)f8)VcU1GT#tYx^>KvX@pN1`wbwD z7AI<+oA8Wr3vcgN=LK)}QI_lEelanFaQtBvHXoKXIvO$)Qp*3*;HSmLuq*{P5935O zPLCGTZR=cvobXVPmCzH8AE3raIM-WO^VU2GtMw0g10|mc(aav|uPz3cx*0_BS(q@( z)^bR&Lv21Ni=cPmko%<$XD*~Wg0TW1IIfwL>@Avf~*vu9P54pK}SPsuQ0 z=t$&4nS9&_xFi;0Ev}h{%M@3XBSa8l;dBPh09z$RBA=O=u}2&raA^~0qbM}A@cqH7Er+<)Hzys!Kah|jFuoxI!!4%vTn1y2E47r*Lvxqkb zLDp)YaK*dM5aRD%%hyYwJhs(coYr%&+FlFQ{Pew2Bx+99y4IB^=Vi{7mGN5F&lp=> zx(GTr%JkL$;9>?T;_nMliP+{gnT|AAtgcb-O!2e7Qf9{wy=_%`vMjOV1AYY$cd$Ox zvm&;Fpsm7?6WqzqQt1)3_>+^I_YN`QC9{dwgg+fxU0k5e^YR#n;alOce_2kDO$+Bw zPp_j%a!37A$frt4izRnM zj)uZgjU${iSFWQqpw@lUmX~I8>B38Gz;FEi|p7Ns{6XG$cPta1gHGg4zD?>xQ_z(0>E?krFVofbi>jc%$kg zOmn4FL%_|y>qWH3k6?o81C^qK#>mMK&NhGTpuyac9tc+74hPdEE(|s1tV@X;7Aprp zG#Utv-Fw1H(YR^1B}ERh>j-K3SKN%)L=;t^#)!@-&LG+*SOaXY*dSctRc~N;Z2)O( z7naxD?pXvPBoyfgI#|U9vs9EP literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/create/textures/gui/schematics_2.png b/src/main/resources/assets/create/textures/gui/schematics_2.png new file mode 100644 index 0000000000000000000000000000000000000000..3d2dffdef0a2021073aef3c1b8a717fb4ce053e8 GIT binary patch literal 4015 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 WX_!ByM^^A-1FX#LNHwP3ss9GfsDr!! literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/create/textures/gui/sequencer.png b/src/main/resources/assets/create/textures/gui/sequencer.png index 13a8cbd33a1331fd77dd7c526e93ee82f20c9748..5dcbea527b17911cdc72bbf8be0f96e607950def 100644 GIT binary patch literal 1696 zcmdT^do+}37=OR{W}2`KhjCmoYFF7vR1)FvjYJ~NG7}{t9h1;bX4KH)E0uLuY1>eT zT-w|#BfB+blx9vBc9v?UNWwA<>oP({&3;pR`fJbrzwbHEd4A9HKJRmW=efKYG=J}9 z+NRn7fMq`0Jp%xMFbILAFs5Q^g6SHI9pLQ&>N?CuFayt|?xX^6Gf!tRf`HkfG(Y+_ zOcMwM91gc+$&%^TI0%9oFL(x70YRZ>*hUDC$LHtgbGh8+=4P6k71e&FqoX5-!^z6Z zQmfTvWn~WEl0_mBgTaW3it6w0m&snrWHPB#T3%j`Wj63wYm2EBoB;noEdDx9OGB&<4L7+!^W@V?Cy5bJHywB-LZ9V%8n8wQ7x`9dt+%a zu$}kQqip-RBDQgNRm{kOS3qTYSDos*>W;#;Gq1q^ihEdryQ(L2U%C5iowqb};rdpl zgS^hxPOWS|T(M4Q^hT}&D)=5m3B&=;)euFm7mBvPSMYD`4K2NGx(ceR56V!qJyOn} zU)(ZCsUpo6dcFbY?WtK2p_ zPCxaIeMZpR<%|2#enqJr$~C1R#6ePX+&~?d$#c*RB=+<=PSNh&epQ%W3#V-Q48>ZM zhTc`sX2plZq(J#|zlG!3545Uk6N@EK(QDDxq>^_QpPq=VhS9K-WA+kjWIQnJNc)3$ z(jhbThYxX69S5p!z@0Yv?Lgk;b29;1*vN6RHxcmQBd1|=Nk!KIS7PkoZ3XZk!Jq1xb`$QS^;;Se(m|b zV{eRkC23MmBOE|MTdHVBfi;gE!Dw!huDvr9p#Wq4Q30f-e0O<#7%(Jw9z(=$L}4OD|3B3JokmjYN##n z7HbI1BwF%emQ!m7G;Ou9hLZmr&U9(gf6l)eLOf_#N={;woF4>KsdD;^=ELY)yTbMq(vLwgVhh2pTI>Dg*^NB zMO*reTg*xrhF;^5`tKLr{3v~2YeWv5K{BJXA3Qrc98jz35C42AX)&-_$KkzjjisRc zCw^5Y_`s!AcR(iY1Bu&2FURn|KZK0`@aqskIRpD^V3EL1;{5TUbNGx3*FLcS7Oa1Q z*eLb9E3Iu^%__i~|TAF^Z)0&bFJ8l1bq zNyAbSX6Tg=dH&zJI#ltpV4{XM6fuh4k7pdX)48JJ)41kN$aZX~nVHVa#>PZM%4eo7 zf5#8|)j`)8B_aD6n&x0gZ&#THAjKDZ=~i-d)TI(`OEmvzCb>VEoA+H@`-2xy&Ohma zZp0|irDDq{uh#ZK`_z99eS={8>b%IVWHu6HuatCoo6??u`APs;cn-LWd)@_EXt5lx zDeB$a1#7Gu0Muk>SD&P9Lq*3G)mL#@dPpE7z?ECE?9gktBLuk=O#|Ih$JK;;+6~JE zdf}?s*~)8ZAar)h7iuI=S_;>*vfT~(MnIt=iqPLL4*k;Q_g&?d0}57EUFzNibmRd?*wCJl^U0|+HRUb7^0P7zcX um0Y$~sE_fNEZ#MO2nb2%e=Ltxs_#82gW%mo{8{V=2R_^UJ?lKePyG%4>(g5R literal 2241 zcmeAS@N?(olHy`uVBq!ia0y~yU<5K58911MRQ8&P5D>38$lZxy-8q?;Kn_c~qpu?a z!^VE@KZ&di49pAxJ|V6^aXoF-XfLDC0QHn`m*i;wta$&t)QIY`yj$0|zk2lws9+R~ zhQM$QftX_~{h(Y^666>Be`EuO;P33JzlBSEK;T4m(d5$B>G+ zw{tJ%EjAEvoxCjf*5CjC&ob>3ab`Q=b$8>^>OPZQS3fj7*HAbvov9!D>BQrrpO>Y# zM{jF*zt6#8TSIjD6RsD6x_Zs0AAkB<`o8nEX>lEk0s|w50|QgZYdat*uwd)b1_l;| z191nQKd<&zSnyT(!@qU*QjI_{hiq>~Mh**+58uA!hjy$x6WXy`nB#@VfwGzFL+-52 zUa$R$^@{buM8-U(uq*Tbb!Mz|hpBqW^ks94U^wHi@}KW-s~mVI=+IC%)!@NTjw=>i z65koQ4>SGw#`sNIaoZt|3v0Qx8F`^DIp8h8$j-Fwbj{L7d9l^86ZIQ}7qcjSYOz*2rK%v*vL0ZxidbtOGu1pxNmo$PWecf1mmvKMAZdg zPj1;JBDI&r-tJmxW5YEjtwoIIwBB9&YV*&_abLsP&I`3aSzJ!ruigH3~u3425_L!V0&qd;T$;YZmv0 zYW5uemR0@^HgL`FAE>_g#s~50s-KGy)^aoM`YL?!(|MpXuI^^o$F1N{Z^8t0YQwc@ zhw3Xi^WqCjMIXImVX_hu=&cAle>fK$%zwV+w=DYj>elP797b(3rbmMPs|0v0!WG~7 zE#bb9d7)!9!`${i*Zfnqfz_|OzTSuVFXs;a`=^9?S=61n8!C=0)^cG!2aG_as}1++ z7V$H#WLs8y;84N$XZ;5bY?!3O{5Q8n?Gw+J?V@^1BwvI&%xYZQFkiMXd!48BqUHV# zH~*yfJ7`~e#?SJ_;ohHgrfvGGH*2|sKhrvLcjl3wyG15g{@>W})+m1Ej_B)g z0uOvMcjCV21oG$B>!Le9v&XlExp>>IawDy9QNZ7&5wB_uWUKP^%;#5rQ4(rB-bu1>J zbPWtgCMJOgdJDX_?BEGwSE@Cr(Z2e~XvKMED@MjY=P&PMs&eT*t?)T6wuxb>E=Rzv f;YmGXlI!2U<~*Cn#D=L)LDh(-tDnm{r-UW|cw-Hm diff --git a/src/main/resources/assets/create/textures/gui/wand_symmetry.png b/src/main/resources/assets/create/textures/gui/wand_symmetry.png deleted file mode 100644 index 49405bd245515ac8a17ebec7576452117137d4d2..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1781 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 literal 2992 zcmeHJX;c$d7JdmvVkm@KSp)=>ifaT516C3fsR)XSAbWs-3RH-sniN?jXb>I1pcohy z1Gs@8OAN@O35#W`(10VdX@cy;u*3*q$uijKkG9k4%>17p@4WZD``vr)`QE+fzH7&i z*{dV;5C8!6LkZ^=}!ieD_~Xd{-gT=VA0iN0k9Rk z<~s*3G5{L2pB6-`&gvxqYIcVX?01dun|j+pa_w2)BDNS_&(kHsHy2hUT(wd!!TGw5 zIu&LiULAJ3k&$1#>+ZqEr$tvQOE$44ijuY#Z`$H)x9Vt-ySvVf%?Iv>H#j;tLNaZ4 zlNv}ChP-MXdEBoKPT$D1VXjwlbA=;0!)iSzM3SdG%<%f)={GfO-7LzysBdFQ`oDC@4bD9OSzH0neC2pL6d37Tn}2^ z87wr0Hn+AqluKwAunWeD)@Iq*?F)?x`Es^K+Bb~v3i{z{YLF&4n|kXbx0UT) zTSl}|MRet!Gux|SnFPLNn?3k(V|HZ|=gw5WS2EpdACm^}{0y3>{wzkoDK=v!%#I|z zBqz!2TH-BNq6{TP@TSj-chc;g#+dk#_lChpu+13s*T0Z5iB=HZ;y!c{Ke8Al zUFVF|W42UYD|>e@R$lxfNv0V2Sad4oI$M=$*;}>NDm!Dw3*WS3fLk_om40Pbpj_NU zQ0_@x4b3}hI*nl`aAFwJ`F`tkoyDYIe6+0aE?hxPXcGFA$AZ>WJ=fz7cG!<%@U1qa zGpNdxd4)*~a*LK%`ii@nTl!RRdLx9-D!kk|x)W)5Y+q)kjdHQ1MQm>yFF|k9L zhxU#R6l&?76oK0e_{$4p^pHv+m7Z20xp|b6aXYa|h$g{b_MKL#FI(UarX|dfkx-A~ z?mMu$$I#h}0Rj6>fpp_&^CG8CD5x2&67~L(->pb3pXed{V7pm3Ucw-v z7wMY&WQrRTyq#hW*36qcpOU%5TY`+x8qEEvsMq^z8VtX{2!UIDM&1|`wVUQ!S4T_> z zv6C$DL2OeF$~=^>BgrpIr8jqnpxXO{+cS!s3ENS5#Q`CkXju8I!@{^gI6ldO z4UjHW50uQ!lm{vgzlJtwpUs8ECtQ_}mhU;CVR2$(`;kQRxe7j^%623=j%(07^NKed z?j1&CkCA8=of+x_(aW}R`ML>RqL^(*7$S7~7WQkV7jt1@>AB`X?Y%odUV%Q;zuO7A z2xX>(i!%J8!#pywe9v**rVP2>C3H?nlZx?skF)rSugjn^l`gFxvtZY5*H14_ z4Uv+%5myTdj%Ap=aYK35!Q-qGBOP#qb);+*Zwv4MX7?X5)oMpHTIgtJZZgY zWHSfzWPgdTnTRzp6Y77NQzm_eiXnUmN1RfM*KKs3`$Y>1Lvs$Z`3)UX?kYu=ZF z?G&9{d+^DEe0T2@EjZO0TOtL1eq+HpjYB@N=Ru1xrX$3rQAuAE+p%0)>hiFU(Vr!K ztu4BVf4H-(nvijwcCDIX);nYt#tw3;b9-$Sp1P!&YN`*y z#CPlb=&N@S!VyHbIN5X3UB%y7NRDHy*k&F8iX{|i9t5Bf4sg0FbI$~TfK|Xa835Yn zfNK74jg=UnAct-WSu@s8Chpn}aGnGFwL1^VNrt^TbM2W=PxC{bZT8%t1&kj}kq}w) zjLVT1c-CrKxKCHf7%=86I3sbt3oX101vHjwJz8iJ$n`1&!ormVL=bcO(y{C+yv9Y zZTA#&P?v7?(4-a0uLOA%Y7L3c=q^<0p$&&8nS-K zzI5`13D6rpgZo*S;f%{rR3i#dum5ZLJbFhyGZlfjTrgkGn6)(iBg!9C*bE{WMZW+G z+i9^fv5+1%ksnT@`_U#QCSte)ue0+wy5Gll1E_c34=kGv|BD*^(*pjTu}*gt-mp&h z9&29q0zely0PNNKAKKw}(f;rGo96k0xBd?bwIbdreV1X&O-4^}E5B@T$nMyIQd|E^ F{{RP?^eX@W diff --git a/src/main/resources/assets/create/textures/gui/zapper.png b/src/main/resources/assets/create/textures/gui/zapper.png deleted file mode 100644 index 771941d43398272902f49043a982a8f554a25af2..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 10750 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 From 378164b8b9dafc991cbb616f5c985e8321bf13fc Mon Sep 17 00:00:00 2001 From: simibubi <31564874+simibubi@users.noreply.github.com> Date: Tue, 6 Oct 2020 20:43:13 +0200 Subject: [PATCH 2/2] More unfinished basin business - Fixed players flailing their limbs around while standing still on a moving contraption - Attempted to reduce drag of remote player positions while on a contraption - Contraptions no longer log out with the player riding them - Attribute filters are now made of brass - Added the ability to disable auto-compat with vanilla recipe types in the configs - Added a recipe type for custom basin/press compacting - Basins can now process items and liquids in recipes - Input items/fluids of a basin can now be extracted or reused in further processing - A basin diagonally below another basin with collect outputs of recipes processed in the top basin for ease of automation - (Temporary debug recipes) --- src/generated/resources/.cache/cache | 12 +- .../assets/create/blockstates/basin.json | 19 +- .../create/blockstates/radial_chassis.json | 24 +- .../assets/create/models/item/basin.json | 2 +- .../crafting/kinetics/attribute_filter.json | 2 +- .../data/create/recipes/compacting/ice.json | 14 + .../recipes/compacting/temp_gabbro.json | 18 ++ .../crafting/kinetics/attribute_filter.json | 2 +- .../create/recipes/emptying/water_bottle.json | 18 ++ .../create/recipes/mixing/temp_cobble.json | 19 ++ .../java/com/simibubi/create/AllBlocks.java | 6 +- .../com/simibubi/create/AllRecipeTypes.java | 15 +- .../simibubi/create/compat/jei/CreateJEI.java | 124 +++++---- .../compat/jei/category/BasinCategory.java | 88 +++++++ .../compat/jei/category/MixingCategory.java | 78 +----- .../compat/jei/category/PackingCategory.java | 47 ++-- .../components/crafter/RecipeGridHandler.java | 15 +- .../CrushingWheelControllerTileEntity.java | 6 +- .../millstone/MillstoneTileEntity.java | 9 +- .../components/mixer/CompactingRecipe.java | 13 + .../mixer/MechanicalMixerTileEntity.java | 72 +---- .../components/mixer/MixingRecipe.java | 89 +------ .../press/MechanicalPressTileEntity.java | 246 ++++++++---------- .../components/press/PressingRecipe.java | 6 +- .../components/saw/SawTileEntity.java | 8 +- .../ContraptionCollider.java | 59 ++++- .../structureMovement/ContraptionEntity.java | 24 +- .../structureMovement/ContraptionHandler.java | 4 +- ...ler.java => ContraptionHandlerClient.java} | 46 +++- .../sync/ClientMotionPacket.java | 10 +- .../sync/LimbSwingUpdatePacket.java | 62 +++++ .../fluids/actors/FillingBySpout.java | 9 +- .../contraptions/processing/BasinBlock.java | 91 ++++++- .../processing/BasinGenerator.java | 32 +++ .../processing/BasinInputInventory.java | 27 -- .../processing/BasinInventory.java | 23 ++ .../processing/BasinOperatingTileEntity.java | 150 +++-------- .../contraptions/processing/BasinRecipe.java | 199 ++++++++++++++ .../processing/BasinRenderer.java | 18 +- .../processing/BasinTileEntity.java | 108 +++++++- .../processing/EmptyingByBasin.java | 75 ++++++ .../processing/EmptyingRecipe.java | 42 +++ .../content/logistics/InWorldProcessing.java | 6 +- .../logistics/item/filter/ItemAttribute.java | 4 +- .../create/foundation/config/CKinetics.java | 4 +- .../create/foundation/config/CRecipes.java | 26 ++ .../create/foundation/config/CServer.java | 2 + .../data/recipe/CompactingRecipeGen.java | 35 +++ .../data/recipe/EmptyingRecipeGen.java | 33 +++ .../data/recipe/MixingRecipeGen.java | 6 + .../data/recipe/ProcessingRecipeGen.java | 2 + .../data/recipe/StandardRecipeGen.java | 4 +- .../foundation/fluid/CombinedTankWrapper.java | 6 + .../create/foundation/fluid/FluidHelper.java | 3 + .../foundation/item/SmartInventory.java | 56 +++- .../foundation/networking/AllPackets.java | 2 + .../fluid/SmartFluidTankBehaviour.java | 43 +-- .../models/block/basin/basin_canal.bbmodel | 1 + .../block/{basin.json => basin/block.json} | 0 .../models/block/basin/block_directional.json | 237 +++++++++++++++++ .../create/textures/block/basin_canal.png | Bin 0 -> 1646 bytes .../textures/item/logistical_filter.png | Bin 376 -> 0 bytes .../create/textures/item/property_filter.png | Bin 329 -> 259 bytes 63 files changed, 1685 insertions(+), 716 deletions(-) create mode 100644 src/generated/resources/data/create/recipes/compacting/ice.json create mode 100644 src/generated/resources/data/create/recipes/compacting/temp_gabbro.json create mode 100644 src/generated/resources/data/create/recipes/emptying/water_bottle.json create mode 100644 src/generated/resources/data/create/recipes/mixing/temp_cobble.json create mode 100644 src/main/java/com/simibubi/create/compat/jei/category/BasinCategory.java create mode 100644 src/main/java/com/simibubi/create/content/contraptions/components/mixer/CompactingRecipe.java rename src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/{ContraptionInteractionHandler.java => ContraptionHandlerClient.java} (72%) create mode 100644 src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/sync/LimbSwingUpdatePacket.java create mode 100644 src/main/java/com/simibubi/create/content/contraptions/processing/BasinGenerator.java delete mode 100644 src/main/java/com/simibubi/create/content/contraptions/processing/BasinInputInventory.java create mode 100644 src/main/java/com/simibubi/create/content/contraptions/processing/BasinInventory.java create mode 100644 src/main/java/com/simibubi/create/content/contraptions/processing/BasinRecipe.java create mode 100644 src/main/java/com/simibubi/create/content/contraptions/processing/EmptyingByBasin.java create mode 100644 src/main/java/com/simibubi/create/content/contraptions/processing/EmptyingRecipe.java create mode 100644 src/main/java/com/simibubi/create/foundation/config/CRecipes.java create mode 100644 src/main/java/com/simibubi/create/foundation/data/recipe/CompactingRecipeGen.java create mode 100644 src/main/java/com/simibubi/create/foundation/data/recipe/EmptyingRecipeGen.java create mode 100644 src/main/resources/assets/create/models/block/basin/basin_canal.bbmodel rename src/main/resources/assets/create/models/block/{basin.json => basin/block.json} (100%) create mode 100644 src/main/resources/assets/create/models/block/basin/block_directional.json create mode 100644 src/main/resources/assets/create/textures/block/basin_canal.png delete mode 100644 src/main/resources/assets/create/textures/item/logistical_filter.png diff --git a/src/generated/resources/.cache/cache b/src/generated/resources/.cache/cache index 5e874a19e..da4fb047b 100644 --- a/src/generated/resources/.cache/cache +++ b/src/generated/resources/.cache/cache @@ -18,7 +18,7 @@ a579c40c43dc2174afb66f42d00d0c4a0efaaeee assets/create/blockstates/andesite_bric 11908c2f8603e61bec88010bc6d0890e6339c6b1 assets/create/blockstates/andesite_funnel.json 398922758a6219544e5b85c91c9cf8a543b437e5 assets/create/blockstates/andesite_pillar.json 1d2d8081581e07d9be4b382aede4f2de4401cc6b assets/create/blockstates/andesite_tunnel.json -f9fa6aa530eb0891a74eadfbebc663172a57147a assets/create/blockstates/basin.json +e555e3c2b2d3f01440e48db4ba88f7e00fd99b6f assets/create/blockstates/basin.json f25693a9429f6337149ff24f27900dc4eb82a7c2 assets/create/blockstates/belt.json cf9045eb16e5299a1d917c4cb536289f49411276 assets/create/blockstates/birch_window.json 94a1a91403eb4b035fec48071e7fcae57a8a6abd assets/create/blockstates/birch_window_pane.json @@ -1045,7 +1045,7 @@ b0f664dd6de3d0ee9afcb6223fbcd53b97fa0d65 assets/create/models/item/andesite_cobb 7490819e7e5445019b6b8cb2538f12a5b6717a46 assets/create/models/item/andesite_funnel.json 75b8b00c2418b9660d35a7fabd0774925cf1c02f assets/create/models/item/andesite_pillar.json c0e35daccfb398947532e9499d6bda963387cd9c assets/create/models/item/andesite_tunnel.json -bf1fc6bdf7fca6f1958a2d3e96202c1cecb50669 assets/create/models/item/basin.json +421e481b7fbca4c4a1080ed703401eb25375e087 assets/create/models/item/basin.json 1da382e7e58eaa9788f5b1d92221ccac573e068f assets/create/models/item/belt_connector.json 9044243882cfd49a2827e1b910a4c9b0e46daa47 assets/create/models/item/birch_window.json 6ed49f59ea91068ef68720f43e67a9237594bdf0 assets/create/models/item/birch_window_pane.json @@ -1481,7 +1481,7 @@ d531f87f425d199aee4777a588c1cd6cab6f5173 data/create/advancements/recipes/create 2eef3201017af03f6a2f0f015645e3ff5e25d9c1 data/create/advancements/recipes/create.base/crafting/curiosities/wand_of_symmetry.json d97d96e1b2ddd25df15fe1ef1c3d084f15bb9789 data/create/advancements/recipes/create.base/crafting/kinetics/adjustable_pulley.json 92416ced6ede6965fd728e1c7336bb05a3e41ea2 data/create/advancements/recipes/create.base/crafting/kinetics/analog_lever.json -2105b4f1fd9a170a100efc083a794fdb9e068924 data/create/advancements/recipes/create.base/crafting/kinetics/attribute_filter.json +3e9753006da898d4569bbeabf95997e8c90847c8 data/create/advancements/recipes/create.base/crafting/kinetics/attribute_filter.json bec8c280b717306f87050b08a418feab53be71cb data/create/advancements/recipes/create.base/crafting/kinetics/basin.json 5af08853632fb5970fe542b3ecbde0ad16d64714 data/create/advancements/recipes/create.base/crafting/kinetics/belt_connector.json 80d87f1dde60adb5334e0cff25a9f0b7f67c1526 data/create/advancements/recipes/create.base/crafting/kinetics/black_seat.json @@ -2428,6 +2428,8 @@ d9021504be855cd2d4d91503a82b84233052adb0 data/create/recipes/blasting/gold_ingot c323b106e88b7de77fea71ff12494abdbb818d15 data/create/recipes/chiseled_limestone_from_limestone_stonecutting.json da9a919b476954c1de34826aa7706bf6056a8f12 data/create/recipes/chiseled_scoria_from_scoria_stonecutting.json 09faa4ddcf9f3907dcdb3ab3e8b68c1deb2486e5 data/create/recipes/chiseled_weathered_limestone_from_weathered_limestone_stonecutting.json +c3cfdc9552a23e4749c42e71fbddd153b76ca708 data/create/recipes/compacting/ice.json +5758a1804287c261e1c953bda599d8495ba7c40a data/create/recipes/compacting/temp_gabbro.json 19526da3a59fc136654ff1bc93c0251581f397a9 data/create/recipes/crafting/appliances/dough.json 7b5f863dda3d05a79cb85943a178eba0bd8a7dc7 data/create/recipes/crafting/appliances/slime_ball.json b159ba84428eee6ef6e23df1766f2a18f2c8a63e data/create/recipes/crafting/appliances/tree_fertilizer.json @@ -2437,7 +2439,7 @@ b159ba84428eee6ef6e23df1766f2a18f2c8a63e data/create/recipes/crafting/appliances fcbc04d0a7eaf820a74bc7e4736a4a581e0a9dff data/create/recipes/crafting/curiosities/wand_of_symmetry.json 696df0fe5f8e29220ea15527f8c119c39b418819 data/create/recipes/crafting/kinetics/adjustable_pulley.json 88de51b451469698665b7319e5b9cfb9a87ae3e0 data/create/recipes/crafting/kinetics/analog_lever.json -6912101930aae627820783c27358dcf2ff4016aa data/create/recipes/crafting/kinetics/attribute_filter.json +cf1f3a6306d47025cebe153cf05949ef69ccbe5a data/create/recipes/crafting/kinetics/attribute_filter.json 059d12526529b2896ed583555373afa31839a0de data/create/recipes/crafting/kinetics/basin.json dcf98e667d321fb4bd9fa6dfec7927a84cdbd5d6 data/create/recipes/crafting/kinetics/belt_connector.json 1123903a11b13448b61cf8f8a5dc2e8013d39ac0 data/create/recipes/crafting/kinetics/black_seat.json @@ -2675,6 +2677,7 @@ ddda28bb6efc43b7e3149756daf53e1664187283 data/create/recipes/dolomite_cobbleston 500ecdfdcf34e9d26256948e206aab4f0b79e659 data/create/recipes/dolomite_cobblestone_wall_from_dolomite_cobblestone_stonecutting.json ff39e629b242ae91e23aec86b0a1f757dd938305 data/create/recipes/dolomite_pillar.json b4a8d14d9a20e812e0acb691b5b511a87e8b0576 data/create/recipes/dolomite_pillar_from_dolomite_stonecutting.json +ae6698363e49f7cb5f2ed52c6b8805bebed31fa2 data/create/recipes/emptying/water_bottle.json 0e11aa1accb71ed62e212f23a7069b7b7b4e8119 data/create/recipes/fancy_andesite_bricks_from_andesite_stonecutting.json 8b86fc9a9416adeaab3f26192a73a481887675c3 data/create/recipes/fancy_andesite_bricks_slab.json c7b762b25c7a6705dba3e922e981be851ac4f36b data/create/recipes/fancy_andesite_bricks_slab_from_fancy_andesite_bricks_stonecutting.json @@ -2860,6 +2863,7 @@ e7bfaa806d57573d060fac0a5e7a84f345b8bb85 data/create/recipes/mixing/andesite_all 76939e4d3e5b615ae21d14c0ff7b917a622bcf80 data/create/recipes/mixing/chromatic_compound.json d9a3dff1288d675ab812eef1eb73cb27dcc71bd2 data/create/recipes/mixing/crushed_brass.json 00b165ea38d834c7955440e87062004a8182c3f8 data/create/recipes/mixing/gunpowder.json +35c4e8a765479861f307afb9ec650f912f92b998 data/create/recipes/mixing/temp_cobble.json 1998c6f84f871d6da58ec29d729401d18f8f1aa1 data/create/recipes/mossy_andesite_from_andesite_stonecutting.json 89929d9cb11b5c589b2ecfa821c61add1ef7b62b data/create/recipes/mossy_dark_scoria_from_dark_scoria_stonecutting.json 4b8b1191dd3a21294293dc5ad237af89b849df28 data/create/recipes/mossy_diorite_from_diorite_stonecutting.json diff --git a/src/generated/resources/assets/create/blockstates/basin.json b/src/generated/resources/assets/create/blockstates/basin.json index 2bc6fd9d1..0e511666e 100644 --- a/src/generated/resources/assets/create/blockstates/basin.json +++ b/src/generated/resources/assets/create/blockstates/basin.json @@ -1,7 +1,22 @@ { "variants": { - "": { - "model": "create:block/basin" + "facing=down": { + "model": "create:block/basin/block" + }, + "facing=north": { + "model": "create:block/basin/block_directional", + "y": 180 + }, + "facing=south": { + "model": "create:block/basin/block_directional" + }, + "facing=west": { + "model": "create:block/basin/block_directional", + "y": 90 + }, + "facing=east": { + "model": "create:block/basin/block_directional", + "y": 270 } } } \ No newline at end of file diff --git a/src/generated/resources/assets/create/blockstates/radial_chassis.json b/src/generated/resources/assets/create/blockstates/radial_chassis.json index c930cf0b5..1aa3d3728 100644 --- a/src/generated/resources/assets/create/blockstates/radial_chassis.json +++ b/src/generated/resources/assets/create/blockstates/radial_chassis.json @@ -149,8 +149,8 @@ }, { "when": { - "sticky_north": "true", - "axis": "x" + "axis": "x", + "sticky_north": "true" }, "apply": { "model": "create:block/radial_chassis_side_x_sticky" @@ -158,8 +158,8 @@ }, { "when": { - "sticky_north": "true", - "axis": "y" + "axis": "y", + "sticky_north": "true" }, "apply": { "model": "create:block/radial_chassis_side_y_sticky", @@ -168,8 +168,8 @@ }, { "when": { - "sticky_north": "true", - "axis": "z" + "axis": "z", + "sticky_north": "true" }, "apply": { "model": "create:block/radial_chassis_side_x_sticky", @@ -178,8 +178,8 @@ }, { "when": { - "sticky_north": "false", - "axis": "x" + "axis": "x", + "sticky_north": "false" }, "apply": { "model": "create:block/radial_chassis_side_x" @@ -187,8 +187,8 @@ }, { "when": { - "sticky_north": "false", - "axis": "y" + "axis": "y", + "sticky_north": "false" }, "apply": { "model": "create:block/radial_chassis_side_y", @@ -197,8 +197,8 @@ }, { "when": { - "sticky_north": "false", - "axis": "z" + "axis": "z", + "sticky_north": "false" }, "apply": { "model": "create:block/radial_chassis_side_x", diff --git a/src/generated/resources/assets/create/models/item/basin.json b/src/generated/resources/assets/create/models/item/basin.json index 1dc14b2e8..a1ed06ff7 100644 --- a/src/generated/resources/assets/create/models/item/basin.json +++ b/src/generated/resources/assets/create/models/item/basin.json @@ -1,3 +1,3 @@ { - "parent": "create:block/basin" + "parent": "create:block/basin/block" } \ No newline at end of file diff --git a/src/generated/resources/data/create/advancements/recipes/create.base/crafting/kinetics/attribute_filter.json b/src/generated/resources/data/create/advancements/recipes/create.base/crafting/kinetics/attribute_filter.json index 5b1c63f80..e41c26b07 100644 --- a/src/generated/resources/data/create/advancements/recipes/create.base/crafting/kinetics/attribute_filter.json +++ b/src/generated/resources/data/create/advancements/recipes/create.base/crafting/kinetics/attribute_filter.json @@ -11,7 +11,7 @@ "conditions": { "items": [ { - "item": "create:andesite_alloy" + "tag": "forge:ingots/brass" } ] } diff --git a/src/generated/resources/data/create/recipes/compacting/ice.json b/src/generated/resources/data/create/recipes/compacting/ice.json new file mode 100644 index 000000000..98ae992e9 --- /dev/null +++ b/src/generated/resources/data/create/recipes/compacting/ice.json @@ -0,0 +1,14 @@ +{ + "type": "create:compacting", + "ingredients": [ + { + "item": "minecraft:ice" + } + ], + "results": [ + { + "fluid": "minecraft:water", + "amount": 250 + } + ] +} \ No newline at end of file diff --git a/src/generated/resources/data/create/recipes/compacting/temp_gabbro.json b/src/generated/resources/data/create/recipes/compacting/temp_gabbro.json new file mode 100644 index 000000000..c5474f6f5 --- /dev/null +++ b/src/generated/resources/data/create/recipes/compacting/temp_gabbro.json @@ -0,0 +1,18 @@ +{ + "type": "create:compacting", + "ingredients": [ + { + "item": "minecraft:cobblestone" + }, + { + "fluidTag": "minecraft:lava", + "amount": 250 + } + ], + "results": [ + { + "item": "create:gabbro", + "count": 1 + } + ] +} \ No newline at end of file diff --git a/src/generated/resources/data/create/recipes/crafting/kinetics/attribute_filter.json b/src/generated/resources/data/create/recipes/crafting/kinetics/attribute_filter.json index 15bd0d895..5e1cfd2cc 100644 --- a/src/generated/resources/data/create/recipes/crafting/kinetics/attribute_filter.json +++ b/src/generated/resources/data/create/recipes/crafting/kinetics/attribute_filter.json @@ -8,7 +8,7 @@ "tag": "minecraft:wool" }, "A": { - "tag": "forge:nuggets/copper" + "tag": "forge:nuggets/brass" } }, "result": { diff --git a/src/generated/resources/data/create/recipes/emptying/water_bottle.json b/src/generated/resources/data/create/recipes/emptying/water_bottle.json new file mode 100644 index 000000000..1a34fd570 --- /dev/null +++ b/src/generated/resources/data/create/recipes/emptying/water_bottle.json @@ -0,0 +1,18 @@ +{ + "type": "create:emptying", + "ingredients": [ + { + "item": "minecraft:potion" + } + ], + "results": [ + { + "item": "minecraft:glass_bottle", + "count": 1 + }, + { + "fluid": "minecraft:water", + "amount": 250 + } + ] +} \ No newline at end of file diff --git a/src/generated/resources/data/create/recipes/mixing/temp_cobble.json b/src/generated/resources/data/create/recipes/mixing/temp_cobble.json new file mode 100644 index 000000000..f20d0e6cf --- /dev/null +++ b/src/generated/resources/data/create/recipes/mixing/temp_cobble.json @@ -0,0 +1,19 @@ +{ + "type": "create:mixing", + "ingredients": [ + { + "fluidTag": "minecraft:water", + "amount": 250 + }, + { + "fluidTag": "minecraft:lava", + "amount": 250 + } + ], + "results": [ + { + "item": "minecraft:cobblestone", + "count": 1 + } + ] +} \ No newline at end of file diff --git a/src/main/java/com/simibubi/create/AllBlocks.java b/src/main/java/com/simibubi/create/AllBlocks.java index c90ae2de4..c7f9c8cef 100644 --- a/src/main/java/com/simibubi/create/AllBlocks.java +++ b/src/main/java/com/simibubi/create/AllBlocks.java @@ -73,6 +73,7 @@ import com.simibubi.create.content.contraptions.fluids.tank.FluidTankGenerator; import com.simibubi.create.content.contraptions.fluids.tank.FluidTankItem; import com.simibubi.create.content.contraptions.fluids.tank.FluidTankModel; import com.simibubi.create.content.contraptions.processing.BasinBlock; +import com.simibubi.create.content.contraptions.processing.BasinGenerator; import com.simibubi.create.content.contraptions.processing.BasinMovementBehaviour; import com.simibubi.create.content.contraptions.processing.burner.BlazeBurnerBlock; import com.simibubi.create.content.contraptions.processing.burner.BlazeBurnerBlockItem; @@ -408,9 +409,10 @@ public class AllBlocks { public static final BlockEntry BASIN = REGISTRATE.block("basin", BasinBlock::new) .initialProperties(SharedProperties::stone) - .blockstate((ctx, prov) -> prov.simpleBlock(ctx.getEntry(), AssetLookup.standardModel(ctx, prov))) + .blockstate(new BasinGenerator()::generate) .onRegister(addMovementBehaviour(new BasinMovementBehaviour())) - .simpleItem() + .item() + .transform(customItemModel("_", "block")) .register(); public static final BlockEntry BLAZE_BURNER = diff --git a/src/main/java/com/simibubi/create/AllRecipeTypes.java b/src/main/java/com/simibubi/create/AllRecipeTypes.java index 2e2e6515e..908e39e87 100644 --- a/src/main/java/com/simibubi/create/AllRecipeTypes.java +++ b/src/main/java/com/simibubi/create/AllRecipeTypes.java @@ -1,5 +1,6 @@ package com.simibubi.create; +import java.util.Optional; import java.util.function.Supplier; import com.simibubi.create.compat.jei.ConversionRecipe; @@ -7,10 +8,13 @@ import com.simibubi.create.content.contraptions.components.crafter.MechanicalCra import com.simibubi.create.content.contraptions.components.crusher.CrushingRecipe; import com.simibubi.create.content.contraptions.components.fan.SplashingRecipe; import com.simibubi.create.content.contraptions.components.millstone.MillingRecipe; +import com.simibubi.create.content.contraptions.components.mixer.CompactingRecipe; import com.simibubi.create.content.contraptions.components.mixer.MixingRecipe; import com.simibubi.create.content.contraptions.components.press.PressingRecipe; import com.simibubi.create.content.contraptions.components.saw.CuttingRecipe; import com.simibubi.create.content.contraptions.fluids.actors.FillingRecipe; +import com.simibubi.create.content.contraptions.processing.BasinRecipe; +import com.simibubi.create.content.contraptions.processing.EmptyingRecipe; import com.simibubi.create.content.contraptions.processing.ProcessingRecipe; import com.simibubi.create.content.contraptions.processing.ProcessingRecipeBuilder.ProcessingRecipeFactory; import com.simibubi.create.content.contraptions.processing.ProcessingRecipeSerializer; @@ -25,22 +29,26 @@ import net.minecraft.item.crafting.IRecipeType; import net.minecraft.item.crafting.ShapedRecipe; import net.minecraft.util.ResourceLocation; import net.minecraft.util.registry.Registry; +import net.minecraft.world.World; import net.minecraftforge.event.RegistryEvent; public enum AllRecipeTypes { BLOCKZAPPER_UPGRADE(BlockzapperUpgradeRecipe.Serializer::new, IRecipeType.CRAFTING), MECHANICAL_CRAFTING(MechanicalCraftingRecipe.Serializer::new), - + CONVERSION(processingSerializer(ConversionRecipe::new)), CRUSHING(processingSerializer(CrushingRecipe::new)), CUTTING(processingSerializer(CuttingRecipe::new)), MILLING(processingSerializer(MillingRecipe::new)), + BASIN(processingSerializer(BasinRecipe::new)), MIXING(processingSerializer(MixingRecipe::new)), + COMPACTING(processingSerializer(CompactingRecipe::new)), PRESSING(processingSerializer(PressingRecipe::new)), SANDPAPER_POLISHING(processingSerializer(SandPaperPolishingRecipe::new)), SPLASHING(processingSerializer(SplashingRecipe::new)), FILLING(processingSerializer(FillingRecipe::new)), + EMPTYING(processingSerializer(EmptyingRecipe::new)), ; @@ -89,4 +97,9 @@ public enum AllRecipeTypes { public > T getType() { return (T) type; } + + public > Optional find(C inv, World world) { + return world.getRecipeManager() + .getRecipe(getType(), inv, world); + } } diff --git a/src/main/java/com/simibubi/create/compat/jei/CreateJEI.java b/src/main/java/com/simibubi/create/compat/jei/CreateJEI.java index 41ba41b63..bdc276c35 100644 --- a/src/main/java/com/simibubi/create/compat/jei/CreateJEI.java +++ b/src/main/java/com/simibubi/create/compat/jei/CreateJEI.java @@ -23,10 +23,12 @@ import com.simibubi.create.compat.jei.category.PressingCategory; import com.simibubi.create.compat.jei.category.SawingCategory; import com.simibubi.create.compat.jei.category.SmokingViaFanCategory; import com.simibubi.create.compat.jei.category.SplashingCategory; -import com.simibubi.create.content.contraptions.components.mixer.MixingRecipe; import com.simibubi.create.content.contraptions.components.press.MechanicalPressTileEntity; +import com.simibubi.create.content.contraptions.processing.BasinRecipe; import com.simibubi.create.content.logistics.block.inventories.AdjustableCrateScreen; import com.simibubi.create.content.schematics.block.SchematicannonScreen; +import com.simibubi.create.foundation.config.AllConfigs; +import com.simibubi.create.foundation.config.CRecipes; import com.simibubi.create.foundation.utility.Lang; import mezz.jei.api.IModPlugin; @@ -96,44 +98,62 @@ public class CreateJEI implements IModPlugin { @Override public void registerCategories(IRecipeCategoryRegistration registration) { - registration - .addRecipeCategories(millingCategory, crushingCategory, splashingCategory, pressingCategory, - smokingCategory, blastingCategory, blockzapperCategory, mixingCategory, sawingCategory, - blockCuttingCategory, packingCategory, polishingCategory, mysteryConversionCategory, - mechanicalCraftingCategory); + registration.addRecipeCategories(millingCategory, crushingCategory, splashingCategory, pressingCategory, + smokingCategory, blastingCategory, blockzapperCategory, mixingCategory, sawingCategory, + blockCuttingCategory, packingCategory, polishingCategory, mysteryConversionCategory, + mechanicalCraftingCategory); } @Override public void registerRecipes(IRecipeRegistration registration) { + CRecipes recipeConfig = AllConfigs.SERVER.recipes; + registration.addRecipes(findRecipes(AllRecipeTypes.MILLING), millingCategory.getUid()); registration.addRecipes(findRecipes(AllRecipeTypes.CRUSHING), crushingCategory.getUid()); - registration.addRecipes(findRecipesByTypeExcluding(AllRecipeTypes.MILLING.getType(), AllRecipeTypes.CRUSHING.getType()), - crushingCategory.getUid()); + registration.addRecipes( + findRecipesByTypeExcluding(AllRecipeTypes.MILLING.getType(), AllRecipeTypes.CRUSHING.getType()), + crushingCategory.getUid()); registration.addRecipes(findRecipes(AllRecipeTypes.SPLASHING), splashingCategory.getUid()); registration.addRecipes(findRecipes(AllRecipeTypes.PRESSING), pressingCategory.getUid()); registration.addRecipes(findRecipesById(AllRecipeTypes.BLOCKZAPPER_UPGRADE.serializer.getRegistryName()), - blockzapperCategory.getUid()); + blockzapperCategory.getUid()); registration.addRecipes(findRecipesByType(IRecipeType.SMOKING), smokingCategory.getUid()); registration.addRecipes(findRecipesByTypeExcluding(IRecipeType.SMELTING, IRecipeType.SMOKING), - blastingCategory.getUid()); + blastingCategory.getUid()); registration.addRecipes(findRecipes(AllRecipeTypes.MIXING), mixingCategory.getUid()); - registration.addRecipes(findRecipes(r -> r.getSerializer() == IRecipeSerializer.CRAFTING_SHAPELESS - && !MechanicalPressTileEntity.canCompress(r.getIngredients())).stream().map(MixingRecipe::convertShapeless) - .collect(Collectors.toList()), + + if (recipeConfig.allowShapelessInMixer.get()) + registration.addRecipes(findRecipes(r -> r.getSerializer() == IRecipeSerializer.CRAFTING_SHAPELESS + && !MechanicalPressTileEntity.canCompress(r.getIngredients())).stream() + .map(BasinRecipe::convert) + .collect(Collectors.toList()), mixingCategory.getUid()); + registration.addRecipes(findRecipes(AllRecipeTypes.CUTTING), sawingCategory.getUid()); - registration.addRecipes( + + if (recipeConfig.allowStonecuttingOnSaw.get()) + registration.addRecipes( CondensedBlockCuttingRecipe.condenseRecipes(findRecipesByType(IRecipeType.STONECUTTING)), blockCuttingCategory.getUid()); - registration.addRecipes(findRecipes( - r -> (r instanceof ICraftingRecipe) && MechanicalPressTileEntity.canCompress(r.getIngredients())), + + registration.addRecipes(findRecipes(AllRecipeTypes.COMPACTING), packingCategory.getUid()); + if (recipeConfig.allowShapedSquareInPress.get()) + registration.addRecipes(findRecipes( + r -> (r instanceof ICraftingRecipe) && MechanicalPressTileEntity.canCompress(r.getIngredients())) + .stream() + .map(BasinRecipe::convert) + .collect(Collectors.toList()), packingCategory.getUid()); + registration.addRecipes(findRecipes(AllRecipeTypes.SANDPAPER_POLISHING), polishingCategory.getUid()); registration.addRecipes(MysteriousItemConversionCategory.getRecipes(), mysteryConversionCategory.getUid()); registration.addRecipes(findRecipes(r -> (r.getType() == AllRecipeTypes.MECHANICAL_CRAFTING.type)), - mechanicalCraftingCategory.getUid()); - registration.addRecipes(findRecipes(r -> (r.getType() == IRecipeType.CRAFTING - && r.getType() != AllRecipeTypes.MECHANICAL_CRAFTING.type) && (r instanceof ShapedRecipe)), + mechanicalCraftingCategory.getUid()); + + if (recipeConfig.allowRegularCraftingInCrafter.get()) + registration.addRecipes(findRecipes( + r -> (r.getType() == IRecipeType.CRAFTING && r.getType() != AllRecipeTypes.MECHANICAL_CRAFTING.type) + && (r instanceof ShapedRecipe)), mechanicalCraftingCategory.getUid()); } @@ -141,17 +161,13 @@ public class CreateJEI implements IModPlugin { public void registerRecipeCatalysts(IRecipeCatalystRegistration registration) { ItemStack fan = new ItemStack(AllBlocks.ENCASED_FAN.get()); - ItemStack splashingFan = fan - .copy() - .setDisplayName(new StringTextComponent(TextFormatting.RESET + Lang.translate("recipe.splashing.fan"))); - ItemStack smokingFan = fan - .copy() - .setDisplayName( - new StringTextComponent(TextFormatting.RESET + Lang.translate("recipe.smokingViaFan.fan"))); - ItemStack blastingFan = fan - .copy() - .setDisplayName( - new StringTextComponent(TextFormatting.RESET + Lang.translate("recipe.blastingViaFan.fan"))); + ItemStack splashingFan = fan.copy() + .setDisplayName(new StringTextComponent(TextFormatting.RESET + Lang.translate("recipe.splashing.fan"))); + ItemStack smokingFan = fan.copy() + .setDisplayName(new StringTextComponent(TextFormatting.RESET + Lang.translate("recipe.smokingViaFan.fan"))); + ItemStack blastingFan = fan.copy() + .setDisplayName( + new StringTextComponent(TextFormatting.RESET + Lang.translate("recipe.blastingViaFan.fan"))); registration.addRecipeCatalyst(new ItemStack(AllBlocks.MILLSTONE.get()), millingCategory.getUid()); registration.addRecipeCatalyst(new ItemStack(AllBlocks.CRUSHING_WHEEL.get()), crushingCategory.getUid()); @@ -170,9 +186,8 @@ public class CreateJEI implements IModPlugin { registration.addRecipeCatalyst(new ItemStack(AllBlocks.BASIN.get()), packingCategory.getUid()); registration.addRecipeCatalyst(AllItems.SAND_PAPER.asStack(), polishingCategory.getUid()); registration.addRecipeCatalyst(AllItems.RED_SAND_PAPER.asStack(), polishingCategory.getUid()); - registration - .addRecipeCatalyst(new ItemStack(AllBlocks.MECHANICAL_CRAFTER.get()), - mechanicalCraftingCategory.getUid()); + registration.addRecipeCatalyst(new ItemStack(AllBlocks.MECHANICAL_CRAFTER.get()), + mechanicalCraftingCategory.getUid()); } @Override @@ -186,30 +201,29 @@ public class CreateJEI implements IModPlugin { } private static List> findRecipes(Predicate> pred) { - return Minecraft.getInstance().world - .getRecipeManager() - .getRecipes() - .stream() - .filter(pred) - .collect(Collectors.toList()); + return Minecraft.getInstance().world.getRecipeManager() + .getRecipes() + .stream() + .filter(pred) + .collect(Collectors.toList()); } private static List> findRecipesByType(IRecipeType type) { - return Minecraft.getInstance().world - .getRecipeManager() - .getRecipes() - .stream() - .filter(r -> r.getType() == type) - .collect(Collectors.toList()); + return Minecraft.getInstance().world.getRecipeManager() + .getRecipes() + .stream() + .filter(r -> r.getType() == type) + .collect(Collectors.toList()); } private static List> findRecipesById(ResourceLocation id) { - return Minecraft.getInstance().world - .getRecipeManager() - .getRecipes() - .stream() - .filter(r -> r.getSerializer().getRegistryName().equals(id)) - .collect(Collectors.toList()); + return Minecraft.getInstance().world.getRecipeManager() + .getRecipes() + .stream() + .filter(r -> r.getSerializer() + .getRegistryName() + .equals(id)) + .collect(Collectors.toList()); } private static List> findRecipesByTypeExcluding(IRecipeType type, IRecipeType excludingType) { @@ -217,10 +231,14 @@ public class CreateJEI implements IModPlugin { List> byExcludingType = findRecipesByType(excludingType); byType.removeIf(recipe -> { for (IRecipe r : byExcludingType) { - ItemStack[] matchingStacks = recipe.getIngredients().get(0).getMatchingStacks(); + ItemStack[] matchingStacks = recipe.getIngredients() + .get(0) + .getMatchingStacks(); if (matchingStacks.length == 0) return true; - if (r.getIngredients().get(0).test(matchingStacks[0])) + if (r.getIngredients() + .get(0) + .test(matchingStacks[0])) return true; } return false; diff --git a/src/main/java/com/simibubi/create/compat/jei/category/BasinCategory.java b/src/main/java/com/simibubi/create/compat/jei/category/BasinCategory.java new file mode 100644 index 000000000..02f1463cb --- /dev/null +++ b/src/main/java/com/simibubi/create/compat/jei/category/BasinCategory.java @@ -0,0 +1,88 @@ +package com.simibubi.create.compat.jei.category; + +import java.util.ArrayList; +import java.util.List; + +import org.apache.commons.lang3.mutable.MutableInt; + +import com.simibubi.create.content.contraptions.processing.BasinRecipe; +import com.simibubi.create.content.contraptions.processing.HeatCondition; +import com.simibubi.create.foundation.gui.AllGuiTextures; +import com.simibubi.create.foundation.item.ItemHelper; +import com.simibubi.create.foundation.utility.Pair; + +import mezz.jei.api.constants.VanillaTypes; +import mezz.jei.api.gui.IRecipeLayout; +import mezz.jei.api.gui.drawable.IDrawable; +import mezz.jei.api.gui.ingredient.IGuiItemStackGroup; +import mezz.jei.api.ingredients.IIngredients; +import net.minecraft.item.ItemStack; +import net.minecraft.item.crafting.Ingredient; +import net.minecraft.util.NonNullList; + +public class BasinCategory extends CreateRecipeCategory { + + public BasinCategory(String id, IDrawable icon, IDrawable background) { + super(id, icon, background); + } + + @Override + public Class getRecipeClass() { + return BasinRecipe.class; + } + + @Override + public void setIngredients(BasinRecipe recipe, IIngredients ingredients) { + ingredients.setInputIngredients(recipe.getIngredients()); + ingredients.setOutput(VanillaTypes.ITEM, recipe.getRecipeOutput()); + } + + @Override + public void setRecipe(IRecipeLayout recipeLayout, BasinRecipe recipe, IIngredients ingredients) { + IGuiItemStackGroup itemStacks = recipeLayout.getItemStacks(); + NonNullList recipeIngredients = recipe.getIngredients(); + List> actualIngredients = ItemHelper.condenseIngredients(recipeIngredients); + + int size = actualIngredients.size(); + int xOffset = size < 3 ? (3 - size) * 19 / 2 : 0; + int yOffset = recipe.getRequiredHeat() != HeatCondition.NONE ? 30 : 10; + + int i; + for (i = 0; i < actualIngredients.size(); i++) { + itemStacks.init(i, true, 16 + xOffset + (i % 3) * 19, 50 - (i / 3) * 19 + yOffset); + List stacks = new ArrayList<>(); + Pair pair = actualIngredients.get(i); + Ingredient ingredient = pair.getFirst(); + MutableInt amount = pair.getSecond(); + + for (ItemStack itemStack : ingredient.getMatchingStacks()) { + ItemStack stack = itemStack.copy(); + stack.setCount(amount.getValue()); + stacks.add(stack); + } + + itemStacks.set(i, stacks); + } + + itemStacks.init(i, false, 141, 50 + yOffset); + itemStacks.set(i, recipe.getRecipeOutput() + .getStack()); + } + + @Override + public void draw(BasinRecipe recipe, double mouseX, double mouseY) { + List> actualIngredients = ItemHelper.condenseIngredients(recipe.getIngredients()); + + int size = actualIngredients.size(); + int xOffset = size < 3 ? (3 - size) * 19 / 2 : 0; + HeatCondition requiredHeat = recipe.getRequiredHeat(); + int yOffset = requiredHeat != HeatCondition.NONE ? 30 : 10; + for (int i = 0; i < size; i++) + AllGuiTextures.JEI_SLOT.draw(16 + xOffset + (i % 3) * 19, 50 - (i / 3) * 19 + yOffset); + + AllGuiTextures.JEI_SLOT.draw(141, 50 + yOffset); + AllGuiTextures.JEI_DOWN_ARROW.draw(136, 32 + yOffset); + AllGuiTextures.JEI_SHADOW.draw(81, 57 + yOffset); + } + +} diff --git a/src/main/java/com/simibubi/create/compat/jei/category/MixingCategory.java b/src/main/java/com/simibubi/create/compat/jei/category/MixingCategory.java index ce8697c94..d379b3436 100644 --- a/src/main/java/com/simibubi/create/compat/jei/category/MixingCategory.java +++ b/src/main/java/com/simibubi/create/compat/jei/category/MixingCategory.java @@ -1,28 +1,12 @@ package com.simibubi.create.compat.jei.category; -import java.util.ArrayList; -import java.util.List; - -import org.apache.commons.lang3.mutable.MutableInt; - import com.simibubi.create.AllBlocks; import com.simibubi.create.compat.jei.category.animations.AnimatedBlazeBurner; import com.simibubi.create.compat.jei.category.animations.AnimatedMixer; -import com.simibubi.create.content.contraptions.components.mixer.MixingRecipe; +import com.simibubi.create.content.contraptions.processing.BasinRecipe; import com.simibubi.create.content.contraptions.processing.HeatCondition; -import com.simibubi.create.foundation.gui.AllGuiTextures; -import com.simibubi.create.foundation.item.ItemHelper; -import com.simibubi.create.foundation.utility.Pair; -import mezz.jei.api.constants.VanillaTypes; -import mezz.jei.api.gui.IRecipeLayout; -import mezz.jei.api.gui.ingredient.IGuiItemStackGroup; -import mezz.jei.api.ingredients.IIngredients; -import net.minecraft.item.ItemStack; -import net.minecraft.item.crafting.Ingredient; -import net.minecraft.util.NonNullList; - -public class MixingCategory extends CreateRecipeCategory { +public class MixingCategory extends BasinCategory { private AnimatedMixer mixer = new AnimatedMixer(); private AnimatedBlazeBurner heater = new AnimatedBlazeBurner(); @@ -33,63 +17,9 @@ public class MixingCategory extends CreateRecipeCategory { } @Override - public Class getRecipeClass() { - return MixingRecipe.class; - } - - @Override - public void setIngredients(MixingRecipe recipe, IIngredients ingredients) { - ingredients.setInputIngredients(recipe.getIngredients()); - ingredients.setOutput(VanillaTypes.ITEM, recipe.getRecipeOutput()); - } - - @Override - public void setRecipe(IRecipeLayout recipeLayout, MixingRecipe recipe, IIngredients ingredients) { - IGuiItemStackGroup itemStacks = recipeLayout.getItemStacks(); - NonNullList recipeIngredients = recipe.getIngredients(); - List> actualIngredients = ItemHelper.condenseIngredients(recipeIngredients); - - int size = actualIngredients.size(); - int xOffset = size < 3 ? (3 - size) * 19 / 2 : 0; - int yOffset = recipe.getRequiredHeat() != HeatCondition.NONE ? 30 : 10; - - int i; - for (i = 0; i < actualIngredients.size(); i++) { - itemStacks.init(i, true, 16 + xOffset + (i % 3) * 19, 50 - (i / 3) * 19 + yOffset); - List stacks = new ArrayList<>(); - Pair pair = actualIngredients.get(i); - Ingredient ingredient = pair.getFirst(); - MutableInt amount = pair.getSecond(); - - for (ItemStack itemStack : ingredient.getMatchingStacks()) { - ItemStack stack = itemStack.copy(); - stack.setCount(amount.getValue()); - stacks.add(stack); - } - - itemStacks.set(i, stacks); - } - - itemStacks.init(i, false, 141, 50 + yOffset); - itemStacks.set(i, recipe.getRecipeOutput() - .getStack()); - } - - @Override - public void draw(MixingRecipe recipe, double mouseX, double mouseY) { - List> actualIngredients = ItemHelper.condenseIngredients(recipe.getIngredients()); - - int size = actualIngredients.size(); - int xOffset = size < 3 ? (3 - size) * 19 / 2 : 0; + public void draw(BasinRecipe recipe, double mouseX, double mouseY) { + super.draw(recipe, mouseX, mouseY); HeatCondition requiredHeat = recipe.getRequiredHeat(); - int yOffset = requiredHeat != HeatCondition.NONE ? 30 : 10; - for (int i = 0; i < size; i++) - AllGuiTextures.JEI_SLOT.draw(16 + xOffset + (i % 3) * 19, 50 - (i / 3) * 19 + yOffset); - - AllGuiTextures.JEI_SLOT.draw(141, 50 + yOffset); - AllGuiTextures.JEI_DOWN_ARROW.draw(136, 32 + yOffset); - AllGuiTextures.JEI_SHADOW.draw(81, 57 + yOffset); - if (requiredHeat != HeatCondition.NONE) heater.withHeat(requiredHeat.visualizeAsBlazeBurner()) .draw(getBackground().getWidth() / 2 + 3, 55); diff --git a/src/main/java/com/simibubi/create/compat/jei/category/PackingCategory.java b/src/main/java/com/simibubi/create/compat/jei/category/PackingCategory.java index daaee43a5..b554fea4f 100644 --- a/src/main/java/com/simibubi/create/compat/jei/category/PackingCategory.java +++ b/src/main/java/com/simibubi/create/compat/jei/category/PackingCategory.java @@ -4,18 +4,16 @@ import java.util.Arrays; import com.simibubi.create.AllBlocks; import com.simibubi.create.compat.jei.category.animations.AnimatedPress; +import com.simibubi.create.content.contraptions.processing.BasinRecipe; import com.simibubi.create.foundation.gui.AllGuiTextures; -import mezz.jei.api.constants.VanillaTypes; import mezz.jei.api.gui.IRecipeLayout; import mezz.jei.api.gui.ingredient.IGuiItemStackGroup; import mezz.jei.api.ingredients.IIngredients; -import net.minecraft.item.crafting.ICraftingRecipe; -import net.minecraft.item.crafting.IRecipe; import net.minecraft.item.crafting.Ingredient; import net.minecraft.util.NonNullList; -public class PackingCategory extends CreateRecipeCategory> { +public class PackingCategory extends BasinCategory { private AnimatedPress press = new AnimatedPress(true); @@ -25,18 +23,12 @@ public class PackingCategory extends CreateRecipeCategory> { } @Override - public Class> getRecipeClass() { - return ICraftingRecipe.class; - } - - @Override - public void setIngredients(IRecipe recipe, IIngredients ingredients) { - ingredients.setInputIngredients(recipe.getIngredients()); - ingredients.setOutput(VanillaTypes.ITEM, recipe.getRecipeOutput()); - } - - @Override - public void setRecipe(IRecipeLayout recipeLayout, IRecipe recipe, IIngredients ingredients) { + public void setRecipe(IRecipeLayout recipeLayout, BasinRecipe recipe, IIngredients ingredients) { + if (!recipe.convertedRecipe) { + super.setRecipe(recipeLayout, recipe, ingredients); + return; + } + IGuiItemStackGroup itemStacks = recipeLayout.getItemStacks(); int i = 0; @@ -55,16 +47,21 @@ public class PackingCategory extends CreateRecipeCategory> { } @Override - public void draw(IRecipe recipe, double mouseX, double mouseY) { - NonNullList ingredients2 = recipe.getIngredients(); - int size = ingredients2.size(); - int rows = size == 4 ? 2 : 3; - for (int i = 0; i < size; i++) { - AllGuiTextures.JEI_SLOT.draw((rows == 2 ? 26 : 17) + (i % rows) * 19, 50 - (i / rows) * 19); + public void draw(BasinRecipe recipe, double mouseX, double mouseY) { + if (!recipe.convertedRecipe) { + super.draw(recipe, mouseX, mouseY); + + } else { + NonNullList ingredients2 = recipe.getIngredients(); + int size = ingredients2.size(); + int rows = size == 4 ? 2 : 3; + for (int i = 0; i < size; i++) + AllGuiTextures.JEI_SLOT.draw((rows == 2 ? 26 : 17) + (i % rows) * 19, 50 - (i / rows) * 19); + AllGuiTextures.JEI_SLOT.draw(141, 50); + AllGuiTextures.JEI_DOWN_ARROW.draw(136, 32); + AllGuiTextures.JEI_SHADOW.draw(81, 57); } - AllGuiTextures.JEI_SLOT.draw(141, 50); - AllGuiTextures.JEI_DOWN_ARROW.draw(136, 32); - AllGuiTextures.JEI_SHADOW.draw(81, 57); + press.draw(getBackground().getWidth() / 2 + 6, 30); } diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/crafter/RecipeGridHandler.java b/src/main/java/com/simibubi/create/content/contraptions/components/crafter/RecipeGridHandler.java index 55c04b434..20de1a509 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/crafter/RecipeGridHandler.java +++ b/src/main/java/com/simibubi/create/content/contraptions/components/crafter/RecipeGridHandler.java @@ -15,6 +15,7 @@ import org.apache.commons.lang3.tuple.Pair; import com.google.common.base.Predicates; import com.simibubi.create.AllBlocks; import com.simibubi.create.AllRecipeTypes; +import com.simibubi.create.foundation.config.AllConfigs; import com.simibubi.create.foundation.utility.Pointing; import net.minecraft.block.BlockState; @@ -139,16 +140,16 @@ public class RecipeGridHandler { public static ItemStack tryToApplyRecipe(World world, GroupedItems items) { items.calcStats(); CraftingInventory craftinginventory = new MechanicalCraftingInventory(items); - ItemStack result = world.getRecipeManager() - .getRecipe(IRecipeType.CRAFTING, craftinginventory, world) - .map(r -> r.getCraftingResult(craftinginventory)) - .orElse(null); - if (result == null) + ItemStack result = null; + if (AllConfigs.SERVER.recipes.allowRegularCraftingInCrafter.get()) result = world.getRecipeManager() - .getRecipe(AllRecipeTypes.MECHANICAL_CRAFTING.getType(), craftinginventory, world) + .getRecipe(IRecipeType.CRAFTING, craftinginventory, world) + .map(r -> r.getCraftingResult(craftinginventory)) + .orElse(null); + if (result == null) + result = AllRecipeTypes.MECHANICAL_CRAFTING.find(craftinginventory, world) .map(r -> r.getCraftingResult(craftinginventory)) .orElse(null); - return result; } diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/crusher/CrushingWheelControllerTileEntity.java b/src/main/java/com/simibubi/create/content/contraptions/components/crusher/CrushingWheelControllerTileEntity.java index d78798576..010bf1610 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/crusher/CrushingWheelControllerTileEntity.java +++ b/src/main/java/com/simibubi/create/content/contraptions/components/crusher/CrushingWheelControllerTileEntity.java @@ -206,11 +206,9 @@ public class CrushingWheelControllerTileEntity extends SmartTileEntity { } public Optional> findRecipe() { - Optional> crushingRecipe = world.getRecipeManager() - .getRecipe(AllRecipeTypes.CRUSHING.getType(), wrapper, world); + Optional> crushingRecipe = AllRecipeTypes.CRUSHING.find(wrapper, world); if (!crushingRecipe.isPresent()) - crushingRecipe = world.getRecipeManager() - .getRecipe(AllRecipeTypes.MILLING.getType(), wrapper, world); + crushingRecipe = AllRecipeTypes.MILLING.find(wrapper, world); return crushingRecipe; } diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/millstone/MillstoneTileEntity.java b/src/main/java/com/simibubi/create/content/contraptions/components/millstone/MillstoneTileEntity.java index e70a13bae..a438ccd31 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/millstone/MillstoneTileEntity.java +++ b/src/main/java/com/simibubi/create/content/contraptions/components/millstone/MillstoneTileEntity.java @@ -65,8 +65,7 @@ public class MillstoneTileEntity extends KineticTileEntity { RecipeWrapper inventoryIn = new RecipeWrapper(inputInv); if (lastRecipe == null || !lastRecipe.matches(inventoryIn, world)) { - Optional recipe = world.getRecipeManager() - .getRecipe(AllRecipeTypes.MILLING.getType(), inventoryIn, world); + Optional recipe = AllRecipeTypes.MILLING.find(inventoryIn, world); if (!recipe.isPresent()) { timer = 100; sendData(); @@ -86,8 +85,7 @@ public class MillstoneTileEntity extends KineticTileEntity { RecipeWrapper inventoryIn = new RecipeWrapper(inputInv); if (lastRecipe == null || !lastRecipe.matches(inventoryIn, world)) { - Optional recipe = world.getRecipeManager() - .getRecipe(AllRecipeTypes.MILLING.getType(), inventoryIn, world); + Optional recipe = AllRecipeTypes.MILLING.find(inventoryIn, world); if (!recipe.isPresent()) return; lastRecipe = recipe.get(); @@ -153,8 +151,7 @@ public class MillstoneTileEntity extends KineticTileEntity { if (lastRecipe != null && lastRecipe.matches(inventoryIn, world)) return true; - return world.getRecipeManager() - .getRecipe(AllRecipeTypes.MILLING.getType(), inventoryIn, world) + return AllRecipeTypes.MILLING.find(inventoryIn, world) .isPresent(); } diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/mixer/CompactingRecipe.java b/src/main/java/com/simibubi/create/content/contraptions/components/mixer/CompactingRecipe.java new file mode 100644 index 000000000..7e25e410e --- /dev/null +++ b/src/main/java/com/simibubi/create/content/contraptions/components/mixer/CompactingRecipe.java @@ -0,0 +1,13 @@ +package com.simibubi.create.content.contraptions.components.mixer; + +import com.simibubi.create.AllRecipeTypes; +import com.simibubi.create.content.contraptions.processing.BasinRecipe; +import com.simibubi.create.content.contraptions.processing.ProcessingRecipeBuilder.ProcessingRecipeParams; + +public class CompactingRecipe extends BasinRecipe { + + public CompactingRecipe(ProcessingRecipeParams params) { + super(AllRecipeTypes.COMPACTING, params); + } + +} diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/mixer/MechanicalMixerTileEntity.java b/src/main/java/com/simibubi/create/content/contraptions/components/mixer/MechanicalMixerTileEntity.java index 360c4b2db..17bbf9fce 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/mixer/MechanicalMixerTileEntity.java +++ b/src/main/java/com/simibubi/create/content/contraptions/components/mixer/MechanicalMixerTileEntity.java @@ -1,37 +1,29 @@ package com.simibubi.create.content.contraptions.components.mixer; -import java.util.ArrayList; -import java.util.Comparator; -import java.util.LinkedList; -import java.util.List; import java.util.Optional; import com.simibubi.create.AllRecipeTypes; -import com.simibubi.create.AllTags; import com.simibubi.create.content.contraptions.components.press.MechanicalPressTileEntity; import com.simibubi.create.content.contraptions.processing.BasinOperatingTileEntity; import com.simibubi.create.content.contraptions.processing.BasinTileEntity; -import com.simibubi.create.content.contraptions.processing.burner.BlazeBurnerBlock; -import com.simibubi.create.content.contraptions.processing.burner.BlazeBurnerBlock.HeatLevel; +import com.simibubi.create.foundation.advancement.AllTriggers; +import com.simibubi.create.foundation.advancement.ITriggerable; +import com.simibubi.create.foundation.config.AllConfigs; import com.simibubi.create.foundation.item.SmartInventory; import com.simibubi.create.foundation.utility.VecHelper; -import net.minecraft.block.BlockState; import net.minecraft.inventory.IInventory; import net.minecraft.item.ItemStack; import net.minecraft.item.crafting.IRecipe; import net.minecraft.item.crafting.IRecipeSerializer; -import net.minecraft.item.crafting.Ingredient; import net.minecraft.nbt.CompoundNBT; import net.minecraft.particles.ItemParticleData; import net.minecraft.particles.ParticleTypes; import net.minecraft.tileentity.TileEntityType; import net.minecraft.util.Direction.Axis; -import net.minecraft.util.NonNullList; import net.minecraft.util.math.AxisAlignedBB; import net.minecraft.util.math.MathHelper; import net.minecraft.util.math.Vec3d; -import net.minecraftforge.fluids.FluidStack; public class MechanicalMixerTileEntity extends BasinOperatingTileEntity { @@ -99,13 +91,6 @@ public class MechanicalMixerTileEntity extends BasinOperatingTileEntity { super.write(compound, clientPacket); } - @Override - public void lazyTick() { - super.lazyTick(); - if (world != null && world.isRemote && running && !basinItemInv.isPresent()) - updateBasin(); - } - @Override public void tick() { super.tick(); @@ -168,45 +153,11 @@ public class MechanicalMixerTileEntity extends BasinOperatingTileEntity { @Override protected boolean matchStaticFilters(IRecipe r) { - return (r.getSerializer() == IRecipeSerializer.CRAFTING_SHAPELESS || r.getType() == AllRecipeTypes.MIXING.type) + return ((r.getSerializer() == IRecipeSerializer.CRAFTING_SHAPELESS + && AllConfigs.SERVER.recipes.allowShapelessInMixer.get()) || r.getType() == AllRecipeTypes.MIXING.type) && !MechanicalPressTileEntity.canCompress(r.getIngredients()); } - @Override - protected boolean matchBasinRecipe(IRecipe recipe) { - if (!super.matchBasinRecipe(recipe)) - return false; - - NonNullList ingredients = recipe.getIngredients(); - List remainingItems = new ArrayList<>(); - itemInputs.forEach(stack -> remainingItems.add(stack.copy())); - List remainingFluids = new ArrayList<>(); - fluidInputs.forEach(stack -> remainingFluids.add(stack.copy())); - - // TODO: match fluid inputs - - // Sort by leniency - List sortedIngredients = new LinkedList<>(ingredients); - sortedIngredients.sort(Comparator.comparingInt(i -> i.getMatchingStacks().length)); - - Ingredients: for (Ingredient ingredient : sortedIngredients) { - for (ItemStack stack : remainingItems) { - if (stack.isEmpty()) - continue; - if (ingredient.test(stack)) { - stack.shrink(1); - continue Ingredients; - } - } - return false; - } - - if (!(recipe instanceof MixingRecipe)) - return true; - return ((MixingRecipe) recipe).getRequiredHeat() - .testBlazeBurner(getHeatLevel()); - } - @Override public void startProcessingBasin() { if (running && runningTicks <= 20) @@ -239,13 +190,10 @@ public class MechanicalMixerTileEntity extends BasinOperatingTileEntity { protected boolean isRunning() { return running; } - - private HeatLevel getHeatLevel() { - if (world == null) - return HeatLevel.NONE; - BlockState state = world.getBlockState(pos.down(3)); - if (state.has(BlazeBurnerBlock.HEAT_LEVEL)) - return state.get(BlazeBurnerBlock.HEAT_LEVEL); - return AllTags.AllBlockTags.FAN_HEATERS.matches(state) ? HeatLevel.SMOULDERING : HeatLevel.NONE; + + @Override + protected Optional getProcessedRecipeTrigger() { + return Optional.of(AllTriggers.MIXER_MIX); } + } diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/mixer/MixingRecipe.java b/src/main/java/com/simibubi/create/content/contraptions/components/mixer/MixingRecipe.java index c36564c57..12e1d7b0f 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/mixer/MixingRecipe.java +++ b/src/main/java/com/simibubi/create/content/contraptions/components/mixer/MixingRecipe.java @@ -1,98 +1,13 @@ package com.simibubi.create.content.contraptions.components.mixer; -import java.util.ArrayList; -import java.util.Comparator; -import java.util.LinkedList; -import java.util.List; - -import javax.annotation.Nonnull; - import com.simibubi.create.AllRecipeTypes; -import com.simibubi.create.content.contraptions.processing.ProcessingRecipe; -import com.simibubi.create.content.contraptions.processing.ProcessingRecipeBuilder; +import com.simibubi.create.content.contraptions.processing.BasinRecipe; import com.simibubi.create.content.contraptions.processing.ProcessingRecipeBuilder.ProcessingRecipeParams; -import com.simibubi.create.foundation.item.SmartInventory; -import net.minecraft.item.ItemStack; -import net.minecraft.item.crafting.IRecipe; -import net.minecraft.item.crafting.Ingredient; -import net.minecraft.util.NonNullList; -import net.minecraft.world.World; - -public class MixingRecipe extends ProcessingRecipe { - - /** - * For JEI purposes only - */ - public static MixingRecipe convertShapeless(IRecipe recipe) { - return new ProcessingRecipeBuilder<>(MixingRecipe::new, recipe.getId()) - .withItemIngredients(recipe.getIngredients()) - .withSingleItemOutput(recipe.getRecipeOutput()) - .build(); - } +public class MixingRecipe extends BasinRecipe { public MixingRecipe(ProcessingRecipeParams params) { super(AllRecipeTypes.MIXING, params); } - @Override - protected int getMaxInputCount() { - return 9; - } - - @Override - protected int getMaxOutputCount() { - return 1;// TODO increase - } - - @Override - protected int getMaxFluidInputCount() { - return 2; - } - - @Override - protected int getMaxFluidOutputCount() { - return 1;// TODO increase? - } - - @Override - protected boolean canRequireHeat() { - return true; - } - - @Override - public boolean matches(SmartInventory inv, @Nonnull World worldIn) { - if (inv.isEmpty()) - return false; - - NonNullList ingredients = this.getIngredients(); - if (!ingredients.stream() - .allMatch(Ingredient::isSimple)) - return false; - - List remaining = new ArrayList<>(); - for (int slot = 0; slot < inv.getSizeInventory(); ++slot) { - ItemStack itemstack = inv.getStackInSlot(slot); - if (!itemstack.isEmpty()) { - remaining.add(itemstack.copy()); - } - } - - // sort by leniency - List sortedIngredients = new LinkedList<>(ingredients); - sortedIngredients.sort(Comparator.comparingInt(i -> i.getMatchingStacks().length)); - Ingredients: for (Ingredient ingredient : sortedIngredients) { - for (ItemStack stack : remaining) { - if (stack.isEmpty()) - continue; - if (ingredient.test(stack)) { - stack.shrink(1); - continue Ingredients; - } - } - return false; - } - return true; - } - } diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/press/MechanicalPressTileEntity.java b/src/main/java/com/simibubi/create/content/contraptions/components/press/MechanicalPressTileEntity.java index a93bc77a1..bc8a0818d 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/press/MechanicalPressTileEntity.java +++ b/src/main/java/com/simibubi/create/content/contraptions/components/press/MechanicalPressTileEntity.java @@ -10,6 +10,8 @@ import com.simibubi.create.content.contraptions.processing.BasinOperatingTileEnt import com.simibubi.create.content.contraptions.processing.BasinTileEntity; import com.simibubi.create.content.logistics.InWorldProcessing; import com.simibubi.create.foundation.advancement.AllTriggers; +import com.simibubi.create.foundation.advancement.ITriggerable; +import com.simibubi.create.foundation.config.AllConfigs; import com.simibubi.create.foundation.item.ItemHelper; import com.simibubi.create.foundation.item.SmartInventory; import com.simibubi.create.foundation.tileEntity.TileEntityBehaviour; @@ -41,29 +43,12 @@ public class MechanicalPressTileEntity extends BasinOperatingTileEntity { private static final Object compressingRecipesKey = new Object(); public List pressedItems = new ArrayList<>(); - - public static class PressingInv extends RecipeWrapper { - public PressingInv() { - super(new ItemStackHandler(1)); - } - } - - enum Mode { - WORLD(1), BELT(19f / 16f), BASIN(22f / 16f) - - ; - - float headOffset; - - Mode(float headOffset) { - this.headOffset = headOffset; - } - } - - private static final PressingInv pressingInv = new PressingInv(); public BeltProcessingBehaviour processingBehaviour; + public int prevRunningTicks; public int runningTicks; + static final int CYCLE = 240; + public boolean running; public Mode mode; public boolean finished; @@ -87,7 +72,7 @@ public class MechanicalPressTileEntity extends BasinOperatingTileEntity { running = compound.getBoolean("Running"); mode = Mode.values()[compound.getInt("Mode")]; finished = compound.getBoolean("Finished"); - runningTicks = compound.getInt("Ticks"); + prevRunningTicks = runningTicks = compound.getInt("Ticks"); super.read(compound, clientPacket); if (clientPacket) { @@ -105,8 +90,10 @@ public class MechanicalPressTileEntity extends BasinOperatingTileEntity { compound.putInt("Ticks", runningTicks); super.write(compound, clientPacket); - if (clientPacket) + if (clientPacket) { compound.put("ParticleItems", NBTHelper.writeCompoundList(pressedItems, ItemStack::serializeNBT)); + pressedItems.clear(); + } } @Override @@ -116,15 +103,12 @@ public class MechanicalPressTileEntity extends BasinOperatingTileEntity { } public float getRenderedHeadOffset(float partialTicks) { - if (running) { - if (runningTicks < 40) { - float num = (runningTicks - 1 + partialTicks) / 30f; - return MathHelper.clamp(num * num * num, 0, mode.headOffset); - } - return MathHelper.clamp(((60 - runningTicks) + 1 - partialTicks) / 20f * mode.headOffset, 0, - mode.headOffset); - } - return 0; + if (!running) + return 0; + float ticks = MathHelper.lerp(partialTicks, prevRunningTicks, runningTicks); + if (runningTicks < (CYCLE * 2) / 3) + return (float) MathHelper.clamp(Math.pow(ticks / CYCLE * 2, 3), 0, mode.headOffset); + return MathHelper.clamp((CYCLE - ticks) / CYCLE * 3 * mode.headOffset, 0, mode.headOffset); } public void start(Mode mode) { @@ -150,50 +134,11 @@ public class MechanicalPressTileEntity extends BasinOperatingTileEntity { if (!running || world == null) return; - if (runningTicks == 30) { - - if (inWorld()) { - AxisAlignedBB bb = new AxisAlignedBB(pos.down(1)); - pressedItems.clear(); - for (Entity entity : world.getEntitiesWithinAABBExcludingEntity(null, bb)) { - if (!(entity instanceof ItemEntity)) - continue; - - ItemEntity itemEntity = (ItemEntity) entity; - - if (!world.isRemote) { - pressedItems.add(itemEntity.getItem()); - sendData(); - Optional recipe = getRecipe(itemEntity.getItem()); - if (recipe.isPresent()) { - InWorldProcessing.applyRecipeOn(itemEntity, recipe.get()); - AllTriggers.triggerForNearbyPlayers(AllTriggers.BONK, world, pos, 4); - } - } - } - } - - if (onBasin()) { - if (!world.isRemote) { - pressedItems.clear(); - applyBasinRecipe(); - - Optional basin = getBasin(); - SmartInventory inputs = basin.get() - .getInputInventory(); - if (basin.isPresent()) { - for (int slot = 0; slot < inputs.getSlots(); slot++) { - ItemStack stackInSlot = inputs.getStackInSlot(slot); - if (stackInSlot.isEmpty()) - continue; - pressedItems.add(stackInSlot); - } - } - sendData(); - } - - } - + if (runningTicks == CYCLE / 2) { + if (inWorld()) + applyPressingInWorld(); + if (onBasin()) + applyCompactingOnBasin(); if (!world.isRemote) { world.playSound(null, getPos(), AllSoundEvents.MECHANICAL_PRESS_ITEM_BREAK.get(), SoundCategory.BLOCKS, .5f, 1f); @@ -202,105 +147,125 @@ public class MechanicalPressTileEntity extends BasinOperatingTileEntity { } } - if (!world.isRemote && runningTicks > 60) { + if (!world.isRemote && runningTicks > CYCLE) { finished = true; if (inWorld()) finished = world.isBlockPowered(pos); running = false; - if (onBasin()) { - gatherInputs(); - if (matchBasinRecipe(lastRecipe)) { - startProcessingBasin(); - } - } + if (onBasin() && matchBasinRecipe(currentRecipe)) + startProcessingBasin(); pressedItems.clear(); sendData(); return; } - runningTicks++; + prevRunningTicks = runningTicks; + runningTicks += getRunningTickSpeed(); + if (prevRunningTicks < CYCLE / 2 && runningTicks >= CYCLE / 2) + runningTicks = CYCLE / 2; + } + + protected void applyCompactingOnBasin() { + if (world.isRemote) + return; + pressedItems.clear(); + applyBasinRecipe(); + Optional basin = getBasin(); + SmartInventory inputs = basin.get() + .getInputInventory(); + if (basin.isPresent()) { + for (int slot = 0; slot < inputs.getSlots(); slot++) { + ItemStack stackInSlot = inputs.getStackInSlot(slot); + if (stackInSlot.isEmpty()) + continue; + pressedItems.add(stackInSlot); + } + } + sendData(); + } + + protected void applyPressingInWorld() { + AxisAlignedBB bb = new AxisAlignedBB(pos.down(1)); + pressedItems.clear(); + if (world.isRemote) + return; + for (Entity entity : world.getEntitiesWithinAABBExcludingEntity(null, bb)) { + if (!(entity instanceof ItemEntity)) + continue; + ItemEntity itemEntity = (ItemEntity) entity; + pressedItems.add(itemEntity.getItem()); + sendData(); + Optional recipe = getRecipe(itemEntity.getItem()); + if (!recipe.isPresent()) + continue; + InWorldProcessing.applyRecipeOn(itemEntity, recipe.get()); + AllTriggers.triggerForNearbyPlayers(AllTriggers.BONK, world, pos, 4); + } + } + + public int getRunningTickSpeed() { + if (getSpeed() == 0) + return 0; + return (int) MathHelper.lerp(MathHelper.clamp(Math.abs(getSpeed()) / 512f, 0, 1), 1, 60); } protected void spawnParticles() { if (pressedItems.isEmpty()) return; - if (mode == Mode.BASIN) { + if (mode == Mode.BASIN) pressedItems.forEach(stack -> makeCompactingParticleEffect(VecHelper.getCenterOf(pos.down(2)), stack)); - } - if (mode == Mode.BELT) { + if (mode == Mode.BELT) pressedItems.forEach(stack -> makePressingParticleEffect(VecHelper.getCenterOf(pos.down(2)) .add(0, 8 / 16f, 0), stack)); - } - if (mode == Mode.WORLD) { + if (mode == Mode.WORLD) pressedItems.forEach(stack -> makePressingParticleEffect(VecHelper.getCenterOf(pos.down(1)) .add(0, -1 / 4f, 0), stack)); - } pressedItems.clear(); } public void makePressingParticleEffect(Vec3d pos, ItemStack stack) { - if (world != null && world.isRemote) { - for (int i = 0; i < 20; i++) { - Vec3d motion = VecHelper.offsetRandomly(Vec3d.ZERO, world.rand, .125f) - .mul(1, 0, 1); - world.addParticle(new ItemParticleData(ParticleTypes.ITEM, stack), pos.x, pos.y - .25f, pos.z, motion.x, - motion.y + .125f, motion.z); - } + if (world == null || !world.isRemote) + return; + for (int i = 0; i < 20; i++) { + Vec3d motion = VecHelper.offsetRandomly(Vec3d.ZERO, world.rand, .125f) + .mul(1, 0, 1); + world.addParticle(new ItemParticleData(ParticleTypes.ITEM, stack), pos.x, pos.y - .25f, pos.z, motion.x, + motion.y + .125f, motion.z); } } public void makeCompactingParticleEffect(Vec3d pos, ItemStack stack) { - if (world != null && world.isRemote) { - for (int i = 0; i < 20; i++) { - Vec3d motion = VecHelper.offsetRandomly(Vec3d.ZERO, world.rand, .175f) - .mul(1, 0, 1); - world.addParticle(new ItemParticleData(ParticleTypes.ITEM, stack), pos.x, pos.y, pos.z, motion.x, - motion.y + .25f, motion.z); - } + if (world == null || !world.isRemote) + return; + for (int i = 0; i < 20; i++) { + Vec3d motion = VecHelper.offsetRandomly(Vec3d.ZERO, world.rand, .175f) + .mul(1, 0, 1); + world.addParticle(new ItemParticleData(ParticleTypes.ITEM, stack), pos.x, pos.y, pos.z, motion.x, + motion.y + .25f, motion.z); } } + private static final RecipeWrapper pressingInv = new RecipeWrapper(new ItemStackHandler(1)); + public Optional getRecipe(ItemStack item) { pressingInv.setInventorySlotContents(0, item); - return world.getRecipeManager() - .getRecipe(AllRecipeTypes.PRESSING.getType(), pressingInv, world); + return AllRecipeTypes.PRESSING.find(pressingInv, world); } public static boolean canCompress(NonNullList ingredients) { - return (ingredients.size() == 4 || ingredients.size() == 9) && ItemHelper.condenseIngredients(ingredients) - .size() == 1; + return AllConfigs.SERVER.recipes.allowShapedSquareInPress.get() + && (ingredients.size() == 4 || ingredients.size() == 9) && ItemHelper.condenseIngredients(ingredients) + .size() == 1; } @Override protected boolean matchStaticFilters(IRecipe recipe) { - return recipe instanceof ICraftingRecipe && canCompress(recipe.getIngredients()); - } - - @Override - protected boolean matchBasinRecipe(IRecipe recipe) { - if (!super.matchBasinRecipe(recipe)) - return false; - - NonNullList ingredients = recipe.getIngredients(); - List remainingItems = new ArrayList<>(); - itemInputs.forEach(stack -> remainingItems.add(stack.copy())); - - Ingredients: for (Ingredient ingredient : ingredients) { - for (ItemStack stack : remainingItems) { - if (stack.isEmpty()) - continue; - if (ingredient.test(stack)) { - stack.shrink(1); - continue Ingredients; - } - } - return false; - } - return true; + return (recipe instanceof ICraftingRecipe && canCompress(recipe.getIngredients())) + || recipe.getType() == AllRecipeTypes.COMPACTING.type; } @Override @@ -310,7 +275,7 @@ public class MechanicalPressTileEntity extends BasinOperatingTileEntity { @Override public void startProcessingBasin() { - if (running && runningTicks <= 30) + if (running && runningTicks <= CYCLE / 2) return; super.startProcessingBasin(); start(Mode.BASIN); @@ -329,4 +294,21 @@ public class MechanicalPressTileEntity extends BasinOperatingTileEntity { return running; } + @Override + protected Optional getProcessedRecipeTrigger() { + return Optional.of(AllTriggers.PRESS_COMPACT); + } + + enum Mode { + WORLD(1), BELT(19f / 16f), BASIN(22f / 16f) + + ; + + float headOffset; + + Mode(float headOffset) { + this.headOffset = headOffset; + } + } + } diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/press/PressingRecipe.java b/src/main/java/com/simibubi/create/content/contraptions/components/press/PressingRecipe.java index b08c0e1c9..481acc8e0 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/press/PressingRecipe.java +++ b/src/main/java/com/simibubi/create/content/contraptions/components/press/PressingRecipe.java @@ -3,21 +3,21 @@ package com.simibubi.create.content.contraptions.components.press; import javax.annotation.ParametersAreNonnullByDefault; import com.simibubi.create.AllRecipeTypes; -import com.simibubi.create.content.contraptions.components.press.MechanicalPressTileEntity.PressingInv; import com.simibubi.create.content.contraptions.processing.ProcessingRecipe; import com.simibubi.create.content.contraptions.processing.ProcessingRecipeBuilder.ProcessingRecipeParams; import net.minecraft.world.World; +import net.minecraftforge.items.wrapper.RecipeWrapper; @ParametersAreNonnullByDefault -public class PressingRecipe extends ProcessingRecipe { +public class PressingRecipe extends ProcessingRecipe { public PressingRecipe(ProcessingRecipeParams params) { super(AllRecipeTypes.PRESSING, params); } @Override - public boolean matches(PressingInv inv, World worldIn) { + public boolean matches(RecipeWrapper inv, World worldIn) { if (inv.isEmpty()) return false; return ingredients.get(0) diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/saw/SawTileEntity.java b/src/main/java/com/simibubi/create/content/contraptions/components/saw/SawTileEntity.java index 97ab1000a..e824c1ebc 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/saw/SawTileEntity.java +++ b/src/main/java/com/simibubi/create/content/contraptions/components/saw/SawTileEntity.java @@ -8,9 +8,11 @@ import java.util.List; import java.util.Random; import java.util.stream.Collectors; +import com.google.common.base.Predicate; import com.simibubi.create.AllRecipeTypes; import com.simibubi.create.content.contraptions.components.actors.BlockBreakingKineticTileEntity; import com.simibubi.create.content.contraptions.processing.ProcessingInventory; +import com.simibubi.create.foundation.config.AllConfigs; import com.simibubi.create.foundation.item.ItemHelper; import com.simibubi.create.foundation.tileEntity.TileEntityBehaviour; import com.simibubi.create.foundation.tileEntity.behaviour.belt.DirectBeltInputBehaviour; @@ -264,8 +266,10 @@ public class SawTileEntity extends BlockBreakingKineticTileEntity { } private List> getRecipes() { - List> startedSearch = RecipeFinder.get(cuttingRecipesKey, world, - RecipeConditions.isOfType(IRecipeType.STONECUTTING, AllRecipeTypes.CUTTING.getType())); + Predicate> types = AllConfigs.SERVER.recipes.allowStonecuttingOnSaw.get() + ? RecipeConditions.isOfType(IRecipeType.STONECUTTING, AllRecipeTypes.CUTTING.getType()) + : RecipeConditions.isOfType(AllRecipeTypes.CUTTING.getType()); + List> startedSearch = RecipeFinder.get(cuttingRecipesKey, world, types); return startedSearch.stream() .filter(RecipeConditions.outputMatchesFilter(filtering)) .filter(RecipeConditions.firstIngredientMatches(inventory.getStackInSlot(0))) diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/ContraptionCollider.java b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/ContraptionCollider.java index 9cc0d311c..9484af64c 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/ContraptionCollider.java +++ b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/ContraptionCollider.java @@ -9,13 +9,13 @@ import java.util.Iterator; import java.util.List; import java.util.stream.Stream; -import com.simibubi.create.AllMovementBehaviours; import org.apache.commons.lang3.mutable.MutableBoolean; import org.apache.commons.lang3.mutable.MutableObject; import com.google.common.base.Predicates; import com.google.common.collect.ImmutableSet; import com.simibubi.create.AllBlocks; +import com.simibubi.create.AllMovementBehaviours; import com.simibubi.create.content.contraptions.components.actors.BlockBreakingMovementBehaviour; import com.simibubi.create.content.contraptions.components.structureMovement.sync.ClientMotionPacket; import com.simibubi.create.foundation.collision.ContinuousOBBCollider.ContinuousSeparationManifold; @@ -28,6 +28,7 @@ import com.simibubi.create.foundation.utility.VecHelper; import net.minecraft.block.BlockState; import net.minecraft.block.CocoaBlock; +import net.minecraft.client.entity.player.ClientPlayerEntity; import net.minecraft.entity.Entity; import net.minecraft.entity.EntityType; import net.minecraft.entity.player.PlayerEntity; @@ -37,6 +38,7 @@ import net.minecraft.util.Direction.AxisDirection; import net.minecraft.util.ReuseableStream; import net.minecraft.util.math.AxisAlignedBB; import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.MathHelper; import net.minecraft.util.math.Vec3d; import net.minecraft.util.math.shapes.IBooleanFunction; import net.minecraft.util.math.shapes.ISelectionContext; @@ -44,6 +46,9 @@ import net.minecraft.util.math.shapes.VoxelShape; import net.minecraft.util.math.shapes.VoxelShapes; import net.minecraft.world.World; import net.minecraft.world.gen.feature.template.Template.BlockInfo; +import net.minecraftforge.api.distmarker.Dist; +import net.minecraftforge.api.distmarker.OnlyIn; +import net.minecraftforge.fml.DistExecutor; public class ContraptionCollider { @@ -54,14 +59,20 @@ public class ContraptionCollider { for (Iterator> iterator = list.iterator(); iterator.hasNext();) { WeakReference weakReference = iterator.next(); ContraptionEntity contraptionEntity = weakReference.get(); - if (contraptionEntity == null || !contraptionEntity.isAlive()) { + if (contraptionEntity == null) { iterator.remove(); continue; } + if (!contraptionEntity.isAlive()) + continue; collideEntities(contraptionEntity); } } + enum PlayerType { + NONE, CLIENT, REMOTE, SERVER + } + private static void collideEntities(ContraptionEntity contraptionEntity) { World world = contraptionEntity.getEntityWorld(); Contraption contraption = contraptionEntity.getContraption(); @@ -87,8 +98,10 @@ public class ContraptionCollider { for (Entity entity : world.getEntitiesWithinAABB((EntityType) null, bounds.grow(2) .expand(0, 32, 0), contraptionEntity::canCollideWith)) { - boolean player = entity instanceof PlayerEntity; - boolean serverPlayer = player && !world.isRemote; + + PlayerType playerType = getPlayerType(entity); + if (playerType == PlayerType.REMOTE) + continue; // Init matrix if (rotation == null) { @@ -199,7 +212,7 @@ public class ContraptionCollider { totalResponse = rotation.transform(totalResponse); rotation.transpose(); - if (futureCollision.isTrue() && !serverPlayer) { + if (futureCollision.isTrue() && playerType != PlayerType.SERVER) { if (motionResponse.y != entityMotion.y) { entity.setMotion(entityMotion.mul(1, 0, 1) .add(0, motionResponse.y, 0)); @@ -212,7 +225,7 @@ public class ContraptionCollider { entity.fallDistance = 0; entity.onGround = true; contraptionEntity.collidingEntities.add(entity); - if (!serverPlayer) + if (playerType != PlayerType.SERVER) contactPointMotion = contraptionEntity.getContactPointMotion(entityPosition); } @@ -236,7 +249,7 @@ public class ContraptionCollider { if (!hardCollision && surfaceCollision.isFalse()) continue; - if (serverPlayer && entity instanceof ServerPlayerEntity) { + if (playerType == PlayerType.SERVER && entity instanceof ServerPlayerEntity) { ((ServerPlayerEntity) entity).connection.floatingTickCount = 0; continue; } @@ -249,8 +262,15 @@ public class ContraptionCollider { entityPosition.z + allowedMovement.z); entity.setMotion(entityMotion); - if (!serverPlayer && player) - AllPackets.channel.sendToServer(new ClientMotionPacket(entityMotion, true)); + if (playerType != PlayerType.CLIENT) + continue; + + double d0 = entity.getX() - entity.prevPosX - contactPointMotion.x; + double d1 = entity.getZ() - entity.prevPosZ - contactPointMotion.z; + float limbSwing = MathHelper.sqrt(d0 * d0 + d1 * d1) * 4.0F; + if (limbSwing > 1.0F) + limbSwing = 1.0F; + AllPackets.channel.sendToServer(new ClientMotionPacket(entityMotion, true, limbSwing)); } } @@ -296,6 +316,21 @@ public class ContraptionCollider { return vec3d; } + private static PlayerType getPlayerType(Entity entity) { + if (!(entity instanceof PlayerEntity)) + return PlayerType.NONE; + if (!entity.world.isRemote) + return PlayerType.SERVER; + MutableBoolean isClient = new MutableBoolean(false); + DistExecutor.runWhenOn(Dist.CLIENT, () -> () -> isClient.setValue(isClientPlayerEntity(entity))); + return isClient.booleanValue() ? PlayerType.CLIENT : PlayerType.REMOTE; + } + + @OnlyIn(Dist.CLIENT) + private static boolean isClientPlayerEntity(Entity entity) { + return entity instanceof ClientPlayerEntity; + } + private static ReuseableStream getPotentiallyCollidedShapes(World world, Contraption contraption, AxisAlignedBB localBB) { @@ -395,10 +430,10 @@ public class ContraptionCollider { BlockInfo blockInfo = contraption.blocks.get(pos); if (AllMovementBehaviours.hasMovementBehaviour(blockInfo.state.getBlock())) { - MovementBehaviour movementBehaviour = AllMovementBehaviours.getMovementBehaviour(blockInfo.state.getBlock()); + MovementBehaviour movementBehaviour = + AllMovementBehaviours.getMovementBehaviour(blockInfo.state.getBlock()); if (movementBehaviour instanceof BlockBreakingMovementBehaviour) { - BlockBreakingMovementBehaviour behaviour = - (BlockBreakingMovementBehaviour) movementBehaviour; + BlockBreakingMovementBehaviour behaviour = (BlockBreakingMovementBehaviour) movementBehaviour; if (!behaviour.canBreak(world, colliderPos, collidedState) && !collidedState.getCollisionShape(world, pos) .isEmpty()) { diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/ContraptionEntity.java b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/ContraptionEntity.java index 29766dc28..072407d4e 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/ContraptionEntity.java +++ b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/ContraptionEntity.java @@ -78,6 +78,7 @@ public class ContraptionEntity extends Entity implements IEntityAdditionalSpawnD final List collidingEntities = new ArrayList<>(); private boolean isSerializingFurnaceCart; private boolean attachedExtraInventories; + private boolean prevPosInvalid; private static final Ingredient FUEL_ITEMS = Ingredient.fromItems(Items.COAL, Items.CHARCOAL); private static final DataParameter STALLED = @@ -107,6 +108,7 @@ public class ContraptionEntity extends Entity implements IEntityAdditionalSpawnD isSerializingFurnaceCart = false; attachedExtraInventories = false; forcedAngle = -1; + prevPosInvalid = true; } public static ContraptionEntity createMounted(World world, Contraption contraption, float initialAngle) { @@ -289,26 +291,32 @@ public class ContraptionEntity extends Entity implements IEntityAdditionalSpawnD remove(); return; } + + prevPosX = getX(); + prevPosY = getY(); + prevPosZ = getZ(); + prevPosInvalid = false; if (!initialized) contraptionInitialize(); - checkController(); Entity mountedEntity = getRidingEntity(); if (mountedEntity != null) { tickAsPassenger(mountedEntity); + super.tick(); return; } if (getMotion().length() < 1 / 4098f) setMotion(Vec3d.ZERO); - + move(getMotion().x, getMotion().y, getMotion().z); if (ContraptionCollider.collideBlocks(this)) getController().collided(); - tickActors(getPositionVec().subtract(prevPosX, prevPosY, prevPosZ)); + Vec3d movement = getPositionVec().subtract(prevPosX, prevPosY, prevPosZ); + tickActors(movement); prevYaw = yaw; prevPitch = pitch; @@ -439,8 +447,6 @@ public class ContraptionEntity extends Entity implements IEntityAdditionalSpawnD furnaceCart.deserializeNBT(nbt); } } - - super.tick(); } public void tickActors(Vec3d movementVector) { @@ -846,6 +852,9 @@ public class ContraptionEntity extends Entity implements IEntityAdditionalSpawnD } public Vec3d getContactPointMotion(Vec3d globalContactPoint) { + if (prevPosInvalid) + return Vec3d.ZERO; + Vec3d positionVec = getPositionVec(); Vec3d conMotion = positionVec.subtract(getPrevPositionVec()); Vec3d conAngularMotion = getRotationVec().subtract(getPrevRotationVec()); @@ -906,5 +915,10 @@ public class ContraptionEntity extends Entity implements IEntityAdditionalSpawnD public void setCoupledCart(UUID id) { dataManager.set(COUPLED_CART, Optional.ofNullable(id)); } + + @Override + public boolean isOnePlayerRiding() { + return false; + } } diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/ContraptionHandler.java b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/ContraptionHandler.java index ff63f6662..e959ea513 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/ContraptionHandler.java +++ b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/ContraptionHandler.java @@ -4,6 +4,7 @@ import static java.util.concurrent.TimeUnit.SECONDS; import java.lang.ref.WeakReference; import java.util.ArrayList; +import java.util.Collections; import java.util.List; import java.util.concurrent.ExecutionException; @@ -28,7 +29,8 @@ public class ContraptionHandler { if (!(entity instanceof ContraptionEntity)) return; try { - List> list = activeContraptions.get(world, ArrayList::new); + List> list = + activeContraptions.get(world, () -> Collections.synchronizedList(new ArrayList<>())); ContraptionEntity contraption = (ContraptionEntity) entity; list.add(new WeakReference<>(contraption)); } catch (ExecutionException e) { diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/ContraptionInteractionHandler.java b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/ContraptionHandlerClient.java similarity index 72% rename from src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/ContraptionInteractionHandler.java rename to src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/ContraptionHandlerClient.java index 36ada9e88..191f19bc3 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/ContraptionInteractionHandler.java +++ b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/ContraptionHandlerClient.java @@ -1,4 +1,5 @@ package com.simibubi.create.content.contraptions.components.structureMovement; + import org.apache.commons.lang3.mutable.MutableObject; import com.simibubi.create.content.contraptions.components.structureMovement.sync.ContraptionInteractionPacket; @@ -9,6 +10,8 @@ import com.simibubi.create.foundation.utility.RaycastHelper.PredicateTraceResult import net.minecraft.block.BlockState; import net.minecraft.client.Minecraft; import net.minecraft.client.entity.player.ClientPlayerEntity; +import net.minecraft.client.entity.player.RemoteClientPlayerEntity; +import net.minecraft.nbt.CompoundNBT; import net.minecraft.util.Direction; import net.minecraft.util.Hand; import net.minecraft.util.math.AxisAlignedBB; @@ -20,11 +23,38 @@ import net.minecraft.world.gen.feature.template.Template.BlockInfo; import net.minecraftforge.api.distmarker.Dist; import net.minecraftforge.api.distmarker.OnlyIn; import net.minecraftforge.client.event.InputEvent.ClickInputEvent; +import net.minecraftforge.event.TickEvent.Phase; +import net.minecraftforge.event.TickEvent.PlayerTickEvent; import net.minecraftforge.eventbus.api.SubscribeEvent; import net.minecraftforge.fml.common.Mod.EventBusSubscriber; @EventBusSubscriber -public class ContraptionInteractionHandler { +public class ContraptionHandlerClient { + + @SubscribeEvent + @OnlyIn(Dist.CLIENT) + public static void preventRemotePlayersWalkingAnimations(PlayerTickEvent event) { + if (event.phase == Phase.START) + return; + if (!(event.player instanceof RemoteClientPlayerEntity)) + return; + RemoteClientPlayerEntity remotePlayer = (RemoteClientPlayerEntity) event.player; + CompoundNBT data = remotePlayer.getPersistentData(); + if (!data.contains("LastOverrideLimbSwingUpdate")) + return; + + int lastOverride = data.getInt("LastOverrideLimbSwingUpdate"); + data.putInt("LastOverrideLimbSwingUpdate", lastOverride + 1); + if (lastOverride > 5) { + data.remove("LastOverrideLimbSwingUpdate"); + data.remove("OverrideLimbSwing"); + return; + } + + float limbSwing = data.getFloat("OverrideLimbSwing"); + remotePlayer.prevPosX = remotePlayer.getX() - (limbSwing / 4); + remotePlayer.prevPosZ = remotePlayer.getZ(); + } @SubscribeEvent @OnlyIn(Dist.CLIENT) @@ -38,11 +68,12 @@ public class ContraptionInteractionHandler { if (!event.isUseItem()) return; Vec3d origin = RaycastHelper.getTraceOrigin(player); - + double reach = mc.playerController.getBlockReachDistance(); - if (mc.objectMouseOver != null && mc.objectMouseOver.getHitVec() != null) - reach = Math.min(mc.objectMouseOver.getHitVec().distanceTo(origin), reach); - + if (mc.objectMouseOver != null && mc.objectMouseOver.getHitVec() != null) + reach = Math.min(mc.objectMouseOver.getHitVec() + .distanceTo(origin), reach); + Vec3d target = RaycastHelper.getTraceTarget(player, reach, origin); for (ContraptionEntity contraptionEntity : mc.world.getEntitiesWithinAABB(ContraptionEntity.class, new AxisAlignedBB(origin, target))) { @@ -75,11 +106,10 @@ public class ContraptionInteractionHandler { Hand hand = event.getHand(); Direction face = rayTraceResult.getFace(); BlockPos pos = rayTraceResult.getPos(); - + if (!contraptionEntity.handlePlayerInteraction(player, pos, face, hand)) return; - AllPackets.channel.sendToServer(new ContraptionInteractionPacket(contraptionEntity, hand, - pos, face)); + AllPackets.channel.sendToServer(new ContraptionInteractionPacket(contraptionEntity, hand, pos, face)); event.setCanceled(true); event.setSwingHand(false); } diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/sync/ClientMotionPacket.java b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/sync/ClientMotionPacket.java index a80351080..f5bb6758e 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/sync/ClientMotionPacket.java +++ b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/sync/ClientMotionPacket.java @@ -2,26 +2,31 @@ package com.simibubi.create.content.contraptions.components.structureMovement.sy import java.util.function.Supplier; +import com.simibubi.create.foundation.networking.AllPackets; import com.simibubi.create.foundation.networking.SimplePacketBase; import net.minecraft.entity.player.ServerPlayerEntity; import net.minecraft.network.PacketBuffer; import net.minecraft.util.math.Vec3d; import net.minecraftforge.fml.network.NetworkEvent.Context; +import net.minecraftforge.fml.network.PacketDistributor; public class ClientMotionPacket extends SimplePacketBase { private Vec3d motion; private boolean onGround; + private float limbSwing; - public ClientMotionPacket(Vec3d motion, boolean onGround) { + public ClientMotionPacket(Vec3d motion, boolean onGround, float limbSwing) { this.motion = motion; this.onGround = onGround; + this.limbSwing = limbSwing; } public ClientMotionPacket(PacketBuffer buffer) { motion = new Vec3d(buffer.readFloat(), buffer.readFloat(), buffer.readFloat()); onGround = buffer.readBoolean(); + limbSwing = buffer.readFloat(); } @Override @@ -30,6 +35,7 @@ public class ClientMotionPacket extends SimplePacketBase { buffer.writeFloat((float) motion.y); buffer.writeFloat((float) motion.z); buffer.writeBoolean(onGround); + buffer.writeFloat(limbSwing); } @Override @@ -47,6 +53,8 @@ public class ClientMotionPacket extends SimplePacketBase { sender.fallDistance = 0; sender.connection.floatingTickCount = 0; } + AllPackets.channel.send(PacketDistributor.TRACKING_ENTITY.with(() -> sender), + new LimbSwingUpdatePacket(sender.getEntityId(), sender.getPositionVec(), limbSwing)); }); context.get() .setPacketHandled(true); diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/sync/LimbSwingUpdatePacket.java b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/sync/LimbSwingUpdatePacket.java new file mode 100644 index 000000000..4d3bfea33 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/sync/LimbSwingUpdatePacket.java @@ -0,0 +1,62 @@ +package com.simibubi.create.content.contraptions.components.structureMovement.sync; + +import java.util.function.Supplier; + +import com.simibubi.create.foundation.networking.SimplePacketBase; + +import net.minecraft.client.Minecraft; +import net.minecraft.client.world.ClientWorld; +import net.minecraft.entity.Entity; +import net.minecraft.nbt.CompoundNBT; +import net.minecraft.network.PacketBuffer; +import net.minecraft.util.math.Vec3d; +import net.minecraftforge.fml.network.NetworkEvent.Context; + +public class LimbSwingUpdatePacket extends SimplePacketBase { + + private int entityId; + private Vec3d position; + private float limbSwing; + + public LimbSwingUpdatePacket(int entityId, Vec3d position, float limbSwing) { + this.entityId = entityId; + this.position = position; + this.limbSwing = limbSwing; + } + + public LimbSwingUpdatePacket(PacketBuffer buffer) { + entityId = buffer.readInt(); + position = new Vec3d(buffer.readFloat(), buffer.readFloat(), buffer.readFloat()); + limbSwing = buffer.readFloat(); + } + + @Override + public void write(PacketBuffer buffer) { + buffer.writeInt(entityId); + buffer.writeFloat((float) position.x); + buffer.writeFloat((float) position.y); + buffer.writeFloat((float) position.z); + buffer.writeFloat(limbSwing); + } + + @Override + public void handle(Supplier context) { + context.get() + .enqueueWork(() -> { + ClientWorld world = Minecraft.getInstance().world; + if (world == null) + return; + Entity entity = world.getEntityByID(entityId); + if (entity == null) + return; + CompoundNBT data = entity.getPersistentData(); + data.putInt("LastOverrideLimbSwingUpdate", 0); + data.putFloat("OverrideLimbSwing", limbSwing); + entity.setPositionAndRotationDirect(position.x, position.y, position.z, entity.rotationYaw, + entity.rotationPitch, 2, false); + }); + context.get() + .setPacketHandled(true); + } + +} diff --git a/src/main/java/com/simibubi/create/content/contraptions/fluids/actors/FillingBySpout.java b/src/main/java/com/simibubi/create/content/contraptions/fluids/actors/FillingBySpout.java index 59a3b3ada..4afe6f0d6 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/fluids/actors/FillingBySpout.java +++ b/src/main/java/com/simibubi/create/content/contraptions/fluids/actors/FillingBySpout.java @@ -24,8 +24,7 @@ public class FillingBySpout { public static boolean canItemBeFilled(World world, ItemStack stack) { wrapper.setInventorySlotContents(0, stack); - if (world.getRecipeManager() - .getRecipe(AllRecipeTypes.FILLING.getType(), wrapper, world) + if (AllRecipeTypes.FILLING.find(wrapper, world) .isPresent()) return true; @@ -44,8 +43,7 @@ public class FillingBySpout { public static int getRequiredAmountForItem(World world, ItemStack stack, FluidStack availableFluid) { wrapper.setInventorySlotContents(0, stack); - Optional> recipe = world.getRecipeManager() - .getRecipe(AllRecipeTypes.FILLING.getType(), wrapper, world); + Optional> recipe = AllRecipeTypes.FILLING.find(wrapper, world); if (recipe.isPresent()) { FillingRecipe fillingRecipe = (FillingRecipe) recipe.get(); FluidIngredient requiredFluid = fillingRecipe.getRequiredFluid(); @@ -71,8 +69,7 @@ public class FillingBySpout { availableFluid.shrink(requiredAmount); wrapper.setInventorySlotContents(0, stack); - Optional> recipe = world.getRecipeManager() - .getRecipe(AllRecipeTypes.FILLING.getType(), wrapper, world); + Optional> recipe = AllRecipeTypes.FILLING.find(wrapper, world); if (recipe.isPresent()) { FillingRecipe fillingRecipe = (FillingRecipe) recipe.get(); FluidIngredient requiredFluid = fillingRecipe.getRequiredFluid(); diff --git a/src/main/java/com/simibubi/create/content/contraptions/processing/BasinBlock.java b/src/main/java/com/simibubi/create/content/contraptions/processing/BasinBlock.java index 39fbddf41..6a57ebbb1 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/processing/BasinBlock.java +++ b/src/main/java/com/simibubi/create/content/contraptions/processing/BasinBlock.java @@ -9,16 +9,23 @@ import com.simibubi.create.foundation.block.ITE; import com.simibubi.create.foundation.item.ItemHelper; import com.simibubi.create.foundation.tileEntity.TileEntityBehaviour; import com.simibubi.create.foundation.tileEntity.behaviour.filtering.FilteringBehaviour; +import com.simibubi.create.foundation.utility.Iterate; +import com.simibubi.create.foundation.utility.Pair; import net.minecraft.block.Block; import net.minecraft.block.BlockState; import net.minecraft.entity.Entity; import net.minecraft.entity.item.ItemEntity; import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.item.BlockItemUseContext; import net.minecraft.item.ItemStack; import net.minecraft.item.ItemUseContext; +import net.minecraft.state.DirectionProperty; +import net.minecraft.state.StateContainer.Builder; +import net.minecraft.state.properties.BlockStateProperties; import net.minecraft.tileentity.TileEntity; import net.minecraft.util.ActionResultType; +import net.minecraft.util.Direction; import net.minecraft.util.Hand; import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.BlockRayTraceResult; @@ -26,14 +33,22 @@ import net.minecraft.util.math.shapes.ISelectionContext; import net.minecraft.util.math.shapes.VoxelShape; import net.minecraft.world.IBlockReader; import net.minecraft.world.World; +import net.minecraftforge.common.util.LazyOptional; +import net.minecraftforge.fluids.FluidStack; +import net.minecraftforge.fluids.capability.CapabilityFluidHandler; +import net.minecraftforge.fluids.capability.IFluidHandler; +import net.minecraftforge.fluids.capability.IFluidHandler.FluidAction; import net.minecraftforge.items.IItemHandlerModifiable; import net.minecraftforge.items.ItemHandlerHelper; import net.minecraftforge.items.ItemStackHandler; public class BasinBlock extends Block implements ITE, IWrenchable { + public static final DirectionProperty FACING = BlockStateProperties.FACING_EXCEPT_UP; + public BasinBlock(Properties p_i48440_1_) { super(p_i48440_1_); + setDefaultState(getDefaultState().with(FACING, Direction.DOWN)); } @Override @@ -41,6 +56,11 @@ public class BasinBlock extends Block implements ITE, IWrenchab return true; } + @Override + protected void fillStateContainer(Builder p_206840_1_) { + super.fillStateContainer(p_206840_1_.add(FACING)); + } + @Override public TileEntity createTileEntity(BlockState state, IBlockReader world) { return AllTileEntities.BASIN.create(); @@ -54,12 +74,16 @@ public class BasinBlock extends Block implements ITE, IWrenchab @Override public ActionResultType onUse(BlockState state, World worldIn, BlockPos pos, PlayerEntity player, Hand handIn, BlockRayTraceResult hit) { - if (!player.getHeldItem(handIn) - .isEmpty()) - return ActionResultType.PASS; + ItemStack heldItem = player.getHeldItem(handIn); try { BasinTileEntity te = getTileEntity(worldIn, pos); + if (!heldItem.isEmpty()) { + if (tryEmptyItemIntoBasin(worldIn, player, handIn, heldItem, te)) + return ActionResultType.SUCCESS; + return ActionResultType.PASS; + } + IItemHandlerModifiable inv = te.itemCapability.orElse(new ItemStackHandler(1)); for (int slot = 0; slot < inv.getSlots(); slot++) { player.inventory.placeItemBackInInventory(worldIn, inv.getStackInSlot(slot)); @@ -72,6 +96,30 @@ public class BasinBlock extends Block implements ITE, IWrenchab return ActionResultType.SUCCESS; } + protected boolean tryEmptyItemIntoBasin(World worldIn, PlayerEntity player, Hand handIn, ItemStack heldItem, + BasinTileEntity te) { + if (!EmptyingByBasin.canItemBeEmptied(worldIn, heldItem)) + return false; + + Pair emptyItem = EmptyingByBasin.emptyItem(worldIn, heldItem, true); + LazyOptional capability = te.getCapability(CapabilityFluidHandler.FLUID_HANDLER_CAPABILITY); + IFluidHandler tank = capability.orElse(null); + FluidStack fluidStack = emptyItem.getFirst(); + + if (tank == null || fluidStack.getAmount() != tank.fill(fluidStack, FluidAction.SIMULATE)) + return false; + if (worldIn.isRemote) + return true; + + EmptyingByBasin.emptyItem(worldIn, heldItem, false); + tank.fill(fluidStack, FluidAction.EXECUTE); + if (heldItem.isEmpty()) + player.setHeldItem(handIn, emptyItem.getSecond()); + else + player.inventory.placeItemBackInInventory(worldIn, emptyItem.getSecond()); + return true; + } + @Override public void onLanded(IBlockReader worldIn, Entity entityIn) { super.onLanded(worldIn, entityIn); @@ -102,6 +150,11 @@ public class BasinBlock extends Block implements ITE, IWrenchab return AllShapes.BASIN_BLOCK_SHAPE; } + @Override + public void onBlockAdded(BlockState state, World world, BlockPos pos, BlockState p_220082_4_, boolean p_220082_5_) { + updateDiagonalNeighbours(state, world, pos); + } + @Override public VoxelShape getCollisionShape(BlockState state, IBlockReader reader, BlockPos pos, ISelectionContext ctx) { if (ctx.getEntity() instanceof ItemEntity) @@ -111,6 +164,7 @@ public class BasinBlock extends Block implements ITE, IWrenchab @Override public void onReplaced(BlockState state, World worldIn, BlockPos pos, BlockState newState, boolean isMoving) { + updateDiagonalNeighbours(state, worldIn, pos); if (!state.hasTileEntity() || state.getBlock() == newState.getBlock()) return; TileEntityBehaviour.destroy(worldIn, pos, FilteringBehaviour.TYPE); @@ -140,4 +194,35 @@ public class BasinBlock extends Block implements ITE, IWrenchab return BasinTileEntity.class; } + @Override + public BlockState getStateForPlacement(BlockItemUseContext ctx) { + BlockState state = super.getStateForPlacement(ctx); + World world = ctx.getWorld(); + BlockPos pos = ctx.getPos(); + return updateDiagonalState(state, world, pos); + } + + protected void updateDiagonalNeighbours(BlockState state, World world, BlockPos pos) { + for (Direction direction : Iterate.horizontalDirections) { + BlockPos toUpdate = pos.up() + .offset(direction); + BlockState stateToUpdate = world.getBlockState(toUpdate); + BlockState updated = updateDiagonalState(stateToUpdate, world, toUpdate); + if (stateToUpdate != updated && !world.isRemote) + world.setBlockState(toUpdate, updated); + } + } + + public static BlockState updateDiagonalState(BlockState state, IBlockReader world, BlockPos pos) { + if (!(state.getBlock() instanceof BasinBlock)) + return state; + for (Direction direction : Iterate.horizontalDirections) { + BlockState diagonaloutputBasin = world.getBlockState(pos.down() + .offset(direction)); + if (diagonaloutputBasin.getBlock() instanceof BasinBlock) + return state.with(FACING, direction); + } + return state.with(FACING, Direction.DOWN); + } + } diff --git a/src/main/java/com/simibubi/create/content/contraptions/processing/BasinGenerator.java b/src/main/java/com/simibubi/create/content/contraptions/processing/BasinGenerator.java new file mode 100644 index 000000000..fe96055ac --- /dev/null +++ b/src/main/java/com/simibubi/create/content/contraptions/processing/BasinGenerator.java @@ -0,0 +1,32 @@ +package com.simibubi.create.content.contraptions.processing; + +import com.simibubi.create.foundation.data.AssetLookup; +import com.simibubi.create.foundation.data.SpecialBlockStateGen; +import com.tterrag.registrate.providers.DataGenContext; +import com.tterrag.registrate.providers.RegistrateBlockstateProvider; + +import net.minecraft.block.Block; +import net.minecraft.block.BlockState; +import net.minecraftforge.client.model.generators.ModelFile; + +public class BasinGenerator extends SpecialBlockStateGen { + + @Override + protected int getXRotation(BlockState state) { + return 0; + } + + @Override + protected int getYRotation(BlockState state) { + return horizontalAngle(state.get(BasinBlock.FACING)); + } + + @Override + public ModelFile getModel(DataGenContext ctx, RegistrateBlockstateProvider prov, + BlockState state) { + if (state.get(BasinBlock.FACING).getAxis().isVertical()) + return AssetLookup.partialBaseModel(ctx, prov); + return AssetLookup.partialBaseModel(ctx, prov, "directional"); + } + +} diff --git a/src/main/java/com/simibubi/create/content/contraptions/processing/BasinInputInventory.java b/src/main/java/com/simibubi/create/content/contraptions/processing/BasinInputInventory.java deleted file mode 100644 index 6f105dd5e..000000000 --- a/src/main/java/com/simibubi/create/content/contraptions/processing/BasinInputInventory.java +++ /dev/null @@ -1,27 +0,0 @@ -package com.simibubi.create.content.contraptions.processing; - -import com.simibubi.create.foundation.item.SmartInventory; - -import net.minecraft.item.ItemStack; -import net.minecraftforge.items.ItemHandlerHelper; - -public class BasinInputInventory extends SmartInventory { - - public BasinInputInventory(int slots, BasinTileEntity te) { - super(slots, te); - } - - @Override - public ItemStack insertItem(int slot, ItemStack stack, boolean simulate) { - // Only insert if no other slot already has a 'full' stack of this item - for (int i = 0; i < getSlots(); i++) { - ItemStack stackInSlot = getStackInSlot(i); - if (ItemHandlerHelper.canItemStacksStack(stack, stackInSlot) - && stackInSlot.getCount() == getStackLimit(i, stackInSlot)) - return stack; - } - - return super.insertItem(slot, stack, simulate); - } - -} diff --git a/src/main/java/com/simibubi/create/content/contraptions/processing/BasinInventory.java b/src/main/java/com/simibubi/create/content/contraptions/processing/BasinInventory.java new file mode 100644 index 000000000..3e3ac469a --- /dev/null +++ b/src/main/java/com/simibubi/create/content/contraptions/processing/BasinInventory.java @@ -0,0 +1,23 @@ +package com.simibubi.create.content.contraptions.processing; + +import com.simibubi.create.foundation.item.SmartInventory; + +import net.minecraft.item.ItemStack; +import net.minecraftforge.items.ItemHandlerHelper; + +public class BasinInventory extends SmartInventory { + + public BasinInventory(int slots, BasinTileEntity te) { + super(slots, te, 16, true); + } + + @Override + public ItemStack insertItem(int slot, ItemStack stack, boolean simulate) { + // Only insert if no other slot already has a stack of this item + for (int i = 0; i < getSlots(); i++) + if (i != slot && ItemHandlerHelper.canItemStacksStack(stack, inv.getStackInSlot(i))) + return stack; + return super.insertItem(slot, stack, simulate); + } + +} diff --git a/src/main/java/com/simibubi/create/content/contraptions/processing/BasinOperatingTileEntity.java b/src/main/java/com/simibubi/create/content/contraptions/processing/BasinOperatingTileEntity.java index 26320f935..20383e4f4 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/processing/BasinOperatingTileEntity.java +++ b/src/main/java/com/simibubi/create/content/contraptions/processing/BasinOperatingTileEntity.java @@ -1,49 +1,29 @@ package com.simibubi.create.content.contraptions.processing; -import java.util.ArrayList; import java.util.List; import java.util.Optional; import java.util.stream.Collectors; -import com.simibubi.create.AllTileEntities; import com.simibubi.create.content.contraptions.base.KineticTileEntity; import com.simibubi.create.foundation.advancement.AllTriggers; -import com.simibubi.create.foundation.advancement.SimpleTrigger; -import com.simibubi.create.foundation.item.SmartInventory; +import com.simibubi.create.foundation.advancement.ITriggerable; import com.simibubi.create.foundation.tileEntity.TileEntityBehaviour; import com.simibubi.create.foundation.tileEntity.behaviour.simple.DeferralBehaviour; import com.simibubi.create.foundation.utility.recipe.RecipeFinder; import net.minecraft.inventory.IInventory; -import net.minecraft.item.ItemStack; import net.minecraft.item.crafting.IRecipe; -import net.minecraft.item.crafting.Ingredient; import net.minecraft.tileentity.TileEntity; import net.minecraft.tileentity.TileEntityType; -import net.minecraft.util.NonNullList; -import net.minecraftforge.common.util.LazyOptional; -import net.minecraftforge.fluids.FluidStack; -import net.minecraftforge.fluids.capability.CapabilityFluidHandler; -import net.minecraftforge.fluids.capability.IFluidHandler; -import net.minecraftforge.items.CapabilityItemHandler; -import net.minecraftforge.items.IItemHandler; -import net.minecraftforge.items.ItemHandlerHelper; public abstract class BasinOperatingTileEntity extends KineticTileEntity { public DeferralBehaviour basinChecker; public boolean basinRemoved; - protected IRecipe lastRecipe; - - protected LazyOptional basinItemInv = LazyOptional.empty(); - protected List itemInputs; - protected LazyOptional basinFluidInv = LazyOptional.empty(); - protected List fluidInputs; + protected IRecipe currentRecipe; public BasinOperatingTileEntity(TileEntityType typeIn) { super(typeIn); - itemInputs = new ArrayList<>(); - fluidInputs = new ArrayList<>(); } @Override @@ -58,29 +38,10 @@ public abstract class BasinOperatingTileEntity extends KineticTileEntity { super.onSpeedChanged(prevSpeed); if (getSpeed() == 0) basinRemoved = true; + basinRemoved = false; basinChecker.scheduleUpdate(); } - public void gatherInputs() { - itemInputs.clear(); - basinItemInv.ifPresent(handler -> { - for (int slot = 0; slot < handler.getSlots(); ++slot) { - ItemStack itemstack = handler.getStackInSlot(slot); - if (!itemstack.isEmpty()) - itemInputs.add(itemstack); - } - }); - - fluidInputs.clear(); - basinFluidInv.ifPresent(handler -> { - for (int tank = 0; tank < handler.getTanks(); tank++) { - FluidStack fluidInTank = handler.getFluidInTank(tank); - if (!fluidInTank.isEmpty()) - fluidInputs.add(fluidInTank); - } - }); - } - @Override public void tick() { if (basinRemoved) { @@ -100,28 +61,13 @@ public abstract class BasinOperatingTileEntity extends KineticTileEntity { return true; if (isRunning()) return false; - - Optional basinTe = getBasin(); - if (!basinTe.isPresent()) - return true; - if (!basinItemInv.isPresent()) - basinItemInv = basinTe.get() - .getCapability(CapabilityItemHandler.ITEM_HANDLER_CAPABILITY); - if (!basinFluidInv.isPresent()) - basinFluidInv = basinTe.get() - .getCapability(CapabilityFluidHandler.FLUID_HANDLER_CAPABILITY); - if (!basinFluidInv.isPresent() || !basinItemInv.isPresent()) - return true; - if (world == null || world.isRemote) return true; - gatherInputs(); List> recipes = getMatchingRecipes(); if (recipes.isEmpty()) return true; - - lastRecipe = recipes.get(0); + currentRecipe = recipes.get(0); startProcessingBasin(); sendData(); return true; @@ -135,58 +81,37 @@ public abstract class BasinOperatingTileEntity extends KineticTileEntity { return true; } - public void applyBasinRecipe() { - if (lastRecipe == null) - return; - if (!basinItemInv.isPresent() || !basinFluidInv.isPresent()) - return; - + protected boolean matchBasinRecipe(IRecipe recipe) { + if (recipe == null) + return false; Optional basin = getBasin(); if (!basin.isPresent()) + return false; + return BasinRecipe.match(basin.get(), recipe); + } + + protected void applyBasinRecipe() { + if (currentRecipe == null) return; - SmartInventory inputs = basin.get().getInputInventory(); - SmartInventory outputs = basin.get().getOutputInventory(); - List containers = new ArrayList<>(); - - NonNullList ingredients = lastRecipe.getIngredients(); - Ingredients: for (int i = 0; i < ingredients.size(); i++) { - Ingredient ingredient = ingredients.get(i); - - for (int slot = 0; slot < inputs.getSlots(); slot++) { - if (!ingredient.test(inputs.extractItem(slot, 1, true))) - continue; - ItemStack extracted = inputs.extractItem(slot, 1, false); - if (extracted.hasContainerItem()) - containers.add(extracted.getContainerItem() - .copy()); - continue Ingredients; - } - - // something wasn't found + + Optional optionalBasin = getBasin(); + if (!optionalBasin.isPresent()) return; - } - - if (world != null && !world.isRemote) { - SimpleTrigger trigger = AllTriggers.MIXER_MIX; - if (AllTileEntities.MECHANICAL_PRESS.is(this)) - trigger = AllTriggers.PRESS_COMPACT; - AllTriggers.triggerForNearbyPlayers(trigger, world, pos, 4); - } - - outputs.allowInsertion(); - ItemHandlerHelper.insertItemStacked(outputs, lastRecipe.getRecipeOutput() - .copy(), false); // TODO only works for single item output - containers.forEach(stack -> ItemHandlerHelper.insertItemStacked(outputs, stack, false)); - outputs.forbidInsertion(); - + BasinTileEntity basin = optionalBasin.get(); + if (!BasinRecipe.apply(basin, currentRecipe)) + return; + Optional processedRecipeTrigger = getProcessedRecipeTrigger(); + if (world != null && !world.isRemote && processedRecipeTrigger.isPresent()) + AllTriggers.triggerForNearbyPlayers(processedRecipeTrigger.get(), world, pos, 4); + basin.inputTank.sendDataImmediately(); + // Continue mixing - gatherInputs(); - if (matchBasinRecipe(lastRecipe)) { + if (matchBasinRecipe(currentRecipe)) { continueWithPreviousRecipe(); sendData(); } - getBasin().ifPresent(BasinTileEntity::notifyChangeOfContents); + basin.notifyChangeOfContents(); } protected List> getMatchingRecipes() { @@ -210,28 +135,13 @@ public abstract class BasinOperatingTileEntity extends KineticTileEntity { return Optional.empty(); return Optional.of((BasinTileEntity) basinTE); } + + protected Optional getProcessedRecipeTrigger() { + return Optional.empty(); + } protected abstract boolean matchStaticFilters(IRecipe recipe); - protected boolean matchBasinRecipe(IRecipe recipe) { - if (recipe == null) - return false; - - Optional basin = getBasin(); - if (!basin.isPresent()) - return false; - BasinTileEntity basinTileEntity = basin.get(); - if (!basinTileEntity.getFilter() - .test(recipe.getRecipeOutput())) - return false; - - NonNullList ingredients = recipe.getIngredients(); - if (!ingredients.stream() - .allMatch(ingredient -> (ingredient.isSimple() || ingredient.getMatchingStacks().length == 1))) - return false; - return true; - } - protected abstract Object getRecipeCacheKey(); } diff --git a/src/main/java/com/simibubi/create/content/contraptions/processing/BasinRecipe.java b/src/main/java/com/simibubi/create/content/contraptions/processing/BasinRecipe.java new file mode 100644 index 000000000..6fc0a451d --- /dev/null +++ b/src/main/java/com/simibubi/create/content/contraptions/processing/BasinRecipe.java @@ -0,0 +1,199 @@ +package com.simibubi.create.content.contraptions.processing; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; +import java.util.LinkedList; +import java.util.List; + +import javax.annotation.Nonnull; + +import com.simibubi.create.AllRecipeTypes; +import com.simibubi.create.content.contraptions.processing.ProcessingRecipeBuilder.ProcessingRecipeParams; +import com.simibubi.create.content.contraptions.processing.burner.BlazeBurnerBlock.HeatLevel; +import com.simibubi.create.foundation.fluid.FluidIngredient; +import com.simibubi.create.foundation.item.SmartInventory; +import com.simibubi.create.foundation.tileEntity.behaviour.filtering.FilteringBehaviour; +import com.simibubi.create.foundation.tileEntity.behaviour.fluid.SmartFluidTankBehaviour; +import com.simibubi.create.foundation.tileEntity.behaviour.fluid.SmartFluidTankBehaviour.TankSegment; +import com.simibubi.create.foundation.utility.Iterate; + +import net.minecraft.item.ItemStack; +import net.minecraft.item.crafting.IRecipe; +import net.minecraft.item.crafting.Ingredient; +import net.minecraft.world.World; +import net.minecraftforge.fluids.FluidStack; +import net.minecraftforge.fluids.capability.CapabilityFluidHandler; +import net.minecraftforge.fluids.capability.IFluidHandler; +import net.minecraftforge.items.CapabilityItemHandler; +import net.minecraftforge.items.IItemHandler; + +public class BasinRecipe extends ProcessingRecipe { + + public static boolean match(BasinTileEntity basin, IRecipe recipe) { + FilteringBehaviour filter = basin.getFilter(); + if (filter == null || !filter.test(recipe.getRecipeOutput())) + return false; + return apply(basin, recipe, true); + } + + public static boolean apply(BasinTileEntity basin, IRecipe recipe) { + return apply(basin, recipe, false); + } + + private static boolean apply(BasinTileEntity basin, IRecipe recipe, boolean test) { + boolean isBasinRecipe = recipe instanceof BasinRecipe; + IItemHandler availableItems = basin.getCapability(CapabilityItemHandler.ITEM_HANDLER_CAPABILITY) + .orElse(null); + IFluidHandler availableFluids = basin.getCapability(CapabilityFluidHandler.FLUID_HANDLER_CAPABILITY) + .orElse(null); + + if (availableItems == null || availableFluids == null) + return false; + + HeatLevel heat = basin.getHeatLevel(); + if (isBasinRecipe && !((BasinRecipe) recipe).getRequiredHeat() + .testBlazeBurner(heat)) + return false; + + List recipeOutputItems = new ArrayList<>(); + List recipeOutputFluids = new ArrayList<>(); + + List ingredients = new LinkedList<>(recipe.getIngredients()); + ingredients.sort(Comparator.comparingInt(i -> i.getMatchingStacks().length)); + List fluidIngredients = + isBasinRecipe ? ((BasinRecipe) recipe).getFluidIngredients() : Collections.emptyList(); + + for (boolean simulate : Iterate.trueAndFalse) { + + if (!simulate && test) + return true; + + int[] extractedItemsFromSlot = new int[availableItems.getSlots()]; + int[] extractedFluidsFromTank = new int[availableFluids.getTanks()]; + + Ingredients: for (int i = 0; i < ingredients.size(); i++) { + Ingredient ingredient = ingredients.get(i); + + for (int slot = 0; slot < availableItems.getSlots(); slot++) { + if (simulate && availableItems.getStackInSlot(slot) + .getCount() <= extractedItemsFromSlot[slot]) + continue; + ItemStack extracted = availableItems.extractItem(slot, 1, true); + if (!ingredient.test(extracted)) + continue; + if (!simulate) + availableItems.extractItem(slot, 1, false); + else if (extracted.hasContainerItem()) + recipeOutputItems.add(extracted.getContainerItem() + .copy()); + extractedItemsFromSlot[slot]++; + continue Ingredients; + } + + // something wasn't found + return false; + } + + boolean fluidsAffected = false; + FluidIngredients: for (int i = 0; i < fluidIngredients.size(); i++) { + FluidIngredient fluidIngredient = fluidIngredients.get(i); + int amountRequired = fluidIngredient.getRequiredAmount(); + + for (int tank = 0; tank < availableFluids.getTanks(); tank++) { + FluidStack fluidStack = availableFluids.getFluidInTank(tank); + if (simulate && fluidStack.getAmount() <= extractedFluidsFromTank[tank]) + continue; + if (!fluidIngredient.test(fluidStack)) + continue; + int drainedAmount = Math.min(amountRequired, fluidStack.getAmount()); + if (!simulate) { + fluidStack.shrink(drainedAmount); + fluidsAffected = true; + } + amountRequired -= drainedAmount; + if (amountRequired != 0) + continue; + extractedFluidsFromTank[tank] += drainedAmount; + continue FluidIngredients; + } + + // something wasn't found + return false; + } + + if (fluidsAffected) { + basin.getBehaviour(SmartFluidTankBehaviour.INPUT) + .foreach(TankSegment::onFluidStackChanged); + basin.getBehaviour(SmartFluidTankBehaviour.OUTPUT) + .foreach(TankSegment::onFluidStackChanged); + } + + if (simulate) { + if (recipe instanceof BasinRecipe) { + recipeOutputItems.addAll(((BasinRecipe) recipe).rollResults()); + recipeOutputFluids.addAll(((BasinRecipe) recipe).getFluidResults()); + } else + recipeOutputItems.add(recipe.getRecipeOutput()); + } + + if (!basin.acceptOutputs(recipeOutputItems, recipeOutputFluids, simulate)) + return false; + } + + return true; + } + + /** + * For JEI purposes only + */ + public boolean convertedRecipe; + + public static BasinRecipe convert(IRecipe recipe) { + BasinRecipe basinRecipe = new ProcessingRecipeBuilder<>(BasinRecipe::new, recipe.getId()) + .withItemIngredients(recipe.getIngredients()) + .withSingleItemOutput(recipe.getRecipeOutput()) + .build(); + basinRecipe.convertedRecipe = true; + return basinRecipe; + } + + protected BasinRecipe(AllRecipeTypes type, ProcessingRecipeParams params) { + super(type, params); + } + + public BasinRecipe(ProcessingRecipeParams params) { + this(AllRecipeTypes.BASIN, params); + } + + @Override + protected int getMaxInputCount() { + return 9; + } + + @Override + protected int getMaxOutputCount() { + return 4; + } + + @Override + protected int getMaxFluidInputCount() { + return 2; + } + + @Override + protected int getMaxFluidOutputCount() { + return 2; + } + + @Override + protected boolean canRequireHeat() { + return true; + } + + @Override + public boolean matches(SmartInventory inv, @Nonnull World worldIn) { + return false; + } + +} diff --git a/src/main/java/com/simibubi/create/content/contraptions/processing/BasinRenderer.java b/src/main/java/com/simibubi/create/content/contraptions/processing/BasinRenderer.java index e9e232abd..a02cb4eed 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/processing/BasinRenderer.java +++ b/src/main/java/com/simibubi/create/content/contraptions/processing/BasinRenderer.java @@ -79,16 +79,19 @@ public class BasinRenderer extends SmartTileEntityRenderer { if (tankSegment.getRenderedFluid() .isEmpty()) continue; - totalUnits += tankSegment.getTotalUnits(partialTicks); + float units = tankSegment.getTotalUnits(partialTicks); + if (units < 1) + continue; + totalUnits += units; renderedFluids++; } } if (renderedFluids == 0) return 0; - if (totalUnits == 0) + if (totalUnits < 1) return 0; - + float fluidLevel = MathHelper.clamp(totalUnits / 2000, 0, 1); float xMin = 2 / 16f; @@ -105,8 +108,11 @@ public class BasinRenderer extends SmartTileEntityRenderer { FluidStack renderedFluid = tankSegment.getRenderedFluid(); if (renderedFluid.isEmpty()) continue; - - float partial = tankSegment.getTotalUnits(partialTicks) / totalUnits; + float units = tankSegment.getTotalUnits(partialTicks); + if (units < 1) + continue; + + float partial = units / totalUnits; xMax += partial * 12 / 16f; FluidRenderer.renderTiledFluidBB(renderedFluid, xMin, yMin, zMin, xMax, yMax, zMax, buffer, ms, light, false); @@ -114,7 +120,7 @@ public class BasinRenderer extends SmartTileEntityRenderer { xMin = xMax; } } - + return fluidLevel; } diff --git a/src/main/java/com/simibubi/create/content/contraptions/processing/BasinTileEntity.java b/src/main/java/com/simibubi/create/content/contraptions/processing/BasinTileEntity.java index 6b437512f..1ee7746c8 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/processing/BasinTileEntity.java +++ b/src/main/java/com/simibubi/create/content/contraptions/processing/BasinTileEntity.java @@ -5,6 +5,9 @@ import java.util.Optional; import javax.annotation.Nonnull; +import com.simibubi.create.AllTags; +import com.simibubi.create.content.contraptions.processing.burner.BlazeBurnerBlock; +import com.simibubi.create.content.contraptions.processing.burner.BlazeBurnerBlock.HeatLevel; import com.simibubi.create.foundation.fluid.CombinedTankWrapper; import com.simibubi.create.foundation.item.SmartInventory; import com.simibubi.create.foundation.tileEntity.SmartTileEntity; @@ -13,30 +16,36 @@ import com.simibubi.create.foundation.tileEntity.behaviour.ValueBoxTransform; import com.simibubi.create.foundation.tileEntity.behaviour.belt.DirectBeltInputBehaviour; import com.simibubi.create.foundation.tileEntity.behaviour.filtering.FilteringBehaviour; import com.simibubi.create.foundation.tileEntity.behaviour.fluid.SmartFluidTankBehaviour; +import com.simibubi.create.foundation.utility.Iterate; import com.simibubi.create.foundation.utility.VecHelper; import net.minecraft.block.BlockState; +import net.minecraft.item.ItemStack; import net.minecraft.nbt.CompoundNBT; import net.minecraft.tileentity.ITickableTileEntity; import net.minecraft.tileentity.TileEntity; import net.minecraft.tileentity.TileEntityType; import net.minecraft.util.Direction; +import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.Vec3d; import net.minecraftforge.api.distmarker.Dist; import net.minecraftforge.api.distmarker.OnlyIn; import net.minecraftforge.common.capabilities.Capability; import net.minecraftforge.common.util.LazyOptional; +import net.minecraftforge.fluids.FluidStack; import net.minecraftforge.fluids.capability.CapabilityFluidHandler; import net.minecraftforge.fluids.capability.IFluidHandler; +import net.minecraftforge.fluids.capability.IFluidHandler.FluidAction; import net.minecraftforge.items.CapabilityItemHandler; +import net.minecraftforge.items.IItemHandler; import net.minecraftforge.items.IItemHandlerModifiable; +import net.minecraftforge.items.ItemHandlerHelper; import net.minecraftforge.items.wrapper.CombinedInvWrapper; public class BasinTileEntity extends SmartTileEntity implements ITickableTileEntity { - public BasinInputInventory inputInventory; + public BasinInventory inputInventory; public SmartFluidTankBehaviour inputTank; - protected SmartInventory outputInventory; protected SmartFluidTankBehaviour outputTank; @@ -48,12 +57,11 @@ public class BasinTileEntity extends SmartTileEntity implements ITickableTileEnt public BasinTileEntity(TileEntityType type) { super(type); - inputInventory = new BasinInputInventory(9, this); - inputInventory.withMaxStackSize(8) - .forbidExtraction(); - outputInventory = new SmartInventory(9, this).forbidInsertion(); - itemCapability = LazyOptional.of(() -> new CombinedInvWrapper(inputInventory, outputInventory)); + inputInventory = new BasinInventory(9, this); + inputInventory.whenContentsChanged(() -> contentsChanged = true); + outputInventory = new BasinInventory(9, this).forbidInsertion(); + itemCapability = LazyOptional.of(() -> new CombinedInvWrapper(inputInventory, outputInventory)); contentsChanged = true; } @@ -65,7 +73,8 @@ public class BasinTileEntity extends SmartTileEntity implements ITickableTileEnt .forRecipes(); behaviours.add(filtering); - inputTank = new SmartFluidTankBehaviour(SmartFluidTankBehaviour.INPUT, this, 2, 1000, true).forbidExtraction(); + inputTank = new SmartFluidTankBehaviour(SmartFluidTankBehaviour.INPUT, this, 2, 1000, true) + .whenFluidUpdates(() -> contentsChanged = true); outputTank = new SmartFluidTankBehaviour(SmartFluidTankBehaviour.OUTPUT, this, 2, 1000, true).forbidInsertion(); behaviours.add(inputTank); behaviours.add(outputTank); @@ -112,6 +121,16 @@ public class BasinTileEntity extends SmartTileEntity implements ITickableTileEnt return super.getCapability(cap, side); } + @Override + public void notifyUpdate() { + super.notifyUpdate(); + } + + @Override + public void lazyTick() { + super.lazyTick(); + } + @Override public void tick() { super.tick(); @@ -119,6 +138,17 @@ public class BasinTileEntity extends SmartTileEntity implements ITickableTileEnt return; contentsChanged = false; getOperator().ifPresent(te -> te.basinChecker.scheduleUpdate()); + + for (Direction offset : Iterate.horizontalDirections) { + BlockPos toUpdate = pos.up() + .offset(offset); + BlockState stateToUpdate = world.getBlockState(toUpdate); + if (stateToUpdate.getBlock() instanceof BasinBlock && stateToUpdate.get(BasinBlock.FACING) == offset.getOpposite()) { + TileEntity te = world.getTileEntity(toUpdate); + if (te instanceof BasinTileEntity) + ((BasinTileEntity) te).contentsChanged = true; + } + } } private Optional getOperator() { @@ -152,11 +182,64 @@ public class BasinTileEntity extends SmartTileEntity implements ITickableTileEnt return 256; } + public boolean acceptOutputs(List outputItems, List outputFluids, boolean simulate) { + outputInventory.allowInsertion(); + outputTank.allowInsertion(); + boolean acceptOutputsInner = acceptOutputsInner(outputItems, outputFluids, simulate); + outputInventory.forbidInsertion(); + outputTank.forbidInsertion(); + return acceptOutputsInner; + } + + private boolean acceptOutputsInner(List outputItems, List outputFluids, boolean simulate) { + BlockState blockState = getBlockState(); + if (!(blockState.getBlock() instanceof BasinBlock)) + return false; + Direction direction = blockState.get(BasinBlock.FACING); + + IItemHandler targetInv = null; + IFluidHandler targetTank = null; + + if (direction == Direction.DOWN) { + // No output basin, gather locally + targetInv = outputInventory; + targetTank = outputTank.getCapability() + .orElse(null); + + } else { + // Output basin, try moving items to it + TileEntity te = world.getTileEntity(pos.down() + .offset(direction)); + if (!(te instanceof BasinTileEntity)) + return false; + targetInv = te.getCapability(CapabilityItemHandler.ITEM_HANDLER_CAPABILITY) + .orElse(null); + targetTank = te.getCapability(CapabilityFluidHandler.FLUID_HANDLER_CAPABILITY) + .orElse(null); + } + + if (targetInv == null) + return false; + for (ItemStack itemStack : outputItems) + if (!ItemHandlerHelper.insertItemStacked(targetInv, itemStack.copy(), simulate) + .isEmpty()) + return false; + + if (targetTank == null) + return false; + for (FluidStack fluidStack : outputFluids) + if (targetTank.fill(fluidStack.copy(), simulate ? FluidAction.SIMULATE : FluidAction.EXECUTE) != fluidStack + .getAmount()) + return false; + + return true; + } + class BasinValueBox extends ValueBoxTransform.Sided { @Override protected Vec3d getSouthLocation() { - return VecHelper.voxelSpace(8, 12, 16); + return VecHelper.voxelSpace(8, 12, 15.75); } @Override @@ -171,4 +254,11 @@ public class BasinTileEntity extends SmartTileEntity implements ITickableTileEnt inputInventory.deserializeNBT(compound.getCompound("InputItems")); outputInventory.deserializeNBT(compound.getCompound("OutputItems")); } + + public HeatLevel getHeatLevel() { + BlockState state = world.getBlockState(pos.down(1)); + if (state.has(BlazeBurnerBlock.HEAT_LEVEL)) + return state.get(BlazeBurnerBlock.HEAT_LEVEL); + return AllTags.AllBlockTags.FAN_HEATERS.matches(state) ? HeatLevel.SMOULDERING : HeatLevel.NONE; + } } diff --git a/src/main/java/com/simibubi/create/content/contraptions/processing/EmptyingByBasin.java b/src/main/java/com/simibubi/create/content/contraptions/processing/EmptyingByBasin.java new file mode 100644 index 000000000..041647651 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/contraptions/processing/EmptyingByBasin.java @@ -0,0 +1,75 @@ +package com.simibubi.create.content.contraptions.processing; + +import java.util.List; +import java.util.Optional; + +import com.simibubi.create.AllRecipeTypes; +import com.simibubi.create.foundation.utility.Pair; + +import net.minecraft.item.ItemStack; +import net.minecraft.item.crafting.IRecipe; +import net.minecraft.world.World; +import net.minecraftforge.common.util.LazyOptional; +import net.minecraftforge.fluids.FluidStack; +import net.minecraftforge.fluids.capability.CapabilityFluidHandler; +import net.minecraftforge.fluids.capability.IFluidHandler.FluidAction; +import net.minecraftforge.fluids.capability.IFluidHandlerItem; +import net.minecraftforge.items.ItemStackHandler; +import net.minecraftforge.items.wrapper.RecipeWrapper; + +public class EmptyingByBasin { + + static RecipeWrapper wrapper = new RecipeWrapper(new ItemStackHandler(1)); + + public static boolean canItemBeEmptied(World world, ItemStack stack) { + wrapper.setInventorySlotContents(0, stack); + if (AllRecipeTypes.EMPTYING.find(wrapper, world) + .isPresent()) + return true; + + LazyOptional capability = + stack.getCapability(CapabilityFluidHandler.FLUID_HANDLER_ITEM_CAPABILITY); + IFluidHandlerItem tank = capability.orElse(null); + if (tank == null) + return false; + for (int i = 0; i < tank.getTanks(); i++) { + if (tank.getFluidInTank(i) + .getAmount() > 0) + return true; + } + return false; + } + + public static Pair emptyItem(World world, ItemStack stack, boolean simulate) { + FluidStack resultingFluid = FluidStack.EMPTY; + ItemStack resultingItem = ItemStack.EMPTY; + + wrapper.setInventorySlotContents(0, stack); + Optional> recipe = AllRecipeTypes.EMPTYING.find(wrapper, world); + if (recipe.isPresent()) { + EmptyingRecipe emptyingRecipe = (EmptyingRecipe) recipe.get(); + List results = emptyingRecipe.rollResults(); + if (!simulate) + stack.shrink(1); + resultingItem = results.isEmpty() ? ItemStack.EMPTY : results.get(0); + resultingFluid = emptyingRecipe.getResultingFluid(); + return Pair.of(resultingFluid, resultingItem); + } + + ItemStack split = stack.copy(); + split.setCount(1); + LazyOptional capability = + split.getCapability(CapabilityFluidHandler.FLUID_HANDLER_ITEM_CAPABILITY); + IFluidHandlerItem tank = capability.orElse(null); + if (tank == null) + return Pair.of(resultingFluid, resultingItem); + resultingFluid = tank.drain(1000, simulate ? FluidAction.SIMULATE : FluidAction.EXECUTE); + resultingItem = tank.getContainer() + .copy(); + if (!simulate) + stack.shrink(1); + + return Pair.of(resultingFluid, resultingItem); + } + +} diff --git a/src/main/java/com/simibubi/create/content/contraptions/processing/EmptyingRecipe.java b/src/main/java/com/simibubi/create/content/contraptions/processing/EmptyingRecipe.java new file mode 100644 index 000000000..fbed9d886 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/contraptions/processing/EmptyingRecipe.java @@ -0,0 +1,42 @@ +package com.simibubi.create.content.contraptions.processing; + +import com.simibubi.create.AllRecipeTypes; +import com.simibubi.create.content.contraptions.processing.ProcessingRecipeBuilder.ProcessingRecipeParams; + +import net.minecraft.world.World; +import net.minecraftforge.fluids.FluidStack; +import net.minecraftforge.items.wrapper.RecipeWrapper; + +public class EmptyingRecipe extends ProcessingRecipe { + + public EmptyingRecipe(ProcessingRecipeParams params) { + super(AllRecipeTypes.EMPTYING, params); + } + + @Override + public boolean matches(RecipeWrapper inv, World p_77569_2_) { + return ingredients.get(0).test(inv.getStackInSlot(0)); + } + + @Override + protected int getMaxInputCount() { + return 1; + } + + @Override + protected int getMaxOutputCount() { + return 1; + } + + @Override + protected int getMaxFluidOutputCount() { + return 1; + } + + public FluidStack getResultingFluid() { + if (fluidResults.isEmpty()) + throw new IllegalStateException("Emptying Recipe: " + id.toString() + " has no fluid output!"); + return fluidResults.get(0); + } + +} diff --git a/src/main/java/com/simibubi/create/content/logistics/InWorldProcessing.java b/src/main/java/com/simibubi/create/content/logistics/InWorldProcessing.java index ca60ccfd3..97aea25f9 100644 --- a/src/main/java/com/simibubi/create/content/logistics/InWorldProcessing.java +++ b/src/main/java/com/simibubi/create/content/logistics/InWorldProcessing.java @@ -120,8 +120,7 @@ public class InWorldProcessing { public static boolean isWashable(ItemStack stack, World world) { splashingInv.setInventorySlotContents(0, stack); - Optional recipe = world.getRecipeManager() - .getRecipe(AllRecipeTypes.SPLASHING.getType(), splashingInv, world); + Optional recipe = AllRecipeTypes.SPLASHING.find(splashingInv, world); return recipe.isPresent(); } @@ -176,8 +175,7 @@ public class InWorldProcessing { private static List process(ItemStack stack, Type type, World world) { if (type == Type.SPLASHING) { splashingInv.setInventorySlotContents(0, stack); - Optional recipe = world.getRecipeManager() - .getRecipe(AllRecipeTypes.SPLASHING.getType(), splashingInv, world); + Optional recipe = AllRecipeTypes.SPLASHING.find(splashingInv, world); if (recipe.isPresent()) return applyRecipeOn(stack, recipe.get()); return null; diff --git a/src/main/java/com/simibubi/create/content/logistics/item/filter/ItemAttribute.java b/src/main/java/com/simibubi/create/content/logistics/item/filter/ItemAttribute.java index 1be6edd4b..fe8dca539 100644 --- a/src/main/java/com/simibubi/create/content/logistics/item/filter/ItemAttribute.java +++ b/src/main/java/com/simibubi/create/content/logistics/item/filter/ItemAttribute.java @@ -127,10 +127,10 @@ public interface ItemAttribute { this.test = test; } - private static boolean testRecipe(ItemStack s, World w, IRecipeType> smelting) { + private static boolean testRecipe(ItemStack s, World w, IRecipeType> type) { RECIPE_WRAPPER.setInventorySlotContents(0, s.copy()); return w.getRecipeManager() - .getRecipe(smelting, RECIPE_WRAPPER, w) + .getRecipe(type, RECIPE_WRAPPER, w) .isPresent(); } diff --git a/src/main/java/com/simibubi/create/foundation/config/CKinetics.java b/src/main/java/com/simibubi/create/foundation/config/CKinetics.java index 3f83c62f2..31a728123 100644 --- a/src/main/java/com/simibubi/create/foundation/config/CKinetics.java +++ b/src/main/java/com/simibubi/create/foundation/config/CKinetics.java @@ -27,6 +27,8 @@ public class CKinetics extends ConfigBase { public ConfigInt maxPistonPoles = i(64, 1, "maxPistonPoles", Comments.maxPistonPoles); public ConfigInt maxRopeLength = i(128, 1, "maxRopeLength", Comments.maxRopeLength); public ConfigInt maxCartCouplingLength = i(32, 1, "maxCartCouplingLength", Comments.maxCartCouplingLength); + + public CStress stressValues = nested(0, CStress::new, Comments.stress); public ConfigGroup state = group(0, "stats", Comments.stats); public ConfigFloat mediumSpeed = f(30, 0, 4096, "mediumSpeed", Comments.rpm, Comments.mediumSpeed); @@ -37,8 +39,6 @@ public class CKinetics extends ConfigBase { public ConfigFloat mediumCapacity = f(128, 0, 4096, "mediumCapacity", Comments.su, Comments.mediumCapacity); public ConfigFloat highCapacity = f(512, 0, 65535, "highCapacity", Comments.su, Comments.highCapacity); - public CStress stressValues = nested(0, CStress::new, Comments.stress); - @Override public String getName() { return "kinetics"; diff --git a/src/main/java/com/simibubi/create/foundation/config/CRecipes.java b/src/main/java/com/simibubi/create/foundation/config/CRecipes.java new file mode 100644 index 000000000..b7eba1242 --- /dev/null +++ b/src/main/java/com/simibubi/create/foundation/config/CRecipes.java @@ -0,0 +1,26 @@ +package com.simibubi.create.foundation.config; + +public class CRecipes extends ConfigBase { + + public ConfigBool allowShapelessInMixer = b(true, "allowShapelessInMixer", Comments.allowShapelessInMixer); + public ConfigBool allowShapedSquareInPress = b(true, "allowShapedSquareInPress", Comments.allowShapedSquareInPress); + public ConfigBool allowRegularCraftingInCrafter = b(true, "allowRegularCraftingInCrafter", Comments.allowRegularCraftingInCrafter); + public ConfigBool allowStonecuttingOnSaw = b(true, "allowStonecuttingOnSaw", Comments.allowStonecuttingOnSaw); + + @Override + public String getName() { + return "recipes"; + } + + private static class Comments { + static String allowShapelessInMixer = + "When true, allows any shapeless crafting recipes to be processed by a Mechanical Mixer + Basin."; + static String allowShapedSquareInPress = + "When true, allows any single-ingredient 2x2 or 3x3 crafting recipes to be processed by a Mechanical Press + Basin."; + static String allowRegularCraftingInCrafter = + "When true, allows any standard crafting recipes to be processed by Mechanical Crafters."; + static String allowStonecuttingOnSaw = + "When true, allows any stonecutting recipes to be processed by a Mechanical Saw."; + } + +} diff --git a/src/main/java/com/simibubi/create/foundation/config/CServer.java b/src/main/java/com/simibubi/create/foundation/config/CServer.java index 5534e8df7..8ce3783bd 100644 --- a/src/main/java/com/simibubi/create/foundation/config/CServer.java +++ b/src/main/java/com/simibubi/create/foundation/config/CServer.java @@ -6,6 +6,7 @@ public class CServer extends ConfigBase { public ConfigInt tickrateSyncTimer = i(20, 5, "tickrateSyncTimer", "[in Ticks]", Comments.tickrateSyncTimer, Comments.tickrateSyncTimer2); + public CRecipes recipes = nested(0, CRecipes::new, Comments.recipes); public CKinetics kinetics = nested(0, CKinetics::new, Comments.kinetics); public CFluids fluids = nested(0, CFluids::new, Comments.fluids); public CLogistics logistics = nested(0, CLogistics::new, Comments.logistics); @@ -19,6 +20,7 @@ public class CServer extends ConfigBase { } private static class Comments { + static String recipes = "Packmakers' control panel for internal recipe compat"; static String schematics = "Everything related to Schematic tools"; static String kinetics = "Parameters and abilities of Create's kinetic mechanisms"; static String fluids = "Create's liquid manipulation tools"; diff --git a/src/main/java/com/simibubi/create/foundation/data/recipe/CompactingRecipeGen.java b/src/main/java/com/simibubi/create/foundation/data/recipe/CompactingRecipeGen.java new file mode 100644 index 000000000..97e135718 --- /dev/null +++ b/src/main/java/com/simibubi/create/foundation/data/recipe/CompactingRecipeGen.java @@ -0,0 +1,35 @@ +package com.simibubi.create.foundation.data.recipe; + +import com.simibubi.create.AllRecipeTypes; +import com.simibubi.create.content.palettes.AllPaletteBlocks; + +import net.minecraft.data.DataGenerator; +import net.minecraft.fluid.Fluids; +import net.minecraft.item.Items; +import net.minecraft.tags.FluidTags; + +public class CompactingRecipeGen extends ProcessingRecipeGen { + + GeneratedRecipe + + TEMPGABBRO = create("temp_gabbro", b -> b + .require(Items.COBBLESTONE) + .require(FluidTags.LAVA, 250) + .output(AllPaletteBlocks.GABBRO.get(), 1)), + + ICE = create("ice", b -> b + .require(Items.ICE) + .output(Fluids.WATER, 250)) + + ; + + public CompactingRecipeGen(DataGenerator p_i48262_1_) { + super(p_i48262_1_); + } + + @Override + protected AllRecipeTypes getRecipeType() { + return AllRecipeTypes.COMPACTING; + } + +} diff --git a/src/main/java/com/simibubi/create/foundation/data/recipe/EmptyingRecipeGen.java b/src/main/java/com/simibubi/create/foundation/data/recipe/EmptyingRecipeGen.java new file mode 100644 index 000000000..9106e54a8 --- /dev/null +++ b/src/main/java/com/simibubi/create/foundation/data/recipe/EmptyingRecipeGen.java @@ -0,0 +1,33 @@ +package com.simibubi.create.foundation.data.recipe; + +import com.simibubi.create.AllRecipeTypes; + +import net.minecraft.data.DataGenerator; +import net.minecraft.fluid.Fluids; +import net.minecraft.item.ItemStack; +import net.minecraft.item.Items; +import net.minecraft.potion.PotionUtils; +import net.minecraft.potion.Potions; +import net.minecraftforge.common.crafting.NBTIngredient; + +public class EmptyingRecipeGen extends ProcessingRecipeGen { + + GeneratedRecipe + + WATER_BOTTLE = create("water_bottle", b -> b + .require(NBTIngredient.fromStacks(PotionUtils.addPotionToItemStack(new ItemStack(Items.POTION), Potions.WATER))) + .output(Fluids.WATER, 250) + .output(Items.GLASS_BOTTLE)) + + ; + + public EmptyingRecipeGen(DataGenerator p_i48262_1_) { + super(p_i48262_1_); + } + + @Override + protected AllRecipeTypes getRecipeType() { + return AllRecipeTypes.EMPTYING; + } + +} diff --git a/src/main/java/com/simibubi/create/foundation/data/recipe/MixingRecipeGen.java b/src/main/java/com/simibubi/create/foundation/data/recipe/MixingRecipeGen.java index 524846b60..31369b8b9 100644 --- a/src/main/java/com/simibubi/create/foundation/data/recipe/MixingRecipeGen.java +++ b/src/main/java/com/simibubi/create/foundation/data/recipe/MixingRecipeGen.java @@ -8,6 +8,7 @@ import com.simibubi.create.content.contraptions.processing.HeatCondition; import net.minecraft.block.Blocks; import net.minecraft.data.DataGenerator; import net.minecraft.item.Items; +import net.minecraft.tags.FluidTags; import net.minecraft.tags.ItemTags; import net.minecraftforge.common.Tags; @@ -15,6 +16,11 @@ public class MixingRecipeGen extends ProcessingRecipeGen { GeneratedRecipe + TEMPCOBBLE = create("temp_cobble", b -> b + .require(FluidTags.WATER, 250) + .require(FluidTags.LAVA, 250) + .output(Blocks.COBBLESTONE, 1)), + BRASS_INGOT = create("brass_ingot", b -> b.require(I.copper()) .require(I.zinc()) .output(AllItems.BRASS_INGOT.get(), 2) diff --git a/src/main/java/com/simibubi/create/foundation/data/recipe/ProcessingRecipeGen.java b/src/main/java/com/simibubi/create/foundation/data/recipe/ProcessingRecipeGen.java index a5daca809..094d59133 100644 --- a/src/main/java/com/simibubi/create/foundation/data/recipe/ProcessingRecipeGen.java +++ b/src/main/java/com/simibubi/create/foundation/data/recipe/ProcessingRecipeGen.java @@ -32,8 +32,10 @@ public abstract class ProcessingRecipeGen extends CreateRecipeProvider { generators.add(new WashingRecipeGen(gen)); generators.add(new PolishingRecipeGen(gen)); generators.add(new MixingRecipeGen(gen)); + generators.add(new CompactingRecipeGen(gen)); generators.add(new PressingRecipeGen(gen)); generators.add(new FillingRecipeGen(gen)); + generators.add(new EmptyingRecipeGen(gen)); gen.addProvider(new IDataProvider() { diff --git a/src/main/java/com/simibubi/create/foundation/data/recipe/StandardRecipeGen.java b/src/main/java/com/simibubi/create/foundation/data/recipe/StandardRecipeGen.java index 4f8716c89..4b72a6da6 100644 --- a/src/main/java/com/simibubi/create/foundation/data/recipe/StandardRecipeGen.java +++ b/src/main/java/com/simibubi/create/foundation/data/recipe/StandardRecipeGen.java @@ -201,9 +201,9 @@ public class StandardRecipeGen extends CreateRecipeProvider { .key('A', Tags.Items.NUGGETS_IRON) .patternLine("ASA")), - ATTRIBUTE_FILTER = create(AllItems.ATTRIBUTE_FILTER).unlockedBy(I::andesite) + ATTRIBUTE_FILTER = create(AllItems.ATTRIBUTE_FILTER).unlockedByTag(I::brass) .viaShaped(b -> b.key('S', ItemTags.WOOL) - .key('A', I.copperNugget()) + .key('A', I.brassNugget()) .patternLine("ASA")), BRASS_HAND = create(AllItems.BRASS_HAND).unlockedByTag(I::brass) diff --git a/src/main/java/com/simibubi/create/foundation/fluid/CombinedTankWrapper.java b/src/main/java/com/simibubi/create/foundation/fluid/CombinedTankWrapper.java index 2a5bb5661..67fce3854 100644 --- a/src/main/java/com/simibubi/create/foundation/fluid/CombinedTankWrapper.java +++ b/src/main/java/com/simibubi/create/foundation/fluid/CombinedTankWrapper.java @@ -62,6 +62,9 @@ public class CombinedTankWrapper implements IFluidHandler { @Override public int fill(FluidStack resource, FluidAction action) { + if (resource.isEmpty()) + return 0; + int filled = 0; resource = resource.copy(); @@ -85,6 +88,9 @@ public class CombinedTankWrapper implements IFluidHandler { @Override public FluidStack drain(FluidStack resource, FluidAction action) { + if (resource.isEmpty()) + return resource; + FluidStack drained = FluidStack.EMPTY; resource = resource.copy(); diff --git a/src/main/java/com/simibubi/create/foundation/fluid/FluidHelper.java b/src/main/java/com/simibubi/create/foundation/fluid/FluidHelper.java index 774927b19..581e9c087 100644 --- a/src/main/java/com/simibubi/create/foundation/fluid/FluidHelper.java +++ b/src/main/java/com/simibubi/create/foundation/fluid/FluidHelper.java @@ -74,6 +74,9 @@ public class FluidHelper { int amount = JSONUtils.getInt(json, "amount"); FluidStack stack = new FluidStack(fluid, amount); + if (!json.has("nbt")) + return stack; + try { JsonElement element = json.get("nbt"); stack.setTag(JsonToNBT.getTagFromJson( diff --git a/src/main/java/com/simibubi/create/foundation/item/SmartInventory.java b/src/main/java/com/simibubi/create/foundation/item/SmartInventory.java index 7e5050848..19773a317 100644 --- a/src/main/java/com/simibubi/create/foundation/item/SmartInventory.java +++ b/src/main/java/com/simibubi/create/foundation/item/SmartInventory.java @@ -10,17 +10,29 @@ import net.minecraftforge.common.util.INBTSerializable; import net.minecraftforge.items.ItemStackHandler; import net.minecraftforge.items.wrapper.RecipeWrapper; -public class SmartInventory extends RecipeWrapper implements IItemHandlerModifiableIntermediate, INBTSerializable { +public class SmartInventory extends RecipeWrapper + implements IItemHandlerModifiableIntermediate, INBTSerializable { - private boolean extractionAllowed; - private boolean insertionAllowed; - private int stackSize; + protected boolean extractionAllowed; + protected boolean insertionAllowed; + protected boolean stackNonStackables; + protected int stackSize; public SmartInventory(int slots, SyncedTileEntity te) { - super(new SyncedStackHandler(slots, te)); + this(slots, te, 64, false); + } + + public SmartInventory(int slots, SyncedTileEntity te, int stackSize, boolean stackNonStackables) { + super(new SyncedStackHandler(slots, te, stackNonStackables, stackSize)); + this.stackNonStackables = stackNonStackables; insertionAllowed = true; extractionAllowed = true; - stackSize = 64; + this.stackSize = stackSize; + } + + public SmartInventory whenContentsChanged(Runnable updateCallback) { + ((SyncedStackHandler) inv).whenContentsChange(updateCallback); + return this; } public SmartInventory allowInsertion() { @@ -43,11 +55,6 @@ public class SmartInventory extends RecipeWrapper implements IItemHandlerModifia return this; } - public SmartInventory withMaxStackSize(int stackSize) { - this.stackSize = stackSize; - return this; - } - @Override public int getSlots() { return inv.getSlots(); @@ -64,6 +71,11 @@ public class SmartInventory extends RecipeWrapper implements IItemHandlerModifia public ItemStack extractItem(int slot, int amount, boolean simulate) { if (!extractionAllowed) return ItemStack.EMPTY; + if (stackNonStackables) { + ItemStack extractItem = inv.extractItem(slot, amount, true); + if (!extractItem.isEmpty() && extractItem.getMaxStackSize() < extractItem.getCount()) + amount = extractItem.getMaxStackSize(); + } return inv.extractItem(slot, amount, simulate); } @@ -86,7 +98,7 @@ public class SmartInventory extends RecipeWrapper implements IItemHandlerModifia public ItemStack getStackInSlot(int slot) { return super.getStackInSlot(slot); } - + public int getStackLimit(int slot, @Nonnull ItemStack stack) { return Math.min(getSlotLimit(slot), stack.getMaxStackSize()); } @@ -100,7 +112,7 @@ public class SmartInventory extends RecipeWrapper implements IItemHandlerModifia public void deserializeNBT(CompoundNBT nbt) { getInv().deserializeNBT(nbt); } - + private SyncedStackHandler getInv() { return (SyncedStackHandler) inv; } @@ -108,18 +120,34 @@ public class SmartInventory extends RecipeWrapper implements IItemHandlerModifia private static class SyncedStackHandler extends ItemStackHandler { private SyncedTileEntity te; + private boolean stackNonStackables; + private int stackSize; + private Runnable updateCallback; - public SyncedStackHandler(int slots, SyncedTileEntity te) { + public SyncedStackHandler(int slots, SyncedTileEntity te, boolean stackNonStackables, int stackSize) { super(slots); this.te = te; + this.stackNonStackables = stackNonStackables; + this.stackSize = stackSize; } @Override protected void onContentsChanged(int slot) { super.onContentsChanged(slot); + if (updateCallback != null) + updateCallback.run(); te.notifyUpdate(); } + @Override + public int getSlotLimit(int slot) { + return Math.min(stackNonStackables ? 64 : super.getSlotLimit(slot), stackSize); + } + + public void whenContentsChange(Runnable updateCallback) { + this.updateCallback = updateCallback; + } + } @Override diff --git a/src/main/java/com/simibubi/create/foundation/networking/AllPackets.java b/src/main/java/com/simibubi/create/foundation/networking/AllPackets.java index ed8de400c..b1e6a8a25 100644 --- a/src/main/java/com/simibubi/create/foundation/networking/AllPackets.java +++ b/src/main/java/com/simibubi/create/foundation/networking/AllPackets.java @@ -10,6 +10,7 @@ import com.simibubi.create.content.contraptions.components.structureMovement.glu import com.simibubi.create.content.contraptions.components.structureMovement.sync.ClientMotionPacket; import com.simibubi.create.content.contraptions.components.structureMovement.sync.ContraptionInteractionPacket; import com.simibubi.create.content.contraptions.components.structureMovement.sync.ContraptionSeatMappingPacket; +import com.simibubi.create.content.contraptions.components.structureMovement.sync.LimbSwingUpdatePacket; import com.simibubi.create.content.contraptions.components.structureMovement.train.MinecartCouplingCreationPacket; import com.simibubi.create.content.contraptions.components.structureMovement.train.MinecartCouplingSyncPacket; import com.simibubi.create.content.contraptions.components.structureMovement.train.PersistantDataPacket; @@ -68,6 +69,7 @@ public enum AllPackets { MINECART_COUPLING_SYNC(MinecartCouplingSyncPacket.class, MinecartCouplingSyncPacket::new), CONTRAPTION_SEAT_MAPPING(ContraptionSeatMappingPacket.class, ContraptionSeatMappingPacket::new), PERSISTANT_DATA(PersistantDataPacket.class, PersistantDataPacket::new), + LIMBSWING_UPDATE(LimbSwingUpdatePacket.class, LimbSwingUpdatePacket::new), ; diff --git a/src/main/java/com/simibubi/create/foundation/tileEntity/behaviour/fluid/SmartFluidTankBehaviour.java b/src/main/java/com/simibubi/create/foundation/tileEntity/behaviour/fluid/SmartFluidTankBehaviour.java index 810f84b60..445ab0a91 100644 --- a/src/main/java/com/simibubi/create/foundation/tileEntity/behaviour/fluid/SmartFluidTankBehaviour.java +++ b/src/main/java/com/simibubi/create/foundation/tileEntity/behaviour/fluid/SmartFluidTankBehaviour.java @@ -34,6 +34,7 @@ public class SmartFluidTankBehaviour extends TileEntityBehaviour { protected LazyOptional capability; protected boolean extractionAllowed; protected boolean insertionAllowed; + protected Runnable fluidUpdateCallback; private BehaviourType behaviourType; @@ -55,6 +56,13 @@ public class SmartFluidTankBehaviour extends TileEntityBehaviour { handlers[i] = tankSegment.tank; } capability = LazyOptional.of(() -> new InternalFluidHandler(handlers, enforceVariety)); + fluidUpdateCallback = () -> { + }; + } + + public SmartFluidTankBehaviour whenFluidUpdates(Runnable fluidUpdateCallback) { + this.fluidUpdateCallback = fluidUpdateCallback; + return this; } public SmartFluidTankBehaviour allowInsertion() { @@ -76,7 +84,7 @@ public class SmartFluidTankBehaviour extends TileEntityBehaviour { extractionAllowed = false; return this; } - + @Override public void initialize() { super.initialize(); @@ -84,7 +92,7 @@ public class SmartFluidTankBehaviour extends TileEntityBehaviour { return; foreach(ts -> { ts.fluidLevel.forceNextSync(); - ts.onFluidStackChanged(ts.tank.getFluid()); + ts.onFluidStackChanged(); }); } @@ -94,8 +102,8 @@ public class SmartFluidTankBehaviour extends TileEntityBehaviour { if (syncCooldown > 0) { syncCooldown--; - if (syncCooldown == 0 && queuedSync) - tileEntity.sendData(); + if (syncCooldown == 0 && queuedSync) + updateFluids(); } foreach(te -> { @@ -108,7 +116,7 @@ public class SmartFluidTankBehaviour extends TileEntityBehaviour { public void sendDataImmediately() { syncCooldown = 0; queuedSync = false; - tileEntity.sendData(); + updateFluids(); } public void sendDataLazily() { @@ -116,11 +124,16 @@ public class SmartFluidTankBehaviour extends TileEntityBehaviour { queuedSync = true; return; } - tileEntity.sendData(); + updateFluids(); queuedSync = false; syncCooldown = SYNC_RATE; } + protected void updateFluids() { + fluidUpdateCallback.run(); + tileEntity.sendData(); + } + @Override public void remove() { super.remove(); @@ -174,36 +187,36 @@ public class SmartFluidTankBehaviour extends TileEntityBehaviour { index.increment(); }); } - + class InternalFluidHandler extends CombinedTankWrapper { - + public InternalFluidHandler(IFluidHandler[] handlers, boolean enforceVariety) { super(handlers); if (enforceVariety) enforceVariety(); } - + @Override public int fill(FluidStack resource, FluidAction action) { if (!insertionAllowed) return 0; return super.fill(resource, action); } - + @Override public FluidStack drain(FluidStack resource, FluidAction action) { if (!extractionAllowed) return FluidStack.EMPTY; return super.drain(resource, action); } - + @Override public FluidStack drain(int maxDrain, FluidAction action) { if (!extractionAllowed) return FluidStack.EMPTY; return super.drain(maxDrain, action); } - + } public class TankSegment { @@ -213,14 +226,14 @@ public class SmartFluidTankBehaviour extends TileEntityBehaviour { protected FluidStack renderedFluid; public TankSegment(int capacity) { - tank = new SmartFluidTank(1000, f -> onFluidStackChanged(f)); + tank = new SmartFluidTank(1000, f -> onFluidStackChanged()); fluidLevel = LerpedFloat.linear() .startWithValue(0) .chase(0, .25, Chaser.EXP); renderedFluid = FluidStack.EMPTY; } - protected void onFluidStackChanged(FluidStack newFluidStack) { + public void onFluidStackChanged() { if (!tileEntity.hasWorld()) return; fluidLevel.chase(tank.getFluidAmount() / (float) tank.getCapacity(), .25, Chaser.EXP); @@ -235,7 +248,7 @@ public class SmartFluidTankBehaviour extends TileEntityBehaviour { public LerpedFloat getFluidLevel() { return fluidLevel; } - + public float getTotalUnits(float partialTicks) { return fluidLevel.getValue(partialTicks) * tank.getCapacity(); } diff --git a/src/main/resources/assets/create/models/block/basin/basin_canal.bbmodel b/src/main/resources/assets/create/models/block/basin/basin_canal.bbmodel new file mode 100644 index 000000000..63122598a --- /dev/null +++ b/src/main/resources/assets/create/models/block/basin/basin_canal.bbmodel @@ -0,0 +1 @@ +{"meta":{"format_version":"3.2","model_format":"java_block","box_uv":false},"name":"basin","parent":"block/block","ambientocclusion":true,"front_gui_light":false,"resolution":{"width":16,"height":16},"elements":[{"name":"Side1","from":[0,2,0],"to":[2,16,16],"autouv":0,"color":2,"locked":false,"origin":[8,24,8],"faces":{"north":{"uv":[14,0,16,14],"texture":0},"east":{"uv":[0,0,16,14],"texture":0},"south":{"uv":[0,0,2,14],"texture":0},"west":{"uv":[0,0,16,14],"texture":0},"up":{"uv":[0,0,2,16],"texture":1},"down":{"uv":[0,0,2,16],"texture":1}},"uuid":"e372420e-1abe-a2b9-ae96-df6b128888ad"},{"name":"BasinBottom","from":[2,0,2],"to":[14,2,14],"autouv":0,"color":0,"locked":false,"origin":[8,25,8],"faces":{"north":{"uv":[2,14,14,16],"texture":0},"east":{"uv":[2,14,14,16],"texture":0},"south":{"uv":[2,14,14,16],"texture":0},"west":{"uv":[2,14,14,16],"texture":0},"up":{"uv":[2,2,14,14],"texture":1},"down":{"uv":[2,2,14,14],"texture":1}},"uuid":"e82556b1-3f66-7c35-71b2-f33c0c4c1385"},{"name":"Side4","from":[2,2,0],"to":[14,16,2],"autouv":0,"color":1,"locked":false,"origin":[8,24,8],"faces":{"north":{"uv":[2,0,14,14],"texture":0},"east":{"uv":[0,0,0,0],"texture":null},"south":{"uv":[2,0,14,14],"texture":0},"west":{"uv":[0,0,0,0],"texture":null},"up":{"uv":[2,0,14,2],"texture":1},"down":{"uv":[2,14,14,16],"texture":1}},"uuid":"2e5cfd25-7f80-2f04-e080-b005bc67fecb"},{"name":"Side2","from":[2,2,14],"to":[14,16,16],"autouv":0,"color":4,"locked":false,"origin":[8,24,8],"faces":{"north":{"uv":[2,0,14,14],"texture":0},"east":{"uv":[0,0,0,0],"texture":null},"south":{"uv":[2,0,14,14],"texture":0},"west":{"uv":[0,0,0,0],"texture":null},"up":{"uv":[2,14,14,16],"texture":1},"down":{"uv":[2,0,14,2],"texture":1}},"uuid":"e007a6de-4ee0-52db-0763-61d4c3ab8a3f"},{"name":"Side3","from":[14,2,0],"to":[16,16,16],"autouv":0,"color":5,"locked":false,"origin":[8,40,8],"faces":{"north":{"uv":[0,0,2,14],"texture":0},"east":{"uv":[0,0,16,14],"texture":0},"south":{"uv":[14,0,16,14],"texture":0},"west":{"uv":[0,0,16,14],"texture":0},"up":{"uv":[14,0,16,16],"texture":1},"down":{"uv":[14,0,16,16],"texture":1}},"uuid":"c5b067a4-6114-bb79-a5bf-1321988a497c"},{"name":"Side2","from":[0,-14,-16],"to":[2,0,0],"autouv":0,"color":2,"locked":false,"origin":[8,8,-8],"faces":{"north":{"uv":[14,0,16,14],"texture":0},"east":{"uv":[0,0,16,14],"texture":0},"south":{"uv":[0,0,2,14],"texture":0},"west":{"uv":[0,0,16,14],"texture":0},"up":{"uv":[0,0,2,16],"texture":1},"down":{"uv":[0,0,2,16],"texture":1}},"uuid":"b641f651-2872-3ebc-e9e3-2dfbbb10e8e4"},{"name":"BasinBottom","from":[2,-16,-14],"to":[14,-14,-2],"autouv":0,"color":0,"locked":false,"origin":[8,9,-8],"faces":{"north":{"uv":[2,14,14,16],"texture":0},"east":{"uv":[2,14,14,16],"texture":0},"south":{"uv":[2,14,14,16],"texture":0},"west":{"uv":[2,14,14,16],"texture":0},"up":{"uv":[2,2,14,14],"texture":1},"down":{"uv":[2,2,14,14],"texture":1}},"uuid":"07500784-c31b-dc51-7e03-f0ec55ee6028"},{"name":"Side5","from":[2,-14,-16],"to":[14,0,-14],"autouv":0,"color":1,"locked":false,"origin":[8,8,-8],"faces":{"north":{"uv":[2,0,14,14],"texture":0},"east":{"uv":[0,0,0,0],"texture":null},"south":{"uv":[2,0,14,14],"texture":0},"west":{"uv":[0,0,0,0],"texture":null},"up":{"uv":[2,0,14,2],"texture":1},"down":{"uv":[2,14,14,16],"texture":1}},"uuid":"dd76fad0-e0ed-1147-e7bd-3870f72987da"},{"name":"Side3","from":[2,-14,-2],"to":[14,0,0],"autouv":0,"color":4,"locked":false,"origin":[8,8,-8],"faces":{"north":{"uv":[2,0,14,14],"texture":0},"east":{"uv":[0,0,0,0],"texture":null},"south":{"uv":[2,0,14,14],"texture":0},"west":{"uv":[0,0,0,0],"texture":null},"up":{"uv":[2,14,14,16],"texture":1},"down":{"uv":[2,0,14,2],"texture":1}},"uuid":"32636eab-627e-34f5-7be6-2a31400bd957"},{"name":"Side4","from":[14,-14,-16],"to":[16,0,0],"autouv":0,"color":5,"locked":false,"origin":[8,24,-8],"faces":{"north":{"uv":[0,0,2,14],"texture":0},"east":{"uv":[0,0,16,14],"texture":0},"south":{"uv":[14,0,16,14],"texture":0},"west":{"uv":[0,0,16,14],"texture":0},"up":{"uv":[14,0,16,16],"texture":1},"down":{"uv":[14,0,16,16],"texture":1}},"uuid":"06344246-e61c-e8fd-c700-dae02563797e"},{"name":"cube","from":[3,0,0],"to":[4,2,2],"autouv":0,"color":6,"locked":false,"origin":[11,8,8],"faces":{"north":{"uv":[0,0,10,2],"texture":2},"east":{"uv":[14,10,16,12],"texture":2},"south":{"uv":[14,10,16,11],"rotation":90,"texture":2},"west":{"uv":[14,10,16,12],"rotation":90,"texture":2},"up":{"uv":[14,10,15,12],"rotation":180,"texture":2},"down":{"uv":[15,10,16,12],"texture":2}},"uuid":"41346be7-9b03-225c-14be-3be6e1719311"},{"name":"cube","from":[3,0,-1],"to":[4,10,0],"autouv":0,"color":6,"locked":false,"origin":[11,8,7],"faces":{"north":{"uv":[6,12,16,13],"rotation":90,"texture":2},"east":{"uv":[6,12,16,13],"rotation":90,"texture":2},"south":{"uv":[6,12,16,13],"rotation":90,"texture":2},"west":{"uv":[6,12,16,13],"rotation":90,"texture":2},"up":{"uv":[6,12,7,13],"texture":2},"down":{"uv":[15,12,16,13],"texture":2}},"uuid":"fa4b61d1-8e47-aa7d-207c-025608871716"},{"name":"cube","from":[5,1,-6],"to":[11,2,3],"autouv":0,"color":4,"locked":false,"rotation":[-22.5,0,0],"origin":[8,9,-1],"faces":{"north":{"uv":[9,7,15,8],"texture":2},"east":{"uv":[0,0,9,1],"texture":2},"south":{"uv":[9,7,15,8],"texture":2},"west":{"uv":[0,0,9,1],"texture":2},"up":{"uv":[1,0,7,9],"texture":2},"down":{"uv":[1,0,7,9],"rotation":180,"texture":2}},"uuid":"c4b10bec-d6bb-cac8-b369-d588c98601ce"},{"name":"cube","from":[4,1,-6],"to":[5,9,3],"autouv":0,"color":4,"locked":false,"rotation":[-22.5,0,0],"origin":[8,9,-1],"faces":{"north":{"uv":[15,0,16,8],"texture":2},"east":{"uv":[0,0,8,9],"rotation":90,"texture":2},"south":{"uv":[8,0,9,8],"texture":2},"west":{"uv":[0,0,8,9],"rotation":90,"texture":2},"up":{"uv":[0,0,1,9],"rotation":180,"texture":2},"down":{"uv":[0,0,1,9],"texture":2}},"uuid":"655e4f5c-68aa-c6ca-ea54-6ee2f1eb0cbf"},{"name":"cube","from":[11,1,-6],"to":[12,9,3],"autouv":0,"color":4,"locked":false,"rotation":[-22.5,0,0],"origin":[15,9,-1],"faces":{"north":{"uv":[8,0,9,8],"texture":2},"east":{"uv":[0,0,8,9],"rotation":270,"texture":2},"south":{"uv":[15,0,16,8],"texture":2},"west":{"uv":[0,0,8,9],"rotation":90,"texture":2},"up":{"uv":[0,0,1,9],"rotation":180,"texture":2},"down":{"uv":[0,0,1,9],"texture":2}},"uuid":"cf5d8d2d-6849-5958-087c-a48f1ab945e5"},{"name":"cube","from":[5,8,-6],"to":[11,9,3],"autouv":0,"color":4,"locked":false,"rotation":[-22.5,0,0],"origin":[8,9,-1],"faces":{"north":{"uv":[9,0,15,1],"texture":2},"east":{"uv":[0,0,9,1],"texture":2},"south":{"uv":[9,0,15,1],"texture":2},"west":{"uv":[0,0,9,1],"texture":2},"up":{"uv":[1,0,7,9],"rotation":180,"texture":2},"down":{"uv":[1,0,7,9],"texture":2}},"uuid":"1655c96c-ae98-f14d-527c-6052c1fab719"},{"name":"cube","from":[5,2,-4],"to":[11,8,2],"autouv":0,"color":4,"locked":false,"rotation":[-22.5,0,0],"origin":[8,9,-1],"faces":{"north":{"uv":[9,1,15,7],"texture":2},"east":{"uv":[0,0,0,0],"texture":null},"south":{"uv":[9,1,15,7],"texture":2},"west":{"uv":[0,0,0,0],"texture":null},"up":{"uv":[0,0,0,0],"texture":null},"down":{"uv":[0,0,0,0],"texture":null}},"uuid":"a2eb892a-15a7-46c2-d526-c062c9c151ba"},{"name":"cube","from":[12,0,-1],"to":[13,10,0],"autouv":0,"color":6,"locked":false,"origin":[20,8,7],"faces":{"north":{"uv":[6,12,16,13],"rotation":90,"texture":2},"east":{"uv":[6,12,16,13],"rotation":90,"texture":2},"south":{"uv":[6,12,16,13],"rotation":90,"texture":2},"west":{"uv":[6,12,16,13],"rotation":90,"texture":2},"up":{"uv":[6,12,7,13],"texture":2},"down":{"uv":[15,12,16,13],"texture":2}},"uuid":"baaf226d-53b0-814c-ca53-75621435fc45"},{"name":"cube","from":[4,9,-1],"to":[12,10,0],"autouv":0,"color":6,"locked":false,"origin":[12,8,7],"faces":{"north":{"uv":[8,9,16,10],"texture":2},"east":{"uv":[0,0,0,0],"rotation":90,"texture":null},"south":{"uv":[8,9,16,10],"texture":2},"west":{"uv":[0,0,0,0],"rotation":90,"texture":null},"up":{"uv":[8,9,16,10],"texture":2},"down":{"uv":[0,0,0,0],"texture":null}},"uuid":"7aebcd85-9ae9-b4b0-9af3-a8a96d6e3709"},{"name":"cube","from":[12,0,0],"to":[13,2,2],"autouv":0,"color":6,"locked":false,"origin":[20,8,8],"faces":{"north":{"uv":[0,0,10,2],"texture":2},"east":{"uv":[14,10,16,12],"texture":2},"south":{"uv":[14,10,16,11],"rotation":90,"texture":2},"west":{"uv":[14,10,16,12],"rotation":90,"texture":2},"up":{"uv":[14,10,15,12],"rotation":180,"texture":2},"down":{"uv":[15,10,16,12],"texture":2}},"uuid":"25e35b80-a713-fd17-aac6-033104233acd"},{"name":"cube","from":[4,0,-1],"to":[12,1,2],"autouv":0,"color":6,"locked":false,"origin":[12,8,7],"faces":{"north":{"uv":[7,15,15,16],"texture":2},"east":{"uv":[14,10,16,12],"texture":2},"south":{"uv":[8,14,9,15],"rotation":90,"texture":2},"west":{"uv":[14,10,16,12],"rotation":90,"texture":2},"up":{"uv":[11,10,12,11],"rotation":180,"texture":2},"down":{"uv":[7,13,15,16],"texture":2}},"uuid":"18b2aeec-e7d6-9262-7e3d-995f9d7320ac"}],"outliner":[{"name":"Basins","uuid":"4822b3b4-2c19-aadd-c096-85534b94f809","export":true,"isOpen":false,"locked":false,"visibility":true,"autouv":0,"origin":[8,8,8],"children":[{"name":"Basin top","uuid":"ef36da1c-a925-5b8d-5f56-b9b2136ca98f","export":true,"isOpen":false,"locked":false,"visibility":true,"autouv":0,"origin":[8,8,8],"children":["e372420e-1abe-a2b9-ae96-df6b128888ad","e82556b1-3f66-7c35-71b2-f33c0c4c1385","2e5cfd25-7f80-2f04-e080-b005bc67fecb","e007a6de-4ee0-52db-0763-61d4c3ab8a3f","c5b067a4-6114-bb79-a5bf-1321988a497c"]},{"name":"Basin bottom","uuid":"52077833-3587-b2ad-4a2a-8a61173f4d54","export":true,"isOpen":false,"locked":false,"visibility":true,"autouv":0,"origin":[8,8,8],"children":["b641f651-2872-3ebc-e9e3-2dfbbb10e8e4","07500784-c31b-dc51-7e03-f0ec55ee6028","dd76fad0-e0ed-1147-e7bd-3870f72987da","32636eab-627e-34f5-7be6-2a31400bd957","06344246-e61c-e8fd-c700-dae02563797e"]}]},{"name":"Canal","uuid":"c916ca14-dcb2-5442-2b8a-1fa3ea05e167","export":true,"isOpen":false,"locked":false,"visibility":true,"autouv":0,"origin":[8,8,8],"children":[{"name":"Frame","uuid":"1dfe7732-4e1a-7674-3237-0ecf68c5c60e","export":true,"isOpen":true,"locked":false,"visibility":true,"autouv":0,"origin":[8,8,8],"children":["41346be7-9b03-225c-14be-3be6e1719311","25e35b80-a713-fd17-aac6-033104233acd","18b2aeec-e7d6-9262-7e3d-995f9d7320ac","fa4b61d1-8e47-aa7d-207c-025608871716","7aebcd85-9ae9-b4b0-9af3-a8a96d6e3709","baaf226d-53b0-814c-ca53-75621435fc45"]},"c4b10bec-d6bb-cac8-b369-d588c98601ce","1655c96c-ae98-f14d-527c-6052c1fab719","a2eb892a-15a7-46c2-d526-c062c9c151ba","cf5d8d2d-6849-5958-087c-a48f1ab945e5","655e4f5c-68aa-c6ca-ea54-6ee2f1eb0cbf"]}],"textures":[{"path":"C:\\Users\\krypp\\Desktop\\create 1.15.2\\assets\\create\\textures\\block\\basin_side.png","name":"basin_side.png","folder":"block","namespace":"create","id":"1","particle":false,"mode":"bitmap","saved":true,"uuid":"a20a92f6-149c-8147-a096-ebf6df449714","source":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAB4UlEQVQ4T2VTy27bMBAcAhVF2bAlpacATr/BQFs7pzy+I0Bv6cXH9Fd8aT4p7U8UObVoTMe1JUoHFrMUJSchIOxyuTuaHXLV19tbn2gNrswYsVzjNO19OnvnZF/VdR9vmwbq5uaLH49SEISBaJkVgRnfHxyYRys/6Hx1cXHlnatRFCWqqpJD7tPUIMsyiXHPFXMYt3YjOWq5PPfGZAA88ryA66hOJtMXLXDTNK4/j8BqPp97rQ3KskQqfSsMxR5N00BrxoPPtd1a1J0WarE490VRyIExRpIJlCQJ2rZFkmi0bdPb3W4nuQSo6wrq8vLas4BtaK07FsBoNMbhcBCgJHknPtkNbXhYawlw5SkGPzKIYvHvchMdE+5ZHER2AwOKmOel9DidFkjT8CZIfWgj6Ri81UEYeB/650cBh76DDjxXircQRIwMnKugFoulL8sTOWAbQXH6ursBMtHY7/+JRhRRxFMKm80T1Le7O//w42cnYigOtxEAuEiRf2VRLKb9/Okj1Gq18tbu8Pj4S0C4yIKCRfs69vxsMZt9QFFMoOIwxTngQHFgjgeLADFGezwzKr5XAv192vZaHL/jOAvUiP77kxzf7++ltgdgK0T+/WfTD08siAKz+Gx2KlO6Xq+l9j+hVCuQux00ywAAAABJRU5ErkJggg=="},{"path":"C:\\Users\\krypp\\Desktop\\create 1.15.2\\assets\\create\\textures\\block\\basin.png","name":"basin.png","folder":"block","namespace":"create","id":"12","particle":true,"mode":"bitmap","saved":true,"uuid":"e8bd46f1-4674-7125-0c6a-15be8f476bed","source":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAABmElEQVQ4T41TyU7DMBB9dpykS8oFKIhFwMfBpcdy4sJXcuHAIhaxHgJp3cR2jGaiJG0poiNFHsfxy7w388TZ6akPowgU3U6HV4p+HDd5nUzyvHmnZzOYooAYjUb+8fGFD8Iw5LXXbYFoP9Wz5qIxpskPDnZbgKJo0ZUKIQUAIaCURFkCZenhnIVzrqqwn2BnZxPifDz2d/dPmEwydLsdKBUgzw1fEEIgigI452Gt4XOtC863t7Yw2OgvAhAFIYA4jvhDKQW89/AenNPfCdRayxUcH+1XAG9vn0jTFKUvIYSsLvxBgconIKpgONyEuLy48LcPz0i/vhAEci0KQRBgY5AsAaQpfKXbvxSiUDGFk8O9toKpniDPC1DlURyy8iSoMQ4lbUBCWhayanV/ESDLMuiZhpSSdaDH2gJKKb5YB7W46sJ2S+Hq+obVdc6srQEBL3Th/eODJ3EdDX61sR4k4vyfBr1egiz7bieRvPD6+smTSJEkA2g9XaEBQbfRjHJtptpItZnIQPOmWmUoNtO8nZctvWzrVXb+ARkgOfimiFHjAAAAAElFTkSuQmCC"},{"path":"C:\\Users\\krypp\\Documents\\Pixel Art\\Create Mod\\basin\\Basin Canal\\Basin Canal.png","name":"Basin Canal.png","folder":"Basin Canal","namespace":"","id":"2","particle":false,"mode":"bitmap","saved":true,"uuid":"4459ee5f-e243-a1a9-b39e-fd8adcac4b69","source":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAABc0lEQVQ4T4VTTU/CQBB9TWi3WiGIMdGYcFD4J0iFhMQDB5Mm3PDSYzlx8Q/I3+FifwrxB5B4kNja3ZKsmdElwdBlLrMfndf33sw6syTR30WBUim4ngcKsz7xfd7b7p1+/0EL4cP3fXieB6UUFxVFASkLdLt3SNN0d86XAH/b6/XgjEaPmoqD4AxlqeC6HmcCIpDrq0u8pSmklKaWsxAC9wQQRRNNB1Toui7KsuSc5zkAjWazjuVyeRBgOBzCCcOB9jzBiOYvZq2URKdzawcYj5+YgRDE4Jc+5Sz7YqrnzbpdAnnQaDRYszHRZPKg3b6xmxjHsV6t3kEyyEwqojD0qZXWNh6bg9fFYs/9/xuHrbbELEmYgRkw7tjfwBG7owBhOGB5RhatSR5l8u4oQBzHB8d8vf7gDlUCvMznyKTcM5DeSJZLBKcCqtQIAlENEEUTq3nmspIBAWw2n9hut6yXdNdqtR0onbdaF9UMnqdTpmsLkvIDiqLjULkp6X8AAAAASUVORK5CYII="}]} \ No newline at end of file diff --git a/src/main/resources/assets/create/models/block/basin.json b/src/main/resources/assets/create/models/block/basin/block.json similarity index 100% rename from src/main/resources/assets/create/models/block/basin.json rename to src/main/resources/assets/create/models/block/basin/block.json diff --git a/src/main/resources/assets/create/models/block/basin/block_directional.json b/src/main/resources/assets/create/models/block/basin/block_directional.json new file mode 100644 index 000000000..6a6e9a8ba --- /dev/null +++ b/src/main/resources/assets/create/models/block/basin/block_directional.json @@ -0,0 +1,237 @@ +{ + "credit": "Made with Blockbench", + "parent": "block/block", + "textures": { + "1": "create:block/basin_side", + "2": "create:block/basin_canal", + "12": "create:block/basin", + "particle": "create:block/basin" + }, + "elements": [ + { + "name": "Side1", + "from": [14, 2, 0], + "to": [16, 16, 16], + "rotation": {"angle": 0, "axis": "y", "origin": [8, 24, 8]}, + "faces": { + "north": {"uv": [0, 0, 2, 14], "texture": "#1"}, + "east": {"uv": [0, 0, 16, 14], "texture": "#1"}, + "south": {"uv": [14, 0, 16, 14], "texture": "#1"}, + "west": {"uv": [0, 0, 16, 14], "texture": "#1"}, + "up": {"uv": [0, 0, 2, 16], "rotation": 180, "texture": "#12"}, + "down": {"uv": [0, 0, 2, 16], "rotation": 180, "texture": "#12"} + } + }, + { + "name": "BasinBottom", + "from": [2, 0, 2], + "to": [14, 2, 14], + "rotation": {"angle": 0, "axis": "y", "origin": [8, 25, 8]}, + "faces": { + "north": {"uv": [2, 14, 14, 16], "texture": "#1"}, + "east": {"uv": [2, 14, 14, 16], "texture": "#1"}, + "south": {"uv": [2, 14, 14, 16], "texture": "#1"}, + "west": {"uv": [2, 14, 14, 16], "texture": "#1"}, + "up": {"uv": [2, 2, 14, 14], "rotation": 180, "texture": "#12"}, + "down": {"uv": [2, 2, 14, 14], "rotation": 180, "texture": "#12"} + } + }, + { + "name": "Side4", + "from": [2, 2, 14], + "to": [14, 16, 16], + "rotation": {"angle": 0, "axis": "y", "origin": [8, 24, 8]}, + "faces": { + "north": {"uv": [2, 0, 14, 14], "texture": "#1"}, + "south": {"uv": [2, 0, 14, 14], "texture": "#1"}, + "up": {"uv": [2, 0, 14, 2], "rotation": 180, "texture": "#12"}, + "down": {"uv": [2, 14, 14, 16], "rotation": 180, "texture": "#12"} + } + }, + { + "name": "Side2", + "from": [2, 2, 0], + "to": [14, 16, 2], + "rotation": {"angle": 0, "axis": "y", "origin": [8, 24, 8]}, + "faces": { + "north": {"uv": [2, 0, 14, 14], "texture": "#1"}, + "south": {"uv": [2, 0, 14, 14], "texture": "#1"}, + "up": {"uv": [2, 14, 14, 16], "rotation": 180, "texture": "#12"}, + "down": {"uv": [2, 0, 14, 2], "rotation": 180, "texture": "#12"} + } + }, + { + "name": "Side3", + "from": [0, 2, 0], + "to": [2, 16, 16], + "rotation": {"angle": 0, "axis": "y", "origin": [8, 40, 8]}, + "faces": { + "north": {"uv": [14, 0, 16, 14], "texture": "#1"}, + "east": {"uv": [0, 0, 16, 14], "texture": "#1"}, + "south": {"uv": [0, 0, 2, 14], "texture": "#1"}, + "west": {"uv": [0, 0, 16, 14], "texture": "#1"}, + "up": {"uv": [14, 0, 16, 16], "rotation": 180, "texture": "#12"}, + "down": {"uv": [14, 0, 16, 16], "rotation": 180, "texture": "#12"} + } + }, + { + "from": [12, 0, 14], + "to": [13, 2, 16], + "rotation": {"angle": 0, "axis": "y", "origin": [5, 8, 8]}, + "faces": { + "north": {"uv": [14, 10, 16, 11], "rotation": 90, "texture": "#2"}, + "east": {"uv": [14, 10, 16, 12], "rotation": 90, "texture": "#2"}, + "south": {"uv": [0, 0, 10, 2], "texture": "#2"}, + "west": {"uv": [14, 10, 16, 12], "texture": "#2"}, + "up": {"uv": [14, 10, 15, 12], "texture": "#2"}, + "down": {"uv": [15, 10, 16, 12], "rotation": 180, "texture": "#2"} + } + }, + { + "from": [3, 0, 14], + "to": [4, 2, 16], + "rotation": {"angle": 0, "axis": "y", "origin": [-4, 8, 8]}, + "faces": { + "north": {"uv": [14, 10, 16, 11], "rotation": 90, "texture": "#2"}, + "east": {"uv": [14, 10, 16, 12], "rotation": 90, "texture": "#2"}, + "south": {"uv": [0, 0, 10, 2], "texture": "#2"}, + "west": {"uv": [14, 10, 16, 12], "texture": "#2"}, + "up": {"uv": [14, 10, 15, 12], "texture": "#2"}, + "down": {"uv": [15, 10, 16, 12], "rotation": 180, "texture": "#2"} + } + }, + { + "from": [4, 0, 14], + "to": [12, 1, 17], + "rotation": {"angle": 0, "axis": "y", "origin": [4, 8, 9]}, + "faces": { + "north": {"uv": [8, 14, 9, 15], "rotation": 90, "texture": "#2"}, + "east": {"uv": [14, 10, 16, 12], "rotation": 90, "texture": "#2"}, + "south": {"uv": [7, 15, 15, 16], "texture": "#2"}, + "west": {"uv": [14, 10, 16, 12], "texture": "#2"}, + "up": {"uv": [11, 10, 12, 11], "texture": "#2"}, + "down": {"uv": [7, 13, 15, 16], "rotation": 180, "texture": "#2"} + } + }, + { + "from": [12, 0, 16], + "to": [13, 10, 17], + "rotation": {"angle": 0, "axis": "y", "origin": [5, 8, 9]}, + "faces": { + "north": {"uv": [6, 12, 16, 13], "rotation": 90, "texture": "#2"}, + "east": {"uv": [6, 12, 16, 13], "rotation": 90, "texture": "#2"}, + "south": {"uv": [6, 12, 16, 13], "rotation": 90, "texture": "#2"}, + "west": {"uv": [6, 12, 16, 13], "rotation": 90, "texture": "#2"}, + "up": {"uv": [6, 12, 7, 13], "rotation": 180, "texture": "#2"}, + "down": {"uv": [15, 12, 16, 13], "rotation": 180, "texture": "#2"} + } + }, + { + "from": [4, 9, 16], + "to": [12, 10, 17], + "rotation": {"angle": 0, "axis": "y", "origin": [4, 8, 9]}, + "faces": { + "north": {"uv": [8, 9, 16, 10], "texture": "#2"}, + "south": {"uv": [8, 9, 16, 10], "texture": "#2"}, + "up": {"uv": [8, 9, 16, 10], "rotation": 180, "texture": "#2"} + } + }, + { + "from": [3, 0, 16], + "to": [4, 10, 17], + "rotation": {"angle": 0, "axis": "y", "origin": [-4, 8, 9]}, + "faces": { + "north": {"uv": [6, 12, 16, 13], "rotation": 90, "texture": "#2"}, + "east": {"uv": [6, 12, 16, 13], "rotation": 90, "texture": "#2"}, + "south": {"uv": [6, 12, 16, 13], "rotation": 90, "texture": "#2"}, + "west": {"uv": [6, 12, 16, 13], "rotation": 90, "texture": "#2"}, + "up": {"uv": [6, 12, 7, 13], "rotation": 180, "texture": "#2"}, + "down": {"uv": [15, 12, 16, 13], "rotation": 180, "texture": "#2"} + } + }, + { + "from": [5, 1, 13], + "to": [11, 2, 22], + "rotation": {"angle": 22.5, "axis": "x", "origin": [8, 9, 17]}, + "faces": { + "north": {"uv": [9, 7, 15, 8], "texture": "#2"}, + "east": {"uv": [0, 0, 9, 1], "texture": "#2"}, + "south": {"uv": [9, 7, 15, 8], "texture": "#2"}, + "west": {"uv": [0, 0, 9, 1], "texture": "#2"}, + "up": {"uv": [1, 0, 7, 9], "rotation": 180, "texture": "#2"}, + "down": {"uv": [1, 0, 7, 9], "texture": "#2"} + } + }, + { + "from": [5, 8, 13], + "to": [11, 9, 22], + "rotation": {"angle": 22.5, "axis": "x", "origin": [8, 9, 17]}, + "faces": { + "north": {"uv": [9, 0, 15, 1], "texture": "#2"}, + "east": {"uv": [0, 0, 9, 1], "texture": "#2"}, + "south": {"uv": [9, 0, 15, 1], "texture": "#2"}, + "west": {"uv": [0, 0, 9, 1], "texture": "#2"}, + "up": {"uv": [1, 0, 7, 9], "texture": "#2"}, + "down": {"uv": [1, 0, 7, 9], "rotation": 180, "texture": "#2"} + } + }, + { + "from": [5, 2, 14], + "to": [11, 8, 20], + "rotation": {"angle": 22.5, "axis": "x", "origin": [8, 9, 17]}, + "faces": { + "north": {"uv": [9, 1, 15, 7], "texture": "#2"}, + "south": {"uv": [9, 1, 15, 7], "texture": "#2"} + } + }, + { + "from": [4, 1, 13], + "to": [5, 9, 22], + "rotation": {"angle": 22.5, "axis": "x", "origin": [1, 9, 17]}, + "faces": { + "north": {"uv": [15, 0, 16, 8], "texture": "#2"}, + "east": {"uv": [0, 0, 8, 9], "rotation": 90, "texture": "#2"}, + "south": {"uv": [8, 0, 9, 8], "texture": "#2"}, + "west": {"uv": [0, 0, 8, 9], "rotation": 270, "texture": "#2"}, + "up": {"uv": [0, 0, 1, 9], "texture": "#2"}, + "down": {"uv": [0, 0, 1, 9], "rotation": 180, "texture": "#2"} + } + }, + { + "from": [11, 1, 13], + "to": [12, 9, 22], + "rotation": {"angle": 22.5, "axis": "x", "origin": [8, 9, 17]}, + "faces": { + "north": {"uv": [8, 0, 9, 8], "texture": "#2"}, + "east": {"uv": [0, 0, 8, 9], "rotation": 90, "texture": "#2"}, + "south": {"uv": [15, 0, 16, 8], "texture": "#2"}, + "west": {"uv": [0, 0, 8, 9], "rotation": 90, "texture": "#2"}, + "up": {"uv": [0, 0, 1, 9], "texture": "#2"}, + "down": {"uv": [0, 0, 1, 9], "rotation": 180, "texture": "#2"} + } + } + ], + "groups": [ + { + "name": "Basins", + "origin": [8, 8, 8], + "children": [ + { + "name": "Basin top", + "origin": [8, 8, 8], + "children": [0, 1, 2, 3, 4] + } + ] + }, + { + "name": "Canal", + "origin": [8, 8, 8], + "children": [ + { + "name": "Frame", + "origin": [8, 8, 8], + "children": [5, 6, 7, 8, 9, 10] + }, 11, 12, 13, 14, 15] + } + ] +} \ No newline at end of file diff --git a/src/main/resources/assets/create/textures/block/basin_canal.png b/src/main/resources/assets/create/textures/block/basin_canal.png new file mode 100644 index 0000000000000000000000000000000000000000..c300a2a1b4d77cd8bc0ac49bdb2153fe41dd4a32 GIT binary patch literal 1646 zcmV-!29f!RP) zaB^>EX>4U6ba`-PAZ2)IW&i+q+O1Y;mNO>|{Ld+J1SGK@hh}*%H^}i*G>h%FduF~# zjNQ-zBvDm>RsHAhrvAc*wb9C0A6#@!<71+UoX`k*d`3+e*Pru6uf~gA?GA=XP|J9A zb&gN4+s6cNru}%eE1##IFdZ$=)1mapjK&-nrX%5Dr}?hpoR`ega^_F`>0%GQz8eoP ziiJ^FaTOAcC-*2aeyQ8=)FOQlO1D@%@%fCM+RY1iyLG`%r)ig0D3o?{fV*Hc?PNb= zcOrCQZAE_RsI)`8Vb@v-t<|x*WE_xkYA$Lm~%0KI_C z10^ep#6Y%@p+boo)w9l&k)q+s9yN1jIc-5aN6w&u#PmXqy+kQW0yxQFO8n_X0ASZB-jX9pqv21ymakPL4D^5J9iIPB;F&6sqCO|{UiZ#kw>#VoI zMw^^CWqOwQ;BV(&E12!FL_he{1I<_$DHca{U6M!PTgegowpCH zm2}=HauU>cVaHTU!@-uYIx@JTtWO;9MgMBJ+0eH=ocm+~YkD+*dF?$22mnSSrrF@z zo`Yr<%JWDFTiIWN=)PS?1IOCg_z-mlQM$$v2EvM^+)TXIj}SG)GZEGAoiQsv^0dd9 zTnsoPP8;Ms!Z~fm3it`H0}j;bc6xxUbG_!Q@9MZlHe(X2;WMqI_Nbk}F|#y_+-C>(Zi$5a0EnlQKx>a zm3^~(PFsDyuJ?7CeVjeypuW+GTRO4(7L&K@pT;eMmbp8XWgnpHvTt*6{Q1(T=Hm+e z{j$|Jcx=vm!+#^Bq5cK5s-YkIfCEAR000JJOGiWi{{a60|De66lK=n!32;bRa{vGf z6951U69E94oEQKA00(qQO+^Rf3Ii4oA3QBDCftfG-dnpFlQ1}R{dTVfW_212^|n<{-*eb+C$I9n`U zo)h|R$ZVDlw8kx^$ zOsu7C+u>)NSj&7q8!WiIx*FX<0lbVAoGlhShmeK)?E|k9@C|N$+-7^K5fPK4_x^i< zA$#lfJ+3yx0vG4!Y+}sg_syH9hy$E!USDBIVDPx#1ZP1_K>z@;j|==^1poj532;bRa{vGi!T+ z`=1t}@*fBou3S0zf8B~nSlNdUu7a~cG)T|(xhemdK7aYd0K!+V9{PXl%0-62@LWc0 zY#X~!I2#0*m>C(qegDnC1m*z&vWE9>Ut(p$)IhZ`{P^{Ufk{|MfB}SY*@n!9sR3zb zWr5hu#LUdhz{to*&vo^AS)up3ykTJivQWz*cc`)xWVY4CH!B2 zla1l;zyH911)2^bpnwq+=s>&PeEP|7_|`kdyabK^no7D1j4&6F3*ZTfTrg??0|Nl8 W(J;=`&GxAP0000v19bQjlHTwWi2WV$y{jbh^32q48*666>B9~m&X9=LM?D8pIc5m^jWa1ewUcTCKF z3l#M5ba4#P2;SObDAb@Jz-+weBE!%B}};QTsy(& zrab+s#(_N-d3xO%GL^5c2vAx2jd9N%{sVQ4+1ogmi}>2I01ajEboFyt=akR{04Lj6 A=>Px# delta 285 zcmV+&0pk9H0?7i983+ad001BJ|6!3KAb$yPNLh0L01m%gf2Y%FWHd^!>*lFozhM(Otm8&VPyQ z1=3sq28@j4hXKgt|9<~sU;@R!i