diff --git a/src/generated/resources/.cache/cache b/src/generated/resources/.cache/cache index abbcb5506..1a8d59043 100644 --- a/src/generated/resources/.cache/cache +++ b/src/generated/resources/.cache/cache @@ -407,21 +407,21 @@ a3a11524cd3515fc01d905767b4b7ea782adaf03 assets/create/blockstates/yellow_seat.j 6801fa1f466f172700e573e5b8ee8ee5f9ca4583 assets/create/blockstates/yellow_valve_handle.json 7f39521b211441f5c3e06d60c5978cebe16cacfb assets/create/blockstates/zinc_block.json b7181bcd8182b2f17088e5aa881f374c9c65470c assets/create/blockstates/zinc_ore.json -e9c463e0cf56ed28ee26a33debeae3ecc2e941d2 assets/create/lang/en_ud.json -dceb2a935135d2ef502cdcba7c9d58f64062513f assets/create/lang/en_us.json -eb40acb99f3c7af50b840f3c2058d7a7bdd5cff7 assets/create/lang/unfinished/de_de.json -bcbfd3a6768daf265a1c01a424e985a3fdec6504 assets/create/lang/unfinished/es_es.json -50dec8a7eb983ac4d29f3eeba3273dbaeca26902 assets/create/lang/unfinished/es_mx.json -cc723673107651024f3fc0e43690ac467ff729b2 assets/create/lang/unfinished/fr_fr.json -99452bacb5d80715ea0a52106b7e2734a32c55d4 assets/create/lang/unfinished/it_it.json -f3058ea623666a43029af307f632197c8ff8dcab assets/create/lang/unfinished/ja_jp.json -d756b02573d6a3a3b73bd03ec69fe760825e1606 assets/create/lang/unfinished/ko_kr.json -281712735ab6437a417dde63c855e18eb19493a0 assets/create/lang/unfinished/nl_nl.json -24056aefb7ff79a2127c194fe2918ab9e745d6b5 assets/create/lang/unfinished/pl_pl.json -0f9c83a9f70d809d8f66c0438529b169b92ffdb1 assets/create/lang/unfinished/pt_br.json -ff35273842d3190aa361f2a8ca7edae80f97864d assets/create/lang/unfinished/ru_ru.json -139a31cfd09d4aaca33d118d28de735ba72f4f0d assets/create/lang/unfinished/zh_cn.json -19bfa8f57e8b395a2cfd98039f44301a61c1f73c assets/create/lang/unfinished/zh_tw.json +c71f5246d2cb8e9913d1552d23fcc82c43cde7a0 assets/create/lang/en_ud.json +16738c5e5eeba8be9808ea44b695a76cd665156d assets/create/lang/en_us.json +ffe020d59e813db401690b6c225b47a6e40c5c0b assets/create/lang/unfinished/de_de.json +37bd77cae941d650e641079ce826894a9d738a15 assets/create/lang/unfinished/es_es.json +5dc0552006fc2ca19bd12801bdfd9ebd34ce9ff1 assets/create/lang/unfinished/es_mx.json +ad91c2c41ec0cbfab9341256f2e9bf5cf08b8cdc assets/create/lang/unfinished/fr_fr.json +effbb185a45057ca686bdd5ef96f722f1c17bf4f assets/create/lang/unfinished/it_it.json +e7a925d5187e3ca3cc417356012bfc68e08e262c assets/create/lang/unfinished/ja_jp.json +3fcd98c23d179b63f48fff65806686f36170c09c assets/create/lang/unfinished/ko_kr.json +04852300087f939dba6cd6941af3e0a35c710dfa assets/create/lang/unfinished/nl_nl.json +b839c1dae703adaf5de99f3f40f3444f363752d9 assets/create/lang/unfinished/pl_pl.json +2a514e604fb6e75ba79670576f2eb1d976be4416 assets/create/lang/unfinished/pt_br.json +67c0bd43defecbc059a0afd89dae55d99198c95e assets/create/lang/unfinished/ru_ru.json +1f5da639f8450d8cd818d938a871fad9a1041b3a assets/create/lang/unfinished/zh_cn.json +25bf9dbb6163fb4be36afa0d4917bedbecb1cd3b assets/create/lang/unfinished/zh_tw.json 487a511a01b2a4531fb672f917922312db78f958 assets/create/models/block/acacia_window.json b48060cba1a382f373a05bf0039054053eccf076 assets/create/models/block/acacia_window_pane_noside.json 3066db1bf03cffa1a9c7fbacf47ae586632f4eb3 assets/create/models/block/acacia_window_pane_noside_alt.json @@ -1273,6 +1273,7 @@ d7cb2f7bac8fae893fc5179af8140786a908f3f5 assets/create/models/item/copper_shingl f56bf22324faf8958eaef4d94b958f1108d52e5a assets/create/models/item/copper_tiles.json 5583368909c319acfcf0f7a419bedf23272fe613 assets/create/models/item/copper_valve_handle.json 4e253e7c0626dfd76e2d39786ce1a34e0baaa62d assets/create/models/item/crafter_slot_cover.json +1f947dafff30da701b7675f5b026ccab3129b079 assets/create/models/item/crafting_blueprint.json 7b333dea353afaa27b182aedc647c9e9e34e92ef assets/create/models/item/creative_crate.json f7d06c52c3ca8c22ad67f5741471f06ac22e7fcb assets/create/models/item/creative_fluid_tank.json 5b39403f6c81f05e566b621b62e267267de47c41 assets/create/models/item/creative_motor.json @@ -1653,7 +1654,7 @@ d080b1b25e5bc8baf5aee68691b08c7f12ece3b0 assets/create/models/item/windmill_bear a80fb25a0b655e76be986b5b49fcb0f03461a1ab assets/create/models/item/zinc_nugget.json b1689617190c05ef34bd18456b0c7ae09bb3210f assets/create/models/item/zinc_ore.json 6490fa0587db770cf7c794b47f3bcd2b691f4226 assets/create/sounds.json -0f1b4b980afba9bf2caf583b88e261bba8b10313 data/create/advancements/aesthetics.json +5d0cc4c0255dc241e61c173b31ddca70c88d08e4 data/create/advancements/aesthetics.json 187921fa131b06721bfaf63f2623a28c141aae9a data/create/advancements/andesite_alloy.json 0ea2db7173b5be28b289ea7c9a6a0cf5805c60c7 data/create/advancements/andesite_casing.json 83c046bd200623933545c9e4326f782fb02c87fa data/create/advancements/arm_blaze_burner.json diff --git a/src/generated/resources/assets/create/lang/en_ud.json b/src/generated/resources/assets/create/lang/en_ud.json index 80d533b06..7e79a2ac9 100644 --- a/src/generated/resources/assets/create/lang/en_ud.json +++ b/src/generated/resources/assets/create/lang/en_ud.json @@ -409,6 +409,7 @@ "block.create.zinc_block": "\u0254u\u0131Z \u025Fo \u029E\u0254o\u05DF\u15FA", "block.create.zinc_ore": "\u01DD\u0279O \u0254u\u0131Z", "entity.create.contraption": "uo\u0131\u0287d\u0250\u0279\u0287uo\u0186", + "entity.create.crafting_blueprint": "\u0287u\u0131\u0279d\u01DDn\u05DF\u15FA bu\u0131\u0287\u025F\u0250\u0279\u0186", "entity.create.gantry_contraption": "uo\u0131\u0287d\u0250\u0279\u0287uo\u0186 \u028E\u0279\u0287u\u0250\u2141", "entity.create.seat": "\u0287\u0250\u01DDS", "entity.create.stationary_contraption": "uo\u0131\u0287d\u0250\u0279\u0287uo\u0186 \u028E\u0279\u0250uo\u0131\u0287\u0250\u0287S", @@ -437,6 +438,7 @@ "item.create.copper_nugget": "\u0287\u01DDbbnN \u0279\u01DDddo\u0186", "item.create.copper_sheet": "\u0287\u01DD\u01DD\u0265S \u0279\u01DDddo\u0186", "item.create.crafter_slot_cover": "\u0279\u01DD\u028Co\u0186 \u0287o\u05DFS \u0279\u01DD\u0287\u025F\u0250\u0279\u0186", + "item.create.crafting_blueprint": "\u0287u\u0131\u0279d\u01DDn\u05DF\u15FA bu\u0131\u0287\u025F\u0250\u0279\u0186", "item.create.crushed_aluminum_ore": "\u01DD\u0279O \u026Fnu\u0131\u026Fn\u05DF\u2C6F p\u01DD\u0265sn\u0279\u0186", "item.create.crushed_brass": "ss\u0250\u0279\u15FA p\u01DD\u0265sn\u0279\u0186", "item.create.crushed_copper_ore": "\u01DD\u0279O \u0279\u01DDddo\u0186 p\u01DD\u0265sn\u0279\u0186", diff --git a/src/generated/resources/assets/create/lang/en_us.json b/src/generated/resources/assets/create/lang/en_us.json index 7dc66e503..3a83298d9 100644 --- a/src/generated/resources/assets/create/lang/en_us.json +++ b/src/generated/resources/assets/create/lang/en_us.json @@ -413,6 +413,7 @@ "block.create.zinc_ore": "Zinc Ore", "entity.create.contraption": "Contraption", + "entity.create.crafting_blueprint": "Crafting Blueprint", "entity.create.gantry_contraption": "Gantry Contraption", "entity.create.seat": "Seat", "entity.create.stationary_contraption": "Stationary Contraption", @@ -443,6 +444,7 @@ "item.create.copper_nugget": "Copper Nugget", "item.create.copper_sheet": "Copper Sheet", "item.create.crafter_slot_cover": "Crafter Slot Cover", + "item.create.crafting_blueprint": "Crafting Blueprint", "item.create.crushed_aluminum_ore": "Crushed Aluminum Ore", "item.create.crushed_brass": "Crushed Brass", "item.create.crushed_copper_ore": "Crushed Copper Ore", @@ -1111,6 +1113,14 @@ "create.linked_controller.frequency_slot_1": "Keybind: %1$s, Freq. #1", "create.linked_controller.frequency_slot_2": "Keybind: %1$s, Freq. #2", + "create.crafting_blueprint.crafting_slot": "Ingredient Slot", + "create.crafting_blueprint.filter_items_viable": "Advanced filter items are viable", + "create.crafting_blueprint.display_slot": "Display Slot", + "create.crafting_blueprint.inferred": "Inferred from recipe", + "create.crafting_blueprint.manually_assigned": "Manually assigned", + "create.crafting_blueprint.secondary_display_slot": "Secondary Display Slot", + "create.crafting_blueprint.optional": "Optional", + "create.hint.hose_pulley.title": "Bottomless Supply", "create.hint.hose_pulley": "The targeted body of fluid is considered infinite.", "create.hint.mechanical_arm_no_targets.title": "No Targets", 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 e9eca8365..87ae9bd17 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: 953", + "_": "Missing Localizations: 962", "_": "->------------------------] Game Elements [------------------------<-", @@ -414,6 +414,7 @@ "block.create.zinc_ore": "Zinkerz", "entity.create.contraption": "Vorrichtung", + "entity.create.crafting_blueprint": "UNLOCALIZED: Crafting Blueprint", "entity.create.gantry_contraption": "Portalkran Vorrichtung", "entity.create.seat": "Sitz", "entity.create.stationary_contraption": "Stationäre Vorrichtung", @@ -444,6 +445,7 @@ "item.create.copper_nugget": "Kupferklumpen", "item.create.copper_sheet": "Kupferblech", "item.create.crafter_slot_cover": "Handwerkseinheit Slot Abdeckung", + "item.create.crafting_blueprint": "UNLOCALIZED: Crafting Blueprint", "item.create.crushed_aluminum_ore": "Zerkleinertes Aluminiumerz", "item.create.crushed_brass": "Zerkleinertes Messing", "item.create.crushed_copper_ore": "Zerkleinertes Kupfererz", @@ -1112,6 +1114,14 @@ "create.linked_controller.frequency_slot_1": "UNLOCALIZED: Keybind: %1$s, Freq. #1", "create.linked_controller.frequency_slot_2": "UNLOCALIZED: Keybind: %1$s, Freq. #2", + "create.crafting_blueprint.crafting_slot": "UNLOCALIZED: Ingredient Slot", + "create.crafting_blueprint.filter_items_viable": "UNLOCALIZED: Advanced filter items are viable", + "create.crafting_blueprint.display_slot": "UNLOCALIZED: Display Slot", + "create.crafting_blueprint.inferred": "UNLOCALIZED: Inferred from recipe", + "create.crafting_blueprint.manually_assigned": "UNLOCALIZED: Manually assigned", + "create.crafting_blueprint.secondary_display_slot": "UNLOCALIZED: Secondary Display Slot", + "create.crafting_blueprint.optional": "UNLOCALIZED: Optional", + "create.hint.hose_pulley.title": "Endlose Versorgung", "create.hint.hose_pulley": "Das angewählte Gewässer wird als unendlich betrachtet.", "create.hint.mechanical_arm_no_targets.title": "Keine Ziele", diff --git a/src/generated/resources/assets/create/lang/unfinished/es_es.json b/src/generated/resources/assets/create/lang/unfinished/es_es.json index fd3961305..34b37e433 100644 --- a/src/generated/resources/assets/create/lang/unfinished/es_es.json +++ b/src/generated/resources/assets/create/lang/unfinished/es_es.json @@ -1,5 +1,5 @@ { - "_": "Missing Localizations: 654", + "_": "Missing Localizations: 663", "_": "->------------------------] Game Elements [------------------------<-", @@ -414,6 +414,7 @@ "block.create.zinc_ore": "Mineral de zinc", "entity.create.contraption": "Artilugio", + "entity.create.crafting_blueprint": "UNLOCALIZED: Crafting Blueprint", "entity.create.gantry_contraption": "Artilugio de grúa", "entity.create.seat": "Asiento", "entity.create.stationary_contraption": "Artilugio estacionario", @@ -444,6 +445,7 @@ "item.create.copper_nugget": "Pepita de cobre", "item.create.copper_sheet": "Lámina de cobre", "item.create.crafter_slot_cover": "Tapa de ranura del Autoensamblador mecánico", + "item.create.crafting_blueprint": "UNLOCALIZED: Crafting Blueprint", "item.create.crushed_aluminum_ore": "Mineral de aluminio molido", "item.create.crushed_brass": "Latón molido", "item.create.crushed_copper_ore": "Mineral de cobre molido", @@ -1112,6 +1114,14 @@ "create.linked_controller.frequency_slot_1": "UNLOCALIZED: Keybind: %1$s, Freq. #1", "create.linked_controller.frequency_slot_2": "UNLOCALIZED: Keybind: %1$s, Freq. #2", + "create.crafting_blueprint.crafting_slot": "UNLOCALIZED: Ingredient Slot", + "create.crafting_blueprint.filter_items_viable": "UNLOCALIZED: Advanced filter items are viable", + "create.crafting_blueprint.display_slot": "UNLOCALIZED: Display Slot", + "create.crafting_blueprint.inferred": "UNLOCALIZED: Inferred from recipe", + "create.crafting_blueprint.manually_assigned": "UNLOCALIZED: Manually assigned", + "create.crafting_blueprint.secondary_display_slot": "UNLOCALIZED: Secondary Display Slot", + "create.crafting_blueprint.optional": "UNLOCALIZED: Optional", + "create.hint.hose_pulley.title": "Suministro sin fondo", "create.hint.hose_pulley": "La masa de fluido objetivo se considera infinita", "create.hint.mechanical_arm_no_targets.title": "No hay objetivos", diff --git a/src/generated/resources/assets/create/lang/unfinished/es_mx.json b/src/generated/resources/assets/create/lang/unfinished/es_mx.json index ed8f9dfdb..214ec5398 100644 --- a/src/generated/resources/assets/create/lang/unfinished/es_mx.json +++ b/src/generated/resources/assets/create/lang/unfinished/es_mx.json @@ -1,5 +1,5 @@ { - "_": "Missing Localizations: 1277", + "_": "Missing Localizations: 1286", "_": "->------------------------] Game Elements [------------------------<-", @@ -414,6 +414,7 @@ "block.create.zinc_ore": "Mineral de Zinc", "entity.create.contraption": "Artefacto", + "entity.create.crafting_blueprint": "UNLOCALIZED: Crafting Blueprint", "entity.create.gantry_contraption": "UNLOCALIZED: Gantry Contraption", "entity.create.seat": "Asiento", "entity.create.stationary_contraption": "Artefacto Estacionario", @@ -444,6 +445,7 @@ "item.create.copper_nugget": "Pepita de Cobre", "item.create.copper_sheet": "Lámina de Cobre", "item.create.crafter_slot_cover": "Cubierta de Ranura del Crafter", + "item.create.crafting_blueprint": "UNLOCALIZED: Crafting Blueprint", "item.create.crushed_aluminum_ore": "Mineral de Aluminio Molido", "item.create.crushed_brass": "Latón Molido", "item.create.crushed_copper_ore": "Mineral de Cobre Molido", @@ -1112,6 +1114,14 @@ "create.linked_controller.frequency_slot_1": "UNLOCALIZED: Keybind: %1$s, Freq. #1", "create.linked_controller.frequency_slot_2": "UNLOCALIZED: Keybind: %1$s, Freq. #2", + "create.crafting_blueprint.crafting_slot": "UNLOCALIZED: Ingredient Slot", + "create.crafting_blueprint.filter_items_viable": "UNLOCALIZED: Advanced filter items are viable", + "create.crafting_blueprint.display_slot": "UNLOCALIZED: Display Slot", + "create.crafting_blueprint.inferred": "UNLOCALIZED: Inferred from recipe", + "create.crafting_blueprint.manually_assigned": "UNLOCALIZED: Manually assigned", + "create.crafting_blueprint.secondary_display_slot": "UNLOCALIZED: Secondary Display Slot", + "create.crafting_blueprint.optional": "UNLOCALIZED: Optional", + "create.hint.hose_pulley.title": "UNLOCALIZED: Bottomless Supply", "create.hint.hose_pulley": "UNLOCALIZED: The targeted body of fluid is considered infinite.", "create.hint.mechanical_arm_no_targets.title": "UNLOCALIZED: No Targets", 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 bb199c9dd..053fa5a69 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: 1205", + "_": "Missing Localizations: 1214", "_": "->------------------------] Game Elements [------------------------<-", @@ -414,6 +414,7 @@ "block.create.zinc_ore": "Minerai de zinc", "entity.create.contraption": "Engin", + "entity.create.crafting_blueprint": "UNLOCALIZED: Crafting Blueprint", "entity.create.gantry_contraption": "UNLOCALIZED: Gantry Contraption", "entity.create.seat": "Siège", "entity.create.stationary_contraption": "Engin stationnaire", @@ -444,6 +445,7 @@ "item.create.copper_nugget": "Pépite de cuivre", "item.create.copper_sheet": "Plaques de cuivre", "item.create.crafter_slot_cover": "Couvercle", + "item.create.crafting_blueprint": "UNLOCALIZED: Crafting Blueprint", "item.create.crushed_aluminum_ore": "Aluminium concassé", "item.create.crushed_brass": "Laiton concassé", "item.create.crushed_copper_ore": "Cuivre concassé", @@ -1112,6 +1114,14 @@ "create.linked_controller.frequency_slot_1": "UNLOCALIZED: Keybind: %1$s, Freq. #1", "create.linked_controller.frequency_slot_2": "UNLOCALIZED: Keybind: %1$s, Freq. #2", + "create.crafting_blueprint.crafting_slot": "UNLOCALIZED: Ingredient Slot", + "create.crafting_blueprint.filter_items_viable": "UNLOCALIZED: Advanced filter items are viable", + "create.crafting_blueprint.display_slot": "UNLOCALIZED: Display Slot", + "create.crafting_blueprint.inferred": "UNLOCALIZED: Inferred from recipe", + "create.crafting_blueprint.manually_assigned": "UNLOCALIZED: Manually assigned", + "create.crafting_blueprint.secondary_display_slot": "UNLOCALIZED: Secondary Display Slot", + "create.crafting_blueprint.optional": "UNLOCALIZED: Optional", + "create.hint.hose_pulley.title": "UNLOCALIZED: Bottomless Supply", "create.hint.hose_pulley": "UNLOCALIZED: The targeted body of fluid is considered infinite.", "create.hint.mechanical_arm_no_targets.title": "UNLOCALIZED: No Targets", 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 6c80f9860..2edf60cdd 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: 671", + "_": "Missing Localizations: 680", "_": "->------------------------] Game Elements [------------------------<-", @@ -414,6 +414,7 @@ "block.create.zinc_ore": "Zinco grezzo", "entity.create.contraption": "Contrazione", + "entity.create.crafting_blueprint": "UNLOCALIZED: Crafting Blueprint", "entity.create.gantry_contraption": "UNLOCALIZED: Gantry Contraption", "entity.create.seat": "Sedile", "entity.create.stationary_contraption": "Contrazione stazionaria", @@ -444,6 +445,7 @@ "item.create.copper_nugget": "Pepita di rame", "item.create.copper_sheet": "Lamiera di rame", "item.create.crafter_slot_cover": "Rivestimento per slot da costruzione", + "item.create.crafting_blueprint": "UNLOCALIZED: Crafting Blueprint", "item.create.crushed_aluminum_ore": "Alluminio grezzo frantumato", "item.create.crushed_brass": "Ottone frantumato", "item.create.crushed_copper_ore": "Rame grezzo frantumato", @@ -1112,6 +1114,14 @@ "create.linked_controller.frequency_slot_1": "UNLOCALIZED: Keybind: %1$s, Freq. #1", "create.linked_controller.frequency_slot_2": "UNLOCALIZED: Keybind: %1$s, Freq. #2", + "create.crafting_blueprint.crafting_slot": "UNLOCALIZED: Ingredient Slot", + "create.crafting_blueprint.filter_items_viable": "UNLOCALIZED: Advanced filter items are viable", + "create.crafting_blueprint.display_slot": "UNLOCALIZED: Display Slot", + "create.crafting_blueprint.inferred": "UNLOCALIZED: Inferred from recipe", + "create.crafting_blueprint.manually_assigned": "UNLOCALIZED: Manually assigned", + "create.crafting_blueprint.secondary_display_slot": "UNLOCALIZED: Secondary Display Slot", + "create.crafting_blueprint.optional": "UNLOCALIZED: Optional", + "create.hint.hose_pulley.title": "Buco senza fondo", "create.hint.hose_pulley": "Il corpo fluido selezionato è considerato infinito.", "create.hint.mechanical_arm_no_targets.title": "Nessun bersaglio", 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 4e2783d3f..da3965537 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: 35", + "_": "Missing Localizations: 44", "_": "->------------------------] Game Elements [------------------------<-", @@ -414,6 +414,7 @@ "block.create.zinc_ore": "亜鉛鉱石", "entity.create.contraption": "からくり", + "entity.create.crafting_blueprint": "UNLOCALIZED: Crafting Blueprint", "entity.create.gantry_contraption": "ガントリーからくり", "entity.create.seat": "シート", "entity.create.stationary_contraption": "付設からくり", @@ -444,6 +445,7 @@ "item.create.copper_nugget": "銅塊", "item.create.copper_sheet": "銅板", "item.create.crafter_slot_cover": "クラフタースロットカバー", + "item.create.crafting_blueprint": "UNLOCALIZED: Crafting Blueprint", "item.create.crushed_aluminum_ore": "砕いたアルミニウム鉱石", "item.create.crushed_brass": "砕いた真鍮", "item.create.crushed_copper_ore": "砕いた銅鉱石", @@ -1112,6 +1114,14 @@ "create.linked_controller.frequency_slot_1": "UNLOCALIZED: Keybind: %1$s, Freq. #1", "create.linked_controller.frequency_slot_2": "UNLOCALIZED: Keybind: %1$s, Freq. #2", + "create.crafting_blueprint.crafting_slot": "UNLOCALIZED: Ingredient Slot", + "create.crafting_blueprint.filter_items_viable": "UNLOCALIZED: Advanced filter items are viable", + "create.crafting_blueprint.display_slot": "UNLOCALIZED: Display Slot", + "create.crafting_blueprint.inferred": "UNLOCALIZED: Inferred from recipe", + "create.crafting_blueprint.manually_assigned": "UNLOCALIZED: Manually assigned", + "create.crafting_blueprint.secondary_display_slot": "UNLOCALIZED: Secondary Display Slot", + "create.crafting_blueprint.optional": "UNLOCALIZED: Optional", + "create.hint.hose_pulley.title": "底なし搬出", "create.hint.hose_pulley": "対象となる液体は無限とみなされています。", "create.hint.mechanical_arm_no_targets.title": "ターゲットが見つかりません", 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 4c28e0a5f..81bc6c533 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: 724", + "_": "Missing Localizations: 733", "_": "->------------------------] Game Elements [------------------------<-", @@ -414,6 +414,7 @@ "block.create.zinc_ore": "아연 광석", "entity.create.contraption": "장치", + "entity.create.crafting_blueprint": "UNLOCALIZED: Crafting Blueprint", "entity.create.gantry_contraption": "UNLOCALIZED: Gantry Contraption", "entity.create.seat": "좌석", "entity.create.stationary_contraption": "고정된 장치", @@ -444,6 +445,7 @@ "item.create.copper_nugget": "구리 조각", "item.create.copper_sheet": "구리 판", "item.create.crafter_slot_cover": "조합기 슬롯 덮개", + "item.create.crafting_blueprint": "UNLOCALIZED: Crafting Blueprint", "item.create.crushed_aluminum_ore": "UNLOCALIZED: Crushed Aluminum Ore", "item.create.crushed_brass": "분쇄된 황동", "item.create.crushed_copper_ore": "분쇄된 구리 광석", @@ -1112,6 +1114,14 @@ "create.linked_controller.frequency_slot_1": "UNLOCALIZED: Keybind: %1$s, Freq. #1", "create.linked_controller.frequency_slot_2": "UNLOCALIZED: Keybind: %1$s, Freq. #2", + "create.crafting_blueprint.crafting_slot": "UNLOCALIZED: Ingredient Slot", + "create.crafting_blueprint.filter_items_viable": "UNLOCALIZED: Advanced filter items are viable", + "create.crafting_blueprint.display_slot": "UNLOCALIZED: Display Slot", + "create.crafting_blueprint.inferred": "UNLOCALIZED: Inferred from recipe", + "create.crafting_blueprint.manually_assigned": "UNLOCALIZED: Manually assigned", + "create.crafting_blueprint.secondary_display_slot": "UNLOCALIZED: Secondary Display Slot", + "create.crafting_blueprint.optional": "UNLOCALIZED: Optional", + "create.hint.hose_pulley.title": "UNLOCALIZED: Bottomless Supply", "create.hint.hose_pulley": "UNLOCALIZED: The targeted body of fluid is considered infinite.", "create.hint.mechanical_arm_no_targets.title": "목표 없음", 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 cf7c6b7f9..260e6ac6b 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: 1588", + "_": "Missing Localizations: 1597", "_": "->------------------------] Game Elements [------------------------<-", @@ -414,6 +414,7 @@ "block.create.zinc_ore": "UNLOCALIZED: Zinc Ore", "entity.create.contraption": "UNLOCALIZED: Contraption", + "entity.create.crafting_blueprint": "UNLOCALIZED: Crafting Blueprint", "entity.create.gantry_contraption": "UNLOCALIZED: Gantry Contraption", "entity.create.seat": "UNLOCALIZED: Seat", "entity.create.stationary_contraption": "UNLOCALIZED: Stationary Contraption", @@ -444,6 +445,7 @@ "item.create.copper_nugget": "Koper klompje", "item.create.copper_sheet": "UNLOCALIZED: Copper Sheet", "item.create.crafter_slot_cover": "UNLOCALIZED: Crafter Slot Cover", + "item.create.crafting_blueprint": "UNLOCALIZED: Crafting Blueprint", "item.create.crushed_aluminum_ore": "UNLOCALIZED: Crushed Aluminum Ore", "item.create.crushed_brass": "Gemalen Brons", "item.create.crushed_copper_ore": "UNLOCALIZED: Crushed Copper Ore", @@ -1112,6 +1114,14 @@ "create.linked_controller.frequency_slot_1": "UNLOCALIZED: Keybind: %1$s, Freq. #1", "create.linked_controller.frequency_slot_2": "UNLOCALIZED: Keybind: %1$s, Freq. #2", + "create.crafting_blueprint.crafting_slot": "UNLOCALIZED: Ingredient Slot", + "create.crafting_blueprint.filter_items_viable": "UNLOCALIZED: Advanced filter items are viable", + "create.crafting_blueprint.display_slot": "UNLOCALIZED: Display Slot", + "create.crafting_blueprint.inferred": "UNLOCALIZED: Inferred from recipe", + "create.crafting_blueprint.manually_assigned": "UNLOCALIZED: Manually assigned", + "create.crafting_blueprint.secondary_display_slot": "UNLOCALIZED: Secondary Display Slot", + "create.crafting_blueprint.optional": "UNLOCALIZED: Optional", + "create.hint.hose_pulley.title": "UNLOCALIZED: Bottomless Supply", "create.hint.hose_pulley": "UNLOCALIZED: The targeted body of fluid is considered infinite.", "create.hint.mechanical_arm_no_targets.title": "UNLOCALIZED: No Targets", diff --git a/src/generated/resources/assets/create/lang/unfinished/pl_pl.json b/src/generated/resources/assets/create/lang/unfinished/pl_pl.json index 409334069..ca84ea0e5 100644 --- a/src/generated/resources/assets/create/lang/unfinished/pl_pl.json +++ b/src/generated/resources/assets/create/lang/unfinished/pl_pl.json @@ -1,5 +1,5 @@ { - "_": "Missing Localizations: 11", + "_": "Missing Localizations: 20", "_": "->------------------------] Game Elements [------------------------<-", @@ -414,6 +414,7 @@ "block.create.zinc_ore": "Ruda cynku", "entity.create.contraption": "Maszyna", + "entity.create.crafting_blueprint": "UNLOCALIZED: Crafting Blueprint", "entity.create.gantry_contraption": "Maszyna suwnicowa", "entity.create.seat": "Siedzenie", "entity.create.stationary_contraption": "Maszyna stacjonarna", @@ -444,6 +445,7 @@ "item.create.copper_nugget": "Bryłka miedzi", "item.create.copper_sheet": "Arkusz miedzi", "item.create.crafter_slot_cover": "Przykrywka na slot stołu rzemieślniczego", + "item.create.crafting_blueprint": "UNLOCALIZED: Crafting Blueprint", "item.create.crushed_aluminum_ore": "Rozkruszona ruda żelaza", "item.create.crushed_brass": "Rozkruszony mosiądz", "item.create.crushed_copper_ore": "Rozkruszona ruda miedzi", @@ -1112,6 +1114,14 @@ "create.linked_controller.frequency_slot_1": "UNLOCALIZED: Keybind: %1$s, Freq. #1", "create.linked_controller.frequency_slot_2": "UNLOCALIZED: Keybind: %1$s, Freq. #2", + "create.crafting_blueprint.crafting_slot": "UNLOCALIZED: Ingredient Slot", + "create.crafting_blueprint.filter_items_viable": "UNLOCALIZED: Advanced filter items are viable", + "create.crafting_blueprint.display_slot": "UNLOCALIZED: Display Slot", + "create.crafting_blueprint.inferred": "UNLOCALIZED: Inferred from recipe", + "create.crafting_blueprint.manually_assigned": "UNLOCALIZED: Manually assigned", + "create.crafting_blueprint.secondary_display_slot": "UNLOCALIZED: Secondary Display Slot", + "create.crafting_blueprint.optional": "UNLOCALIZED: Optional", + "create.hint.hose_pulley.title": "Niewyczerpany zapas", "create.hint.hose_pulley": "Wybrane zbiornik cieczy jest uznany za nieskończony", "create.hint.mechanical_arm_no_targets.title": "Brak celi", 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 3f00b608d..f428487a4 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: 1640", + "_": "Missing Localizations: 1649", "_": "->------------------------] Game Elements [------------------------<-", @@ -414,6 +414,7 @@ "block.create.zinc_ore": "UNLOCALIZED: Zinc Ore", "entity.create.contraption": "UNLOCALIZED: Contraption", + "entity.create.crafting_blueprint": "UNLOCALIZED: Crafting Blueprint", "entity.create.gantry_contraption": "UNLOCALIZED: Gantry Contraption", "entity.create.seat": "UNLOCALIZED: Seat", "entity.create.stationary_contraption": "UNLOCALIZED: Stationary Contraption", @@ -444,6 +445,7 @@ "item.create.copper_nugget": "UNLOCALIZED: Copper Nugget", "item.create.copper_sheet": "UNLOCALIZED: Copper Sheet", "item.create.crafter_slot_cover": "UNLOCALIZED: Crafter Slot Cover", + "item.create.crafting_blueprint": "UNLOCALIZED: Crafting Blueprint", "item.create.crushed_aluminum_ore": "UNLOCALIZED: Crushed Aluminum Ore", "item.create.crushed_brass": "UNLOCALIZED: Crushed Brass", "item.create.crushed_copper_ore": "UNLOCALIZED: Crushed Copper Ore", @@ -1112,6 +1114,14 @@ "create.linked_controller.frequency_slot_1": "UNLOCALIZED: Keybind: %1$s, Freq. #1", "create.linked_controller.frequency_slot_2": "UNLOCALIZED: Keybind: %1$s, Freq. #2", + "create.crafting_blueprint.crafting_slot": "UNLOCALIZED: Ingredient Slot", + "create.crafting_blueprint.filter_items_viable": "UNLOCALIZED: Advanced filter items are viable", + "create.crafting_blueprint.display_slot": "UNLOCALIZED: Display Slot", + "create.crafting_blueprint.inferred": "UNLOCALIZED: Inferred from recipe", + "create.crafting_blueprint.manually_assigned": "UNLOCALIZED: Manually assigned", + "create.crafting_blueprint.secondary_display_slot": "UNLOCALIZED: Secondary Display Slot", + "create.crafting_blueprint.optional": "UNLOCALIZED: Optional", + "create.hint.hose_pulley.title": "UNLOCALIZED: Bottomless Supply", "create.hint.hose_pulley": "UNLOCALIZED: The targeted body of fluid is considered infinite.", "create.hint.mechanical_arm_no_targets.title": "UNLOCALIZED: No Targets", 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 ea60579ad..8364eeb7f 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: 568", + "_": "Missing Localizations: 577", "_": "->------------------------] Game Elements [------------------------<-", @@ -414,6 +414,7 @@ "block.create.zinc_ore": "Цинковая руда", "entity.create.contraption": "Штуковина", + "entity.create.crafting_blueprint": "UNLOCALIZED: Crafting Blueprint", "entity.create.gantry_contraption": "UNLOCALIZED: Gantry Contraption", "entity.create.seat": "Сиденье", "entity.create.stationary_contraption": "Стационарная штуковина", @@ -444,6 +445,7 @@ "item.create.copper_nugget": "Кусочек меди", "item.create.copper_sheet": "Медный лист", "item.create.crafter_slot_cover": "Крышка на слот крафтера", + "item.create.crafting_blueprint": "UNLOCALIZED: Crafting Blueprint", "item.create.crushed_aluminum_ore": "Измельчённая алюминиевая руда", "item.create.crushed_brass": "Дроблёная латунь", "item.create.crushed_copper_ore": "Дроблёная медная руда", @@ -1112,6 +1114,14 @@ "create.linked_controller.frequency_slot_1": "UNLOCALIZED: Keybind: %1$s, Freq. #1", "create.linked_controller.frequency_slot_2": "UNLOCALIZED: Keybind: %1$s, Freq. #2", + "create.crafting_blueprint.crafting_slot": "UNLOCALIZED: Ingredient Slot", + "create.crafting_blueprint.filter_items_viable": "UNLOCALIZED: Advanced filter items are viable", + "create.crafting_blueprint.display_slot": "UNLOCALIZED: Display Slot", + "create.crafting_blueprint.inferred": "UNLOCALIZED: Inferred from recipe", + "create.crafting_blueprint.manually_assigned": "UNLOCALIZED: Manually assigned", + "create.crafting_blueprint.secondary_display_slot": "UNLOCALIZED: Secondary Display Slot", + "create.crafting_blueprint.optional": "UNLOCALIZED: Optional", + "create.hint.hose_pulley.title": "Безграничное снабжение", "create.hint.hose_pulley": "Целевой водный резервуар считается бесконечным.", "create.hint.mechanical_arm_no_targets.title": "Нет целей", 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 afa6e0de7..135eb472d 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: 54", + "_": "Missing Localizations: 63", "_": "->------------------------] Game Elements [------------------------<-", @@ -414,6 +414,7 @@ "block.create.zinc_ore": "锌矿石", "entity.create.contraption": "装置", + "entity.create.crafting_blueprint": "UNLOCALIZED: Crafting Blueprint", "entity.create.gantry_contraption": "起重机装置", "entity.create.seat": "坐垫", "entity.create.stationary_contraption": "固定装置", @@ -444,6 +445,7 @@ "item.create.copper_nugget": "铜粒", "item.create.copper_sheet": "铜板", "item.create.crafter_slot_cover": "合成器盖板", + "item.create.crafting_blueprint": "UNLOCALIZED: Crafting Blueprint", "item.create.crushed_aluminum_ore": "粉碎铝矿石", "item.create.crushed_brass": "粉碎黄铜", "item.create.crushed_copper_ore": "粉碎铜矿石", @@ -1112,6 +1114,14 @@ "create.linked_controller.frequency_slot_1": "UNLOCALIZED: Keybind: %1$s, Freq. #1", "create.linked_controller.frequency_slot_2": "UNLOCALIZED: Keybind: %1$s, Freq. #2", + "create.crafting_blueprint.crafting_slot": "UNLOCALIZED: Ingredient Slot", + "create.crafting_blueprint.filter_items_viable": "UNLOCALIZED: Advanced filter items are viable", + "create.crafting_blueprint.display_slot": "UNLOCALIZED: Display Slot", + "create.crafting_blueprint.inferred": "UNLOCALIZED: Inferred from recipe", + "create.crafting_blueprint.manually_assigned": "UNLOCALIZED: Manually assigned", + "create.crafting_blueprint.secondary_display_slot": "UNLOCALIZED: Secondary Display Slot", + "create.crafting_blueprint.optional": "UNLOCALIZED: Optional", + "create.hint.hose_pulley.title": "无限供应", "create.hint.hose_pulley": "目标液体对象被视为无限量的。", "create.hint.mechanical_arm_no_targets.title": "没有目标", diff --git a/src/generated/resources/assets/create/lang/unfinished/zh_tw.json b/src/generated/resources/assets/create/lang/unfinished/zh_tw.json index 2c4a92d15..af725e332 100644 --- a/src/generated/resources/assets/create/lang/unfinished/zh_tw.json +++ b/src/generated/resources/assets/create/lang/unfinished/zh_tw.json @@ -1,5 +1,5 @@ { - "_": "Missing Localizations: 47", + "_": "Missing Localizations: 56", "_": "->------------------------] Game Elements [------------------------<-", @@ -414,6 +414,7 @@ "block.create.zinc_ore": "鋅礦石", "entity.create.contraption": "結構", + "entity.create.crafting_blueprint": "UNLOCALIZED: Crafting Blueprint", "entity.create.gantry_contraption": "門式結構", "entity.create.seat": "坐墊", "entity.create.stationary_contraption": "固定結構", @@ -444,6 +445,7 @@ "item.create.copper_nugget": "銅粒", "item.create.copper_sheet": "銅板", "item.create.crafter_slot_cover": "合成器蓋板", + "item.create.crafting_blueprint": "UNLOCALIZED: Crafting Blueprint", "item.create.crushed_aluminum_ore": "碎狀鋁礦石", "item.create.crushed_brass": "碎狀黃銅", "item.create.crushed_copper_ore": "碎狀銅礦石", @@ -1112,6 +1114,14 @@ "create.linked_controller.frequency_slot_1": "UNLOCALIZED: Keybind: %1$s, Freq. #1", "create.linked_controller.frequency_slot_2": "UNLOCALIZED: Keybind: %1$s, Freq. #2", + "create.crafting_blueprint.crafting_slot": "UNLOCALIZED: Ingredient Slot", + "create.crafting_blueprint.filter_items_viable": "UNLOCALIZED: Advanced filter items are viable", + "create.crafting_blueprint.display_slot": "UNLOCALIZED: Display Slot", + "create.crafting_blueprint.inferred": "UNLOCALIZED: Inferred from recipe", + "create.crafting_blueprint.manually_assigned": "UNLOCALIZED: Manually assigned", + "create.crafting_blueprint.secondary_display_slot": "UNLOCALIZED: Secondary Display Slot", + "create.crafting_blueprint.optional": "UNLOCALIZED: Optional", + "create.hint.hose_pulley.title": "無限供應", "create.hint.hose_pulley": "目標液體為無限供應", "create.hint.mechanical_arm_no_targets.title": "沒有目標", diff --git a/src/generated/resources/assets/create/models/item/crafting_blueprint.json b/src/generated/resources/assets/create/models/item/crafting_blueprint.json new file mode 100644 index 000000000..94ec8d07a --- /dev/null +++ b/src/generated/resources/assets/create/models/item/crafting_blueprint.json @@ -0,0 +1,6 @@ +{ + "parent": "minecraft:item/generated", + "textures": { + "layer0": "create:item/crafting_blueprint" + } +} \ No newline at end of file diff --git a/src/generated/resources/data/create/advancements/aesthetics.json b/src/generated/resources/data/create/advancements/aesthetics.json index d723cbe38..59a86f429 100644 --- a/src/generated/resources/data/create/advancements/aesthetics.json +++ b/src/generated/resources/data/create/advancements/aesthetics.json @@ -28,8 +28,8 @@ "trigger": "create:bracket_apply", "conditions": { "accepted_entries": [ - "create:cogwheel", - "create:large_cogwheel" + "create:large_cogwheel", + "create:cogwheel" ] } }, diff --git a/src/main/java/com/simibubi/create/AllBlockPartials.java b/src/main/java/com/simibubi/create/AllBlockPartials.java index 046ca169d..415f2b189 100644 --- a/src/main/java/com/simibubi/create/AllBlockPartials.java +++ b/src/main/java/com/simibubi/create/AllBlockPartials.java @@ -102,6 +102,10 @@ public class AllBlockPartials { COPPER_BACKTANK_SHAFT = get("copper_backtank/block_shaft_input"), COPPER_BACKTANK_COGS = get("copper_backtank/block_cogs"), + CRAFTING_BLUEPRINT_1x1 = getEntity("crafting_blueprint_small"), + CRAFTING_BLUEPRINT_2x2 = getEntity("crafting_blueprint_medium"), + CRAFTING_BLUEPRINT_3x3 = getEntity("crafting_blueprint_large"), + COUPLING_ATTACHMENT = getEntity("minecart_coupling/attachment"), COUPLING_RING = getEntity("minecart_coupling/ring"), COUPLING_CONNECTOR = getEntity("minecart_coupling/connector") diff --git a/src/main/java/com/simibubi/create/AllContainerTypes.java b/src/main/java/com/simibubi/create/AllContainerTypes.java index e171543a9..85480ca72 100644 --- a/src/main/java/com/simibubi/create/AllContainerTypes.java +++ b/src/main/java/com/simibubi/create/AllContainerTypes.java @@ -1,5 +1,7 @@ package com.simibubi.create; +import com.simibubi.create.content.curiosities.tools.BlueprintContainer; +import com.simibubi.create.content.curiosities.tools.BlueprintScreen; import com.simibubi.create.content.logistics.block.inventories.AdjustableCrateContainer; import com.simibubi.create.content.logistics.block.inventories.AdjustableCrateScreen; import com.simibubi.create.content.logistics.item.LinkedControllerContainer; @@ -38,6 +40,9 @@ public class AllContainerTypes { public static final ContainerEntry ATTRIBUTE_FILTER = register("attribute_filter", AttributeFilterContainer::new, () -> AttributeFilterScreen::new); + public static final ContainerEntry CRAFTING_BLUEPRINT = + register("crafting_blueprint", BlueprintContainer::new, () -> BlueprintScreen::new); + public static final ContainerEntry LINKED_CONTROLLER = register("linked_controller", LinkedControllerContainer::new, () -> LinkedControllerScreen::new); diff --git a/src/main/java/com/simibubi/create/AllEntityTypes.java b/src/main/java/com/simibubi/create/AllEntityTypes.java index b6a6fb322..e63cea3bb 100644 --- a/src/main/java/com/simibubi/create/AllEntityTypes.java +++ b/src/main/java/com/simibubi/create/AllEntityTypes.java @@ -9,6 +9,8 @@ import com.simibubi.create.content.contraptions.components.structureMovement.Ori import com.simibubi.create.content.contraptions.components.structureMovement.gantry.GantryContraptionEntity; import com.simibubi.create.content.contraptions.components.structureMovement.glue.SuperGlueEntity; import com.simibubi.create.content.contraptions.components.structureMovement.glue.SuperGlueRenderer; +import com.simibubi.create.content.curiosities.tools.BlueprintEntity; +import com.simibubi.create.content.curiosities.tools.BlueprintRenderer; import com.simibubi.create.foundation.utility.Lang; import com.tterrag.registrate.util.entry.EntityEntry; import com.tterrag.registrate.util.nullness.NonNullConsumer; @@ -35,6 +37,11 @@ public class AllEntityTypes { public static final EntityEntry SUPER_GLUE = register("super_glue", SuperGlueEntity::new, () -> SuperGlueRenderer::new, EntityClassification.MISC, 10, Integer.MAX_VALUE, false, true, SuperGlueEntity::build); + + public static final EntityEntry CRAFTING_BLUEPRINT = + register("crafting_blueprint", BlueprintEntity::new, () -> BlueprintRenderer::new, + EntityClassification.MISC, 10, Integer.MAX_VALUE, false, true, BlueprintEntity::build); + public static final EntityEntry SEAT = register("seat", SeatEntity::new, () -> SeatEntity.Render::new, EntityClassification.MISC, 0, Integer.MAX_VALUE, false, true, SeatEntity::build); diff --git a/src/main/java/com/simibubi/create/AllItems.java b/src/main/java/com/simibubi/create/AllItems.java index 0de68e70a..18c157b7a 100644 --- a/src/main/java/com/simibubi/create/AllItems.java +++ b/src/main/java/com/simibubi/create/AllItems.java @@ -35,6 +35,7 @@ import com.simibubi.create.content.curiosities.armor.DivingBootsItem; import com.simibubi.create.content.curiosities.armor.DivingHelmetItem; import com.simibubi.create.content.curiosities.symmetry.SymmetryWandItem; import com.simibubi.create.content.curiosities.symmetry.client.SymmetryWandModel; +import com.simibubi.create.content.curiosities.tools.BlueprintItem; import com.simibubi.create.content.curiosities.tools.ExtendoGripItem; import com.simibubi.create.content.curiosities.tools.ExtendoGripModel; import com.simibubi.create.content.curiosities.tools.SandPaperItem; @@ -197,6 +198,10 @@ public class AllItems { REGISTRATE.item("minecart_coupling", MinecartCouplingItem::new) .register(); + public static final ItemEntry CRAFTING_BLUEPRINT = + REGISTRATE.item("crafting_blueprint", BlueprintItem::new) + .register(); + public static final ItemEntry SAND_PAPER = REGISTRATE.item("sand_paper", SandPaperItem::new) .transform(CreateRegistrate.customRenderedItem(() -> SandPaperModel::new)) .register(); @@ -222,7 +227,7 @@ public class AllItems { .transform(CreateRegistrate.customRenderedItem(() -> LinkedControllerModel::new)) .model(AssetLookup.itemModelWithPartials()) .register(); - + public static final ItemEntry WAND_OF_SYMMETRY = REGISTRATE.item("wand_of_symmetry", SymmetryWandItem::new) .transform(CreateRegistrate.customRenderedItem(() -> SymmetryWandModel::new)) diff --git a/src/main/java/com/simibubi/create/compat/jei/BlueprintTransferHandler.java b/src/main/java/com/simibubi/create/compat/jei/BlueprintTransferHandler.java new file mode 100644 index 000000000..47848a981 --- /dev/null +++ b/src/main/java/com/simibubi/create/compat/jei/BlueprintTransferHandler.java @@ -0,0 +1,31 @@ +package com.simibubi.create.compat.jei; + +import com.simibubi.create.content.curiosities.tools.BlueprintAssignCompleteRecipePacket; +import com.simibubi.create.content.curiosities.tools.BlueprintContainer; +import com.simibubi.create.foundation.networking.AllPackets; + +import mezz.jei.api.gui.IRecipeLayout; +import mezz.jei.api.recipe.transfer.IRecipeTransferError; +import mezz.jei.api.recipe.transfer.IRecipeTransferHandler; +import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.item.crafting.IRecipe; + +public class BlueprintTransferHandler implements IRecipeTransferHandler { + + @Override + public Class getContainerClass() { + return BlueprintContainer.class; + } + + @Override + public IRecipeTransferError transferRecipe(BlueprintContainer container, Object recipe, IRecipeLayout recipeLayout, + PlayerEntity player, boolean maxTransfer, boolean doTransfer) { + if (!(recipe instanceof IRecipe)) + return null; + IRecipe iRecipe = (IRecipe) recipe; + // Continued server-side in BlueprintItem.assignCompleteRecipe() + AllPackets.channel.sendToServer(new BlueprintAssignCompleteRecipePacket(iRecipe.getId())); + return null; + } + +} 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 7cbb79a56..e377882ad 100644 --- a/src/main/java/com/simibubi/create/compat/jei/CreateJEI.java +++ b/src/main/java/com/simibubi/create/compat/jei/CreateJEI.java @@ -39,6 +39,7 @@ import com.simibubi.create.content.contraptions.components.press.MechanicalPress import com.simibubi.create.content.contraptions.components.saw.SawTileEntity; import com.simibubi.create.content.contraptions.fluids.recipe.PotionMixingRecipeManager; import com.simibubi.create.content.contraptions.processing.BasinRecipe; +import com.simibubi.create.content.curiosities.tools.BlueprintScreen; import com.simibubi.create.content.logistics.block.inventories.AdjustableCrateScreen; import com.simibubi.create.content.logistics.item.filter.AbstractFilterScreen; import com.simibubi.create.content.logistics.item.filter.AttributeFilterScreen; @@ -51,10 +52,12 @@ import com.simibubi.create.foundation.config.ConfigBase.ConfigBool; import mezz.jei.api.IModPlugin; import mezz.jei.api.JeiPlugin; +import mezz.jei.api.constants.VanillaRecipeCategoryUid; import mezz.jei.api.registration.IGuiHandlerRegistration; import mezz.jei.api.registration.IRecipeCatalystRegistration; import mezz.jei.api.registration.IRecipeCategoryRegistration; import mezz.jei.api.registration.IRecipeRegistration; +import mezz.jei.api.registration.IRecipeTransferRegistration; import mezz.jei.api.runtime.IIngredientManager; import net.minecraft.client.Minecraft; import net.minecraft.item.ItemStack; @@ -84,9 +87,9 @@ public class CreateJEI implements IModPlugin { private final List> allCategories = new ArrayList<>(); private final CreateRecipeCategory - milling = register("milling", MillingCategory::new).recipes(AllRecipeTypes.MILLING) - .catalyst(AllBlocks.MILLSTONE::get) - .build(), + milling = register("milling", MillingCategory::new).recipes(AllRecipeTypes.MILLING) + .catalyst(AllBlocks.MILLSTONE::get) + .build(), crushing = register("crushing", CrushingCategory::new).recipes(AllRecipeTypes.CRUSHING) .recipesExcluding(AllRecipeTypes.MILLING::getType, AllRecipeTypes.CRUSHING::getType) @@ -167,9 +170,10 @@ public class CreateJEI implements IModPlugin { .catalyst(AllItems.SAND_PAPER::get) .catalyst(AllItems.RED_SAND_PAPER::get) .build(), - + deploying = register("deploying", DeployingCategory::new) - .recipeList(() -> DeployerApplicationRecipe.convert(findRecipesByType(AllRecipeTypes.SANDPAPER_POLISHING.type))) + .recipeList( + () -> DeployerApplicationRecipe.convert(findRecipesByType(AllRecipeTypes.SANDPAPER_POLISHING.type))) .recipes(AllRecipeTypes.DEPLOYING) .catalyst(AllBlocks.DEPLOYER::get) .catalyst(AllBlocks.DEPOT::get) @@ -213,6 +217,11 @@ public class CreateJEI implements IModPlugin { return new CategoryBuilder(name, supplier); } + @Override + public void registerRecipeTransferHandlers(IRecipeTransferRegistration registration) { + registration.addRecipeTransferHandler(new BlueprintTransferHandler(), VanillaRecipeCategoryUid.CRAFTING); + } + @Override public void registerCategories(IRecipeCategoryRegistration registration) { allCategories.forEach(registration::addRecipeCategories); @@ -238,7 +247,8 @@ public class CreateJEI implements IModPlugin { registration.addGuiContainerHandler(SchematicTableScreen.class, slotMover); registration.addGuiContainerHandler(FilterScreen.class, slotMover); registration.addGuiContainerHandler(AttributeFilterScreen.class, slotMover); - registration.addGhostIngredientHandler(AbstractFilterScreen.class, new FilterGhostIngredientHandler()); + registration.addGhostIngredientHandler(AbstractFilterScreen.class, new GhostIngredientHandler()); + registration.addGhostIngredientHandler(BlueprintScreen.class, new GhostIngredientHandler()); } private class CategoryBuilder> { @@ -278,12 +288,12 @@ public class CreateJEI implements IModPlugin { return recipeList(list, null); } - public CategoryBuilder recipeList(Supplier>> list, Function, T> converter) { + public CategoryBuilder recipeList(Supplier>> list, + Function, T> converter) { recipeListConsumers.add(recipes -> { List> toAdd = list.get(); if (converter != null) - toAdd = toAdd - .stream() + toAdd = toAdd.stream() .map(converter) .collect(Collectors.toList()); recipes.addAll(toAdd); diff --git a/src/main/java/com/simibubi/create/compat/jei/FilterGhostIngredientHandler.java b/src/main/java/com/simibubi/create/compat/jei/GhostIngredientHandler.java similarity index 60% rename from src/main/java/com/simibubi/create/compat/jei/FilterGhostIngredientHandler.java rename to src/main/java/com/simibubi/create/compat/jei/GhostIngredientHandler.java index c5ee188cd..fc43997d2 100644 --- a/src/main/java/com/simibubi/create/compat/jei/FilterGhostIngredientHandler.java +++ b/src/main/java/com/simibubi/create/compat/jei/GhostIngredientHandler.java @@ -5,12 +5,10 @@ import java.util.List; import javax.annotation.ParametersAreNonnullByDefault; -import org.apache.logging.log4j.LogManager; - -import com.simibubi.create.content.logistics.item.filter.AbstractFilterContainer; -import com.simibubi.create.content.logistics.item.filter.AbstractFilterScreen; import com.simibubi.create.content.logistics.item.filter.AttributeFilterScreen; -import com.simibubi.create.content.logistics.item.filter.FilterScreenPacket; +import com.simibubi.create.foundation.gui.AbstractSimiContainerScreen; +import com.simibubi.create.foundation.gui.GhostItemContainer; +import com.simibubi.create.foundation.gui.GhostItemSubmitPacket; import com.simibubi.create.foundation.networking.AllPackets; import mcp.MethodsReturnNonnullByDefault; @@ -18,21 +16,20 @@ import mezz.jei.api.gui.handlers.IGhostIngredientHandler; import net.minecraft.client.renderer.Rectangle2d; import net.minecraft.inventory.container.Slot; import net.minecraft.item.ItemStack; -import net.minecraft.nbt.CompoundNBT; @MethodsReturnNonnullByDefault @ParametersAreNonnullByDefault -public class FilterGhostIngredientHandler - implements IGhostIngredientHandler> { +public class GhostIngredientHandler> + implements IGhostIngredientHandler> { @Override - public List> getTargets(AbstractFilterScreen gui, I ingredient, boolean doStart) { + public List> getTargets(AbstractSimiContainerScreen gui, I ingredient, boolean doStart) { List> targets = new ArrayList<>(); boolean isAttributeFilter = gui instanceof AttributeFilterScreen; if (ingredient instanceof ItemStack) { for (int i = 36; i < gui.getContainer().inventorySlots.size(); i++) { - targets.add(new FilterGhostTarget<>(gui, i - 36, isAttributeFilter)); + targets.add(new GhostTarget<>(gui, i - 36, isAttributeFilter)); // Only accept items in 1st slot. 2nd is used for functionality, don't wanna override that one if (isAttributeFilter) @@ -52,14 +49,14 @@ public class FilterGhostIngredientHandler return true; } - private static class FilterGhostTarget implements Target { + private static class GhostTarget> implements Target { private final Rectangle2d area; - private final AbstractFilterScreen gui; + private final AbstractSimiContainerScreen gui; private final int slotIndex; private final boolean isAttributeFilter; - public FilterGhostTarget(AbstractFilterScreen gui, int slotIndex, boolean isAttributeFilter) { + public GhostTarget(AbstractSimiContainerScreen gui, int slotIndex, boolean isAttributeFilter) { this.gui = gui; this.slotIndex = slotIndex; this.isAttributeFilter = isAttributeFilter; @@ -75,19 +72,14 @@ public class FilterGhostIngredientHandler @Override public void accept(I ingredient) { ItemStack stack = ((ItemStack) ingredient).copy(); - LogManager.getLogger() - .info(stack); stack.setCount(1); - gui.getContainer().filterInventory.setStackInSlot(slotIndex, stack); + gui.getContainer().ghostInventory.setStackInSlot(slotIndex, stack); if (isAttributeFilter) return; // sync new filter contents with server - CompoundNBT data = new CompoundNBT(); - data.putInt("Slot", slotIndex); - data.put("Item", stack.serializeNBT()); - AllPackets.channel.sendToServer(new FilterScreenPacket(FilterScreenPacket.Option.UPDATE_FILTER_ITEM, data)); + AllPackets.channel.sendToServer(new GhostItemSubmitPacket(stack, slotIndex)); } } } diff --git a/src/main/java/com/simibubi/create/content/curiosities/tools/BlueprintAssignCompleteRecipePacket.java b/src/main/java/com/simibubi/create/content/curiosities/tools/BlueprintAssignCompleteRecipePacket.java new file mode 100644 index 000000000..ae0afb30b --- /dev/null +++ b/src/main/java/com/simibubi/create/content/curiosities/tools/BlueprintAssignCompleteRecipePacket.java @@ -0,0 +1,49 @@ +package com.simibubi.create.content.curiosities.tools; + +import java.util.function.Supplier; + +import com.simibubi.create.foundation.networking.SimplePacketBase; + +import net.minecraft.entity.player.ServerPlayerEntity; +import net.minecraft.network.PacketBuffer; +import net.minecraft.util.ResourceLocation; +import net.minecraftforge.fml.network.NetworkEvent.Context; + +public class BlueprintAssignCompleteRecipePacket extends SimplePacketBase { + + private ResourceLocation recipeID; + + public BlueprintAssignCompleteRecipePacket(ResourceLocation recipeID) { + this.recipeID = recipeID; + } + + public BlueprintAssignCompleteRecipePacket(PacketBuffer buffer) { + recipeID = buffer.readResourceLocation(); + } + + @Override + public void write(PacketBuffer buffer) { + buffer.writeResourceLocation(recipeID); + } + + @Override + public void handle(Supplier context) { + context.get() + .enqueueWork(() -> { + ServerPlayerEntity player = context.get() + .getSender(); + if (player == null) + return; + if (player.openContainer instanceof BlueprintContainer) { + BlueprintContainer c = (BlueprintContainer) player.openContainer; + player.getServerWorld() + .getRecipeManager() + .getRecipe(recipeID) + .ifPresent(r -> BlueprintItem.assignCompleteRecipe(c.ghostInventory, r)); + } + }); + context.get() + .setPacketHandled(true); + } + +} diff --git a/src/main/java/com/simibubi/create/content/curiosities/tools/BlueprintContainer.java b/src/main/java/com/simibubi/create/content/curiosities/tools/BlueprintContainer.java new file mode 100644 index 000000000..8343b36b5 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/curiosities/tools/BlueprintContainer.java @@ -0,0 +1,172 @@ +package com.simibubi.create.content.curiosities.tools; + +import java.util.Optional; + +import com.simibubi.create.AllContainerTypes; +import com.simibubi.create.content.curiosities.tools.BlueprintEntity.BlueprintSection; +import com.simibubi.create.foundation.gui.GhostItemContainer; +import com.simibubi.create.foundation.gui.IClearableContainer; + +import net.minecraft.client.Minecraft; +import net.minecraft.entity.Entity; +import net.minecraft.entity.player.PlayerInventory; +import net.minecraft.entity.player.ServerPlayerEntity; +import net.minecraft.inventory.CraftingInventory; +import net.minecraft.inventory.container.Container; +import net.minecraft.inventory.container.ContainerType; +import net.minecraft.item.ItemStack; +import net.minecraft.item.crafting.ICraftingRecipe; +import net.minecraft.item.crafting.IRecipeType; +import net.minecraft.network.PacketBuffer; +import net.minecraft.network.play.server.SSetSlotPacket; +import net.minecraftforge.api.distmarker.Dist; +import net.minecraftforge.api.distmarker.OnlyIn; +import net.minecraftforge.items.IItemHandler; +import net.minecraftforge.items.ItemStackHandler; +import net.minecraftforge.items.SlotItemHandler; + +public class BlueprintContainer extends GhostItemContainer implements IClearableContainer { + + public BlueprintContainer(ContainerType type, int id, PlayerInventory inv, PacketBuffer extraData) { + super(type, id, inv, extraData); + } + + public BlueprintContainer(ContainerType type, int id, PlayerInventory inv, BlueprintSection section) { + super(type, id, inv, section); + } + + public static BlueprintContainer create(int id, PlayerInventory inv, BlueprintSection section) { + return new BlueprintContainer(AllContainerTypes.CRAFTING_BLUEPRINT.get(), id, inv, section); + } + + @Override + protected boolean allowRepeats() { + return true; + } + + @Override + protected void addSlots() { + addPlayerSlots(33, 137); + + int x = 29; + int y = 21; + int index = 0; + for (int row = 0; row < 3; ++row) + for (int col = 0; col < 3; ++col) + this.addSlot(new BlueprintCraftSlot(ghostInventory, index++, x + col * 18, y + row * 18)); + + addSlot(new BlueprintCraftSlot(ghostInventory, index++, 123, 40)); + addSlot(new SlotItemHandler(ghostInventory, index++, 135, 57)); + } + + public void onCraftMatrixChanged() { + if (contentHolder.getBlueprintWorld().isRemote) + return; + + ServerPlayerEntity serverplayerentity = (ServerPlayerEntity) player; + CraftingInventory craftingInventory = new BlueprintCraftingInventory(this, ghostInventory); + Optional optional = player.getServer() + .getRecipeManager() + .getRecipe(IRecipeType.CRAFTING, craftingInventory, player.getEntityWorld()); + + if (!optional.isPresent()) { + if (ghostInventory.getStackInSlot(9) + .isEmpty()) + return; + if (!contentHolder.inferredIcon) + return; + + ghostInventory.setStackInSlot(9, ItemStack.EMPTY); + serverplayerentity.connection.sendPacket(new SSetSlotPacket(windowId, 36 + 9, ItemStack.EMPTY)); + contentHolder.inferredIcon = false; + return; + } + + ICraftingRecipe icraftingrecipe = optional.get(); + ItemStack itemstack = icraftingrecipe.getCraftingResult(craftingInventory); + ghostInventory.setStackInSlot(9, itemstack); + contentHolder.inferredIcon = true; + ItemStack toSend = itemstack.copy(); + toSend.getOrCreateTag() + .putBoolean("InferredFromRecipe", true); + serverplayerentity.connection.sendPacket(new SSetSlotPacket(windowId, 36 + 9, toSend)); + } + + @Override + public void putStackInSlot(int p_75141_1_, ItemStack p_75141_2_) { + if (p_75141_1_ == 36 + 9) { + if (p_75141_2_.hasTag()) { + contentHolder.inferredIcon = p_75141_2_.getTag() + .getBoolean("InferredFromRecipe"); + p_75141_2_.getTag() + .remove("InferredFromRecipe"); + } else + contentHolder.inferredIcon = false; + } + super.putStackInSlot(p_75141_1_, p_75141_2_); + } + + @Override + protected ItemStackHandler createGhostInventory() { + return contentHolder.getItems(); + } + + @Override + protected void readData(BlueprintSection contentHolder) {} + + @Override + protected void saveData(BlueprintSection contentHolder) { + contentHolder.save(ghostInventory); + } + + @Override + @OnlyIn(Dist.CLIENT) + protected BlueprintSection createOnClient(PacketBuffer extraData) { + int entityID = extraData.readVarInt(); + int section = extraData.readVarInt(); + Entity entityByID = Minecraft.getInstance().world.getEntityByID(entityID); + if (!(entityByID instanceof BlueprintEntity)) + return null; + BlueprintEntity blueprintEntity = (BlueprintEntity) entityByID; + BlueprintSection blueprintSection = blueprintEntity.getSection(section); + return blueprintSection; + } + + static class BlueprintCraftingInventory extends CraftingInventory { + + public BlueprintCraftingInventory(Container container, ItemStackHandler items) { + super(container, 3, 3); + for (int y = 0; y < 3; y++) { + for (int x = 0; x < 3; x++) { + ItemStack stack = items.getStackInSlot(y * 3 + x); + setInventorySlotContents(y * 3 + x, stack == null ? ItemStack.EMPTY : stack.copy()); + } + } + } + + } + + class BlueprintCraftSlot extends SlotItemHandler { + + private int index; + + public BlueprintCraftSlot(IItemHandler itemHandler, int index, int xPosition, int yPosition) { + super(itemHandler, index, xPosition, yPosition); + this.index = index; + } + + @Override + public void onSlotChanged() { + super.onSlotChanged(); + if (index == 9 && getHasStack() && !contentHolder.getBlueprintWorld().isRemote) { + contentHolder.inferredIcon = false; + ServerPlayerEntity serverplayerentity = (ServerPlayerEntity) player; + serverplayerentity.connection.sendPacket(new SSetSlotPacket(windowId, 36 + 9, getStack())); + } + if (index < 9) + onCraftMatrixChanged(); + } + + } + +} \ No newline at end of file diff --git a/src/main/java/com/simibubi/create/content/curiosities/tools/BlueprintEntity.java b/src/main/java/com/simibubi/create/content/curiosities/tools/BlueprintEntity.java new file mode 100644 index 000000000..4f1728126 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/curiosities/tools/BlueprintEntity.java @@ -0,0 +1,527 @@ +package com.simibubi.create.content.curiosities.tools; + +import java.util.HashMap; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Optional; + +import javax.annotation.Nullable; + +import org.apache.commons.lang3.Validate; + +import com.simibubi.create.AllEntityTypes; +import com.simibubi.create.AllItems; +import com.simibubi.create.Create; +import com.simibubi.create.content.logistics.item.filter.FilterItem; +import com.simibubi.create.content.schematics.ISpecialEntityItemRequirement; +import com.simibubi.create.content.schematics.ItemRequirement; +import com.simibubi.create.content.schematics.ItemRequirement.ItemUseType; +import com.simibubi.create.foundation.networking.ISyncPersistentData; +import com.simibubi.create.foundation.utility.Couple; +import com.simibubi.create.foundation.utility.VecHelper; + +import net.minecraft.block.Block; +import net.minecraft.block.BlockState; +import net.minecraft.block.RedstoneDiodeBlock; +import net.minecraft.entity.Entity; +import net.minecraft.entity.EntitySize; +import net.minecraft.entity.EntityType; +import net.minecraft.entity.Pose; +import net.minecraft.entity.item.HangingEntity; +import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.entity.player.PlayerInventory; +import net.minecraft.entity.player.ServerPlayerEntity; +import net.minecraft.inventory.CraftingInventory; +import net.minecraft.inventory.container.Container; +import net.minecraft.inventory.container.INamedContainerProvider; +import net.minecraft.item.ItemStack; +import net.minecraft.item.crafting.ICraftingRecipe; +import net.minecraft.item.crafting.IRecipeType; +import net.minecraft.nbt.CompoundNBT; +import net.minecraft.network.IPacket; +import net.minecraft.network.PacketBuffer; +import net.minecraft.util.ActionResultType; +import net.minecraft.util.Direction; +import net.minecraft.util.Direction.Axis; +import net.minecraft.util.Hand; +import net.minecraft.util.NonNullList; +import net.minecraft.util.SoundCategory; +import net.minecraft.util.SoundEvents; +import net.minecraft.util.math.AxisAlignedBB; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.MathHelper; +import net.minecraft.util.math.RayTraceResult; +import net.minecraft.util.math.vector.Vector3d; +import net.minecraft.util.text.ITextComponent; +import net.minecraft.util.text.StringTextComponent; +import net.minecraft.world.GameRules; +import net.minecraft.world.World; +import net.minecraftforge.api.distmarker.Dist; +import net.minecraftforge.api.distmarker.OnlyIn; +import net.minecraftforge.common.ForgeHooks; +import net.minecraftforge.common.util.FakePlayer; +import net.minecraftforge.fml.common.registry.IEntityAdditionalSpawnData; +import net.minecraftforge.fml.hooks.BasicEventHooks; +import net.minecraftforge.fml.network.NetworkHooks; +import net.minecraftforge.items.IItemHandlerModifiable; +import net.minecraftforge.items.ItemStackHandler; +import net.minecraftforge.items.wrapper.InvWrapper; + +public class BlueprintEntity extends HangingEntity + implements IEntityAdditionalSpawnData, ISpecialEntityItemRequirement, ISyncPersistentData { + + protected int size; + protected Direction verticalOrientation; + + @SuppressWarnings("unchecked") + public BlueprintEntity(EntityType p_i50221_1_, World p_i50221_2_) { + super((EntityType) p_i50221_1_, p_i50221_2_); + size = 1; + } + + public BlueprintEntity(World world, BlockPos pos, Direction facing, Direction verticalOrientation) { + super(AllEntityTypes.CRAFTING_BLUEPRINT.get(), world, pos); + + for (int size = 3; size > 0; size--) { + this.size = size; + this.updateFacingWithBoundingBox(facing, verticalOrientation); + if (this.onValidSurface()) + break; + } + } + + public static EntityType.Builder build(EntityType.Builder builder) { + @SuppressWarnings("unchecked") + EntityType.Builder entityBuilder = (EntityType.Builder) builder; + return entityBuilder; + } + + @Override + public IPacket createSpawnPacket() { + return NetworkHooks.getEntitySpawningPacket(this); + } + + @Override + public void writeAdditional(CompoundNBT p_213281_1_) { + p_213281_1_.putByte("Facing", (byte) this.facingDirection.getIndex()); + p_213281_1_.putByte("Orientation", (byte) this.verticalOrientation.getIndex()); + p_213281_1_.putInt("Size", size); + super.writeAdditional(p_213281_1_); + } + + @Override + public void readAdditional(CompoundNBT p_70037_1_) { + this.facingDirection = Direction.byIndex(p_70037_1_.getByte("Facing")); + this.verticalOrientation = Direction.byIndex(p_70037_1_.getByte("Orientation")); + this.size = p_70037_1_.getInt("Size"); + super.readAdditional(p_70037_1_); + this.updateFacingWithBoundingBox(this.facingDirection, this.verticalOrientation); + } + + protected void updateFacingWithBoundingBox(Direction facing, Direction verticalOrientation) { + Validate.notNull(facing); + this.facingDirection = facing; + this.verticalOrientation = verticalOrientation; + if (facing.getAxis() + .isHorizontal()) { + this.rotationPitch = 0.0F; + this.rotationYaw = (float) (this.facingDirection.getHorizontalIndex() * 90); + } else { + this.rotationPitch = (float) (-90 * facing.getAxisDirection() + .getOffset()); + this.rotationYaw = verticalOrientation.getAxis() + .isHorizontal() ? 180 + verticalOrientation.getHorizontalAngle() : 0; + } + + this.prevRotationPitch = this.rotationPitch; + this.prevRotationYaw = this.rotationYaw; + this.updateBoundingBox(); + } + + @Override + protected float getEyeHeight(Pose p_213316_1_, EntitySize p_213316_2_) { + return 0; + } + + @Override + protected void updateBoundingBox() { + if (this.facingDirection == null) + return; + if (this.verticalOrientation == null) + return; + + Vector3d pos = Vector3d.of(hangingPosition) + .add(.5, .5, .5) + .subtract(Vector3d.of(facingDirection.getDirectionVec()) + .scale(0.46875)); + double d1 = pos.x; + double d2 = pos.y; + double d3 = pos.z; + this.setPos(d1, d2, d3); + + Axis axis = facingDirection.getAxis(); + if (size == 2) + pos = pos.add(Vector3d.of(axis.isHorizontal() ? facingDirection.rotateYCCW() + .getDirectionVec() + : verticalOrientation.rotateY() + .getDirectionVec()) + .scale(0.5)) + .add(Vector3d + .of(axis.isHorizontal() ? Direction.UP.getDirectionVec() + : facingDirection == Direction.UP ? verticalOrientation.getDirectionVec() + : verticalOrientation.getOpposite() + .getDirectionVec()) + .scale(0.5)); + + d1 = pos.x; + d2 = pos.y; + d3 = pos.z; + + double d4 = (double) this.getWidthPixels(); + double d5 = (double) this.getHeightPixels(); + double d6 = (double) this.getWidthPixels(); + Direction.Axis direction$axis = this.facingDirection.getAxis(); + switch (direction$axis) { + case X: + d4 = 1.0D; + break; + case Y: + d5 = 1.0D; + break; + case Z: + d6 = 1.0D; + } + + d4 = d4 / 32.0D; + d5 = d5 / 32.0D; + d6 = d6 / 32.0D; + this.setBoundingBox(new AxisAlignedBB(d1 - d4, d2 - d5, d3 - d6, d1 + d4, d2 + d5, d3 + d6)); + } + + public boolean onValidSurface() { + if (!world.isSpaceEmpty(this)) + return false; + + int i = Math.max(1, this.getWidthPixels() / 16); + int j = Math.max(1, this.getHeightPixels() / 16); + BlockPos blockpos = this.hangingPosition.offset(this.facingDirection.getOpposite()); + Direction upDirection = facingDirection.getAxis() + .isHorizontal() ? Direction.UP + : facingDirection == Direction.UP ? verticalOrientation : verticalOrientation.getOpposite(); + Direction direction = facingDirection.getAxis() + .isVertical() ? verticalOrientation.rotateY() : facingDirection.rotateYCCW(); + BlockPos.Mutable blockpos$mutable = new BlockPos.Mutable(); + + for (int k = 0; k < i; ++k) { + for (int l = 0; l < j; ++l) { + int i1 = (i - 1) / -2; + int j1 = (j - 1) / -2; + blockpos$mutable.setPos(blockpos) + .move(direction, k + i1) + .move(upDirection, l + j1); + BlockState blockstate = this.world.getBlockState(blockpos$mutable); + if (Block.hasEnoughSolidSide(this.world, blockpos$mutable, this.facingDirection)) + continue; + if (!blockstate.getMaterial() + .isSolid() && !RedstoneDiodeBlock.isDiode(blockstate)) { + return false; + } + } + } + + return this.world.getEntitiesInAABBexcluding(this, this.getBoundingBox(), IS_HANGING_ENTITY) + .isEmpty(); + } + + @Override + public int getWidthPixels() { + return 16 * size; + } + + @Override + public int getHeightPixels() { + return 16 * size; + } + + @Override + public void onBroken(@Nullable Entity p_110128_1_) { + if (!world.getGameRules() + .getBoolean(GameRules.DO_ENTITY_DROPS)) + return; + + playSound(SoundEvents.ENTITY_PAINTING_BREAK, 1.0F, 1.0F); + if (p_110128_1_ instanceof PlayerEntity) { + PlayerEntity playerentity = (PlayerEntity) p_110128_1_; + if (playerentity.abilities.isCreativeMode) { + return; + } + } + + entityDropItem(AllItems.CRAFTING_BLUEPRINT.asStack()); + } + + @Override + public ItemStack getPickedResult(RayTraceResult target) { + return AllItems.CRAFTING_BLUEPRINT.asStack(); + } + + @Override + public ItemRequirement getRequiredItems() { + return new ItemRequirement(ItemUseType.CONSUME, AllItems.CRAFTING_BLUEPRINT.get()); + } + + @Override + public void playPlaceSound() { + this.playSound(SoundEvents.ENTITY_PAINTING_PLACE, 1.0F, 1.0F); + } + + @Override + public void setLocationAndAngles(double p_70012_1_, double p_70012_3_, double p_70012_5_, float p_70012_7_, + float p_70012_8_) { + this.setPosition(p_70012_1_, p_70012_3_, p_70012_5_); + } + + @Override + @OnlyIn(Dist.CLIENT) + public void setPositionAndRotationDirect(double p_180426_1_, double p_180426_3_, double p_180426_5_, + float p_180426_7_, float p_180426_8_, int p_180426_9_, boolean p_180426_10_) { + BlockPos blockpos = + this.hangingPosition.add(p_180426_1_ - this.getX(), p_180426_3_ - this.getY(), p_180426_5_ - this.getZ()); + this.setPosition((double) blockpos.getX(), (double) blockpos.getY(), (double) blockpos.getZ()); + } + + @Override + public void writeSpawnData(PacketBuffer buffer) { + CompoundNBT compound = new CompoundNBT(); + writeAdditional(compound); + buffer.writeCompoundTag(compound); + buffer.writeCompoundTag(getPersistentData()); + } + + @Override + public void readSpawnData(PacketBuffer additionalData) { + readAdditional(additionalData.readCompoundTag()); + getPersistentData().merge(additionalData.readCompoundTag()); + } + + @Override + public ActionResultType applyPlayerInteraction(PlayerEntity player, Vector3d vec, Hand hand) { + if (player instanceof FakePlayer) + return ActionResultType.PASS; + + BlueprintSection section = getSectionAt(vec); + + if (!AllItems.WRENCH.isIn(player.getHeldItem(hand)) && !world.isRemote) { + boolean empty = true; + ItemStackHandler items = section.getItems(); + for (int i = 0; i < 9; i++) { + if (!items.getStackInSlot(i) + .isEmpty()) { + empty = false; + break; + } + } + + if (!empty) { + IItemHandlerModifiable playerInv = new InvWrapper(player.inventory); + boolean firstPass = true; + int amountCrafted = 0; + ForgeHooks.setCraftingPlayer(player); + Optional recipe = Optional.empty(); + + do { + Map stacksTaken = new HashMap<>(); + Map craftingGrid = new HashMap<>(); + boolean success = true; + + Search: for (int i = 0; i < 9; i++) { + ItemStack requestedItem = items.getStackInSlot(i); + if (requestedItem.isEmpty()) { + craftingGrid.put(i, ItemStack.EMPTY); + continue; + } + + for (int slot = 0; slot < playerInv.getSlots(); slot++) { + if (!FilterItem.test(world, playerInv.getStackInSlot(slot), requestedItem)) + continue; + ItemStack currentItem = playerInv.extractItem(slot, 1, false); + if (stacksTaken.containsKey(slot)) { + stacksTaken.get(slot) + .grow(1); + } else { + stacksTaken.put(slot, currentItem.copy()); + } + craftingGrid.put(i, currentItem); + continue Search; + } + + success = false; + break; + } + + if (success) { + CraftingInventory craftingInventory = new BlueprintCraftingInventory(craftingGrid); + + if (!recipe.isPresent()) + recipe = world.getRecipeManager() + .getRecipe(IRecipeType.CRAFTING, craftingInventory, world); + ItemStack result = recipe.filter(r -> r.matches(craftingInventory, world)) + .map(r -> r.getCraftingResult(craftingInventory)) + .orElse(ItemStack.EMPTY); + + if (result.isEmpty()) { + success = false; + } else if (result.getCount() + amountCrafted > 64) { + success = false; + } else { + amountCrafted += result.getCount(); + result.onCrafting(player.world, player, 1); + BasicEventHooks.firePlayerCraftingEvent(player, result, craftingInventory); + NonNullList nonnulllist = world.getRecipeManager() + .getRecipeNonNull(IRecipeType.CRAFTING, craftingInventory, world); + + if (firstPass) + world.playSound(null, player.getBlockPos(), SoundEvents.ENTITY_ITEM_PICKUP, + SoundCategory.PLAYERS, .2f, 1f + Create.RANDOM.nextFloat()); + player.inventory.placeItemBackInInventory(world, result); + for (ItemStack itemStack : nonnulllist) + player.inventory.placeItemBackInInventory(world, itemStack); + firstPass = false; + } + } + + if (!success) { + for (Entry entry : stacksTaken.entrySet()) + playerInv.insertItem(entry.getKey(), entry.getValue(), false); + break; + } + + } while (player.isSneaking()); + ForgeHooks.setCraftingPlayer(null); + + return ActionResultType.SUCCESS; + } + } + + int i = section.index; + if (!world.isRemote && player instanceof ServerPlayerEntity) { + NetworkHooks.openGui((ServerPlayerEntity) player, section, buf -> { + buf.writeVarInt(getEntityId()); + buf.writeVarInt(i); + }); + } + + return ActionResultType.SUCCESS; + } + + public BlueprintSection getSectionAt(Vector3d vec) { + int index = 0; + if (size > 1) { + vec = VecHelper.rotate(vec, rotationYaw, Axis.Y); + vec = VecHelper.rotate(vec, -rotationPitch, Axis.X); + vec = vec.add(0.5, 0.5, 0); + if (size == 3) + vec = vec.add(1, 1, 0); + int x = MathHelper.clamp(MathHelper.floor(vec.x), 0, size - 1); + int y = MathHelper.clamp(MathHelper.floor(vec.y), 0, size - 1); + index = x + y * size; + } + + BlueprintSection section = getSection(index); + return section; + } + + static class BlueprintCraftingInventory extends CraftingInventory { + + private static Container dummyContainer = new Container(null, -1) { + public boolean canInteractWith(PlayerEntity playerIn) { + return false; + } + }; + + public BlueprintCraftingInventory(Map items) { + super(dummyContainer, 3, 3); + for (int y = 0; y < 3; y++) { + for (int x = 0; x < 3; x++) { + ItemStack stack = items.get(y * 3 + x); + setInventorySlotContents(y * 3 + x, stack == null ? ItemStack.EMPTY : stack.copy()); + } + } + } + + } + + public CompoundNBT getOrCreateRecipeCompound() { + CompoundNBT persistentData = getPersistentData(); + if (!persistentData.contains("Recipes")) + persistentData.put("Recipes", new CompoundNBT()); + return persistentData.getCompound("Recipes"); + } + + private Map sectionCache = new HashMap<>(); + + public BlueprintSection getSection(int index) { + return sectionCache.computeIfAbsent(index, i -> new BlueprintSection(i)); + } + + class BlueprintSection implements INamedContainerProvider { + int index; + Couple cachedDisplayItems; + public boolean inferredIcon = false; + + public BlueprintSection(int index) { + this.index = index; + } + + public Couple getDisplayItems() { + if (cachedDisplayItems != null) + return cachedDisplayItems; + ItemStackHandler items = getItems(); + return cachedDisplayItems = Couple.create(items.getStackInSlot(9), items.getStackInSlot(10)); + } + + public ItemStackHandler getItems() { + ItemStackHandler newInv = new ItemStackHandler(11); + CompoundNBT list = getOrCreateRecipeCompound(); + CompoundNBT invNBT = list.getCompound(index + ""); + inferredIcon = list.getBoolean("InferredIcon"); + if (!invNBT.isEmpty()) + newInv.deserializeNBT(invNBT); + return newInv; + } + + public void save(ItemStackHandler inventory) { + CompoundNBT list = getOrCreateRecipeCompound(); + list.put(index + "", inventory.serializeNBT()); + list.putBoolean("InferredIcon", inferredIcon); + cachedDisplayItems = null; + if (!world.isRemote) + syncPersistentDataWithTracking(BlueprintEntity.this); + } + + public boolean isEntityAlive() { + return isAlive(); + } + + public World getBlueprintWorld() { + return world; + } + + @Override + public Container createMenu(int id, PlayerInventory inv, PlayerEntity player) { + return BlueprintContainer.create(id, inv, this); + } + + @Override + public ITextComponent getDisplayName() { + return new StringTextComponent(""); + } + + } + + @Override + public void onPersistentDataUpdated() { + sectionCache.clear(); + } + +} \ No newline at end of file diff --git a/src/main/java/com/simibubi/create/content/curiosities/tools/BlueprintItem.java b/src/main/java/com/simibubi/create/content/curiosities/tools/BlueprintItem.java new file mode 100644 index 000000000..aef821318 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/curiosities/tools/BlueprintItem.java @@ -0,0 +1,154 @@ +package com.simibubi.create.content.curiosities.tools; + +import java.util.Collection; + +import com.simibubi.create.AllItems; +import com.simibubi.create.content.logistics.item.filter.AttributeFilterContainer.WhitelistMode; +import com.simibubi.create.content.logistics.item.filter.FilterItem; +import com.simibubi.create.content.logistics.item.filter.ItemAttribute; + +import net.minecraft.entity.EntityType; +import net.minecraft.entity.item.HangingEntity; +import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.item.Item; +import net.minecraft.item.ItemStack; +import net.minecraft.item.ItemUseContext; +import net.minecraft.item.crafting.IRecipe; +import net.minecraft.item.crafting.Ingredient; +import net.minecraft.item.crafting.Ingredient.IItemList; +import net.minecraft.item.crafting.Ingredient.SingleItemList; +import net.minecraft.item.crafting.Ingredient.TagList; +import net.minecraft.item.crafting.ShapedRecipe; +import net.minecraft.nbt.CompoundNBT; +import net.minecraft.nbt.ListNBT; +import net.minecraft.util.ActionResultType; +import net.minecraft.util.Direction; +import net.minecraft.util.JSONUtils; +import net.minecraft.util.NonNullList; +import net.minecraft.util.ResourceLocation; +import net.minecraft.util.math.BlockPos; +import net.minecraft.world.World; +import net.minecraftforge.common.crafting.StackList; +import net.minecraftforge.fml.common.ObfuscationReflectionHelper; +import net.minecraftforge.items.ItemStackHandler; + +public class BlueprintItem extends Item { + + public BlueprintItem(Properties p_i48487_1_) { + super(p_i48487_1_); + } + + @Override + public ActionResultType onItemUse(ItemUseContext ctx) { + Direction face = ctx.getFace(); + PlayerEntity player = ctx.getPlayer(); + ItemStack stack = ctx.getItem(); + BlockPos pos = ctx.getPos() + .offset(face); + + if (player != null && !player.canPlayerEdit(pos, face, stack)) + return ActionResultType.FAIL; + + World world = ctx.getWorld(); + HangingEntity hangingentity = new BlueprintEntity(world, pos, face, face.getAxis() + .isHorizontal() ? Direction.DOWN : ctx.getPlacementHorizontalFacing()); + CompoundNBT compoundnbt = stack.getTag(); + + if (compoundnbt != null) + EntityType.applyItemNBT(world, player, hangingentity, compoundnbt); + if (!hangingentity.onValidSurface()) + return ActionResultType.CONSUME; + if (!world.isRemote) { + hangingentity.playPlaceSound(); + world.addEntity(hangingentity); + } + + stack.shrink(1); + return ActionResultType.success(world.isRemote); + } + + protected boolean canPlace(PlayerEntity p_200127_1_, Direction p_200127_2_, ItemStack p_200127_3_, + BlockPos p_200127_4_) { + return p_200127_1_.canPlayerEdit(p_200127_4_, p_200127_2_, p_200127_3_); + } + + public static void assignCompleteRecipe(ItemStackHandler inv, IRecipe recipe) { + NonNullList ingredients = recipe.getIngredients(); + + for (int i = 0; i < 9; i++) + inv.setStackInSlot(i, ItemStack.EMPTY); + inv.setStackInSlot(9, recipe.getRecipeOutput()); + + if (recipe instanceof ShapedRecipe) { + ShapedRecipe shapedRecipe = (ShapedRecipe) recipe; + for (int row = 0; row < shapedRecipe.getHeight(); row++) + for (int col = 0; col < shapedRecipe.getWidth(); col++) + inv.setStackInSlot(row * 3 + col, + convertIngredientToFilter(ingredients.get(row * shapedRecipe.getWidth() + col))); + } else { + for (int i = 0; i < ingredients.size(); i++) + inv.setStackInSlot(i, convertIngredientToFilter(ingredients.get(i))); + } + } + + private static ItemStack convertIngredientToFilter(Ingredient ingredient) { + Ingredient.IItemList[] acceptedItems = + ObfuscationReflectionHelper.getPrivateValue(Ingredient.class, ingredient, "field_199807_b"); + if (acceptedItems == null || acceptedItems.length > 18) + return ItemStack.EMPTY; + if (acceptedItems.length == 0) + return ItemStack.EMPTY; + if (acceptedItems.length == 1) + return convertIItemListToFilter(acceptedItems[0]); + + ItemStack result = AllItems.FILTER.asStack(); + ItemStackHandler filterItems = FilterItem.getFilterItems(result); + for (int i = 0; i < acceptedItems.length; i++) + filterItems.setStackInSlot(i, convertIItemListToFilter(acceptedItems[i])); + result.getOrCreateTag() + .put("Items", filterItems.serializeNBT()); + return result; + } + + private static ItemStack convertIItemListToFilter(IItemList itemList) { + Collection stacks = itemList.getStacks(); + if (itemList instanceof SingleItemList) { + for (ItemStack itemStack : stacks) + return itemStack; + } + + if (itemList instanceof TagList) { + ResourceLocation resourcelocation = new ResourceLocation(JSONUtils.getString(itemList.serialize(), "tag")); + ItemStack filterItem = AllItems.ATTRIBUTE_FILTER.asStack(); + filterItem.getOrCreateTag() + .putInt("WhitelistMode", WhitelistMode.WHITELIST_DISJ.ordinal()); + ListNBT attributes = new ListNBT(); + ItemAttribute at = new ItemAttribute.InTag(resourcelocation); + CompoundNBT compoundNBT = new CompoundNBT(); + at.serializeNBT(compoundNBT); + compoundNBT.putBoolean("Inverted", false); + attributes.add(compoundNBT); + filterItem.getOrCreateTag() + .put("MatchedAttributes", attributes); + return filterItem; + } + + if (itemList instanceof StackList) { + ItemStack result = AllItems.FILTER.asStack(); + ItemStackHandler filterItems = FilterItem.getFilterItems(result); + int i = 0; + for (ItemStack itemStack : stacks) { + if (i >= 18) + break; + filterItems.setStackInSlot(i++, itemStack); + } + CompoundNBT tag = result.getOrCreateTag(); + tag.put("Items", filterItems.serializeNBT()); + tag.putBoolean("RespectNBT", true); + return result; + } + + return ItemStack.EMPTY; + } + +} diff --git a/src/main/java/com/simibubi/create/content/curiosities/tools/BlueprintOverlayRenderer.java b/src/main/java/com/simibubi/create/content/curiosities/tools/BlueprintOverlayRenderer.java new file mode 100644 index 000000000..edb9b3e93 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/curiosities/tools/BlueprintOverlayRenderer.java @@ -0,0 +1,240 @@ +package com.simibubi.create.content.curiosities.tools; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Optional; + +import com.mojang.blaze3d.matrix.MatrixStack; +import com.mojang.blaze3d.systems.RenderSystem; +import com.simibubi.create.content.curiosities.tools.BlueprintEntity.BlueprintCraftingInventory; +import com.simibubi.create.content.curiosities.tools.BlueprintEntity.BlueprintSection; +import com.simibubi.create.content.logistics.item.filter.FilterItem; +import com.simibubi.create.foundation.gui.AllGuiTextures; +import com.simibubi.create.foundation.gui.GuiGameElement; +import com.simibubi.create.foundation.utility.AnimationTickHolder; +import com.simibubi.create.foundation.utility.Pair; + +import net.minecraft.client.Minecraft; +import net.minecraft.client.renderer.IRenderTypeBuffer; +import net.minecraft.inventory.CraftingInventory; +import net.minecraft.item.ItemStack; +import net.minecraft.item.Items; +import net.minecraft.item.crafting.ICraftingRecipe; +import net.minecraft.item.crafting.IRecipeType; +import net.minecraft.util.math.EntityRayTraceResult; +import net.minecraft.util.math.RayTraceResult; +import net.minecraft.util.math.RayTraceResult.Type; +import net.minecraft.util.text.TextFormatting; +import net.minecraftforge.items.ItemHandlerHelper; +import net.minecraftforge.items.ItemStackHandler; + +public class BlueprintOverlayRenderer { + + static boolean active; + static boolean empty; + static boolean lastSneakState; + static BlueprintSection lastTargetedSection; + + static List> ingredients = new ArrayList<>(); + static ItemStack result = ItemStack.EMPTY; + static boolean resultCraftable = false; + + public static void tick() { + Minecraft mc = Minecraft.getInstance(); + RayTraceResult mouseOver = mc.objectMouseOver; + BlueprintSection last = lastTargetedSection; + boolean sneak = mc.player.isSneaking(); + lastTargetedSection = null; + active = false; + if (mouseOver == null) + return; + if (mouseOver.getType() != Type.ENTITY) + return; + + EntityRayTraceResult entityRay = (EntityRayTraceResult) mouseOver; + if (!(entityRay.getEntity() instanceof BlueprintEntity)) + return; + + BlueprintEntity blueprintEntity = (BlueprintEntity) entityRay.getEntity(); + BlueprintSection sectionAt = blueprintEntity.getSectionAt(entityRay.getHitVec() + .subtract(blueprintEntity.getPositionVec())); + + lastTargetedSection = last; + active = true; + + if (sectionAt != lastTargetedSection || AnimationTickHolder.getTicks() % 10 == 0 || lastSneakState != sneak) + rebuild(sectionAt, sneak); + + lastTargetedSection = sectionAt; + lastSneakState = sneak; + } + + public static void rebuild(BlueprintSection sectionAt, boolean sneak) { + ItemStackHandler items = sectionAt.getItems(); + boolean empty = true; + for (int i = 0; i < 9; i++) { + if (!items.getStackInSlot(i) + .isEmpty()) { + empty = false; + break; + } + } + + BlueprintOverlayRenderer.empty = empty; + BlueprintOverlayRenderer.result = ItemStack.EMPTY; + + if (empty) + return; + + boolean firstPass = true; + boolean success = true; + Minecraft mc = Minecraft.getInstance(); + ItemStackHandler playerInv = new ItemStackHandler(mc.player.inventory.getSizeInventory()); + for (int i = 0; i < playerInv.getSlots(); i++) + playerInv.setStackInSlot(i, mc.player.inventory.getStackInSlot(i) + .copy()); + + int amountCrafted = 0; + Optional recipe = Optional.empty(); + Map craftingGrid = new HashMap<>(); + ingredients.clear(); + ItemStackHandler missingItems = new ItemStackHandler(64); + ItemStackHandler availableItems = new ItemStackHandler(64); + List newlyAdded = new ArrayList<>(); + List newlyMissing = new ArrayList<>(); + boolean invalid = false; + + do { + craftingGrid.clear(); + newlyAdded.clear(); + newlyMissing.clear(); + + Search: for (int i = 0; i < 9; i++) { + ItemStack requestedItem = items.getStackInSlot(i); + if (requestedItem.isEmpty()) { + craftingGrid.put(i, ItemStack.EMPTY); + continue; + } + + for (int slot = 0; slot < playerInv.getSlots(); slot++) { + if (!FilterItem.test(mc.world, playerInv.getStackInSlot(slot), requestedItem)) + continue; + ItemStack currentItem = playerInv.extractItem(slot, 1, false); + craftingGrid.put(i, currentItem); + newlyAdded.add(currentItem); + continue Search; + } + + success = false; + newlyMissing.add(requestedItem); + } + + if (success) { + CraftingInventory craftingInventory = new BlueprintCraftingInventory(craftingGrid); + if (!recipe.isPresent()) + recipe = mc.world.getRecipeManager() + .getRecipe(IRecipeType.CRAFTING, craftingInventory, mc.world); + ItemStack resultFromRecipe = recipe.filter(r -> r.matches(craftingInventory, mc.world)) + .map(r -> r.getCraftingResult(craftingInventory)) + .orElse(ItemStack.EMPTY); + + if (resultFromRecipe.isEmpty()) { + if (!recipe.isPresent()) + invalid = true; + success = false; + } else if (resultFromRecipe.getCount() + amountCrafted > 64) { + success = false; + } else { + amountCrafted += resultFromRecipe.getCount(); + if (result.isEmpty()) + result = resultFromRecipe.copy(); + else + result.grow(resultFromRecipe.getCount()); + resultCraftable = true; + firstPass = false; + } + } + + if (success || firstPass) { + newlyAdded.forEach(s -> ItemHandlerHelper.insertItemStacked(availableItems, s, false)); + newlyMissing.forEach(s -> ItemHandlerHelper.insertItemStacked(missingItems, s, false)); + } + + if (!success) { + if (firstPass) { + result = invalid ? ItemStack.EMPTY : items.getStackInSlot(9); + resultCraftable = false; + } + break; + } + + if (!sneak) + break; + + } while (success); + + for (int i = 0; i < 9; i++) { + ItemStack available = availableItems.getStackInSlot(i); + if (available.isEmpty()) + continue; + ingredients.add(Pair.of(available, true)); + } + for (int i = 0; i < 9; i++) { + ItemStack missing = missingItems.getStackInSlot(i); + if (missing.isEmpty()) + continue; + ingredients.add(Pair.of(missing, false)); + } + } + + public static void renderOverlay(MatrixStack ms, IRenderTypeBuffer buffer, int light, int overlay, + float partialTicks) { + if (!active || empty) + return; + + Minecraft mc = Minecraft.getInstance(); + int w = 30 + 21 * ingredients.size() + 21; + + int x = (mc.getWindow() + .getScaledWidth() - w) / 2; + int y = (int) (mc.getWindow() + .getScaledHeight() / 3f * 2); + + for (Pair pair : ingredients) { + RenderSystem.enableBlend(); + (pair.getSecond() ? AllGuiTextures.HOTSLOT_ACTIVE : AllGuiTextures.HOTSLOT).draw(ms, x, y); + ItemStack itemStack = pair.getFirst(); + GuiGameElement.of(itemStack) + .at(x + 3, y + 3) + .render(ms); + mc.getItemRenderer() + .renderItemOverlayIntoGUI(mc.fontRenderer, itemStack, x + 3, y + 3, + pair.getSecond() || itemStack.getCount() == 1 ? null + : TextFormatting.GOLD.toString() + itemStack.getCount()); + x += 21; + } + + x += 5; + RenderSystem.enableBlend(); + AllGuiTextures.HOTSLOT_ARROW.draw(ms, x, y + 4); + x += 25; + + if (result.isEmpty()) { + AllGuiTextures.HOTSLOT.draw(ms, x, y); + GuiGameElement.of(Items.BARRIER) + .at(x + 3, y + 3) + .render(ms); + } else { + (resultCraftable ? AllGuiTextures.HOTSLOT_SUPER_ACTIVE : AllGuiTextures.HOTSLOT).draw(ms, + resultCraftable ? x - 1 : x, resultCraftable ? y - 1 : y); + GuiGameElement.of(result) + .at(x + 3, y + 3) + .render(ms); + mc.getItemRenderer() + .renderItemOverlayIntoGUI(mc.fontRenderer, result, x + 3, y + 3, null); + } + } + +} diff --git a/src/main/java/com/simibubi/create/content/curiosities/tools/BlueprintRenderer.java b/src/main/java/com/simibubi/create/content/curiosities/tools/BlueprintRenderer.java new file mode 100644 index 000000000..13825d42c --- /dev/null +++ b/src/main/java/com/simibubi/create/content/curiosities/tools/BlueprintRenderer.java @@ -0,0 +1,116 @@ +package com.simibubi.create.content.curiosities.tools; + +import com.mojang.blaze3d.matrix.MatrixStack; +import com.simibubi.create.AllBlockPartials; +import com.simibubi.create.content.curiosities.tools.BlueprintEntity.BlueprintSection; +import com.simibubi.create.foundation.render.PartialBufferer; +import com.simibubi.create.foundation.render.SuperByteBuffer; +import com.simibubi.create.foundation.render.backend.core.PartialModel; +import com.simibubi.create.foundation.utility.Couple; +import com.simibubi.create.foundation.utility.MatrixStacker; + +import net.minecraft.block.Blocks; +import net.minecraft.client.Minecraft; +import net.minecraft.client.renderer.IRenderTypeBuffer; +import net.minecraft.client.renderer.RenderType; +import net.minecraft.client.renderer.WorldRenderer; +import net.minecraft.client.renderer.entity.EntityRenderer; +import net.minecraft.client.renderer.entity.EntityRendererManager; +import net.minecraft.client.renderer.model.ItemCameraTransforms.TransformType; +import net.minecraft.item.ItemStack; +import net.minecraft.util.ResourceLocation; +import net.minecraft.util.math.vector.Matrix3f; + +public class BlueprintRenderer extends EntityRenderer { + + public BlueprintRenderer(EntityRendererManager p_i46179_1_) { + super(p_i46179_1_); + } + + @Override + public void render(BlueprintEntity entity, float yaw, float pt, MatrixStack ms, IRenderTypeBuffer buffer, + int overlay) { + PartialModel partialModel = entity.size == 3 ? AllBlockPartials.CRAFTING_BLUEPRINT_3x3 + : entity.size == 2 ? AllBlockPartials.CRAFTING_BLUEPRINT_2x2 : AllBlockPartials.CRAFTING_BLUEPRINT_1x1; + SuperByteBuffer sbb = PartialBufferer.get(partialModel, Blocks.AIR.getDefaultState()); + int light = WorldRenderer.getLightmapCoordinates(entity.world, entity.getBlockPos()); + sbb.matrixStacker() + .rotateY(-yaw) + .rotateX(90.0F + entity.rotationPitch) + .translate(-.5, -1 / 32f, -.5); + if (entity.size == 2) + sbb.translate(.5, 0, -.5); + sbb.light(light) + .renderInto(ms, buffer.getBuffer(RenderType.getSolid())); + super.render(entity, yaw, pt, ms, buffer, light); + + ms.push(); + + MatrixStacker.of(ms) + .rotateY(-yaw) + .rotateX(entity.rotationPitch == -90 ? -45 : entity.rotationPitch == 0 ? -15 : -5); + Matrix3f copy = ms.peek() + .getNormal() + .copy(); + + ms.pop(); + ms.push(); + + MatrixStacker.of(ms) + .rotateY(-yaw) + .rotateX(entity.rotationPitch) + .translate(0, 0, 1 / 32f + .001); + + if (entity.size == 3) + ms.translate(-1, -1, 0); + + for (int x = 0; x < entity.size; x++) { + ms.push(); + for (int y = 0; y < entity.size; y++) { + BlueprintSection section = entity.getSection(x * entity.size + y); + Couple displayItems = section.getDisplayItems(); + ms.push(); + ms.scale(.5f, .5f, 1 / 1024f); + displayItems.forEachWithContext((stack, primary) -> { + if (stack.isEmpty()) + return; + + ms.push(); + if (!primary) { + ms.translate(0.325f, -0.325f, 1); + ms.scale(.625f, .625f, 1); + } + + Matrix3f n = ms.peek() + .getNormal(); + n.a00 = copy.a00; + n.a01 = copy.a01; + n.a02 = copy.a02; + n.a10 = copy.a10; + n.a11 = copy.a11; + n.a12 = copy.a12; + n.a20 = copy.a20; + n.a21 = copy.a21; + n.a22 = copy.a22; + + Minecraft.getInstance() + .getItemRenderer() + .renderItem(stack, TransformType.GUI, light, overlay, ms, buffer); + ms.pop(); + }); + ms.pop(); + ms.translate(1, 0, 0); + } + ms.pop(); + ms.translate(0, 1, 0); + } + + ms.pop(); + } + + @Override + public ResourceLocation getEntityTexture(BlueprintEntity p_110775_1_) { + return null; + } + +} diff --git a/src/main/java/com/simibubi/create/content/curiosities/tools/BlueprintScreen.java b/src/main/java/com/simibubi/create/content/curiosities/tools/BlueprintScreen.java new file mode 100644 index 000000000..d2183e6a4 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/curiosities/tools/BlueprintScreen.java @@ -0,0 +1,192 @@ +package com.simibubi.create.content.curiosities.tools; + +import static com.simibubi.create.foundation.gui.AllGuiTextures.PLAYER_INVENTORY; + +import java.util.Collections; +import java.util.LinkedList; +import java.util.List; + +import com.google.common.collect.ImmutableList; +import com.mojang.blaze3d.matrix.MatrixStack; +import com.simibubi.create.AllBlockPartials; +import com.simibubi.create.AllItems; +import com.simibubi.create.content.logistics.item.filter.FilterScreenPacket; +import com.simibubi.create.content.logistics.item.filter.FilterScreenPacket.Option; +import com.simibubi.create.foundation.gui.AbstractSimiContainerScreen; +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; +import com.simibubi.create.foundation.utility.Lang; + +import net.minecraft.client.renderer.Rectangle2d; +import net.minecraft.client.resources.I18n; +import net.minecraft.entity.player.PlayerInventory; +import net.minecraft.item.ItemStack; +import net.minecraft.util.text.ITextComponent; +import net.minecraft.util.text.TextFormatting; + +public class BlueprintScreen extends AbstractSimiContainerScreen { + + protected AllGuiTextures background; + private List extraAreas = Collections.emptyList(); + + private IconButton resetButton; + private IconButton confirmButton; + + public BlueprintScreen(BlueprintContainer container, PlayerInventory inv, ITextComponent title) { + super(container, inv, title); + this.background = AllGuiTextures.BLUEPRINT; + } + + @Override + protected void init() { + setWindowSize(background.width + 50, background.height + PLAYER_INVENTORY.height + 20); + super.init(); + widgets.clear(); + int x = guiLeft; + int offset = guiTop < 30 ? 30 - guiTop : 0; + extraAreas = + ImmutableList.of(new Rectangle2d(x, guiTop + offset, background.width + 70, background.height - offset)); + + resetButton = new IconButton(x + background.width - 62, guiTop + background.height - 24, AllIcons.I_TRASH); + confirmButton = new IconButton(x + background.width - 33, guiTop + background.height - 24, AllIcons.I_CONFIRM); + + widgets.add(resetButton); + widgets.add(confirmButton); + } + + @Override + protected void renderWindow(MatrixStack ms, int mouseX, int mouseY, float partialTicks) { + int x = guiLeft; + int y = guiTop; + background.draw(ms, this, x, y); + + int invX = guiLeft + 25; + int invY = y + background.height + 10; + PLAYER_INVENTORY.draw(ms, this, invX, invY); + + String localizedName = I18n.format(AllItems.CRAFTING_BLUEPRINT.get() + .getTranslationKey()); + textRenderer.draw(ms, playerInventory.getDisplayName(), invX + 7, invY + 6, 0x666666); + textRenderer.draw(ms, localizedName, x + 15, y + 4, 0xFFFFFF); + + GuiGameElement.of(AllBlockPartials.CRAFTING_BLUEPRINT_1x1).at(x + background.width + 20, guiTop + background.height - 35, 0) + .rotate(45, -45, 22.5f) + .scale(40) + .render(ms); + } + + @Override + protected void drawMouseoverTooltip(MatrixStack ms, int x, int y) { + if (!this.client.player.inventory.getItemStack() + .isEmpty() || this.hoveredSlot == null || this.hoveredSlot.getHasStack() + || hoveredSlot.inventory == container.playerInventory) { + super.drawMouseoverTooltip(ms, x, y); + return; + } + renderWrappedToolTip(ms, addToTooltip(new LinkedList<>(), hoveredSlot.getSlotIndex(), true), x, y, + textRenderer); + } + + @Override + public List getTooltipFromItem(ItemStack stack) { + List list = super.getTooltipFromItem(stack); + if (hoveredSlot.inventory == container.playerInventory) + return list; + return hoveredSlot != null ? addToTooltip(list, hoveredSlot.getSlotIndex(), false) : list; + } + + private List addToTooltip(List list, int slot, boolean isEmptySlot) { + if (slot < 0 || slot > 10) + return list; + + if (slot < 9) { + list.add(Lang.createTranslationTextComponent("crafting_blueprint.crafting_slot") + .formatted(TextFormatting.GOLD)); + if (isEmptySlot) + list.add(Lang.createTranslationTextComponent("crafting_blueprint.filter_items_viable") + .formatted(TextFormatting.GRAY)); + + } else if (slot == 9) { + list.add(Lang.createTranslationTextComponent("crafting_blueprint.display_slot") + .formatted(TextFormatting.GOLD)); + if (!isEmptySlot) + list.add(Lang + .createTranslationTextComponent("crafting_blueprint." + + (container.contentHolder.inferredIcon ? "inferred" : "manually_assigned")) + .formatted(TextFormatting.GRAY)); + + } else if (slot == 10) { + list.add(Lang.createTranslationTextComponent("crafting_blueprint.secondary_display_slot") + .formatted(TextFormatting.GOLD)); + if (isEmptySlot) + list.add(Lang.createTranslationTextComponent("crafting_blueprint.optional") + .formatted(TextFormatting.GRAY)); + } + + return list; + } + + @Override + public void tick() { +// handleTooltips(); + super.tick(); + + if (!container.contentHolder.isEntityAlive()) + client.player.closeScreen(); + } + +// protected void handleTooltips() { +// List tooltipButtons = getTooltipButtons(); +// +// for (IconButton button : tooltipButtons) { +// if (!button.getToolTip() +// .isEmpty()) { +// button.setToolTip(button.getToolTip() +// .get(0)); +// button.getToolTip() +// .add(TooltipHelper.holdShift(Palette.Yellow, hasShiftDown())); +// } +// } +// +// if (hasShiftDown()) { +// List tooltipDescriptions = getTooltipDescriptions(); +// for (int i = 0; i < tooltipButtons.size(); i++) +// fillToolTip(tooltipButtons.get(i), tooltipDescriptions.get(i)); +// } +// } + + @Override + public boolean mouseClicked(double x, double y, int button) { + boolean mouseClicked = super.mouseClicked(x, y, button); + + if (button == 0) { + if (confirmButton.isHovered()) { + client.player.closeScreen(); + return true; + } + if (resetButton.isHovered()) { + container.clearContents(); + contentsCleared(); + container.sendClearPacket(); + return true; + } + } + + return mouseClicked; + } + + protected void contentsCleared() {} + + protected void sendOptionUpdate(Option option) { + AllPackets.channel.sendToServer(new FilterScreenPacket(option)); + } + + @Override + public List getExtraAreas() { + return extraAreas; + } +} diff --git a/src/main/java/com/simibubi/create/content/logistics/item/LinkedControllerScreen.java b/src/main/java/com/simibubi/create/content/logistics/item/LinkedControllerScreen.java index 24a7acab3..37b4ef40b 100644 --- a/src/main/java/com/simibubi/create/content/logistics/item/LinkedControllerScreen.java +++ b/src/main/java/com/simibubi/create/content/logistics/item/LinkedControllerScreen.java @@ -38,7 +38,8 @@ public class LinkedControllerScreen extends AbstractSimiContainerScreen getTooltipFromItem(ItemStack stack) { List list = super.getTooltipFromItem(stack); + if (hoveredSlot.inventory == container.playerInventory) + return list; return hoveredSlot != null ? addToTooltip(list, hoveredSlot.getSlotIndex()) : list; } diff --git a/src/main/java/com/simibubi/create/content/logistics/item/filter/AbstractFilterContainer.java b/src/main/java/com/simibubi/create/content/logistics/item/filter/AbstractFilterContainer.java index ef433e77e..3e3bc612f 100644 --- a/src/main/java/com/simibubi/create/content/logistics/item/filter/AbstractFilterContainer.java +++ b/src/main/java/com/simibubi/create/content/logistics/item/filter/AbstractFilterContainer.java @@ -1,145 +1,58 @@ package com.simibubi.create.content.logistics.item.filter; -import com.simibubi.create.foundation.gui.IClearableContainer; +import com.simibubi.create.foundation.gui.GhostItemContainer; import net.minecraft.entity.player.PlayerEntity; import net.minecraft.entity.player.PlayerInventory; import net.minecraft.inventory.container.ClickType; -import net.minecraft.inventory.container.Container; import net.minecraft.inventory.container.ContainerType; -import net.minecraft.inventory.container.Slot; import net.minecraft.item.ItemStack; import net.minecraft.network.PacketBuffer; -import net.minecraftforge.items.ItemHandlerHelper; -import net.minecraftforge.items.ItemStackHandler; +import net.minecraftforge.api.distmarker.Dist; +import net.minecraftforge.api.distmarker.OnlyIn; -public abstract class AbstractFilterContainer extends Container implements IClearableContainer { - - public PlayerEntity player; - protected PlayerInventory playerInventory; - public ItemStack filterItem; - public ItemStackHandler filterInventory; +public abstract class AbstractFilterContainer extends GhostItemContainer { protected AbstractFilterContainer(ContainerType type, int id, PlayerInventory inv, PacketBuffer extraData) { - this(type, id, inv, extraData.readItemStack()); + super(type, id, inv, extraData); } - protected AbstractFilterContainer(ContainerType type, int id, PlayerInventory inv, ItemStack filterItem) { - super(type, id); - player = inv.player; - playerInventory = inv; - this.filterItem = filterItem; - init(); - } - - protected void init() { - this.filterInventory = createFilterInventory(); - readData(filterItem); - addPlayerSlots(); - addFilterSlots(); - detectAndSendChanges(); - } - - @Override - public void clearContents() { - for (int i = 0; i < filterInventory.getSlots(); i++) - filterInventory.setStackInSlot(i, ItemStack.EMPTY); - } - - protected abstract int getInventoryOffset(); - - protected abstract void addFilterSlots(); - - protected abstract ItemStackHandler createFilterInventory(); - - protected abstract void readData(ItemStack filterItem); - - protected abstract void saveData(ItemStack filterItem); - - protected void addPlayerSlots() { - int x = 8; - int y = 28 + getInventoryOffset(); - - for (int hotbarSlot = 0; hotbarSlot < 9; ++hotbarSlot) - this.addSlot(new Slot(playerInventory, hotbarSlot, x + hotbarSlot * 18, y + 58)); - for (int row = 0; row < 3; ++row) - for (int col = 0; col < 9; ++col) - this.addSlot(new Slot(playerInventory, col + row * 9 + 9, x + col * 18, y + row * 18)); - } - - @Override - public boolean canMergeSlot(ItemStack stack, Slot slotIn) { - return canDragIntoSlot(slotIn); - } - - @Override - public boolean canDragIntoSlot(Slot slotIn) { - return slotIn.inventory == playerInventory; - } - - @Override - public boolean canInteractWith(PlayerEntity playerIn) { - return true; + protected AbstractFilterContainer(ContainerType type, int id, PlayerInventory inv, ItemStack contentHolder) { + super(type, id, inv, contentHolder); } @Override public ItemStack slotClick(int slotId, int dragType, ClickType clickTypeIn, PlayerEntity player) { if (slotId == playerInventory.currentItem && clickTypeIn != ClickType.THROW) return ItemStack.EMPTY; - - ItemStack held = playerInventory.getItemStack(); - if (slotId < 36) - return super.slotClick(slotId, dragType, clickTypeIn, player); - if (clickTypeIn == ClickType.THROW) - return ItemStack.EMPTY; - - int slot = slotId - 36; - if (clickTypeIn == ClickType.CLONE) { - if (player.isCreative() && held.isEmpty()) { - ItemStack stackInSlot = filterInventory.getStackInSlot(slot).copy(); - stackInSlot.setCount(64); - playerInventory.setItemStack(stackInSlot); - return ItemStack.EMPTY; - } - return ItemStack.EMPTY; - } - - if (held.isEmpty()) { - filterInventory.setStackInSlot(slot, ItemStack.EMPTY); - return ItemStack.EMPTY; - } - - ItemStack insert = held.copy(); - insert.setCount(1); - filterInventory.setStackInSlot(slot, insert); - return held; + return super.slotClick(slotId, dragType, clickTypeIn, player); } @Override - public ItemStack transferStackInSlot(PlayerEntity playerIn, int index) { - if (index < 36) { - ItemStack stackToInsert = playerInventory.getStackInSlot(index); - for (int i = 0; i < filterInventory.getSlots(); i++) { - ItemStack stack = filterInventory.getStackInSlot(i); - if (ItemHandlerHelper.canItemStacksStack(stack, stackToInsert)) - break; - if (stack.isEmpty()) { - ItemStack copy = stackToInsert.copy(); - copy.setCount(1); - filterInventory.insertItem(i, copy, false); - break; - } - } - } else - filterInventory.extractItem(index - 36, 1, false); - return ItemStack.EMPTY; + protected boolean allowRepeats() { + return false; } @Override - public void onContainerClosed(PlayerEntity playerIn) { - super.onContainerClosed(playerIn); - filterItem.getOrCreateTag().put("Items", filterInventory.serializeNBT()); - saveData(filterItem); + @OnlyIn(Dist.CLIENT) + protected ItemStack createOnClient(PacketBuffer extraData) { + return extraData.readItemStack(); + } + + protected abstract int getPlayerInventoryXOffset(); + + protected abstract void addFilterSlots(); + + @Override + protected void addSlots() { + addPlayerSlots(8, 28 + getPlayerInventoryXOffset()); + addFilterSlots(); + } + + @Override + protected void saveData(ItemStack contentHolder) { + contentHolder.getOrCreateTag() + .put("Items", ghostInventory.serializeNBT()); } } 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 de8703059..8202b29a6 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 @@ -66,9 +66,9 @@ public abstract class AbstractFilterScreen ex int invY = y + background.height + 10; PLAYER_INVENTORY.draw(ms, this, invX, invY); textRenderer.draw(ms, playerInventory.getDisplayName(), invX + 7, invY + 6, 0x666666); - textRenderer.draw(ms, I18n.format(container.filterItem.getTranslationKey()), x + 15, y + 3, 0xdedede); + textRenderer.draw(ms, I18n.format(container.contentHolder.getTranslationKey()), x + 15, y + 3, 0xdedede); - GuiGameElement.of(container.filterItem) + GuiGameElement.of(container.contentHolder) .at(x + background.width, guiTop + background.height - 60, -200) .scale(5) .render(ms); @@ -82,7 +82,7 @@ public abstract class AbstractFilterScreen ex handleIndicators(); if (!container.player.getHeldItemMainhand() - .equals(container.filterItem, false)) + .equals(container.contentHolder, false)) client.player.closeScreen(); } 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 487f801d7..210689b69 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 @@ -53,22 +53,22 @@ public class AttributeFilterContainer extends AbstractFilterContainer { } @Override - protected void init() { - super.init(); + protected void init(PlayerInventory inv, ItemStack contentHolder) { + super.init(inv, contentHolder); ItemStack stack = new ItemStack(Items.NAME_TAG); stack.setDisplayName( new StringTextComponent("Selected Tags").formatted(TextFormatting.RESET, TextFormatting.BLUE)); - filterInventory.setStackInSlot(1, stack); + ghostInventory.setStackInSlot(1, stack); } @Override - protected ItemStackHandler createFilterInventory() { + protected ItemStackHandler createGhostInventory() { return new ItemStackHandler(2); } protected void addFilterSlots() { - this.addSlot(new SlotItemHandler(filterInventory, 0, -34, 22)); - this.addSlot(new SlotItemHandler(filterInventory, 1, -28, 57) { + this.addSlot(new SlotItemHandler(ghostInventory, 0, -34, 22)); + this.addSlot(new SlotItemHandler(ghostInventory, 1, -28, 57) { @Override public boolean canTakeStack(PlayerEntity playerIn) { return false; @@ -102,20 +102,20 @@ public class AttributeFilterContainer extends AbstractFilterContainer { if (index == 37) return ItemStack.EMPTY; if (index == 36) { - filterInventory.setStackInSlot(37, ItemStack.EMPTY); + ghostInventory.setStackInSlot(37, ItemStack.EMPTY); return ItemStack.EMPTY; } if (index < 36) { ItemStack stackToInsert = playerInventory.getStackInSlot(index); ItemStack copy = stackToInsert.copy(); copy.setCount(1); - filterInventory.setStackInSlot(0, copy); + ghostInventory.setStackInSlot(0, copy); } return ItemStack.EMPTY; } @Override - protected int getInventoryOffset() { + protected int getPlayerInventoryXOffset() { return 83; } @@ -134,6 +134,7 @@ public class AttributeFilterContainer extends AbstractFilterContainer { @Override protected void saveData(ItemStack filterItem) { + super.saveData(filterItem); filterItem.getOrCreateTag() .putInt("WhitelistMode", whitelistMode.ordinal()); ListNBT attributes = new ListNBT(); @@ -141,7 +142,8 @@ public class AttributeFilterContainer extends AbstractFilterContainer { if (at == null) return; CompoundNBT compoundNBT = new CompoundNBT(); - at.getFirst().serializeNBT(compoundNBT); + at.getFirst() + .serializeNBT(compoundNBT); compoundNBT.putBoolean("Inverted", at.getSecond()); attributes.add(compoundNBT); }); 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 b71172708..9a016fc0f 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 @@ -91,7 +91,7 @@ public class AttributeFilterScreen extends AbstractFilterScreen extends Container implements IClearableContainer { + + public PlayerEntity player; + public PlayerInventory playerInventory; + public ItemStackHandler ghostInventory; + public T contentHolder; + + protected GhostItemContainer(ContainerType type, int id, PlayerInventory inv, PacketBuffer extraData) { + super(type, id); + init(inv, createOnClient(extraData)); + } + + protected GhostItemContainer(ContainerType type, int id, PlayerInventory inv, T contentHolder) { + super(type, id); + init(inv, contentHolder); + } + + @OnlyIn(Dist.CLIENT) + protected abstract T createOnClient(PacketBuffer extraData); + + protected abstract void addSlots(); + + protected abstract ItemStackHandler createGhostInventory(); + + protected abstract void readData(T contentHolder); + + protected abstract void saveData(T contentHolder); + + protected abstract boolean allowRepeats(); + + protected void init(PlayerInventory inv, T contentHolder) { + player = inv.player; + playerInventory = inv; + this.contentHolder = contentHolder; + ghostInventory = createGhostInventory(); + readData(contentHolder); + addSlots(); + detectAndSendChanges(); + } + + @Override + public void clearContents() { + for (int i = 0; i < ghostInventory.getSlots(); i++) + ghostInventory.setStackInSlot(i, ItemStack.EMPTY); + } + + protected void addPlayerSlots(int x, int y) { + for (int hotbarSlot = 0; hotbarSlot < 9; ++hotbarSlot) + this.addSlot(new Slot(playerInventory, hotbarSlot, x + hotbarSlot * 18, y + 58)); + for (int row = 0; row < 3; ++row) + for (int col = 0; col < 9; ++col) + this.addSlot(new Slot(playerInventory, col + row * 9 + 9, x + col * 18, y + row * 18)); + } + + @Override + public boolean canMergeSlot(ItemStack stack, Slot slotIn) { + return slotIn.inventory == playerInventory; + } + + @Override + public boolean canDragIntoSlot(Slot slotIn) { + if (allowRepeats()) + return true; + return slotIn.inventory == playerInventory; + } + + @Override + public boolean canInteractWith(PlayerEntity playerIn) { + return true; + } + + @Override + public ItemStack slotClick(int slotId, int dragType, ClickType clickTypeIn, PlayerEntity player) { + ItemStack held = playerInventory.getItemStack(); + if (slotId < 36) + return super.slotClick(slotId, dragType, clickTypeIn, player); + if (clickTypeIn == ClickType.THROW) + return ItemStack.EMPTY; + + int slot = slotId - 36; + if (clickTypeIn == ClickType.CLONE) { + if (player.isCreative() && held.isEmpty()) { + ItemStack stackInSlot = ghostInventory.getStackInSlot(slot) + .copy(); + stackInSlot.setCount(stackInSlot.getMaxStackSize()); + playerInventory.setItemStack(stackInSlot); + return ItemStack.EMPTY; + } + return ItemStack.EMPTY; + } + + if (held.isEmpty()) { + ghostInventory.setStackInSlot(slot, ItemStack.EMPTY); + getSlot(slotId).onSlotChanged(); + return ItemStack.EMPTY; + } + + ItemStack insert = held.copy(); + insert.setCount(1); + ghostInventory.setStackInSlot(slot, insert); + getSlot(slotId).onSlotChanged(); + return held; + } + + @Override + public ItemStack transferStackInSlot(PlayerEntity playerIn, int index) { + if (index < 36) { + ItemStack stackToInsert = playerInventory.getStackInSlot(index); + for (int i = 0; i < ghostInventory.getSlots(); i++) { + ItemStack stack = ghostInventory.getStackInSlot(i); + if (!allowRepeats() && ItemHandlerHelper.canItemStacksStack(stack, stackToInsert)) + break; + if (stack.isEmpty()) { + ItemStack copy = stackToInsert.copy(); + copy.setCount(1); + ghostInventory.insertItem(i, copy, false); + getSlot(i + 36).onSlotChanged(); + break; + } + } + } else { + ghostInventory.extractItem(index - 36, 1, false); + getSlot(index).onSlotChanged(); + } + return ItemStack.EMPTY; + } + + @Override + public void onContainerClosed(PlayerEntity playerIn) { + super.onContainerClosed(playerIn); + saveData(contentHolder); + } + +} diff --git a/src/main/java/com/simibubi/create/foundation/gui/GhostItemSubmitPacket.java b/src/main/java/com/simibubi/create/foundation/gui/GhostItemSubmitPacket.java new file mode 100644 index 000000000..286711dcd --- /dev/null +++ b/src/main/java/com/simibubi/create/foundation/gui/GhostItemSubmitPacket.java @@ -0,0 +1,53 @@ +package com.simibubi.create.foundation.gui; + +import java.util.function.Supplier; + +import com.simibubi.create.foundation.networking.SimplePacketBase; + +import net.minecraft.entity.player.ServerPlayerEntity; +import net.minecraft.item.ItemStack; +import net.minecraft.network.PacketBuffer; +import net.minecraftforge.fml.network.NetworkEvent.Context; + +public class GhostItemSubmitPacket extends SimplePacketBase { + + private final ItemStack item; + private final int slot; + + public GhostItemSubmitPacket(ItemStack item, int slot) { + this.item = item; + this.slot = slot; + } + + public GhostItemSubmitPacket(PacketBuffer buffer) { + item = buffer.readItemStack(); + slot = buffer.readInt(); + } + + @Override + public void write(PacketBuffer buffer) { + buffer.writeItemStack(item); + buffer.writeInt(slot); + } + + @Override + public void handle(Supplier context) { + context.get() + .enqueueWork(() -> { + ServerPlayerEntity player = context.get() + .getSender(); + if (player == null) + return; + + if (player.openContainer instanceof GhostItemContainer) { + GhostItemContainer c = (GhostItemContainer) player.openContainer; + c.ghostInventory.setStackInSlot(slot, item); + c.getSlot(36 + slot).onSlotChanged(); + } + + }); + context.get() + .setPacketHandled(true); + } + +} 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 26cb098a5..c41418f15 100644 --- a/src/main/java/com/simibubi/create/foundation/networking/AllPackets.java +++ b/src/main/java/com/simibubi/create/foundation/networking/AllPackets.java @@ -22,6 +22,7 @@ import com.simibubi.create.content.contraptions.components.structureMovement.tra import com.simibubi.create.content.contraptions.fluids.actors.FluidSplashPacket; import com.simibubi.create.content.contraptions.relays.advanced.sequencer.ConfigureSequencedGearshiftPacket; import com.simibubi.create.content.curiosities.symmetry.SymmetryEffectPacket; +import com.simibubi.create.content.curiosities.tools.BlueprintAssignCompleteRecipePacket; import com.simibubi.create.content.curiosities.tools.ExtendoGripInteractionPacket; import com.simibubi.create.content.curiosities.zapper.ZapperBeamPacket; import com.simibubi.create.content.logistics.block.depot.EjectorElytraPacket; @@ -44,6 +45,7 @@ import com.simibubi.create.foundation.command.HighlightPacket; import com.simibubi.create.foundation.command.SConfigureConfigPacket; import com.simibubi.create.foundation.config.ui.CConfigureConfigPacket; import com.simibubi.create.foundation.gui.ClearContainerPacket; +import com.simibubi.create.foundation.gui.GhostItemSubmitPacket; import com.simibubi.create.foundation.tileEntity.behaviour.filtering.FilteringCountUpdatePacket; import com.simibubi.create.foundation.tileEntity.behaviour.scrollvalue.ScrollValueUpdatePacket; import com.simibubi.create.foundation.utility.ServerSpeedProvider; @@ -88,6 +90,8 @@ public enum AllPackets { LINKED_CONTROLLER_INPUT(LinkedControllerInputPacket.class, LinkedControllerInputPacket::new, PLAY_TO_SERVER), LINKED_CONTROLLER_BIND(LinkedControllerBindPacket.class, LinkedControllerBindPacket::new, PLAY_TO_SERVER), C_CONFIGURE_CONFIG(CConfigureConfigPacket.class, CConfigureConfigPacket::new, PLAY_TO_SERVER), + SUBMIT_GHOST_ITEM(GhostItemSubmitPacket.class, GhostItemSubmitPacket::new, PLAY_TO_SERVER), + BLUEPRINT_COMPLETE_RECIPE(BlueprintAssignCompleteRecipePacket.class, BlueprintAssignCompleteRecipePacket::new, PLAY_TO_SERVER), // Server to Client SYMMETRY_EFFECT(SymmetryEffectPacket.class, SymmetryEffectPacket::new, PLAY_TO_CLIENT), @@ -106,6 +110,7 @@ public enum AllPackets { BLOCK_HIGHLIGHT(HighlightPacket.class, HighlightPacket::new, PLAY_TO_CLIENT), TUNNEL_FLAP(TunnelFlapPacket.class, TunnelFlapPacket::new, PLAY_TO_CLIENT), FUNNEL_FLAP(FunnelFlapPacket.class, FunnelFlapPacket::new, PLAY_TO_CLIENT), + PERSISTENT_DATA(ISyncPersistentData.Packet.class, ISyncPersistentData.Packet::new, PLAY_TO_CLIENT), ; diff --git a/src/main/java/com/simibubi/create/foundation/networking/ISyncPersistentData.java b/src/main/java/com/simibubi/create/foundation/networking/ISyncPersistentData.java new file mode 100644 index 000000000..0bd2e9117 --- /dev/null +++ b/src/main/java/com/simibubi/create/foundation/networking/ISyncPersistentData.java @@ -0,0 +1,64 @@ +package com.simibubi.create.foundation.networking; + +import java.util.Iterator; +import java.util.function.Supplier; + +import net.minecraft.client.Minecraft; +import net.minecraft.entity.Entity; +import net.minecraft.nbt.CompoundNBT; +import net.minecraft.network.PacketBuffer; +import net.minecraftforge.fml.network.NetworkEvent.Context; +import net.minecraftforge.fml.network.PacketDistributor; + +public interface ISyncPersistentData { + + void onPersistentDataUpdated(); + + default void syncPersistentDataWithTracking(Entity self) { + AllPackets.channel.send(PacketDistributor.TRACKING_ENTITY.with(() -> self), new Packet(self)); + } + + public static class Packet extends SimplePacketBase { + + private int entityId; + private Entity entity; + private CompoundNBT readData; + + public Packet(Entity entity) { + this.entity = entity; + this.entityId = entity.getEntityId(); + } + + public Packet(PacketBuffer buffer) { + entityId = buffer.readInt(); + readData = buffer.readCompoundTag(); + } + + @Override + public void write(PacketBuffer buffer) { + buffer.writeInt(entityId); + buffer.writeCompoundTag(entity.getPersistentData()); + } + + @Override + public void handle(Supplier context) { + context.get() + .enqueueWork(() -> { + Entity entityByID = Minecraft.getInstance().world.getEntityByID(entityId); + if (!(entityByID instanceof ISyncPersistentData)) + return; + CompoundNBT data = entityByID.getPersistentData(); + for (Iterator iterator = data.keySet() + .iterator(); iterator.hasNext();) { + data.remove(iterator.next()); + } + data.merge(readData); + ((ISyncPersistentData) entityByID).onPersistentDataUpdated(); + }); + context.get() + .setPacketHandled(true); + } + + } + +} diff --git a/src/main/resources/assets/create/lang/default/messages.json b/src/main/resources/assets/create/lang/default/messages.json index ce2e8e7e6..a0b4fc711 100644 --- a/src/main/resources/assets/create/lang/default/messages.json +++ b/src/main/resources/assets/create/lang/default/messages.json @@ -470,6 +470,14 @@ "create.linked_controller.frequency_slot_1": "Keybind: %1$s, Freq. #1", "create.linked_controller.frequency_slot_2": "Keybind: %1$s, Freq. #2", + "create.crafting_blueprint.crafting_slot": "Ingredient Slot", + "create.crafting_blueprint.filter_items_viable": "Advanced filter items are viable", + "create.crafting_blueprint.display_slot": "Display Slot", + "create.crafting_blueprint.inferred": "Inferred from recipe", + "create.crafting_blueprint.manually_assigned": "Manually assigned", + "create.crafting_blueprint.secondary_display_slot": "Secondary Display Slot", + "create.crafting_blueprint.optional": "Optional", + "create.hint.hose_pulley.title": "Bottomless Supply", "create.hint.hose_pulley": "The targeted body of fluid is considered infinite.", "create.hint.mechanical_arm_no_targets.title": "No Targets", diff --git a/src/main/resources/assets/create/models/entity/crafting_blueprint_large.json b/src/main/resources/assets/create/models/entity/crafting_blueprint_large.json new file mode 100644 index 000000000..f00cdee84 --- /dev/null +++ b/src/main/resources/assets/create/models/entity/crafting_blueprint_large.json @@ -0,0 +1,21 @@ +{ + "credit": "Made with Blockbench", + "textures": { + "0": "create:entity/blueprint_large", + "particle": "create:entity/blueprint_large" + }, + "elements": [ + { + "from": [-16, 0, -16], + "to": [32, 1, 32], + "faces": { + "north": {"uv": [0, 0, 12, 0.25], "rotation": 180, "texture": "#0"}, + "east": {"uv": [11.75, 0, 12, 12], "rotation": 90, "texture": "#0"}, + "south": {"uv": [0, 11.75, 12, 12], "texture": "#0"}, + "west": {"uv": [0, 0, 0.25, 12], "rotation": 270, "texture": "#0"}, + "up": {"uv": [0, 0, 12, 12], "texture": "#0"}, + "down": {"uv": [0, 0, 12, 12], "rotation": 270, "texture": "#0"} + } + } + ] +} \ No newline at end of file diff --git a/src/main/resources/assets/create/models/entity/crafting_blueprint_medium.json b/src/main/resources/assets/create/models/entity/crafting_blueprint_medium.json new file mode 100644 index 000000000..0c092f1d2 --- /dev/null +++ b/src/main/resources/assets/create/models/entity/crafting_blueprint_medium.json @@ -0,0 +1,21 @@ +{ + "credit": "Made with Blockbench", + "textures": { + "0": "create:entity/blueprint_medium", + "particle": "create:entity/blueprint_medium" + }, + "elements": [ + { + "from": [-8, 0, -8], + "to": [24, 1, 24], + "faces": { + "north": {"uv": [0, 0, 16, 0.5], "rotation": 180, "texture": "#0"}, + "east": {"uv": [0, 15.5, 16, 16], "rotation": 180, "texture": "#0"}, + "south": {"uv": [0, 15.5, 16, 16], "texture": "#0"}, + "west": {"uv": [0, 0, 0.5, 16], "rotation": 270, "texture": "#0"}, + "up": {"uv": [0, 0, 16, 16], "texture": "#0"}, + "down": {"uv": [0, 0, 16, 16], "rotation": 270, "texture": "#0"} + } + } + ] +} \ No newline at end of file diff --git a/src/main/resources/assets/create/models/entity/crafting_blueprint_small.json b/src/main/resources/assets/create/models/entity/crafting_blueprint_small.json new file mode 100644 index 000000000..1dcc69deb --- /dev/null +++ b/src/main/resources/assets/create/models/entity/crafting_blueprint_small.json @@ -0,0 +1,21 @@ +{ + "credit": "Made with Blockbench", + "textures": { + "0": "create:entity/blueprint_small", + "particle": "create:entity/blueprint_small" + }, + "elements": [ + { + "from": [0, 0, 0], + "to": [16, 1, 16], + "faces": { + "north": {"uv": [0, 0, 16, 1], "rotation": 180, "texture": "#0"}, + "east": {"uv": [0, 15, 16, 16], "rotation": 180, "texture": "#0"}, + "south": {"uv": [0, 15, 16, 16], "texture": "#0"}, + "west": {"uv": [0, 0, 1, 16], "rotation": 270, "texture": "#0"}, + "up": {"uv": [0, 0, 16, 16], "texture": "#0"}, + "down": {"uv": [0, 0, 16, 16], "rotation": 270, "texture": "#0"} + } + } + ] +} \ No newline at end of file diff --git a/src/main/resources/assets/create/textures/entity/blueprint_large.png b/src/main/resources/assets/create/textures/entity/blueprint_large.png new file mode 100644 index 000000000..6df19d1c5 Binary files /dev/null and b/src/main/resources/assets/create/textures/entity/blueprint_large.png differ diff --git a/src/main/resources/assets/create/textures/entity/blueprint_medium.png b/src/main/resources/assets/create/textures/entity/blueprint_medium.png new file mode 100644 index 000000000..cbb319665 Binary files /dev/null and b/src/main/resources/assets/create/textures/entity/blueprint_medium.png differ diff --git a/src/main/resources/assets/create/textures/entity/blueprint_small.png b/src/main/resources/assets/create/textures/entity/blueprint_small.png new file mode 100644 index 000000000..df49c6070 Binary files /dev/null and b/src/main/resources/assets/create/textures/entity/blueprint_small.png differ diff --git a/src/main/resources/assets/create/textures/gui/curiosities2.png b/src/main/resources/assets/create/textures/gui/curiosities2.png index 26fce588c..c20b9d645 100644 Binary files a/src/main/resources/assets/create/textures/gui/curiosities2.png and b/src/main/resources/assets/create/textures/gui/curiosities2.png differ diff --git a/src/main/resources/assets/create/textures/gui/widgets.png b/src/main/resources/assets/create/textures/gui/widgets.png index 33cfed66c..3588a5cfc 100644 Binary files a/src/main/resources/assets/create/textures/gui/widgets.png and b/src/main/resources/assets/create/textures/gui/widgets.png differ diff --git a/src/main/resources/assets/create/textures/item/crafting_blueprint.png b/src/main/resources/assets/create/textures/item/crafting_blueprint.png new file mode 100644 index 000000000..4481759f1 Binary files /dev/null and b/src/main/resources/assets/create/textures/item/crafting_blueprint.png differ