Merge branch 'mc1.18/dev' into mc1.18/global-railways

This commit is contained in:
simibubi 2022-05-22 18:10:40 +02:00
commit 841bf3f350
101 changed files with 5877 additions and 4786 deletions

View file

@ -49,6 +49,7 @@ body:
label: Mod Version label: Mod Version
description: The version of the mod you were using when the bug occured description: The version of the mod you were using when the bug occured
options: options:
- "0.4.1"
- "0.4.0f" - "0.4.0f"
- "0.4.0e" - "0.4.0e"
- "0.4.0d" - "0.4.0d"
@ -101,6 +102,7 @@ body:
label: Minecraft Version label: Minecraft Version
description: The version of Minecraft you were using when the bug occured description: The version of Minecraft you were using when the bug occured
options: options:
- "1.18.2"
- "1.18.1" - "1.18.1"
- "1.18" - "1.18"
- "1.17.1" - "1.17.1"

View file

@ -11,14 +11,13 @@ Welcome to Create, a mod offering a variety of tools and blocks for Building, De
The added elements of tech are designed to leave as many design choices to the player as possible, where item processing doesn't happen inside a single block with funny textures, it requires a set of actors working together in many possible arrangements. The added elements of tech are designed to leave as many design choices to the player as possible, where item processing doesn't happen inside a single block with funny textures, it requires a set of actors working together in many possible arrangements.
Check out the wiki and in-game Tool-tips for further info on how to use these features, and stay tuned for an ever-growing selection of possibilities for Creative and Survival Minecraft. Check out the in-game Documentation for further info on how to use the added features, and stay tuned for an ever-growing selection of possibilities for Creative and Survival Minecraft.
[<img src="https://i.imgur.com/0lLX9Oy.jpg" width="200">](https://github.com/Creators-of-Create/Create/issues "Report Issues") [<img src="https://i.imgur.com/0lLX9Oy.jpg" width="200">](https://github.com/Creators-of-Create/Create/issues "Report Issues")
[<img src="https://i.imgur.com/bjEZraY.jpg" width="200">](https://www.youtube.com/channel/UCrKV2QTuyGcv4E3eSJpBiYA/playlists "Watch Videos") [<img src="https://i.imgur.com/bjEZraY.jpg" width="200">](https://www.youtube.com/channel/UCrKV2QTuyGcv4E3eSJpBiYA/playlists "Watch Videos")
[<img src="https://i.imgur.com/aWrjfKJ.jpg" width="200">](https://discord.gg/hmaD7Se "Feedback & Help") [<img src="https://i.imgur.com/aWrjfKJ.jpg" width="200">](https://discord.gg/hmaD7Se "Feedback & Help")
[<img src="https://i.imgur.com/xj8o2xC.jpg" width="200">](https://www.patreon.com/simibubi "Support Us") [<img src="https://i.imgur.com/xj8o2xC.jpg" width="200">](https://www.patreon.com/simibubi "Support Us")
- Support for Minecraft 1.12: Not planned
- Support for Fabric: Not planned
<hr> <hr>
<h4 align="center">Find out more about Create on our <a href="https://www.curseforge.com/minecraft/mc-mods/create">Project Page</a></h4> <h4 align="center">Find out more about Create on our <a href="https://www.curseforge.com/minecraft/mc-mods/create">Project Page</a></h4>
<h4 align="center">Looking for the Fabric port? <a href="https://github.com/Fabricators-of-Create/Create">Find it here</a></h4>

View file

@ -135,6 +135,10 @@ repositories {
//location of the maven for dynamic trees //location of the maven for dynamic trees
url 'https://harleyoconnor.com/maven' url 'https://harleyoconnor.com/maven'
} }
maven {
//location of the maven for curios api
url = "https://maven.theillusivec4.top/"
}
} }
configurations { configurations {
@ -157,6 +161,9 @@ dependencies {
compileOnly fg.deobf("mezz.jei:jei-${jei_minecraft_version}:${jei_version}:api") compileOnly fg.deobf("mezz.jei:jei-${jei_minecraft_version}:${jei_version}:api")
runtimeOnly fg.deobf("mezz.jei:jei-${jei_minecraft_version}:${jei_version}") runtimeOnly fg.deobf("mezz.jei:jei-${jei_minecraft_version}:${jei_version}")
compileOnly fg.deobf("top.theillusivec4.curios:curios-forge:${curios_minecraft_version}-${curios_version}:api")
runtimeOnly fg.deobf("top.theillusivec4.curios:curios-forge:${curios_minecraft_version}-${curios_version}")
// implementation fg.deobf("curse.maven:druidcraft-340991:3101903") // implementation fg.deobf("curse.maven:druidcraft-340991:3101903")
// implementation fg.deobf("com.ferreusveritas.dynamictrees:DynamicTrees-1.16.5:0.10.0-Beta25") // implementation fg.deobf("com.ferreusveritas.dynamictrees:DynamicTrees-1.16.5:0.10.0-Beta25")
// runtimeOnly fg.deobf("vazkii.arl:AutoRegLib:1.4-35.69") // runtimeOnly fg.deobf("vazkii.arl:AutoRegLib:1.4-35.69")

View file

@ -6,7 +6,7 @@ org.gradle.daemon = false
# mod version info # mod version info
mod_version = 0.5.0 mod_version = 0.5.0
minecraft_version = 1.18.2 minecraft_version = 1.18.2
forge_version = 40.0.34 forge_version = 40.1.0
# build dependency versions # build dependency versions
forgegradle_version = 5.1.+ forgegradle_version = 5.1.+
@ -19,9 +19,11 @@ parchment_version = 2022.03.13
# dependency versions # dependency versions
registrate_version = MC1.18.2-1.0.25 registrate_version = MC1.18.2-1.0.25
flywheel_version = 1.18-0.6.2.66 flywheel_version = 1.18-0.7.0.67
jei_minecraft_version = 1.18.2 jei_minecraft_version = 1.18.2
jei_version = 9.5.3.143 jei_version = 9.5.3.143
curios_minecraft_version = 1.18.2
curios_version = 5.0.7.0
# curseforge information # curseforge information
projectId = 328085 projectId = 328085

View file

@ -546,20 +546,20 @@ bf2b0310500213ff853c748c236eb5d01f61658e assets/create/blockstates/yellow_toolbo
b7181bcd8182b2f17088e5aa881f374c9c65470c assets/create/blockstates/zinc_ore.json b7181bcd8182b2f17088e5aa881f374c9c65470c assets/create/blockstates/zinc_ore.json
bc34b2c5574a903a43729369b32c8981a4098ac1 assets/create/lang/en_ud.json bc34b2c5574a903a43729369b32c8981a4098ac1 assets/create/lang/en_ud.json
8ff43211f8611542dc2b80125eabe13153bc1fbf assets/create/lang/en_us.json 8ff43211f8611542dc2b80125eabe13153bc1fbf assets/create/lang/en_us.json
4c857eab126af9dba639b6483e02628f81cc46fb assets/create/lang/unfinished/de_de.json 8bf1cfb8b68fd54b9cb796360beba73d83b2ec7f assets/create/lang/unfinished/de_de.json
0ce3a240ac9fa0b44674cf886a71dfe43f2bd164 assets/create/lang/unfinished/es_cl.json 0ce3a240ac9fa0b44674cf886a71dfe43f2bd164 assets/create/lang/unfinished/es_cl.json
bc0318d36ad5249bcfe7dd526372137fd8af86b6 assets/create/lang/unfinished/es_es.json 3b28c641fdb7ff5eee3b81ffc7b6f37ce38194e3 assets/create/lang/unfinished/es_es.json
c15da57f79901b1cddbf6fa3d94e953480ab9467 assets/create/lang/unfinished/fr_fr.json c15da57f79901b1cddbf6fa3d94e953480ab9467 assets/create/lang/unfinished/fr_fr.json
c2e763d4e611143f9a42c0a6a0b8cfa58f254b37 assets/create/lang/unfinished/it_it.json c2e763d4e611143f9a42c0a6a0b8cfa58f254b37 assets/create/lang/unfinished/it_it.json
5a173ee5e1f6b5a6ffeff2b301c28e9f75eb762c assets/create/lang/unfinished/ja_jp.json 5a173ee5e1f6b5a6ffeff2b301c28e9f75eb762c assets/create/lang/unfinished/ja_jp.json
a1d09b3588d98762d0fa56fece59e600507311da assets/create/lang/unfinished/ko_kr.json a1d09b3588d98762d0fa56fece59e600507311da assets/create/lang/unfinished/ko_kr.json
9ad05595229b0ac2ef8d8b21d43dc86396167485 assets/create/lang/unfinished/nl_nl.json 9ad05595229b0ac2ef8d8b21d43dc86396167485 assets/create/lang/unfinished/nl_nl.json
76052baa07a1c9d34a5e98e75e1c7f8a935076c9 assets/create/lang/unfinished/pl_pl.json 76052baa07a1c9d34a5e98e75e1c7f8a935076c9 assets/create/lang/unfinished/pl_pl.json
d6fc8c6f6a1e88021d21546d5363c425863e4204 assets/create/lang/unfinished/pt_br.json f7dd233fa675c1c2c1ff6c4402c16744c6189616 assets/create/lang/unfinished/pt_br.json
541b9a302d8ddf3827f29a7ab67b482e345bc207 assets/create/lang/unfinished/pt_pt.json 541b9a302d8ddf3827f29a7ab67b482e345bc207 assets/create/lang/unfinished/pt_pt.json
69ba5f485d16706f5438856162fcc337d23c5400 assets/create/lang/unfinished/ro_ro.json 69ba5f485d16706f5438856162fcc337d23c5400 assets/create/lang/unfinished/ro_ro.json
64431b39b4cfa1fe1988ec8c4f36145e66714847 assets/create/lang/unfinished/ru_ru.json 64431b39b4cfa1fe1988ec8c4f36145e66714847 assets/create/lang/unfinished/ru_ru.json
1dd6ff7ee8d61c16bed0583a5f5d4567f5c76257 assets/create/lang/unfinished/zh_cn.json 54faaacfdf8aa4ee3575fbc9ee6e81b5f9bcffe0 assets/create/lang/unfinished/zh_cn.json
e8db253724c9b2eeb07b4587d3efb10811941df5 assets/create/lang/unfinished/zh_tw.json e8db253724c9b2eeb07b4587d3efb10811941df5 assets/create/lang/unfinished/zh_tw.json
487a511a01b2a4531fb672f917922312db78f958 assets/create/models/block/acacia_window.json 487a511a01b2a4531fb672f917922312db78f958 assets/create/models/block/acacia_window.json
b48060cba1a382f373a05bf0039054053eccf076 assets/create/models/block/acacia_window_pane_noside.json b48060cba1a382f373a05bf0039054053eccf076 assets/create/models/block/acacia_window_pane_noside.json
@ -4180,7 +4180,7 @@ a7c97582bae243ab04ff5ff9914b24af25d40d59 data/create/recipes/crushing/iron_horse
554b6555888fe01de349efaaab36b68a338ac397 data/create/recipes/crushing/iron_ore.json 554b6555888fe01de349efaaab36b68a338ac397 data/create/recipes/crushing/iron_ore.json
c9a9d6d28a7eac1210108d52840b60b26d58bcfe data/create/recipes/crushing/lapis_ore.json c9a9d6d28a7eac1210108d52840b60b26d58bcfe data/create/recipes/crushing/lapis_ore.json
e870d049abc5cd5f389f70414c67e76ddc14060d data/create/recipes/crushing/leather_horse_armor.json e870d049abc5cd5f389f70414c67e76ddc14060d data/create/recipes/crushing/leather_horse_armor.json
cc5a817901d6f0d68e4ceb3e65d7f2187ab37ceb data/create/recipes/crushing/nether_gold_ore.json cab15acd2d62f1d70e0972b443f7987048d5183a data/create/recipes/crushing/nether_gold_ore.json
6cd97c6f12687790943db810f85036b02586c753 data/create/recipes/crushing/nether_quartz_ore.json 6cd97c6f12687790943db810f85036b02586c753 data/create/recipes/crushing/nether_quartz_ore.json
6e424d7e9f7d8b585384053a713db28f9d36448b data/create/recipes/crushing/nether_wart_block.json 6e424d7e9f7d8b585384053a713db28f9d36448b data/create/recipes/crushing/nether_wart_block.json
8003e7db3ee11066b365c251f04f84028820de94 data/create/recipes/crushing/netherrack.json 8003e7db3ee11066b365c251f04f84028820de94 data/create/recipes/crushing/netherrack.json

View file

@ -1,5 +1,5 @@
{ {
"_": "Missing Localizations: 240", "_": "Missing Localizations: 233",
"_": "->------------------------] Game Elements [------------------------<-", "_": "->------------------------] Game Elements [------------------------<-",
@ -582,12 +582,12 @@
"item.create.chromatic_compound": "Compuesto cromático", "item.create.chromatic_compound": "Compuesto cromático",
"item.create.cinder_flour": "Harina del Nether", "item.create.cinder_flour": "Harina del Nether",
"item.create.copper_backtank": "Depósito trasero de cobre", "item.create.copper_backtank": "Depósito trasero de cobre",
"item.create.copper_backtank_placeable": "UNLOCALIZED: Copper Backtank Placeable", "item.create.copper_backtank_placeable": "Depósito de cobre colocable",
"item.create.copper_nugget": "Pepita de cobre", "item.create.copper_nugget": "Pepita de cobre",
"item.create.copper_sheet": "Lámina de cobre", "item.create.copper_sheet": "Lámina de cobre",
"item.create.crafter_slot_cover": "Tapa de ranura del ensamblador mecánico", "item.create.crafter_slot_cover": "Tapa de ranura del ensamblador mecánico",
"item.create.crafting_blueprint": "Plano de elaboración", "item.create.crafting_blueprint": "Plano de elaboración",
"item.create.creative_blaze_cake": "´Pastel de blaze creativo", "item.create.creative_blaze_cake": "Pastel de blaze creativo",
"item.create.crushed_aluminum_ore": "Mineral de aluminio molido", "item.create.crushed_aluminum_ore": "Mineral de aluminio molido",
"item.create.crushed_copper_ore": "Mineral de cobre molido", "item.create.crushed_copper_ore": "Mineral de cobre molido",
"item.create.crushed_gold_ore": "Mineral de oro molido", "item.create.crushed_gold_ore": "Mineral de oro molido",
@ -654,7 +654,7 @@
"advancement.create.root": "Bienvenido a Create", "advancement.create.root": "Bienvenido a Create",
"advancement.create.root.desc": "¡Es hora de empezar a construir increíbles artefactos animados!", "advancement.create.root.desc": "¡Es hora de empezar a construir increíbles artefactos animados!",
"advancement.create.andesite_alloy": "UNLOCALIZED: Alliterations Aplenty", "advancement.create.andesite_alloy": "Aliteraciones a montones",
"advancement.create.andesite_alloy.desc": "Los materiales de Create tienen nombres extraños, la aleación de andesita es uno de ellos.", "advancement.create.andesite_alloy.desc": "Los materiales de Create tienen nombres extraños, la aleación de andesita es uno de ellos.",
"advancement.create.its_alive": "¡Está vivo!", "advancement.create.its_alive": "¡Está vivo!",
"advancement.create.its_alive.desc": "Mira cómo gira tu primer componente cinético.", "advancement.create.its_alive.desc": "Mira cómo gira tu primer componente cinético.",
@ -840,8 +840,8 @@
"create.recipe.fan_washing.fan": "Ventilador detrás del agua fluyente", "create.recipe.fan_washing.fan": "Ventilador detrás del agua fluyente",
"create.recipe.fan_smoking": "Ahumador a granel", "create.recipe.fan_smoking": "Ahumador a granel",
"create.recipe.fan_smoking.fan": "Ventilador detrás del fuego", "create.recipe.fan_smoking.fan": "Ventilador detrás del fuego",
"create.recipe.fan_haunting": "UNLOCALIZED: Bulk Haunting", "create.recipe.fan_haunting": "Maldecidor a granel",
"create.recipe.fan_haunting.fan": "UNLOCALIZED: Fan behind Soul Fire", "create.recipe.fan_haunting.fan": "Ventilador detrás del fuego de alma",
"create.recipe.fan_blasting": "Voladuras a granel", "create.recipe.fan_blasting": "Voladuras a granel",
"create.recipe.fan_blasting.fan": "Ventilador detrás de la lava", "create.recipe.fan_blasting.fan": "Ventilador detrás de la lava",
"create.recipe.pressing": "Prensando", "create.recipe.pressing": "Prensando",
@ -1193,8 +1193,8 @@
"create.item_attributes.furnace_fuel.inverted": "no es combustible para hornos", "create.item_attributes.furnace_fuel.inverted": "no es combustible para hornos",
"create.item_attributes.washable": "se puede lavar", "create.item_attributes.washable": "se puede lavar",
"create.item_attributes.washable.inverted": "no se puede lavar", "create.item_attributes.washable.inverted": "no se puede lavar",
"create.item_attributes.hauntable": "UNLOCALIZED: can be Haunted", "create.item_attributes.hauntable": "puede ser maldito",
"create.item_attributes.hauntable.inverted": "UNLOCALIZED: cannot be Haunted", "create.item_attributes.hauntable.inverted": "no puede ser maldito",
"create.item_attributes.crushable": "puede ser molido", "create.item_attributes.crushable": "puede ser molido",
"create.item_attributes.crushable.inverted": "no puede ser molido", "create.item_attributes.crushable.inverted": "no puede ser molido",
"create.item_attributes.smeltable": "se puede fundir", "create.item_attributes.smeltable": "se puede fundir",
@ -1259,7 +1259,7 @@
"create.tooltip.keyCtrl": "Ctrl", "create.tooltip.keyCtrl": "Ctrl",
"create.tooltip.speedRequirement": "Requisitos de velocidad: %1$s", "create.tooltip.speedRequirement": "Requisitos de velocidad: %1$s",
"create.tooltip.speedRequirement.none": "Ninguno", "create.tooltip.speedRequirement.none": "Ninguno",
"create.tooltip.speedRequirement.slow": "UNLOCALIZED: Slow", "create.tooltip.speedRequirement.slow": "Lento",
"create.tooltip.speedRequirement.medium": "Moderado", "create.tooltip.speedRequirement.medium": "Moderado",
"create.tooltip.speedRequirement.fast": "Rápido", "create.tooltip.speedRequirement.fast": "Rápido",
"create.tooltip.stressImpact": "Impacto de estrés: %1$s", "create.tooltip.stressImpact": "Impacto de estrés: %1$s",

View file

@ -1,5 +1,5 @@
{ {
"_": "Missing Localizations: 1409", "_": "Missing Localizations: 1103",
"_": "->------------------------] Game Elements [------------------------<-", "_": "->------------------------] Game Elements [------------------------<-",
@ -823,16 +823,16 @@
"death.attack.create.cuckoo_clock_explosion.player": "%1$s foi explodido por relógio cuco adulterado", "death.attack.create.cuckoo_clock_explosion.player": "%1$s foi explodido por relógio cuco adulterado",
"death.attack.create.run_over": "UNLOCALIZED: %1$s was run over by %2$s", "death.attack.create.run_over": "UNLOCALIZED: %1$s was run over by %2$s",
"create.block.deployer.damage_source_name": "UNLOCALIZED: a rogue Deployer", "create.block.deployer.damage_source_name": "Implantador rebelde",
"create.block.cart_assembler.invalid": "UNLOCALIZED: Place your Cart Assembler on a rail block", "create.block.cart_assembler.invalid": "Coloque o seu montador de carrinho de minas num trilho",
"create.menu.return": "UNLOCALIZED: Return to Menu", "create.menu.return": "Retornar ao menu",
"create.menu.configure": "UNLOCALIZED: Configure...", "create.menu.configure": "Configurar...",
"create.menu.ponder_index": "UNLOCALIZED: Ponder Index", "create.menu.ponder_index": "Tabela do ponderamento",
"create.menu.only_ingame": "UNLOCALIZED: Available in the Pause Menu", "create.menu.only_ingame": "Disponível no menu de pausa",
"create.menu.project_page": "UNLOCALIZED: Project Page", "create.menu.project_page": "Página do projeto",
"create.menu.report_bugs": "UNLOCALIZED: Report Issues", "create.menu.report_bugs": "Informar um erro",
"create.menu.support": "UNLOCALIZED: Support Us", "create.menu.support": "Suporte nós",
"create.recipe.crushing": "Triturando", "create.recipe.crushing": "Triturando",
"create.recipe.milling": "Moendo", "create.recipe.milling": "Moendo",
@ -848,7 +848,7 @@
"create.recipe.mixing": "Misturando", "create.recipe.mixing": "Misturando",
"create.recipe.deploying": "Implantando", "create.recipe.deploying": "Implantando",
"create.recipe.automatic_shapeless": "Fabricação sem forma automático", "create.recipe.automatic_shapeless": "Fabricação sem forma automático",
"create.recipe.automatic_brewing": "UNLOCALIZED: Automated Brewing", "create.recipe.automatic_brewing": "Produção de poções",
"create.recipe.packing": "Compactando", "create.recipe.packing": "Compactando",
"create.recipe.automatic_packing": "Compactamento automático", "create.recipe.automatic_packing": "Compactamento automático",
"create.recipe.sawing": "Serrando", "create.recipe.sawing": "Serrando",
@ -909,22 +909,22 @@
"create.action.discard": "Descartar", "create.action.discard": "Descartar",
"create.keyinfo.toolmenu": "Menu Focal da Ferramenta", "create.keyinfo.toolmenu": "Menu Focal da Ferramenta",
"create.keyinfo.toolbelt": "UNLOCALIZED: Access Nearby Toolboxes", "create.keyinfo.toolbelt": "Acessa caixas de ferramenta próximas",
"create.keyinfo.scrollup": "UNLOCALIZED: Simulate Mousewheel Up (inworld)", "create.keyinfo.scrollup": "Simular a roda do mouse (para cima) (no mundo)",
"create.keyinfo.scrolldown": "UNLOCALIZED: Simulate Mousewheel Down (inworld)", "create.keyinfo.scrolldown": "Simular a roda do mouse (para baixo) (no mundo)",
"create.gui.scrollInput.defaultTitle": "Escolha uma Opção:", "create.gui.scrollInput.defaultTitle": "Escolha uma Opção:",
"create.gui.scrollInput.scrollToModify": "Role o mouse para Modificar", "create.gui.scrollInput.scrollToModify": "Role o mouse para Modificar",
"create.gui.scrollInput.scrollToAdjustAmount": "Role o mouse para ajustar a quantidade", "create.gui.scrollInput.scrollToAdjustAmount": "Role o mouse para ajustar a quantidade",
"create.gui.scrollInput.scrollToSelect": "Role o mouse para Selecionar", "create.gui.scrollInput.scrollToSelect": "Role o mouse para Selecionar",
"create.gui.scrollInput.shiftScrollsFaster": "UNLOCALIZED: Shift to Scroll Faster", "create.gui.scrollInput.shiftScrollsFaster": "Shift para rolar o mouse mais rapido",
"create.gui.toolmenu.focusKey": "Segure [%1$s] para Focar", "create.gui.toolmenu.focusKey": "Segure [%1$s] para Focar",
"create.gui.toolmenu.cycle": "[SCROLL] para Circular", "create.gui.toolmenu.cycle": "[SCROLL] para Circular",
"create.toolbox.unequip": "Desequipar: %1$s", "create.toolbox.unequip": "Desequipar: %1$s",
"create.toolbox.outOfRange": "Caixa de ferramentas do item segurado fora de alcance", "create.toolbox.outOfRange": "Caixa de ferramentas do item segurado fora de alcance",
"create.toolbox.detach": "Parar de rastrear e manter item", "create.toolbox.detach": "Parar de rastrear e manter item",
"create.toolbox.depositAll": "Retornar itens para caixa de ferramenta próxima", "create.toolbox.depositAll": "Retorna itens para caixa de ferramenta próxima",
"create.toolbox.depositBox": "Retornar itens para caixa de ferramenta", "create.toolbox.depositBox": "Retornar itens para caixa de ferramenta",
"create.gui.symmetryWand.mirrorType": "Espelhar", "create.gui.symmetryWand.mirrorType": "Espelhar",
@ -972,90 +972,90 @@
"create.terrainzapper.usingBlock": "UNLOCALIZED: Using: %1$s", "create.terrainzapper.usingBlock": "UNLOCALIZED: Using: %1$s",
"create.terrainzapper.leftClickToSet": "UNLOCALIZED: Left-Click a Block to set Material", "create.terrainzapper.leftClickToSet": "UNLOCALIZED: Left-Click a Block to set Material",
"create.minecart_coupling.two_couplings_max": "UNLOCALIZED: Minecarts cannot have more than two couplings each", "create.minecart_coupling.two_couplings_max": "Carrinhos de mina não podem ter mais de dois acoplamentos cada",
"create.minecart_coupling.unloaded": "UNLOCALIZED: Parts of your train seem to be in unloaded chunks", "create.minecart_coupling.unloaded": "Partes do seu trem aparentam estar em um chunk descarregado",
"create.minecart_coupling.no_loops": "UNLOCALIZED: Couplings cannot form a loop", "create.minecart_coupling.no_loops": "Acoplamentos não podem formar um loop",
"create.minecart_coupling.removed": "UNLOCALIZED: Removed all couplings from minecart", "create.minecart_coupling.removed": "Removeu todos os acoplamentos do carrinho de mina",
"create.minecart_coupling.too_far": "UNLOCALIZED: Minecarts are too far apart", "create.minecart_coupling.too_far": "Carrinhos de mina estão muito distanciados",
"create.contraptions.movement_mode": "UNLOCALIZED: Movement Mode", "create.contraptions.movement_mode": "Modo de movimento",
"create.contraptions.movement_mode.move_place": "UNLOCALIZED: Always Place when Stopped", "create.contraptions.movement_mode.move_place": "Sempre colocar quando parado",
"create.contraptions.movement_mode.move_place_returned": "UNLOCALIZED: Place only in Starting Position", "create.contraptions.movement_mode.move_place_returned": "Colocar apenas na posição inicial",
"create.contraptions.movement_mode.move_never_place": "UNLOCALIZED: Place only when Anchor Destroyed", "create.contraptions.movement_mode.move_never_place": "Colocar apenas caso a âncora seja destruída",
"create.contraptions.movement_mode.rotate_place": "UNLOCALIZED: Always Place when Stopped", "create.contraptions.movement_mode.rotate_place": "Sempre colocar quando parado",
"create.contraptions.movement_mode.rotate_place_returned": "UNLOCALIZED: Only Place near Initial Angle", "create.contraptions.movement_mode.rotate_place_returned": "Apenas colocar perto do angulo inicial",
"create.contraptions.movement_mode.rotate_never_place": "UNLOCALIZED: Only Place when Anchor Destroyed", "create.contraptions.movement_mode.rotate_never_place": "Colocar apenas caso a âncora seja destruída",
"create.contraptions.cart_movement_mode": "UNLOCALIZED: Cart Movement Mode", "create.contraptions.cart_movement_mode": "Modo de movimento do carrinho",
"create.contraptions.cart_movement_mode.rotate": "UNLOCALIZED: Always face toward motion", "create.contraptions.cart_movement_mode.rotate": "Sempre apontar para a direção do movimento",
"create.contraptions.cart_movement_mode.rotate_paused": "UNLOCALIZED: Pause actors while rotating", "create.contraptions.cart_movement_mode.rotate_paused": "Pausar atores quando girando",
"create.contraptions.cart_movement_mode.rotation_locked": "UNLOCALIZED: Lock rotation", "create.contraptions.cart_movement_mode.rotation_locked": "Travar a rotação",
"create.contraptions.windmill.rotation_direction": "UNLOCALIZED: Rotation Direction", "create.contraptions.windmill.rotation_direction": "Direção da rotação",
"create.contraptions.clockwork.clock_hands": "UNLOCALIZED: Clock Hands", "create.contraptions.clockwork.clock_hands": "Ponteiros do relogio",
"create.contraptions.clockwork.hour_first": "UNLOCALIZED: Hour hand first", "create.contraptions.clockwork.hour_first": "Ponteiro da hora primeiro",
"create.contraptions.clockwork.minute_first": "UNLOCALIZED: Minute hand first", "create.contraptions.clockwork.minute_first": "Ponteiro do minuto primeiro",
"create.contraptions.clockwork.hour_first_24": "UNLOCALIZED: 24-Hour hand first", "create.contraptions.clockwork.hour_first_24": "Ponteiro das 24 horas primeiro",
"create.logistics.filter": "UNLOCALIZED: Filter", "create.logistics.filter": "Filtro",
"create.logistics.recipe_filter": "UNLOCALIZED: Recipe Filter", "create.logistics.recipe_filter": "Filtro de receitas",
"create.logistics.fluid_filter": "UNLOCALIZED: Fluid Filter", "create.logistics.fluid_filter": "Filtro de fluido",
"create.logistics.firstFrequency": "UNLOCALIZED: Freq. #1", "create.logistics.firstFrequency": "Freq. #1",
"create.logistics.secondFrequency": "UNLOCALIZED: Freq. #2", "create.logistics.secondFrequency": "Freq. #2",
"create.logistics.filter.apply": "UNLOCALIZED: Applied filter to %1$s.", "create.logistics.filter.apply": "Aplicou filtro para %1$s.",
"create.logistics.filter.apply_click_again": "UNLOCALIZED: Applied filter to %1$s, click again to copy the amount.", "create.logistics.filter.apply_click_again": "Aplicou filtro para %1$s, Clique denovo para copiar quantidade.",
"create.logistics.filter.apply_count": "UNLOCALIZED: Applied extraction count to filter.", "create.logistics.filter.apply_count": "Aplicou quantidade de extração para o filtro.",
"create.gui.goggles.generator_stats": "Estatísticas do gerador:", "create.gui.goggles.generator_stats": "Estatísticas do gerador:",
"create.gui.goggles.kinetic_stats": "Estatísticas cinéticas:", "create.gui.goggles.kinetic_stats": "Estatísticas cinéticas:",
"create.gui.goggles.at_current_speed": "Na velocidade atual", "create.gui.goggles.at_current_speed": "Na velocidade atual",
"create.gui.goggles.pole_length": "Comprimento da vara:", "create.gui.goggles.pole_length": "Comprimento da vara:",
"create.gui.goggles.fluid_container": "UNLOCALIZED: Fluid Container Info:", "create.gui.goggles.fluid_container": "Informação do recipiente de fluido:",
"create.gui.goggles.fluid_container.capacity": "UNLOCALIZED: Capacity: ", "create.gui.goggles.fluid_container.capacity": "Capacidade: ",
"create.gui.assembly.exception": "UNLOCALIZED: This Contraption was unable to assemble:", "create.gui.assembly.exception": "Não foi possível montar essa engenhoca:",
"create.gui.assembly.exception.unmovableBlock": "UNLOCALIZED: Unmovable Block (%4$s) at [%1$s,%2$s,%3$s]", "create.gui.assembly.exception.unmovableBlock": "Bloco imovel (%4$s) em [%1$s,%2$s,%3$s]",
"create.gui.assembly.exception.chunkNotLoaded": "UNLOCALIZED: The Block at [%1$s,%2$s,%3$s] was not in a loaded chunk", "create.gui.assembly.exception.chunkNotLoaded": "O bloco em [%1$s,%2$s,%3$s] não estava em um chunk carregado",
"create.gui.assembly.exception.structureTooLarge": "UNLOCALIZED: There are too many Blocks included in the contraption.\nThe configured maximum is: %1$s", "create.gui.assembly.exception.structureTooLarge": "Tem muitos blocos incluídos na engenhoca. O limite configurado é: %1$s",
"create.gui.assembly.exception.tooManyPistonPoles": "UNLOCALIZED: There are too many extension Poles attached to this Piston.\nThe configured maximum is: %1$s", "create.gui.assembly.exception.tooManyPistonPoles": "Tem muitas varetas de extensão colocadas nesse pistão. O limite configurado é: %1$s",
"create.gui.assembly.exception.noPistonPoles": "UNLOCALIZED: The Piston is missing some extension Poles", "create.gui.assembly.exception.noPistonPoles": "O pistão esta faltando algumas varetas de extensão",
"create.gui.assembly.exception.not_enough_sails": "UNLOCALIZED: Attached structure does not include enough sail-like blocks: %1$s\nA minimum of %2$s are required", "create.gui.assembly.exception.not_enough_sails": "A estrutura conectada não possui o número suficiente de blocos tipo vela: %1$s\nUm mínimo de %2$s são requeridos",
"create.gui.gauge.info_header": "UNLOCALIZED: Gauge Information:", "create.gui.gauge.info_header": "Informação do medidor:",
"create.gui.speedometer.title": "UNLOCALIZED: Rotation Speed", "create.gui.speedometer.title": "Velocidade de rotação",
"create.gui.stressometer.title": "UNLOCALIZED: Network Stress", "create.gui.stressometer.title": "Estresse do sistema",
"create.gui.stressometer.capacity": "UNLOCALIZED: Remaining Capacity", "create.gui.stressometer.capacity": "Capacidade restante",
"create.gui.stressometer.overstressed": "UNLOCALIZED: Overstressed", "create.gui.stressometer.overstressed": "Sobre estressado",
"create.gui.stressometer.no_rotation": "UNLOCALIZED: No Rotation", "create.gui.stressometer.no_rotation": "Nenhuma rotação",
"create.gui.contraptions.not_fast_enough": "UNLOCALIZED: It appears that this %1$s is _not_ rotating with _enough_ _speed_.", "create.gui.contraptions.not_fast_enough": "Aparenta que esse %1$s não _está_ girando com _a velocidade_ _necessária_.",
"create.gui.contraptions.network_overstressed": "UNLOCALIZED: It appears that this contraption is _overstressed_. Add more sources or _slow_ _down_ the components with a high _stress_ _impact_.", "create.gui.contraptions.network_overstressed": "Aparenta que essa engenhoca está _sobre estressada_. Adicione mais fontes ou _desacelere_ __ os componentes que tem um _impacto de_ _stress alto_.",
"create.gui.adjustable_crate.title": "UNLOCALIZED: Adjustable Crate", "create.gui.adjustable_crate.title": "UNLOCALIZED: Adjustable Crate",
"create.gui.adjustable_crate.storageSpace": "UNLOCALIZED: Storage Space", "create.gui.adjustable_crate.storageSpace": "UNLOCALIZED: Storage Space",
"create.gui.stockpile_switch.title": "UNLOCALIZED: Stockpile Switch", "create.gui.stockpile_switch.title": "Dijuntor de armazenamento",
"create.gui.stockpile_switch.invert_signal": "UNLOCALIZED: Invert Signal", "create.gui.stockpile_switch.invert_signal": "Inverter sinal",
"create.gui.stockpile_switch.move_to_lower_at": "UNLOCALIZED: Move to lower lane at %1$s%%", "create.gui.stockpile_switch.move_to_lower_at": "Mover para a faixa mais baixa %1$s%%",
"create.gui.stockpile_switch.move_to_upper_at": "UNLOCALIZED: Move to upper lane at %1$s%%", "create.gui.stockpile_switch.move_to_upper_at": "Mover para a faixa mais alta %1$s%%",
"create.gui.sequenced_gearshift.title": "UNLOCALIZED: Sequenced Gearshift", "create.gui.sequenced_gearshift.title": "Câmbio sequenciado",
"create.gui.sequenced_gearshift.instruction": "UNLOCALIZED: Instruction", "create.gui.sequenced_gearshift.instruction": "Instruções",
"create.gui.sequenced_gearshift.instruction.turn_angle.descriptive": "UNLOCALIZED: Turn by angle", "create.gui.sequenced_gearshift.instruction.turn_angle.descriptive": "Rotacionar por angulo",
"create.gui.sequenced_gearshift.instruction.turn_angle": "UNLOCALIZED: Turn", "create.gui.sequenced_gearshift.instruction.turn_angle": "Giro",
"create.gui.sequenced_gearshift.instruction.turn_angle.angle": "UNLOCALIZED: Angle", "create.gui.sequenced_gearshift.instruction.turn_angle.angle": "Angulo",
"create.gui.sequenced_gearshift.instruction.turn_distance.descriptive": "UNLOCALIZED: Turn to move Piston/Pulley/Gantry", "create.gui.sequenced_gearshift.instruction.turn_distance.descriptive": "Rotacionar par mover Pistão/Polia/Portico",
"create.gui.sequenced_gearshift.instruction.turn_distance": "UNLOCALIZED: Piston", "create.gui.sequenced_gearshift.instruction.turn_distance": "Pistão",
"create.gui.sequenced_gearshift.instruction.turn_distance.distance": "UNLOCALIZED: Distance", "create.gui.sequenced_gearshift.instruction.turn_distance.distance": "Distancia",
"create.gui.sequenced_gearshift.instruction.delay.descriptive": "UNLOCALIZED: Timed Delay", "create.gui.sequenced_gearshift.instruction.delay.descriptive": "Espera",
"create.gui.sequenced_gearshift.instruction.delay": "UNLOCALIZED: Delay", "create.gui.sequenced_gearshift.instruction.delay": "Esperar",
"create.gui.sequenced_gearshift.instruction.delay.duration": "UNLOCALIZED: Duration", "create.gui.sequenced_gearshift.instruction.delay.duration": "Duração",
"create.gui.sequenced_gearshift.instruction.end.descriptive": "UNLOCALIZED: End", "create.gui.sequenced_gearshift.instruction.end.descriptive": "Terminar",
"create.gui.sequenced_gearshift.instruction.end": "UNLOCALIZED: End", "create.gui.sequenced_gearshift.instruction.end": "Termino",
"create.gui.sequenced_gearshift.instruction.await.descriptive": "UNLOCALIZED: Await new Redstone Pulse", "create.gui.sequenced_gearshift.instruction.await.descriptive": "Esperar novo pulso de redstone",
"create.gui.sequenced_gearshift.instruction.await": "UNLOCALIZED: Await", "create.gui.sequenced_gearshift.instruction.await": "Espera",
"create.gui.sequenced_gearshift.speed": "UNLOCALIZED: Speed, Direction", "create.gui.sequenced_gearshift.speed": "Velocidade, Direção",
"create.gui.sequenced_gearshift.speed.forward": "UNLOCALIZED: Input speed, Forwards", "create.gui.sequenced_gearshift.speed.forward": "Velocidade inicial, Para frente",
"create.gui.sequenced_gearshift.speed.forward_fast": "UNLOCALIZED: Double speed, Forwards", "create.gui.sequenced_gearshift.speed.forward_fast": "Dobro da velocidade, Para frente",
"create.gui.sequenced_gearshift.speed.back": "UNLOCALIZED: Input speed, Reversed", "create.gui.sequenced_gearshift.speed.back": "Velocidade inicial, Para trás",
"create.gui.sequenced_gearshift.speed.back_fast": "UNLOCALIZED: Double speed, Reversed", "create.gui.sequenced_gearshift.speed.back_fast": "Dobro da velocidade, Para trás",
"create.schematicAndQuill.dimensions": "Tamanho Esquema: %1$sx%2$sx%3$s", "create.schematicAndQuill.dimensions": "Tamanho Esquema: %1$sx%2$sx%3$s",
"create.schematicAndQuill.firstPos": "Primeira posição feita.", "create.schematicAndQuill.firstPos": "Primeira posição feita.",
"create.schematicAndQuill.secondPos": "Segunda posição feita.", "create.schematicAndQuill.secondPos": "Segunda posição feita.",
"create.schematicAndQuill.noTarget": "Seguro [Ctrl] para selecionar Blocos de Ar.", "create.schematicAndQuill.noTarget": "Seguro [Ctrl] para seleccionar Blocos de Ar.",
"create.schematicAndQuill.abort": "Seleção removida.", "create.schematicAndQuill.abort": "Seleção removida.",
"create.schematicAndQuill.title": "Nome do esquema:", "create.schematicAndQuill.title": "Nome do esquema:",
"create.schematicAndQuill.convert": "Salvar e carregar arquivo imediatamente", "create.schematicAndQuill.convert": "Salvar e carregar arquivo imediatamente",
@ -1095,7 +1095,7 @@
"create.schematic.tool.rotate.description.1": "[CTRL]-Rolar para rolar 90 Graus", "create.schematic.tool.rotate.description.1": "[CTRL]-Rolar para rolar 90 Graus",
"create.schematic.tool.rotate.description.2": "", "create.schematic.tool.rotate.description.2": "",
"create.schematic.tool.rotate.description.3": "", "create.schematic.tool.rotate.description.3": "",
"create.schematic.tool.print.description.0": "Coloca estrutura no mundo instantaneamente", "create.schematic.tool.print.description.0": "Colocá estrutura no mundo instantaneamente",
"create.schematic.tool.print.description.1": "[Botão-Direito] para confirmar a posição atual.", "create.schematic.tool.print.description.1": "[Botão-Direito] para confirmar a posição atual.",
"create.schematic.tool.print.description.2": "Esta ferramenta é para o Modo Criativo apenas.", "create.schematic.tool.print.description.2": "Esta ferramenta é para o Modo Criativo apenas.",
"create.schematic.tool.print.description.3": "", "create.schematic.tool.print.description.3": "",
@ -1108,11 +1108,11 @@
"create.schematics.uploadTooLarge": "Seu esquema é muito grande", "create.schematics.uploadTooLarge": "Seu esquema é muito grande",
"create.schematics.maxAllowedSize": "O tamanho máximo permitido para o esquema é:", "create.schematics.maxAllowedSize": "O tamanho máximo permitido para o esquema é:",
"create.gui.schematicTable.refresh": "UNLOCALIZED: Refresh Files", "create.gui.schematicTable.refresh": "atualizar arquivos",
"create.gui.schematicTable.open_folder": "UNLOCALIZED: Open Folder", "create.gui.schematicTable.open_folder": "Abrir pasta",
"create.gui.schematicTable.title": "Mesa de Desenho", "create.gui.schematicTable.title": "Mesa de Desenho",
"create.gui.schematicTable.availableSchematics": "UNLOCALIZED: Available Schematics", "create.gui.schematicTable.availableSchematics": "Esquema disponíveis",
"create.gui.schematicTable.noSchematics": "UNLOCALIZED: No Schematics Saved", "create.gui.schematicTable.noSchematics": "Nenhum esquema salvo",
"create.gui.schematicTable.uploading": "Importando...", "create.gui.schematicTable.uploading": "Importando...",
"create.gui.schematicTable.finished": "Envio Concluído!", "create.gui.schematicTable.finished": "Envio Concluído!",
"create.gui.schematicannon.title": "Canhão de esquema", "create.gui.schematicannon.title": "Canhão de esquema",
@ -1122,18 +1122,18 @@
"create.gui.schematicannon.shotsRemainingWithBackup": "Com backup: %1$s", "create.gui.schematicannon.shotsRemainingWithBackup": "Com backup: %1$s",
"create.gui.schematicannon.optionEnabled": "Habilitado Atualmente", "create.gui.schematicannon.optionEnabled": "Habilitado Atualmente",
"create.gui.schematicannon.optionDisabled": "Desabilitado Atualmente", "create.gui.schematicannon.optionDisabled": "Desabilitado Atualmente",
"create.gui.schematicannon.showOptions": "UNLOCALIZED: Show Printer Settings", "create.gui.schematicannon.showOptions": "Mostrar as configurações da impressora",
"create.gui.schematicannon.option.dontReplaceSolid": "Não Substituir Blocos Sólidos", "create.gui.schematicannon.option.dontReplaceSolid": "Não Substituir Blocos Sólidos",
"create.gui.schematicannon.option.replaceWithSolid": "Substituir Blocos Sólidos", "create.gui.schematicannon.option.replaceWithSolid": "Substituir Blocos Sólidos",
"create.gui.schematicannon.option.replaceWithAny": "Substituir Sólidos com Qualquer", "create.gui.schematicannon.option.replaceWithAny": "Substituir Sólidos com Qualquer",
"create.gui.schematicannon.option.replaceWithEmpty": "Substituir Sólidos com Vazio", "create.gui.schematicannon.option.replaceWithEmpty": "Substituir Sólidos com Vazio",
"create.gui.schematicannon.option.skipMissing": "Pulando Blocos faltantes", "create.gui.schematicannon.option.skipMissing": "Pulando Blocos faltantes",
"create.gui.schematicannon.option.skipTileEntities": "Proteger Entidades Entalhadas", "create.gui.schematicannon.option.skipTileEntities": "Proteger tile entities",
"create.gui.schematicannon.slot.gunpowder": "UNLOCALIZED: Add gunpowder to fuel the cannon", "create.gui.schematicannon.slot.gunpowder": "Adicionar pólvora para carregar o canhão",
"create.gui.schematicannon.slot.listPrinter": "UNLOCALIZED: Place books here to print a Checklist for your Schematic", "create.gui.schematicannon.slot.listPrinter": "Coloque livros aqui para imprimir uma lista para o seu esquema",
"create.gui.schematicannon.slot.schematic": "UNLOCALIZED: Add your Schematic here. Make sure it is deployed at a specific location.", "create.gui.schematicannon.slot.schematic": "Adicione o seu esquema aqui. Tenha certeza que ele está colocado em um lugar especifico.",
"create.gui.schematicannon.option.skipMissing.description": "Se o Canhão de esquema não encontrar o Bloco para colocar, ele irá continuar para a próx. Posição.", "create.gui.schematicannon.option.skipMissing.description": "Se o Canhão de esquema não encontrar o Bloco para colocar, ele irá continuar para a próxima. Posição.",
"create.gui.schematicannon.option.skipTileEntities.description": "O Canhão de esquema vai evitar substituir blocos que contêm dados como Baus.", "create.gui.schematicannon.option.skipTileEntities.description": "O Canhão de esquema vai evitar substituir blocos que contêm dados como Baús.",
"create.gui.schematicannon.option.dontReplaceSolid.description": "O Canhão de esquema nunca irá substituir Blocos sólidos na área em trabalho, apenas não-Sólidos e Ar.", "create.gui.schematicannon.option.dontReplaceSolid.description": "O Canhão de esquema nunca irá substituir Blocos sólidos na área em trabalho, apenas não-Sólidos e Ar.",
"create.gui.schematicannon.option.replaceWithSolid.description": "O Canhão de esquema irá apenas substituir Blocos sólidos na área de trabalho, se o Esquema conter um bloco Sólido naquela posição.", "create.gui.schematicannon.option.replaceWithSolid.description": "O Canhão de esquema irá apenas substituir Blocos sólidos na área de trabalho, se o Esquema conter um bloco Sólido naquela posição.",
"create.gui.schematicannon.option.replaceWithAny.description": "O Canhão de esquema irá substituir Blocos sólidos na área de trabalho, se o Esquema conter qualquer Bloco naquela posição.", "create.gui.schematicannon.option.replaceWithAny.description": "O Canhão de esquema irá substituir Blocos sólidos na área de trabalho, se o Esquema conter qualquer Bloco naquela posição.",
@ -1157,187 +1157,187 @@
"create.schematicannon.status.schematicNotPlaced": "Esquema não Colocado", "create.schematicannon.status.schematicNotPlaced": "Esquema não Colocado",
"create.schematicannon.status.schematicExpired": "Arquivo de Esquema Expirado", "create.schematicannon.status.schematicExpired": "Arquivo de Esquema Expirado",
"create.materialChecklist": "UNLOCALIZED: Material Checklist", "create.materialChecklist": "Lista de materiais",
"create.materialChecklist.blocksNotLoaded": "UNLOCALIZED: * Disclaimer *\n\nMaterial List may be inaccurate due to relevant chunks not being loaded.", "create.materialChecklist.blocksNotLoaded": "UNLOCALIZED: * Disclaimer *\n\nMaterial List may be inaccurate due to relevant chunks not being loaded.",
"create.gui.filter.deny_list": "UNLOCALIZED: Deny-List", "create.gui.filter.deny_list": "Lista de negação",
"create.gui.filter.deny_list.description": "UNLOCALIZED: Items pass if they do NOT match any of the above. An empty Deny-List accepts everything.", "create.gui.filter.deny_list.description": "Itens passam se eles não encaixam em nenhum dos acima. Uma lista de negação vazia aceita tudo.",
"create.gui.filter.allow_list": "UNLOCALIZED: Allow-List", "create.gui.filter.allow_list": "Lista de permissão",
"create.gui.filter.allow_list.description": "UNLOCALIZED: Items pass if they match any of the above. An empty Allow-List rejects everything.", "create.gui.filter.allow_list.description": "Itens passam se eles se encaixam em algum dos acima. Uma lista de permissão vazia rejeita tudo.",
"create.gui.filter.respect_data": "UNLOCALIZED: Respect Data", "create.gui.filter.respect_data": "Respeitar informação",
"create.gui.filter.respect_data.description": "UNLOCALIZED: Items only match if their durability, enchantments, and other attributes match as well.", "create.gui.filter.respect_data.description": "Itens apenas se encaixam caso a durabilidade, encantamentos e outros atributos se encaixam também.",
"create.gui.filter.ignore_data": "UNLOCALIZED: Ignore Data", "create.gui.filter.ignore_data": "Ignorar informação",
"create.gui.filter.ignore_data.description": "UNLOCALIZED: Items match regardless of their attributes.", "create.gui.filter.ignore_data.description": "Itens se enquadram não importa os seus atributos.",
"create.item_attributes.placeable": "UNLOCALIZED: is placeable", "create.item_attributes.placeable": "É colocavel",
"create.item_attributes.placeable.inverted": "UNLOCALIZED: is not placeable", "create.item_attributes.placeable.inverted": "Não é colocavel",
"create.item_attributes.consumable": "UNLOCALIZED: can be eaten", "create.item_attributes.consumable": "É comestivel",
"create.item_attributes.consumable.inverted": "UNLOCALIZED: cannot be eaten", "create.item_attributes.consumable.inverted": "Não é comestivel",
"create.item_attributes.fluid_container": "UNLOCALIZED: can store fluids", "create.item_attributes.fluid_container": "Pode armazenar fluidos",
"create.item_attributes.fluid_container.inverted": "UNLOCALIZED: cannot store fluids", "create.item_attributes.fluid_container.inverted": "Não pode armazenar fluidos",
"create.item_attributes.enchanted": "UNLOCALIZED: is enchanted", "create.item_attributes.enchanted": "Está encantado",
"create.item_attributes.enchanted.inverted": "UNLOCALIZED: is unenchanted", "create.item_attributes.enchanted.inverted": "Não está encantado",
"create.item_attributes.max_enchanted": "UNLOCALIZED: is enchanted at max level", "create.item_attributes.max_enchanted": "Está encantado no nível máximo",
"create.item_attributes.max_enchanted.inverted": "UNLOCALIZED: is not enchanted at max level", "create.item_attributes.max_enchanted.inverted": "Não está encantado no nível maximo",
"create.item_attributes.renamed": "UNLOCALIZED: has a custom name", "create.item_attributes.renamed": "Tem nome customizado",
"create.item_attributes.renamed.inverted": "UNLOCALIZED: does not have a custom name", "create.item_attributes.renamed.inverted": "Não tem nome customizado",
"create.item_attributes.damaged": "UNLOCALIZED: is damaged", "create.item_attributes.damaged": "Está danificado",
"create.item_attributes.damaged.inverted": "UNLOCALIZED: is not damaged", "create.item_attributes.damaged.inverted": "Não está danificado",
"create.item_attributes.badly_damaged": "UNLOCALIZED: is heavily damaged", "create.item_attributes.badly_damaged": "Está severamente danificado",
"create.item_attributes.badly_damaged.inverted": "UNLOCALIZED: is not heavily damaged", "create.item_attributes.badly_damaged.inverted": "Não esta severamente danificado",
"create.item_attributes.not_stackable": "UNLOCALIZED: cannot stack", "create.item_attributes.not_stackable": "Não pode ser empilhado",
"create.item_attributes.not_stackable.inverted": "UNLOCALIZED: can be stacked", "create.item_attributes.not_stackable.inverted": "Pode ser empilhado",
"create.item_attributes.equipable": "UNLOCALIZED: can be equipped", "create.item_attributes.equipable": "Pode ser equipado",
"create.item_attributes.equipable.inverted": "UNLOCALIZED: cannot be equipped", "create.item_attributes.equipable.inverted": "Não pode ser equipado",
"create.item_attributes.furnace_fuel": "UNLOCALIZED: is furnace fuel", "create.item_attributes.furnace_fuel": "è combustivel",
"create.item_attributes.furnace_fuel.inverted": "UNLOCALIZED: is not furnace fuel", "create.item_attributes.furnace_fuel.inverted": "Não é combustivel",
"create.item_attributes.washable": "UNLOCALIZED: can be Washed", "create.item_attributes.washable": "Pode ser lavado",
"create.item_attributes.washable.inverted": "UNLOCALIZED: cannot be Washed", "create.item_attributes.washable.inverted": "Não pode ser lavado",
"create.item_attributes.hauntable": "UNLOCALIZED: can be Haunted", "create.item_attributes.hauntable": "Pode ser amaldiçoado",
"create.item_attributes.hauntable.inverted": "UNLOCALIZED: cannot be Haunted", "create.item_attributes.hauntable.inverted": "Não pode ser amaldiçoado",
"create.item_attributes.crushable": "UNLOCALIZED: can be Crushed", "create.item_attributes.crushable": "Pode ser triturado",
"create.item_attributes.crushable.inverted": "UNLOCALIZED: cannot be Crushed", "create.item_attributes.crushable.inverted": "Não pode ser triturado",
"create.item_attributes.smeltable": "UNLOCALIZED: can be Smelted", "create.item_attributes.smeltable": "Pode ser fundido",
"create.item_attributes.smeltable.inverted": "UNLOCALIZED: cannot be Smelted", "create.item_attributes.smeltable.inverted": "Não pode ser fundido",
"create.item_attributes.smokable": "UNLOCALIZED: can be Smoked", "create.item_attributes.smokable": "Pode ser defumado",
"create.item_attributes.smokable.inverted": "UNLOCALIZED: cannot be Smoked", "create.item_attributes.smokable.inverted": "Não pode ser defumado",
"create.item_attributes.blastable": "UNLOCALIZED: is smeltable in Blast Furnace", "create.item_attributes.blastable": "È fundível no alto-forno",
"create.item_attributes.blastable.inverted": "UNLOCALIZED: is not smeltable in Blast Furnace", "create.item_attributes.blastable.inverted": "Não é fundível no alto-forno",
"create.item_attributes.shulker_level": "UNLOCALIZED: is shulker %1$s", "create.item_attributes.shulker_level": "O shulker é %1$s",
"create.item_attributes.shulker_level.inverted": "UNLOCALIZED: is shulker not %1$s", "create.item_attributes.shulker_level.inverted": "O shulker não é %1$s",
"create.item_attributes.shulker_level.full": "UNLOCALIZED: full", "create.item_attributes.shulker_level.full": "Cheio",
"create.item_attributes.shulker_level.empty": "UNLOCALIZED: empty", "create.item_attributes.shulker_level.empty": "Vazio",
"create.item_attributes.shulker_level.partial": "UNLOCALIZED: partially filled", "create.item_attributes.shulker_level.partial": "Parcialmente cheio",
"create.item_attributes.in_tag": "UNLOCALIZED: is tagged %1$s", "create.item_attributes.in_tag": "è marcado %1$s",
"create.item_attributes.in_tag.inverted": "UNLOCALIZED: is not tagged %1$s", "create.item_attributes.in_tag.inverted": "Não é marcado %1$s",
"create.item_attributes.in_item_group": "UNLOCALIZED: is in group '%1$s'", "create.item_attributes.in_item_group": "Está no grupo '%1$s'",
"create.item_attributes.in_item_group.inverted": "UNLOCALIZED: is not in group '%1$s'", "create.item_attributes.in_item_group.inverted": "Não esta no grupo '%1$s'",
"create.item_attributes.added_by": "UNLOCALIZED: was added by %1$s", "create.item_attributes.added_by": "Foi adicionado por %1$s",
"create.item_attributes.added_by.inverted": "UNLOCALIZED: was not added by %1$s", "create.item_attributes.added_by.inverted": "Não foi adicionado por %1$s",
"create.item_attributes.has_enchant": "UNLOCALIZED: is enchanted with %1$s", "create.item_attributes.has_enchant": "Está encantado com %1$s",
"create.item_attributes.has_enchant.inverted": "UNLOCALIZED: is not enchanted with %1$s", "create.item_attributes.has_enchant.inverted": "Não esta encantado com %1$s",
"create.item_attributes.color": "UNLOCALIZED: is dyed %1$s", "create.item_attributes.color": "Esta tingido de %1$s",
"create.item_attributes.color.inverted": "UNLOCALIZED: is not dyed %1$s", "create.item_attributes.color.inverted": "Não está tingido de %1$s",
"create.item_attributes.has_fluid": "UNLOCALIZED: contains %1$s", "create.item_attributes.has_fluid": "Contem %1$s",
"create.item_attributes.has_fluid.inverted": "UNLOCALIZED: does not contain %1$s", "create.item_attributes.has_fluid.inverted": "Não contem %1$s",
"create.item_attributes.has_name": "UNLOCALIZED: has the custom name %1$s", "create.item_attributes.has_name": "Tem o nome %1$s",
"create.item_attributes.has_name.inverted": "UNLOCALIZED: does not have the custom name %1$s", "create.item_attributes.has_name.inverted": "Não tem o nome %1$s",
"create.item_attributes.book_author": "UNLOCALIZED: was authored by %1$s", "create.item_attributes.book_author": "Tem a autoria de %1$s",
"create.item_attributes.book_author.inverted": "UNLOCALIZED: was not authored by %1$s", "create.item_attributes.book_author.inverted": "Não tem a autoria de %1$s",
"create.item_attributes.book_copy_original": "UNLOCALIZED: is an original", "create.item_attributes.book_copy_original": "É original",
"create.item_attributes.book_copy_original.inverted": "UNLOCALIZED: is not an original", "create.item_attributes.book_copy_original.inverted": "Não é original",
"create.item_attributes.book_copy_first": "UNLOCALIZED: is a first-generation copy", "create.item_attributes.book_copy_first": "É uma cópia da primeira geração",
"create.item_attributes.book_copy_first.inverted": "UNLOCALIZED: is not a first-generation copy", "create.item_attributes.book_copy_first.inverted": "Não é uma copia de primeira geração",
"create.item_attributes.book_copy_second": "UNLOCALIZED: is a second-generation copy", "create.item_attributes.book_copy_second": "É uma cópia de segunda geração",
"create.item_attributes.book_copy_second.inverted": "UNLOCALIZED: is not a second-generation copy", "create.item_attributes.book_copy_second.inverted": "Não é uma copia de segunda geração",
"create.item_attributes.book_copy_tattered": "UNLOCALIZED: is a tattered mess", "create.item_attributes.book_copy_tattered": "É uma bagunça esfarrapada",
"create.item_attributes.book_copy_tattered.inverted": "UNLOCALIZED: is not a tattered mess", "create.item_attributes.book_copy_tattered.inverted": "Não é uma bagunça esfarrapada",
"create.item_attributes.astralsorcery_amulet": "UNLOCALIZED: improves %1$s", "create.item_attributes.astralsorcery_amulet": "Melhora %1$s",
"create.item_attributes.astralsorcery_amulet.inverted": "UNLOCALIZED: does not improve %1$s", "create.item_attributes.astralsorcery_amulet.inverted": "Não melhora %1$s",
"create.item_attributes.astralsorcery_constellation": "UNLOCALIZED: is attuned to %1$s", "create.item_attributes.astralsorcery_constellation": "Esta sintonizado a %1$s",
"create.item_attributes.astralsorcery_constellation.inverted": "UNLOCALIZED: is not attuned to %1$s", "create.item_attributes.astralsorcery_constellation.inverted": "Não esta sintonizado a %1$s",
"create.item_attributes.astralsorcery_crystal": "UNLOCALIZED: has crystal attribute %1$s", "create.item_attributes.astralsorcery_crystal": "Tem atributos de cristais %1$s",
"create.item_attributes.astralsorcery_crystal.inverted": "UNLOCALIZED: does not have crystal attribute %1$s", "create.item_attributes.astralsorcery_crystal.inverted": "Não tem atributos de cristais %1$s",
"create.item_attributes.astralsorcery_perk_gem": "UNLOCALIZED: has perk attribute %1$s", "create.item_attributes.astralsorcery_perk_gem": " %1$s Tem um atributo de benefio",
"create.item_attributes.astralsorcery_perk_gem.inverted": "UNLOCALIZED: does not have perk attribute %1$s", "create.item_attributes.astralsorcery_perk_gem.inverted": "%1$s Não tem um atributo de benefio",
"create.gui.attribute_filter.no_selected_attributes": "UNLOCALIZED: No attributes selected", "create.gui.attribute_filter.no_selected_attributes": "Nenhum atributo selecionado",
"create.gui.attribute_filter.selected_attributes": "UNLOCALIZED: Selected attributes:", "create.gui.attribute_filter.selected_attributes": "Atributos selecionados:",
"create.gui.attribute_filter.add_attribute": "UNLOCALIZED: Add attribute to List", "create.gui.attribute_filter.add_attribute": "Adicionar atributo a lista",
"create.gui.attribute_filter.add_inverted_attribute": "UNLOCALIZED: Add opposite attribute to List", "create.gui.attribute_filter.add_inverted_attribute": "Adicionar atributo oposto a lista",
"create.gui.attribute_filter.allow_list_disjunctive": "UNLOCALIZED: Allow-List (Any)", "create.gui.attribute_filter.allow_list_disjunctive": "Lista de permissão (Qualquer)",
"create.gui.attribute_filter.allow_list_disjunctive.description": "UNLOCALIZED: Items pass if they have any of the selected attributes.", "create.gui.attribute_filter.allow_list_disjunctive.description": "Itens passam se eles tiverem qualquer atributo selecionado.",
"create.gui.attribute_filter.allow_list_conjunctive": "UNLOCALIZED: Allow-List (All)", "create.gui.attribute_filter.allow_list_conjunctive": "Lista de permissão (Todos)",
"create.gui.attribute_filter.allow_list_conjunctive.description": "UNLOCALIZED: Items pass only if they have ALL of the selected attributes.", "create.gui.attribute_filter.allow_list_conjunctive.description": "Itens passam se eles tiverem TODOS atributos selecionados.",
"create.gui.attribute_filter.deny_list": "UNLOCALIZED: Deny-List", "create.gui.attribute_filter.deny_list": "lista de negação",
"create.gui.attribute_filter.deny_list.description": "UNLOCALIZED: Items pass if they do NOT have any of the selected attributes.", "create.gui.attribute_filter.deny_list.description": "Itens passam se eles NÃO tiverem qualquer atributo selecionado.",
"create.gui.attribute_filter.add_reference_item": "UNLOCALIZED: Add Reference Item", "create.gui.attribute_filter.add_reference_item": "Adicionar item referência",
"create.tooltip.holdForDescription": "UNLOCALIZED: Hold [%1$s] for Summary", "create.tooltip.holdForDescription": "Segure [%1$s] para o sumário",
"create.tooltip.holdForControls": "UNLOCALIZED: Hold [%1$s] for Controls", "create.tooltip.holdForControls": "Segure [%1$s] para os controles",
"create.tooltip.keyShift": "UNLOCALIZED: Shift", "create.tooltip.keyShift": "Shift",
"create.tooltip.keyCtrl": "UNLOCALIZED: Ctrl", "create.tooltip.keyCtrl": "Ctrl",
"create.tooltip.speedRequirement": "UNLOCALIZED: Speed Requirement: %1$s", "create.tooltip.speedRequirement": "Requerimento de velocidade: %1$s",
"create.tooltip.speedRequirement.none": "UNLOCALIZED: None", "create.tooltip.speedRequirement.none": "Nenhum",
"create.tooltip.speedRequirement.slow": "UNLOCALIZED: Slow", "create.tooltip.speedRequirement.slow": "Devagar",
"create.tooltip.speedRequirement.medium": "UNLOCALIZED: Moderate", "create.tooltip.speedRequirement.medium": "Modereado",
"create.tooltip.speedRequirement.fast": "UNLOCALIZED: Fast", "create.tooltip.speedRequirement.fast": "Rapido",
"create.tooltip.stressImpact": "UNLOCALIZED: Kinetic Stress Impact: %1$s", "create.tooltip.stressImpact": "Impacto de stress: %1$s",
"create.tooltip.stressImpact.low": "UNLOCALIZED: Low", "create.tooltip.stressImpact.low": " Baixo",
"create.tooltip.stressImpact.medium": "UNLOCALIZED: Moderate", "create.tooltip.stressImpact.medium": " Moderado",
"create.tooltip.stressImpact.high": "UNLOCALIZED: High", "create.tooltip.stressImpact.high": " Alto",
"create.tooltip.stressImpact.overstressed": "UNLOCALIZED: Overstressed", "create.tooltip.stressImpact.overstressed": ": Sobre estresse",
"create.tooltip.capacityProvided": "UNLOCALIZED: Kinetic Stress Capacity: %1$s", "create.tooltip.capacityProvided": "Capacidade de stress cinético: %1$s",
"create.tooltip.capacityProvided.low": "UNLOCALIZED: Small", "create.tooltip.capacityProvided.low": " Pequeno",
"create.tooltip.capacityProvided.medium": "UNLOCALIZED: Medium", "create.tooltip.capacityProvided.medium": " Médio",
"create.tooltip.capacityProvided.high": "UNLOCALIZED: Large", "create.tooltip.capacityProvided.high": " Grande",
"create.tooltip.generationSpeed": "UNLOCALIZED: Generates at %1$s %2$s", "create.tooltip.generationSpeed": " Gera em %1$s %2$s",
"create.tooltip.analogStrength": "UNLOCALIZED: Analog Strength: %1$s/15", "create.tooltip.analogStrength": " Força analogica: %1$s/15",
"create.mechanical_arm.extract_from": "UNLOCALIZED: Take items from %1$s", "create.mechanical_arm.extract_from": " Pegar itens de %1$s",
"create.mechanical_arm.deposit_to": "UNLOCALIZED: Deposit items to %1$s", "create.mechanical_arm.deposit_to": " Depositar itens para %1$s",
"create.mechanical_arm.summary": "UNLOCALIZED: Mechanical Arm has %1$s input(s) and %2$s output(s).", "create.mechanical_arm.summary": "Braço mecânico tem %1$s entrada(s) e %2$s saida(s).",
"create.mechanical_arm.points_outside_range": "UNLOCALIZED: %1$s selected interaction point(s) removed due to range limitations.", "create.mechanical_arm.points_outside_range": "%1$s Ponto(s) de interação removidos pelas limitações de alcance.",
"create.weighted_ejector.target_set": "UNLOCALIZED: Target Selected", "create.weighted_ejector.target_set": "Alvo selecionado",
"create.weighted_ejector.target_not_valid": "UNLOCALIZED: Ejecting to Adjacent block (Target was not Valid)", "create.weighted_ejector.target_not_valid": "Ejetando para o bloco adjacente (Alvo não foi valido)",
"create.weighted_ejector.no_target": "UNLOCALIZED: Ejecting to Adjacent block (No Target was Selected)", "create.weighted_ejector.no_target": "Ejetando para o bloco adjacente (Nenhum alvo foi selecionado)",
"create.weighted_ejector.targeting": "UNLOCALIZED: Ejecting to [%1$s,%2$s,%3$s]", "create.weighted_ejector.targeting": "Ejetando para [%1$s,%2$s,%3$s]",
"create.weighted_ejector.stack_size": "UNLOCALIZED: Ejected Stack Size", "create.weighted_ejector.stack_size": "Tamanho da pilha ejetada",
"create.logistics.when_multiple_outputs_available": "UNLOCALIZED: When Multiple Outputs Available", "create.logistics.when_multiple_outputs_available": "Quando multiplas saidas selecionadas",
"create.mechanical_arm.selection_mode.round_robin": "UNLOCALIZED: Round Robin", "create.mechanical_arm.selection_mode.round_robin": "Rodízio",
"create.mechanical_arm.selection_mode.forced_round_robin": "UNLOCALIZED: Forced Round Robin", "create.mechanical_arm.selection_mode.forced_round_robin": "Rodízio forçado",
"create.mechanical_arm.selection_mode.prefer_first": "UNLOCALIZED: Prefer First Target", "create.mechanical_arm.selection_mode.prefer_first": "Preferir primeiro alvo",
"create.tunnel.selection_mode.split": "UNLOCALIZED: Split", "create.tunnel.selection_mode.split": "Dividir",
"create.tunnel.selection_mode.forced_split": "UNLOCALIZED: Forced Split", "create.tunnel.selection_mode.forced_split": "Divisão forçada",
"create.tunnel.selection_mode.round_robin": "UNLOCALIZED: Round Robin", "create.tunnel.selection_mode.round_robin": "Rodízio",
"create.tunnel.selection_mode.forced_round_robin": "UNLOCALIZED: Forced Round Robin", "create.tunnel.selection_mode.forced_round_robin": "Rodízio forçado",
"create.tunnel.selection_mode.prefer_nearest": "UNLOCALIZED: Prefer Nearest", "create.tunnel.selection_mode.prefer_nearest": "Preferir o mais perto",
"create.tunnel.selection_mode.randomize": "UNLOCALIZED: Randomize", "create.tunnel.selection_mode.randomize": "Aleatorizar",
"create.tunnel.selection_mode.synchronize": "UNLOCALIZED: Synchronize Inputs", "create.tunnel.selection_mode.synchronize": "Sincronizar as entradas",
"create.tooltip.chute.header": "UNLOCALIZED: Chute Information", "create.tooltip.chute.header": "Informação da calha",
"create.tooltip.chute.items_move_down": "UNLOCALIZED: Items move Downward", "create.tooltip.chute.items_move_down": "Itens movimentam para baixo",
"create.tooltip.chute.items_move_up": "UNLOCALIZED: Items move Upward", "create.tooltip.chute.items_move_up": "Itens movem para cima",
"create.tooltip.chute.no_fans_attached": "UNLOCALIZED: No attached fans", "create.tooltip.chute.no_fans_attached": "Não conectado com um ventilador",
"create.tooltip.chute.fans_push_up": "UNLOCALIZED: Fans push from Below", "create.tooltip.chute.fans_push_up": "Ventiladores sopram de baixo",
"create.tooltip.chute.fans_push_down": "UNLOCALIZED: Fans push from Above", "create.tooltip.chute.fans_push_down": "Ventiladores sopram de cima",
"create.tooltip.chute.fans_pull_up": "UNLOCALIZED: Fans pull from Above", "create.tooltip.chute.fans_pull_up": "Ventiladores sugam de cima",
"create.tooltip.chute.fans_pull_down": "UNLOCALIZED: Fans pull from Below", "create.tooltip.chute.fans_pull_down": "Ventiladores sugam de baixo",
"create.tooltip.chute.contains": "UNLOCALIZED: Contains: %1$s x%2$s", "create.tooltip.chute.contains": "Contem: %1$s x%2$s",
"create.tooltip.brass_tunnel.contains": "UNLOCALIZED: Currently distributing:", "create.tooltip.brass_tunnel.contains": "Distribuindo:",
"create.tooltip.brass_tunnel.contains_entry": "UNLOCALIZED: > %1$s x%2$s", "create.tooltip.brass_tunnel.contains_entry": " > %1$s x%2$s",
"create.tooltip.brass_tunnel.retrieve": "UNLOCALIZED: Right-Click to retrieve", "create.tooltip.brass_tunnel.retrieve": "Clique direito para recuperar item",
"create.linked_controller.bind_mode": "UNLOCALIZED: Bind mode active", "create.linked_controller.bind_mode": "Modo de vinculação",
"create.linked_controller.press_keybind": "UNLOCALIZED: Press %1$s, %2$s, %3$s, %4$s, %5$s or %6$s, to bind this frequency to the respective key", "create.linked_controller.press_keybind": "Aperte %1$s, %2$s, %3$s, %4$s, %5$s or %6$s, para vincular essa frequencia para tecla respectiva",
"create.linked_controller.key_bound": "UNLOCALIZED: Frequency bound to %1$s", "create.linked_controller.key_bound": "Frequência vinculada com %1$s",
"create.linked_controller.frequency_slot_1": "UNLOCALIZED: Keybind: %1$s, Freq. #1", "create.linked_controller.frequency_slot_1": "Tecla: %1$s, Freq. #1",
"create.linked_controller.frequency_slot_2": "UNLOCALIZED: Keybind: %1$s, Freq. #2", "create.linked_controller.frequency_slot_2": "Tecla: %1$s, Freq. #2",
"create.crafting_blueprint.crafting_slot": "UNLOCALIZED: Ingredient Slot", "create.crafting_blueprint.crafting_slot": "Slot de ingrediente",
"create.crafting_blueprint.filter_items_viable": "UNLOCALIZED: Advanced filter items are viable", "create.crafting_blueprint.filter_items_viable": "Filtros avançados são viaveis",
"create.crafting_blueprint.display_slot": "UNLOCALIZED: Display Slot", "create.crafting_blueprint.display_slot": "Slot de exibição",
"create.crafting_blueprint.inferred": "UNLOCALIZED: Inferred from recipe", "create.crafting_blueprint.inferred": "Deduzido pela receita",
"create.crafting_blueprint.manually_assigned": "UNLOCALIZED: Manually assigned", "create.crafting_blueprint.manually_assigned": "Designado manualmente",
"create.crafting_blueprint.secondary_display_slot": "UNLOCALIZED: Secondary Display Slot", "create.crafting_blueprint.secondary_display_slot": "Slot de exibição secundario",
"create.crafting_blueprint.optional": "UNLOCALIZED: Optional", "create.crafting_blueprint.optional": "Opcional",
"create.potato_cannon.ammo.attack_damage": "UNLOCALIZED: %1$s Attack Damage", "create.potato_cannon.ammo.attack_damage": " %1$s Dano de ataque",
"create.potato_cannon.ammo.reload_ticks": "UNLOCALIZED: %1$s Reload Ticks", "create.potato_cannon.ammo.reload_ticks": " %1$s Velocidade de recarregamento",
"create.potato_cannon.ammo.knockback": "UNLOCALIZED: %1$s Knockback", "create.potato_cannon.ammo.knockback": " %1$s Repulsão do projetil",
"create.hint.hose_pulley.title": "UNLOCALIZED: Bottomless Supply", "create.hint.hose_pulley.title": "Abastecimento sem fundo",
"create.hint.hose_pulley": "UNLOCALIZED: The targeted body of fluid is considered infinite.", "create.hint.hose_pulley": "O corpo de fluido selecionado é considerado infinito.",
"create.hint.mechanical_arm_no_targets.title": "UNLOCALIZED: No Targets", "create.hint.mechanical_arm_no_targets.title": "Sem alvos",
"create.hint.mechanical_arm_no_targets": "UNLOCALIZED: It appears this _Mechanical_ _Arm_ has not been assigned any _targets._ Select belts, depots, funnels and other blocks by _right-clicking_ them while _holding_ the _Mechanical_ _Arm_ in your _hand_.", "create.hint.mechanical_arm_no_targets": "Aparentemente esse _Braço_ _Mecânico_ não foi designado nenhum _alvo._ Selecione esteiras, depósitos, funis e outros blocos com o _botão direito do mouse_ enquanto _segurando_ o _Braço_ _Mecanico_ na sua _mão_.",
"create.hint.empty_bearing.title": "UNLOCALIZED: Update Bearing", "create.hint.empty_bearing.title": "Atualizar o rolamento",
"create.hint.empty_bearing": "UNLOCALIZED: _Right-click_ the bearing with an _empty_ _hand_ to _attach_ the structure you just built in front of it.", "create.hint.empty_bearing": " _clique com o botão direito_ o rolamento com a _mão_ _vazia_ para _conectar_ a estrutura que você construiu não frente disso.",
"create.hint.full_deployer.title": "UNLOCALIZED: Deployer Item Overflow", "create.hint.full_deployer.title": "Implantador transbordando de itens",
"create.hint.full_deployer": "UNLOCALIZED: It appears this _Deployer_ contains _excess_ _items_ that need to be _extracted._ Use a _hopper,_ _funnel_ or other means to free it from its overflow.", "create.hint.full_deployer": "Aparenta que esse _inplantador_ contém _itens_ em _excesso_ que precisam ser _extraídos._ Use um _funil,_ _funil de andesito/latão_ ou outros meios para extrair os itens excedentes.",
"create.hint.derailed_train.title": "UNLOCALIZED: Derailed Train", "create.hint.derailed_train.title": "UNLOCALIZED: Derailed Train",
"create.hint.derailed_train": "UNLOCALIZED: It appears this _Train_ is no longer sitting on a connected track piece. _Right-Click_ using a _wrench_ in order to relocate it to a nearby track.", "create.hint.derailed_train": "UNLOCALIZED: It appears this _Train_ is no longer sitting on a connected track piece. _Right-Click_ using a _wrench_ in order to relocate it to a nearby track.",
@ -1551,7 +1551,7 @@
"create.super_glue.not_enough": "UNLOCALIZED: Not enough glue in inventory", "create.super_glue.not_enough": "UNLOCALIZED: Not enough glue in inventory",
"create.super_glue.sucess": "UNLOCALIZED: Applying Glue...", "create.super_glue.sucess": "UNLOCALIZED: Applying Glue...",
"create.gui.config.overlay1": "UNLOCALIZED: Hi :)", "create.gui.config.overlay1": "Oi :)",
"create.gui.config.overlay2": "UNLOCALIZED: This is a sample overlay", "create.gui.config.overlay2": "UNLOCALIZED: This is a sample overlay",
"create.gui.config.overlay3": "UNLOCALIZED: Click or drag with your mouse", "create.gui.config.overlay3": "UNLOCALIZED: Click or drag with your mouse",
"create.gui.config.overlay4": "UNLOCALIZED: to move this preview", "create.gui.config.overlay4": "UNLOCALIZED: to move this preview",
@ -1560,62 +1560,62 @@
"create.gui.config.overlay7": "UNLOCALIZED: Run /create overlay reset", "create.gui.config.overlay7": "UNLOCALIZED: Run /create overlay reset",
"create.gui.config.overlay8": "UNLOCALIZED: to reset to the default position", "create.gui.config.overlay8": "UNLOCALIZED: to reset to the default position",
"create.command.killTPSCommand": "UNLOCALIZED: killtps", "create.command.killTPSCommand": " killtps",
"create.command.killTPSCommand.status.slowed_by.0": "UNLOCALIZED: [Create]: Server tick is currently slowed by %s ms :o", "create.command.killTPSCommand.status.slowed_by.0": " [Create]: Server tick is currently slowed by %s ms :o",
"create.command.killTPSCommand.status.slowed_by.1": "UNLOCALIZED: [Create]: Server tick is slowed by %s ms now >:)", "create.command.killTPSCommand.status.slowed_by.1": " [Create]: Server tick is slowed by %s ms now >:)",
"create.command.killTPSCommand.status.slowed_by.2": "UNLOCALIZED: [Create]: Server tick is back to regular speed :D", "create.command.killTPSCommand.status.slowed_by.2": " [Create]: Server tick is back to regular speed :D",
"create.command.killTPSCommand.status.usage.0": "UNLOCALIZED: [Create]: use /killtps stop to bring back server tick to regular speed", "create.command.killTPSCommand.status.usage.0": " [Create]: use /killtps stop to bring back server tick to regular speed",
"create.command.killTPSCommand.status.usage.1": "UNLOCALIZED: [Create]: use /killtps start <tickTime> to artificially slow down the server tick", "create.command.killTPSCommand.status.usage.1": " [Create]: use /killtps start <tickTime> to artificially slow down the server tick",
"create.command.killTPSCommand.argument.tickTime": "UNLOCALIZED: tickTime", "create.command.killTPSCommand.argument.tickTime": "tickTime",
"create.contraption.minecart_contraption_too_big": "UNLOCALIZED: This Cart Contraption seems too big to pick up", "create.contraption.minecart_contraption_too_big": "Essa engenhoca de carrinho aparenta ser muita grande para pegar",
"create.contraption.minecart_contraption_illegal_pickup": "UNLOCALIZED: A mystical force is binding this Cart Contraption to the world", "create.contraption.minecart_contraption_illegal_pickup": "Uma força mistica esta segurando esta engenhoca de carrinho",
"_": "->------------------------] Subtitles [------------------------<-", "_": "->------------------------] Subtitles [------------------------<-",
"create.subtitle.contraption_disassemble": "UNLOCALIZED: Contraption stops", "create.subtitle.contraption_disassemble": "Engenhoca para",
"create.subtitle.peculiar_bell_use": "UNLOCALIZED: Peculiar Bell tolls", "create.subtitle.peculiar_bell_use": "Sino peculiar toca",
"create.subtitle.mixing": "UNLOCALIZED: Mixing noises", "create.subtitle.mixing": "Sons de mistura",
"create.subtitle.mechanical_press_activation_belt": "UNLOCALIZED: Mechanical Press bonks", "create.subtitle.mechanical_press_activation_belt": "Bonks da prensa mecanica",
"create.subtitle.fwoomp": "UNLOCALIZED: Potato Launcher fwoomps", "create.subtitle.fwoomp": "Fwoomps do canhão de batata",
"create.subtitle.worldshaper_place": "UNLOCALIZED: Worldshaper zaps", "create.subtitle.worldshaper_place": "Zaps do terraformador",
"create.subtitle.sanding_long": "UNLOCALIZED: Sanding noises", "create.subtitle.sanding_long": "Sons de lixa",
"create.subtitle.crushing_1": "UNLOCALIZED: Crushing noises", "create.subtitle.crushing_1": "Sons de trituração",
"create.subtitle.depot_slide": "UNLOCALIZED: Item slides", "create.subtitle.depot_slide": "Item escorrega",
"create.subtitle.saw_activate_stone": "UNLOCALIZED: Mechanical Saw activates", "create.subtitle.saw_activate_stone": "Serra mecânica ativa",
"create.subtitle.blaze_munch": "UNLOCALIZED: Blaze Burner munches", "create.subtitle.blaze_munch": "Queimador de blazer mastiga",
"create.subtitle.funnel_flap": "UNLOCALIZED: Funnel flaps", "create.subtitle.funnel_flap": "Abas do funil batendo",
"create.subtitle.schematicannon_finish": "UNLOCALIZED: Schematicannon dings", "create.subtitle.schematicannon_finish": "Ding do canhão de esquema",
"create.subtitle.haunted_bell_use": "UNLOCALIZED: Haunted Bell tolls", "create.subtitle.haunted_bell_use": "Sino assombrado toca",
"create.subtitle.scroll_value": "UNLOCALIZED: Scroll-input clicks", "create.subtitle.scroll_value": "click do scroll",
"create.subtitle.crafter_craft": "UNLOCALIZED: Crafter crafts", "create.subtitle.crafter_craft": "Fabricador fábrica",
"create.subtitle.controller_put": "UNLOCALIZED: Controller thumps", "create.subtitle.controller_put": "Thumps do controle",
"create.subtitle.cranking": "UNLOCALIZED: Hand Crank turns", "create.subtitle.cranking": "Manivela gira",
"create.subtitle.wrench_remove": "UNLOCALIZED: Component breaks", "create.subtitle.wrench_remove": "Componente quebra",
"create.subtitle.sanding_short": "UNLOCALIZED: Sanding noises", "create.subtitle.sanding_short": "Sons de lixa",
"create.subtitle.whistle": "UNLOCALIZED: Whistling", "create.subtitle.whistle": "UNLOCALIZED: Whistling",
"create.subtitle.cogs": "UNLOCALIZED: Cogwheels rumble", "create.subtitle.cogs": "tremer da rodas dentadas",
"create.subtitle.slime_added": "UNLOCALIZED: Slime squishes", "create.subtitle.slime_added": "Slime sendo espremido",
"create.subtitle.wrench_rotate": "UNLOCALIZED: Wrench used", "create.subtitle.wrench_rotate": "Chave inglesa usada",
"create.subtitle.potato_hit": "UNLOCALIZED: Vegetable impacts", "create.subtitle.potato_hit": "Impacto vegetal",
"create.subtitle.saw_activate_wood": "UNLOCALIZED: Mechanical Saw activates", "create.subtitle.saw_activate_wood": "Serra mecânica ativa",
"create.subtitle.whistle_high": "UNLOCALIZED: High whistling", "create.subtitle.whistle_high": "UNLOCALIZED: High whistling",
"create.subtitle.whistle_train": "UNLOCALIZED: Whistling", "create.subtitle.whistle_train": "UNLOCALIZED: Whistling",
"create.subtitle.haunted_bell_convert": "UNLOCALIZED: Haunted Bell awakens", "create.subtitle.haunted_bell_convert": "Sino assombrado acorda",
"create.subtitle.whistle_train_high": "UNLOCALIZED: High whistling", "create.subtitle.whistle_train_high": "UNLOCALIZED: High whistling",
"create.subtitle.whistle_train_low": "UNLOCALIZED: Low whistling", "create.subtitle.whistle_train_low": "UNLOCALIZED: Low whistling",
"create.subtitle.deny": "UNLOCALIZED: Declining boop", "create.subtitle.deny": "Boop de negação",
"create.subtitle.controller_click": "UNLOCALIZED: Controller clicks", "create.subtitle.controller_click": "Clicks do controle",
"create.subtitle.whistle_low": "UNLOCALIZED: Low whistling", "create.subtitle.whistle_low": "UNLOCALIZED: Low whistling",
"create.subtitle.schematicannon_launch_block": "UNLOCALIZED: Schematicannon fires", "create.subtitle.schematicannon_launch_block": "Canhão de esquema atira",
"create.subtitle.copper_armor_equip": "UNLOCALIZED: Diving equipment clinks", "create.subtitle.copper_armor_equip": "Tilintar dos equipamentos de mergulho",
"create.subtitle.controller_take": "UNLOCALIZED: Lectern empties", "create.subtitle.controller_take": "Atril esvaziado",
"create.subtitle.mechanical_press_activation": "UNLOCALIZED: Mechanical Press clangs", "create.subtitle.mechanical_press_activation": "Clang da prensa mecânica",
"create.subtitle.contraption_assemble": "UNLOCALIZED: Contraption moves", "create.subtitle.contraption_assemble": "Engenhoca move",
"create.subtitle.crafter_click": "UNLOCALIZED: Crafter clicks", "create.subtitle.crafter_click": "Clicks do fabricador",
"create.subtitle.depot_plop": "UNLOCALIZED: Item lands", "create.subtitle.depot_plop": "Item pousa",
"create.subtitle.confirm": "UNLOCALIZED: Affirmative ding", "create.subtitle.confirm": "Ding afirmativo",
"_": "->------------------------] Item Descriptions [------------------------<-", "_": "->------------------------] Item Descriptions [------------------------<-",

View file

@ -8,11 +8,7 @@
"results": [ "results": [
{ {
"item": "minecraft:gold_nugget", "item": "minecraft:gold_nugget",
"count": 7 "count": 18
},
{
"item": "minecraft:gold_nugget",
"chance": 0.5
}, },
{ {
"item": "create:experience_nugget", "item": "create:experience_nugget",

View file

@ -8,11 +8,14 @@ import org.apache.logging.log4j.Logger;
import com.google.gson.Gson; import com.google.gson.Gson;
import com.google.gson.GsonBuilder; import com.google.gson.GsonBuilder;
import com.simibubi.create.api.behaviour.BlockSpoutingBehaviour; import com.simibubi.create.api.behaviour.BlockSpoutingBehaviour;
import com.simibubi.create.compat.Mods;
import com.simibubi.create.compat.curios.Curios;
import com.simibubi.create.content.CreateItemGroup; import com.simibubi.create.content.CreateItemGroup;
import com.simibubi.create.content.contraptions.TorquePropagator; import com.simibubi.create.content.contraptions.TorquePropagator;
import com.simibubi.create.content.curiosities.weapons.BuiltinPotatoProjectileTypes; import com.simibubi.create.content.curiosities.weapons.BuiltinPotatoProjectileTypes;
import com.simibubi.create.content.logistics.RedstoneLinkNetworkHandler; import com.simibubi.create.content.logistics.RedstoneLinkNetworkHandler;
import com.simibubi.create.content.logistics.block.display.AllDisplayBehaviours; import com.simibubi.create.content.logistics.block.display.AllDisplayBehaviours;
import com.simibubi.create.content.logistics.block.mechanicalArm.AllArmInteractionPointTypes;
import com.simibubi.create.content.logistics.trains.GlobalRailwayManager; import com.simibubi.create.content.logistics.trains.GlobalRailwayManager;
import com.simibubi.create.content.palettes.AllPaletteBlocks; import com.simibubi.create.content.palettes.AllPaletteBlocks;
import com.simibubi.create.content.palettes.PalettesItemGroup; import com.simibubi.create.content.palettes.PalettesItemGroup;
@ -98,6 +101,7 @@ public class Create {
AllMovementBehaviours.register(); AllMovementBehaviours.register();
AllDisplayBehaviours.register(); AllDisplayBehaviours.register();
AllInteractionBehaviours.register(); AllInteractionBehaviours.register();
AllArmInteractionPointTypes.register();
AllWorldFeatures.register(); AllWorldFeatures.register();
AllEnchantments.register(); AllEnchantments.register();
AllConfigs.register(modLoadingContext); AllConfigs.register(modLoadingContext);
@ -120,6 +124,8 @@ public class Create {
modEventBus.addGenericListener(DataSerializerEntry.class, AllEntityDataSerializers::register); modEventBus.addGenericListener(DataSerializerEntry.class, AllEntityDataSerializers::register);
DistExecutor.unsafeRunWhenOn(Dist.CLIENT, () -> () -> CreateClient.onCtorClient(modEventBus, forgeEventBus)); DistExecutor.unsafeRunWhenOn(Dist.CLIENT, () -> () -> CreateClient.onCtorClient(modEventBus, forgeEventBus));
Mods.CURIOS.executeIfInstalled(() -> Curios::init);
} }
public static void init(final FMLCommonSetupEvent event) { public static void init(final FMLCommonSetupEvent event) {

View file

@ -0,0 +1,447 @@
package com.simibubi.create.api.connectivity;
import com.simibubi.create.content.contraptions.fluids.tank.CreativeFluidTankTileEntity;
import com.simibubi.create.foundation.tileEntity.IMultiTileContainer;
import com.simibubi.create.foundation.utility.Iterate;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.world.level.BlockGetter;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraft.world.level.block.entity.BlockEntityType;
import net.minecraftforge.fluids.FluidStack;
import net.minecraftforge.fluids.IFluidTank;
import net.minecraftforge.fluids.capability.CapabilityFluidHandler;
import net.minecraftforge.fluids.capability.IFluidHandler;
import net.minecraftforge.items.CapabilityItemHandler;
import org.apache.commons.lang3.tuple.Pair;
import javax.annotation.Nullable;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.PriorityQueue;
import java.util.Set;
public class ConnectivityHandler {
public static <T extends BlockEntity & IMultiTileContainer> void formMulti(T be) {
SearchCache<T> cache = new SearchCache<>();
List<T> frontier = new ArrayList<>();
frontier.add(be);
formMulti(be.getType(), be.getLevel(), cache, frontier);
}
private static <T extends BlockEntity & IMultiTileContainer> void formMulti(BlockEntityType<?> type,
BlockGetter level, SearchCache<T> cache, List<T> frontier) {
PriorityQueue<Pair<Integer, T>> creationQueue = makeCreationQueue();
Set<BlockPos> visited = new HashSet<>();
Direction.Axis mainAxis = frontier.get(0)
.getMainConnectionAxis();
// essentially, if it's a vertical multi then the search won't be restricted by
// Y
// alternately, a horizontal multi search shouldn't be restricted by X or Z
int minX = (mainAxis == Direction.Axis.Y ? Integer.MAX_VALUE : Integer.MIN_VALUE);
int minY = (mainAxis != Direction.Axis.Y ? Integer.MAX_VALUE : Integer.MIN_VALUE);
int minZ = (mainAxis == Direction.Axis.Y ? Integer.MAX_VALUE : Integer.MIN_VALUE);
for (T be : frontier) {
BlockPos pos = be.getBlockPos();
minX = Math.min(pos.getX(), minX);
minY = Math.min(pos.getY(), minY);
minZ = Math.min(pos.getZ(), minZ);
}
if (mainAxis == Direction.Axis.Y)
minX -= frontier.get(0)
.getMaxWidth();
if (mainAxis != Direction.Axis.Y)
minY -= frontier.get(0)
.getMaxWidth();
if (mainAxis == Direction.Axis.Y)
minZ -= frontier.get(0)
.getMaxWidth();
while (!frontier.isEmpty()) {
T part = frontier.remove(0);
BlockPos partPos = part.getBlockPos();
if (visited.contains(partPos))
continue;
visited.add(partPos);
int amount = tryToFormNewMulti(part, cache, true);
if (amount > 1) {
creationQueue.add(Pair.of(amount, part));
}
for (Direction.Axis axis : Iterate.axes) {
Direction dir = Direction.get(Direction.AxisDirection.NEGATIVE, axis);
BlockPos next = partPos.relative(dir);
if (next.getX() <= minX || next.getY() <= minY || next.getZ() <= minZ)
continue;
if (visited.contains(next))
continue;
T nextBe = partAt(type, level, next);
if (nextBe == null)
continue;
if (nextBe.isRemoved())
continue;
frontier.add(nextBe);
}
}
visited.clear();
while (!creationQueue.isEmpty()) {
Pair<Integer, T> next = creationQueue.poll();
T toCreate = next.getValue();
if (visited.contains(toCreate.getBlockPos()))
continue;
visited.add(toCreate.getBlockPos());
tryToFormNewMulti(toCreate, cache, false);
}
}
private static <T extends BlockEntity & IMultiTileContainer> int tryToFormNewMulti(T be, SearchCache<T> cache,
boolean simulate) {
int bestWidth = 1;
int bestAmount = -1;
if (!be.isController())
return 0;
int radius = be.getMaxWidth();
for (int w = 1; w <= radius; w++) {
int amount = tryToFormNewMultiOfWidth(be, w, cache, true);
if (amount < bestAmount)
continue;
bestWidth = w;
bestAmount = amount;
}
if (!simulate) {
int beWidth = be.getWidth();
if (beWidth == bestWidth && beWidth * beWidth * be.getHeight() == bestAmount)
return bestAmount;
splitMultiAndInvalidate(be, cache, false);
if (be instanceof IMultiTileContainer.Fluid ifluid && ifluid.hasTank())
ifluid.setTankSize(0, bestAmount);
tryToFormNewMultiOfWidth(be, bestWidth, cache, false);
be.preventConnectivityUpdate();
be.setWidth(bestWidth);
be.setHeight(bestAmount / bestWidth / bestWidth);
be.notifyMultiUpdated();
}
return bestAmount;
}
private static <T extends BlockEntity & IMultiTileContainer> int tryToFormNewMultiOfWidth(T be, int width,
SearchCache<T> cache, boolean simulate) {
int amount = 0;
int height = 0;
BlockEntityType<?> type = be.getType();
Level level = be.getLevel();
if (level == null)
return 0;
BlockPos origin = be.getBlockPos();
// optional fluid handling
IFluidTank beTank = null;
FluidStack fluid = FluidStack.EMPTY;
if (be instanceof IMultiTileContainer.Fluid ifluid && ifluid.hasTank()) {
beTank = ifluid.getTank(0);
fluid = beTank.getFluid();
}
Direction.Axis axis = be.getMainConnectionAxis();
Search: for (int yOffset = 0; yOffset < be.getMaxLength(axis, width); yOffset++) {
for (int xOffset = 0; xOffset < width; xOffset++) {
for (int zOffset = 0; zOffset < width; zOffset++) {
BlockPos pos = switch (axis) {
case X -> origin.offset(yOffset, xOffset, zOffset);
case Y -> origin.offset(xOffset, yOffset, zOffset);
case Z -> origin.offset(xOffset, zOffset, yOffset);
};
Optional<T> part = cache.getOrCache(type, level, pos);
if (part.isEmpty())
break Search;
T controller = part.get();
int otherWidth = controller.getWidth();
if (otherWidth > width)
break Search;
if (otherWidth == width && controller.getHeight() == be.getMaxLength(axis, width))
break Search;
Direction.Axis conAxis = controller.getMainConnectionAxis();
if (axis != conAxis)
break Search;
BlockPos conPos = controller.getBlockPos();
if (!conPos.equals(origin)) {
if (axis == Direction.Axis.Y) { // vertical multi, like a FluidTank
if (conPos.getX() < origin.getX())
break Search;
if (conPos.getZ() < origin.getZ())
break Search;
if (conPos.getX() + otherWidth > origin.getX() + width)
break Search;
if (conPos.getZ() + otherWidth > origin.getZ() + width)
break Search;
} else { // horizontal multi, like an ItemVault
if (axis == Direction.Axis.Z && conPos.getX() < origin.getX())
break Search;
if (conPos.getY() < origin.getY())
break Search;
if (axis == Direction.Axis.X && conPos.getZ() < origin.getZ())
break Search;
if (axis == Direction.Axis.Z && conPos.getX() + otherWidth > origin.getX() + width)
break Search;
if (conPos.getY() + otherWidth > origin.getY() + width)
break Search;
if (axis == Direction.Axis.X && conPos.getZ() + otherWidth > origin.getZ() + width)
break Search;
}
}
if (controller instanceof IMultiTileContainer.Fluid ifluidCon && ifluidCon.hasTank()) {
FluidStack otherFluid = ifluidCon.getFluid(0);
if (!fluid.isEmpty() && !otherFluid.isEmpty() && !fluid.isFluidEqual(otherFluid))
break Search;
}
}
}
amount += width * width;
height++;
}
if (simulate)
return amount;
Object extraData = be.getExtraData();
for (int yOffset = 0; yOffset < height; yOffset++) {
for (int xOffset = 0; xOffset < width; xOffset++) {
for (int zOffset = 0; zOffset < width; zOffset++) {
BlockPos pos = switch (axis) {
case X -> origin.offset(yOffset, xOffset, zOffset);
case Y -> origin.offset(xOffset, yOffset, zOffset);
case Z -> origin.offset(xOffset, zOffset, yOffset);
};
T part = partAt(type, level, pos);
if (part == null)
continue;
if (part == be)
continue;
extraData = be.modifyExtraData(extraData);
if (part instanceof IMultiTileContainer.Fluid ifluidPart && ifluidPart.hasTank()) {
IFluidTank tankAt = ifluidPart.getTank(0);
FluidStack fluidAt = tankAt.getFluid();
if (!fluidAt.isEmpty()) {
// making this generic would be a rather large mess, unfortunately
if (beTank != null && fluid.isEmpty()
&& beTank instanceof CreativeFluidTankTileEntity.CreativeSmartFluidTank) {
((CreativeFluidTankTileEntity.CreativeSmartFluidTank) beTank)
.setContainedFluid(fluidAt);
}
if (be instanceof IMultiTileContainer.Fluid ifluidBE && ifluidBE.hasTank()
&& beTank != null) {
beTank.fill(fluidAt, IFluidHandler.FluidAction.EXECUTE);
}
}
tankAt.drain(tankAt.getCapacity(), IFluidHandler.FluidAction.EXECUTE);
}
splitMultiAndInvalidate(part, cache, false);
part.setController(origin);
part.preventConnectivityUpdate();
cache.put(pos, be);
part.setHeight(height);
part.setWidth(width);
part.notifyMultiUpdated();
}
}
}
be.setExtraData(extraData);
be.notifyMultiUpdated();
return amount;
}
public static <T extends BlockEntity & IMultiTileContainer> void splitMulti(T be) {
splitMultiAndInvalidate(be, null, false);
}
// tryReconnect helps whenever only a few tanks have been removed
private static <T extends BlockEntity & IMultiTileContainer> void splitMultiAndInvalidate(T be,
@Nullable SearchCache<T> cache, boolean tryReconnect) {
Level level = be.getLevel();
if (level == null)
return;
be = be.getControllerTE();
if (be == null)
return;
int height = be.getHeight();
int width = be.getWidth();
if (width == 1 && height == 1)
return;
BlockPos origin = be.getBlockPos();
List<T> frontier = new ArrayList<>();
Direction.Axis axis = be.getMainConnectionAxis();
// fluid handling, if present
FluidStack toDistribute = FluidStack.EMPTY;
int maxCapacity = 0;
if (be instanceof IMultiTileContainer.Fluid ifluidBE && ifluidBE.hasTank()) {
toDistribute = ifluidBE.getFluid(0);
maxCapacity = ifluidBE.getTankSize(0);
if (!toDistribute.isEmpty() && !be.isRemoved())
toDistribute.shrink(maxCapacity);
ifluidBE.setTankSize(0, 1);
}
for (int yOffset = 0; yOffset < height; yOffset++) {
for (int xOffset = 0; xOffset < width; xOffset++) {
for (int zOffset = 0; zOffset < width; zOffset++) {
BlockPos pos = switch (axis) {
case X -> origin.offset(yOffset, xOffset, zOffset);
case Y -> origin.offset(xOffset, yOffset, zOffset);
case Z -> origin.offset(xOffset, zOffset, yOffset);
};
T partAt = partAt(be.getType(), level, pos);
if (partAt == null)
continue;
if (!partAt.getController()
.equals(origin))
continue;
T controllerBE = partAt.getControllerTE();
partAt.setExtraData((controllerBE == null ? null : controllerBE.getExtraData()));
partAt.removeController(true);
if (!toDistribute.isEmpty() && partAt != be) {
FluidStack copy = toDistribute.copy();
IFluidTank tank =
(partAt instanceof IMultiTileContainer.Fluid ifluidPart ? ifluidPart.getTank(0) : null);
// making this generic would be a rather large mess, unfortunately
if (tank instanceof CreativeFluidTankTileEntity.CreativeSmartFluidTank creativeTank) {
if (creativeTank.isEmpty())
creativeTank.setContainedFluid(toDistribute);
} else {
int split = Math.min(maxCapacity, toDistribute.getAmount());
copy.setAmount(split);
toDistribute.shrink(split);
if (tank != null)
tank.fill(copy, IFluidHandler.FluidAction.EXECUTE);
}
}
if (tryReconnect) {
frontier.add(partAt);
partAt.preventConnectivityUpdate();
}
if (cache != null) {
cache.put(pos, partAt);
}
}
}
}
if (be instanceof IMultiTileContainer.Inventory iinv && iinv.hasInventory()) {
be.getCapability(CapabilityItemHandler.ITEM_HANDLER_CAPABILITY)
.invalidate();
}
if (be instanceof IMultiTileContainer.Fluid ifluid && ifluid.hasTank()) {
be.getCapability(CapabilityFluidHandler.FLUID_HANDLER_CAPABILITY)
.invalidate();
}
if (tryReconnect) {
formMulti(be.getType(), level, cache == null ? new SearchCache<>() : cache, frontier);
}
}
private static <T extends BlockEntity & IMultiTileContainer> PriorityQueue<Pair<Integer, T>> makeCreationQueue() {
return new PriorityQueue<>((one, two) -> two.getKey() - one.getKey());
}
@Nullable
public static <T extends BlockEntity & IMultiTileContainer> T partAt(BlockEntityType<?> type, BlockGetter level,
BlockPos pos) {
BlockEntity be = level.getBlockEntity(pos);
if (be != null && be.getType() == type)
return checked(be);
return null;
}
public static <T extends BlockEntity & IMultiTileContainer> boolean isConnected(BlockGetter level, BlockPos pos,
BlockPos other) {
T one = checked(level.getBlockEntity(pos));
T two = checked(level.getBlockEntity(other));
if (one == null || two == null)
return false;
return one.getController()
.equals(two.getController());
}
@Nullable
@SuppressWarnings("unchecked")
private static <T extends BlockEntity & IMultiTileContainer> T checked(BlockEntity be) {
if (be instanceof IMultiTileContainer)
return (T) be;
return null;
}
private static class SearchCache<T extends BlockEntity & IMultiTileContainer> {
Map<BlockPos, Optional<T>> controllerMap;
public SearchCache() {
controllerMap = new HashMap<>();
}
void put(BlockPos pos, T target) {
controllerMap.put(pos, Optional.of(target));
}
void putEmpty(BlockPos pos) {
controllerMap.put(pos, Optional.empty());
}
boolean hasVisited(BlockPos pos) {
return controllerMap.containsKey(pos);
}
Optional<T> getOrCache(BlockEntityType<?> type, BlockGetter level, BlockPos pos) {
if (hasVisited(pos))
return controllerMap.get(pos);
T partAt = partAt(type, level, pos);
if (partAt == null) {
putEmpty(pos);
return Optional.empty();
}
T controller = checked(level.getBlockEntity(partAt.getController()));
if (controller == null) {
putEmpty(pos);
return Optional.empty();
}
put(pos, controller);
return Optional.of(controller);
}
}
}

View file

@ -12,7 +12,8 @@ import net.minecraftforge.fml.ModList;
*/ */
public enum Mods { public enum Mods {
DYNAMICTREES, DYNAMICTREES,
TCONSTRUCT; TCONSTRUCT,
CURIOS;
/** /**
* @return a boolean of whether the mod is loaded or not based on mod id * @return a boolean of whether the mod is loaded or not based on mod id

View file

@ -0,0 +1,43 @@
package com.simibubi.create.compat.curios;
import java.util.concurrent.atomic.AtomicBoolean;
import com.simibubi.create.AllItems;
import com.simibubi.create.content.contraptions.goggles.GogglesItem;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.fml.DistExecutor;
import net.minecraftforge.fml.InterModComms;
import net.minecraftforge.fml.event.lifecycle.FMLClientSetupEvent;
import net.minecraftforge.fml.event.lifecycle.InterModEnqueueEvent;
import net.minecraftforge.fml.javafmlmod.FMLJavaModLoadingContext;
import top.theillusivec4.curios.api.CuriosCapability;
import top.theillusivec4.curios.api.SlotTypeMessage;
import top.theillusivec4.curios.api.SlotTypePreset;
import top.theillusivec4.curios.api.type.inventory.ICurioStacksHandler;
public class Curios {
public static void init() {
FMLJavaModLoadingContext.get().getModEventBus().addListener(Curios::onInterModEnqueue);
FMLJavaModLoadingContext.get().getModEventBus().addListener(Curios::onClientSetup);
GogglesItem.addIsWearingPredicate(player -> {
AtomicBoolean hasGoggles = new AtomicBoolean(false);
player.getCapability(CuriosCapability.INVENTORY).ifPresent(handler -> {
ICurioStacksHandler stacksHandler = handler.getCurios().get("head");
if(stacksHandler != null) hasGoggles.set(stacksHandler.getStacks().getStackInSlot(0).getItem() == AllItems.GOGGLES.get());
});
return hasGoggles.get();
});
DistExecutor.unsafeRunWhenOn(Dist.CLIENT, () -> () -> FMLJavaModLoadingContext.get().getModEventBus().addListener(CuriosRenderers::onLayerRegister));
}
private static void onInterModEnqueue(final InterModEnqueueEvent event) {
InterModComms.sendTo("curios", SlotTypeMessage.REGISTER_TYPE, () -> SlotTypePreset.HEAD.getMessageBuilder().build());
}
private static void onClientSetup(final FMLClientSetupEvent event) {
CuriosRenderers.register();
}
}

View file

@ -0,0 +1,21 @@
package com.simibubi.create.compat.curios;
import com.simibubi.create.AllItems;
import net.minecraft.client.Minecraft;
import net.minecraft.client.model.geom.builders.LayerDefinition;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.api.distmarker.OnlyIn;
import net.minecraftforge.client.event.EntityRenderersEvent;
import top.theillusivec4.curios.api.client.CuriosRendererRegistry;
@OnlyIn(Dist.CLIENT)
public class CuriosRenderers {
public static void register() {
CuriosRendererRegistry.register(AllItems.GOGGLES.get(), () -> new GogglesCurioRenderer(Minecraft.getInstance().getEntityModels().bakeLayer(GogglesCurioRenderer.LAYER)));
}
public static void onLayerRegister(final EntityRenderersEvent.RegisterLayerDefinitions event) {
event.registerLayerDefinition(GogglesCurioRenderer.LAYER, () -> LayerDefinition.create(GogglesCurioRenderer.mesh(), 1, 1));
}
}

View file

@ -0,0 +1,73 @@
package com.simibubi.create.compat.curios;
import com.mojang.blaze3d.vertex.PoseStack;
import com.mojang.math.Vector3f;
import com.simibubi.create.Create;
import net.minecraft.client.Minecraft;
import net.minecraft.client.model.EntityModel;
import net.minecraft.client.model.HumanoidModel;
import net.minecraft.client.model.geom.ModelLayerLocation;
import net.minecraft.client.model.geom.ModelPart;
import net.minecraft.client.model.geom.PartPose;
import net.minecraft.client.model.geom.builders.CubeDeformation;
import net.minecraft.client.model.geom.builders.CubeListBuilder;
import net.minecraft.client.model.geom.builders.MeshDefinition;
import net.minecraft.client.renderer.MultiBufferSource;
import net.minecraft.client.renderer.block.model.ItemTransforms;
import net.minecraft.client.renderer.entity.RenderLayerParent;
import net.minecraft.client.renderer.texture.OverlayTexture;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.entity.EquipmentSlot;
import net.minecraft.world.entity.LivingEntity;
import net.minecraft.world.item.ItemStack;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.api.distmarker.OnlyIn;
import top.theillusivec4.curios.api.SlotContext;
import top.theillusivec4.curios.api.client.ICurioRenderer;
@OnlyIn(Dist.CLIENT)
public class GogglesCurioRenderer implements ICurioRenderer {
public static final ModelLayerLocation LAYER = new ModelLayerLocation(new ResourceLocation(Create.ID, "goggles"), "goggles");
private final HumanoidModel<LivingEntity> model;
public GogglesCurioRenderer(ModelPart part) {
this.model = new HumanoidModel<>(part);
}
@Override
public <T extends LivingEntity, M extends EntityModel<T>> void render(ItemStack stack, SlotContext slotContext, PoseStack matrixStack, RenderLayerParent<T, M> renderLayerParent, MultiBufferSource renderTypeBuffer, int light, float limbSwing, float limbSwingAmount, float partialTicks, float ageInTicks, float netHeadYaw, float headPitch) {
// Prepare values for transformation
model.setupAnim(slotContext.entity(), limbSwing, limbSwingAmount, ageInTicks, netHeadYaw, headPitch);
model.prepareMobModel(slotContext.entity(), limbSwing, limbSwingAmount, partialTicks);
ICurioRenderer.followHeadRotations(slotContext.entity(), model.head);
// Translate and rotate with our head
matrixStack.pushPose();
matrixStack.translate(model.head.x / 16.0, model.head.y / 16.0, model.head.z / 16.0);
matrixStack.mulPose(Vector3f.YP.rotation(model.head.yRot));
matrixStack.mulPose(Vector3f.XP.rotation(model.head.xRot));
// Translate and scale to our head
matrixStack.translate(0, -0.25, 0);
matrixStack.mulPose(Vector3f.ZP.rotationDegrees(180.0f));
matrixStack.scale(0.625f, 0.625f, 0.625f);
if(!slotContext.entity().getItemBySlot(EquipmentSlot.HEAD).isEmpty()) {
matrixStack.mulPose(Vector3f.ZP.rotationDegrees(180.0f));
matrixStack.translate(0, -0.25, 0);
}
// Render
Minecraft.getInstance().getItemRenderer().renderStatic(stack, ItemTransforms.TransformType.HEAD, light, OverlayTexture.NO_OVERLAY, matrixStack, renderTypeBuffer, 0);
matrixStack.popPose();
}
public static MeshDefinition mesh() {
CubeListBuilder builder = new CubeListBuilder();
MeshDefinition mesh = HumanoidModel.createMesh(CubeDeformation.NONE, 0);
mesh.getRoot().addOrReplaceChild("head", builder, PartPose.ZERO);
return mesh;
}
}

View file

@ -16,7 +16,7 @@ public class HalfShaftInstance extends SingleRotatingInstance {
@Override @Override
protected Instancer<RotatingData> getModel() { protected Instancer<RotatingData> getModel() {
Direction dir = getShaftDirection(); Direction dir = getShaftDirection();
return getRotatingMaterial().getModel(AllBlockPartials.SHAFT_HALF, blockState, dir); return getRotatingMaterial().getModel(AllBlockPartials.SHAFT_HALF, dir);
} }
protected Direction getShaftDirection() { protected Direction getShaftDirection() {

View file

@ -39,14 +39,14 @@ public class DrillActorInstance extends ActorInstance {
else else
eulerY = facing.toYRot() + ((axis == Direction.Axis.X) ? 180 : 0); eulerY = facing.toYRot() + ((axis == Direction.Axis.X) ? 180 : 0);
drillHead = material.getModel(AllBlockPartials.DRILL_HEAD, state).createInstance(); drillHead = material.getModel(AllBlockPartials.DRILL_HEAD)
.createInstance()
drillHead.setPosition(context.localPos) .setPosition(context.localPos)
.setBlockLight(localBlockLight()) .setBlockLight(localBlockLight())
.setRotationOffset(0) .setRotationOffset(0)
.setRotationAxis(0, 0, 1) .setRotationAxis(0, 0, 1)
.setLocalRotation(new Quaternion(eulerX, eulerY, 0, true)) .setLocalRotation(new Quaternion(eulerX, eulerY, 0, true))
.setSpeed(getSpeed(facing)); .setSpeed(getSpeed(facing));
} }
@Override @Override

View file

@ -21,6 +21,6 @@ public class DrillInstance extends SingleRotatingInstance {
protected Instancer<RotatingData> getModel() { protected Instancer<RotatingData> getModel() {
BlockState referenceState = blockEntity.getBlockState(); BlockState referenceState = blockEntity.getBlockState();
Direction facing = referenceState.getValue(BlockStateProperties.FACING); Direction facing = referenceState.getValue(BlockStateProperties.FACING);
return getRotatingMaterial().getModel(AllBlockPartials.DRILL_HEAD, referenceState, facing); return getRotatingMaterial().getModel(AllBlockPartials.DRILL_HEAD, facing);
} }
} }

View file

@ -3,6 +3,7 @@ package com.simibubi.create.content.contraptions.components.actors;
import com.jozufozu.flywheel.api.Material; import com.jozufozu.flywheel.api.Material;
import com.jozufozu.flywheel.api.MaterialManager; import com.jozufozu.flywheel.api.MaterialManager;
import com.jozufozu.flywheel.core.Materials; import com.jozufozu.flywheel.core.Materials;
import com.jozufozu.flywheel.core.Models;
import com.jozufozu.flywheel.core.materials.model.ModelData; import com.jozufozu.flywheel.core.materials.model.ModelData;
import com.jozufozu.flywheel.core.virtual.VirtualRenderWorld; import com.jozufozu.flywheel.core.virtual.VirtualRenderWorld;
import com.simibubi.create.AllBlockPartials; import com.simibubi.create.AllBlockPartials;
@ -41,7 +42,8 @@ public class HarvesterActorInstance extends ActorInstance {
facing = state.getValue(BlockStateProperties.HORIZONTAL_FACING); facing = state.getValue(BlockStateProperties.HORIZONTAL_FACING);
harvester = material.getModel(AllBlockPartials.HARVESTER_BLADE, state).createInstance(); harvester = material.model(Models.partial(AllBlockPartials.HARVESTER_BLADE))
.createInstance();
horizontalAngle = facing.toYRot() + ((facing.getAxis() == Direction.Axis.X) ? 180 : 0); horizontalAngle = facing.toYRot() + ((facing.getAxis() == Direction.Axis.X) ? 180 : 0);

View file

@ -33,11 +33,11 @@ public class PIInstance {
this.lit = lit; this.lit = lit;
middle = materialManager.defaultSolid() middle = materialManager.defaultSolid()
.material(Materials.TRANSFORMED) .material(Materials.TRANSFORMED)
.getModel(PortableStorageInterfaceRenderer.getMiddleForState(blockState, lit), blockState) .getModel(PortableStorageInterfaceRenderer.getMiddleForState(blockState, lit))
.createInstance(); .createInstance();
top = materialManager.defaultSolid() top = materialManager.defaultSolid()
.material(Materials.TRANSFORMED) .material(Materials.TRANSFORMED)
.getModel(PortableStorageInterfaceRenderer.getTopForState(blockState), blockState) .getModel(PortableStorageInterfaceRenderer.getTopForState(blockState))
.createInstance(); .createInstance();
} }
@ -66,7 +66,7 @@ public class PIInstance {
this.lit = lit; this.lit = lit;
materialManager.defaultSolid() materialManager.defaultSolid()
.material(Materials.TRANSFORMED) .material(Materials.TRANSFORMED)
.getModel(PortableStorageInterfaceRenderer.getMiddleForState(blockState, lit), blockState) .getModel(PortableStorageInterfaceRenderer.getMiddleForState(blockState, lit))
.stealInstance(middle); .stealInstance(middle);
} }
} }

View file

@ -23,7 +23,7 @@ public class MechanicalCrafterInstance extends SingleRotatingInstance {
protected Instancer<RotatingData> getModel() { protected Instancer<RotatingData> getModel() {
Direction facing = blockState.getValue(MechanicalCrafterBlock.HORIZONTAL_FACING); Direction facing = blockState.getValue(MechanicalCrafterBlock.HORIZONTAL_FACING);
return getRotatingMaterial().getModel(AllBlockPartials.SHAFTLESS_COGWHEEL, blockState, facing, rotateToFace(facing)); return getRotatingMaterial().getModel(AllBlockPartials.SHAFTLESS_COGWHEEL, facing, rotateToFace(facing));
} }
private Supplier<PoseStack> rotateToFace(Direction facing) { private Supplier<PoseStack> rotateToFace(Direction facing) {

View file

@ -31,7 +31,7 @@ public class HandCrankInstance extends SingleRotatingInstance implements Dynamic
facing = blockState.getValue(BlockStateProperties.FACING); facing = blockState.getValue(BlockStateProperties.FACING);
Direction opposite = facing.getOpposite(); Direction opposite = facing.getOpposite();
Instancer<ModelData> model = getTransformMaterial().getModel(renderedHandle, blockState, opposite); Instancer<ModelData> model = getTransformMaterial().getModel(renderedHandle, opposite);
crank = model.createInstance(); crank = model.createInstance();
rotateCrank(); rotateCrank();

View file

@ -61,8 +61,8 @@ public class DeployerActorInstance extends ActorInstance {
xRot = facing == Direction.UP ? 270 : facing == Direction.DOWN ? 90 : 0; xRot = facing == Direction.UP ? 270 : facing == Direction.DOWN ? 90 : 0;
zRot = rotatePole ? 90 : 0; zRot = rotatePole ? 90 : 0;
pole = mat.getModel(AllBlockPartials.DEPLOYER_POLE, state).createInstance(); pole = mat.getModel(AllBlockPartials.DEPLOYER_POLE).createInstance();
hand = mat.getModel(handPose, state).createInstance(); hand = mat.getModel(handPose).createInstance();
Direction.Axis axis = ((IRotate) state.getBlock()).getRotationAxis(state); Direction.Axis axis = ((IRotate) state.getBlock()).getRotationAxis(state);
shaft = materialManager.defaultSolid() shaft = materialManager.defaultSolid()

View file

@ -47,11 +47,11 @@ public class DeployerInstance extends ShaftInstance implements DynamicInstance,
xRot = facing == Direction.UP ? 270 : facing == Direction.DOWN ? 90 : 0; xRot = facing == Direction.UP ? 270 : facing == Direction.DOWN ? 90 : 0;
zRot = rotatePole ? 90 : 0; zRot = rotatePole ? 90 : 0;
pole = getOrientedMaterial().getModel(AllBlockPartials.DEPLOYER_POLE, blockState).createInstance(); pole = getOrientedMaterial().getModel(AllBlockPartials.DEPLOYER_POLE).createInstance();
currentHand = this.tile.getHandPose(); currentHand = this.tile.getHandPose();
hand = getOrientedMaterial().getModel(currentHand, blockState).createInstance(); hand = getOrientedMaterial().getModel(currentHand).createInstance();
progress = getProgress(AnimationTickHolder.getPartialTicks()); progress = getProgress(AnimationTickHolder.getPartialTicks());
updateRotation(pole, hand, yRot, xRot, zRot); updateRotation(pole, hand, yRot, xRot, zRot);
@ -64,7 +64,7 @@ public class DeployerInstance extends ShaftInstance implements DynamicInstance,
if (currentHand != handPose) { if (currentHand != handPose) {
currentHand = handPose; currentHand = handPose;
getOrientedMaterial().getModel(currentHand, blockState) getOrientedMaterial().getModel(currentHand)
.stealInstance(hand); .stealInstance(hand);
} }
} }

View file

@ -25,10 +25,10 @@ public class FanInstance extends KineticTileInstance<EncasedFanTileEntity> {
direction = blockState.getValue(FACING); direction = blockState.getValue(FACING);
opposite = direction.getOpposite(); opposite = direction.getOpposite();
shaft = getRotatingMaterial().getModel(AllBlockPartials.SHAFT_HALF, blockState, opposite).createInstance(); shaft = getRotatingMaterial().getModel(AllBlockPartials.SHAFT_HALF, opposite).createInstance();
fan = modelManager.defaultCutout() fan = modelManager.defaultCutout()
.material(AllMaterialSpecs.ROTATING) .material(AllMaterialSpecs.ROTATING)
.getModel(AllBlockPartials.ENCASED_FAN_INNER, blockState, opposite) .getModel(AllBlockPartials.ENCASED_FAN_INNER, opposite)
.createInstance(); .createInstance();
setup(shaft); setup(shaft);

View file

@ -15,6 +15,6 @@ public class MillStoneCogInstance extends SingleRotatingInstance {
@Override @Override
protected Instancer<RotatingData> getModel() { protected Instancer<RotatingData> getModel() {
return getRotatingMaterial().getModel(AllBlockPartials.MILLSTONE_COG, blockEntity.getBlockState()); return getRotatingMaterial().getModel(AllBlockPartials.MILLSTONE_COG);
} }
} }

View file

@ -22,13 +22,13 @@ public class MixerInstance extends EncasedCogInstance implements DynamicInstance
super(dispatcher, tile, false); super(dispatcher, tile, false);
this.mixer = tile; this.mixer = tile;
mixerHead = getRotatingMaterial().getModel(AllBlockPartials.MECHANICAL_MIXER_HEAD, blockState) mixerHead = getRotatingMaterial().getModel(AllBlockPartials.MECHANICAL_MIXER_HEAD)
.createInstance(); .createInstance();
mixerHead.setRotationAxis(Direction.Axis.Y); mixerHead.setRotationAxis(Direction.Axis.Y);
mixerPole = getOrientedMaterial() mixerPole = getOrientedMaterial()
.getModel(AllBlockPartials.MECHANICAL_MIXER_POLE, blockState) .getModel(AllBlockPartials.MECHANICAL_MIXER_POLE)
.createInstance(); .createInstance();
@ -42,7 +42,7 @@ public class MixerInstance extends EncasedCogInstance implements DynamicInstance
protected Instancer<RotatingData> getCogModel() { protected Instancer<RotatingData> getCogModel() {
return materialManager.defaultSolid() return materialManager.defaultSolid()
.material(AllMaterialSpecs.ROTATING) .material(AllMaterialSpecs.ROTATING)
.getModel(AllBlockPartials.SHAFTLESS_COGWHEEL, blockEntity.getBlockState()); .getModel(AllBlockPartials.SHAFTLESS_COGWHEEL);
} }
@Override @Override

View file

@ -22,7 +22,7 @@ public class PressInstance extends ShaftInstance implements DynamicInstance {
pressHead = dispatcher.defaultSolid() pressHead = dispatcher.defaultSolid()
.material(Materials.ORIENTED) .material(Materials.ORIENTED)
.getModel(AllBlockPartials.MECHANICAL_PRESS_HEAD, blockState) .getModel(AllBlockPartials.MECHANICAL_PRESS_HEAD)
.createInstance(); .createInstance();
Quaternion q = Vector3f.YP Quaternion q = Vector3f.YP

View file

@ -25,7 +25,7 @@ public class SawInstance extends SingleRotatingInstance {
.isHorizontal()) { .isHorizontal()) {
BlockState referenceState = blockState.rotate(blockEntity.getLevel(), blockEntity.getBlockPos(), Rotation.CLOCKWISE_180); BlockState referenceState = blockState.rotate(blockEntity.getLevel(), blockEntity.getBlockPos(), Rotation.CLOCKWISE_180);
Direction facing = referenceState.getValue(BlockStateProperties.FACING); Direction facing = referenceState.getValue(BlockStateProperties.FACING);
return getRotatingMaterial().getModel(AllBlockPartials.SHAFT_HALF, referenceState, facing); return getRotatingMaterial().getModel(AllBlockPartials.SHAFT_HALF, facing);
} else { } else {
return getRotatingMaterial().getModel(shaft()); return getRotatingMaterial().getModel(shaft());
} }

View file

@ -5,6 +5,7 @@ import java.util.List;
import com.simibubi.create.AllBlocks; import com.simibubi.create.AllBlocks;
import com.simibubi.create.AllTags.AllBlockTags; import com.simibubi.create.AllTags.AllBlockTags;
import com.simibubi.create.api.connectivity.ConnectivityHandler;
import com.simibubi.create.content.contraptions.components.actors.AttachedActorBlock; import com.simibubi.create.content.contraptions.components.actors.AttachedActorBlock;
import com.simibubi.create.content.contraptions.components.actors.HarvesterBlock; import com.simibubi.create.content.contraptions.components.actors.HarvesterBlock;
import com.simibubi.create.content.contraptions.components.actors.PloughBlock; import com.simibubi.create.content.contraptions.components.actors.PloughBlock;
@ -28,10 +29,8 @@ import com.simibubi.create.content.contraptions.components.structureMovement.pis
import com.simibubi.create.content.contraptions.components.structureMovement.pulley.PulleyBlock; import com.simibubi.create.content.contraptions.components.structureMovement.pulley.PulleyBlock;
import com.simibubi.create.content.contraptions.components.structureMovement.pulley.PulleyTileEntity; import com.simibubi.create.content.contraptions.components.structureMovement.pulley.PulleyTileEntity;
import com.simibubi.create.content.contraptions.fluids.tank.FluidTankBlock; import com.simibubi.create.content.contraptions.fluids.tank.FluidTankBlock;
import com.simibubi.create.content.contraptions.fluids.tank.FluidTankConnectivityHandler;
import com.simibubi.create.content.logistics.block.redstone.RedstoneLinkBlock; import com.simibubi.create.content.logistics.block.redstone.RedstoneLinkBlock;
import com.simibubi.create.content.logistics.block.vault.ItemVaultBlock; import com.simibubi.create.content.logistics.block.vault.ItemVaultBlock;
import com.simibubi.create.content.logistics.block.vault.ItemVaultConnectivityHandler;
import com.simibubi.create.content.logistics.trains.IBogeyBlock; import com.simibubi.create.content.logistics.trains.IBogeyBlock;
import com.simibubi.create.content.logistics.trains.ITrackBlock; import com.simibubi.create.content.logistics.trains.ITrackBlock;
import com.simibubi.create.content.logistics.trains.management.edgePoint.station.StationBlock; import com.simibubi.create.content.logistics.trains.management.edgePoint.station.StationBlock;
@ -338,9 +337,9 @@ public class BlockMovementChecks {
return direction.getAxis() != state.getValue(SailBlock.FACING) return direction.getAxis() != state.getValue(SailBlock.FACING)
.getAxis(); .getAxis();
if (state.getBlock() instanceof FluidTankBlock) if (state.getBlock() instanceof FluidTankBlock)
return FluidTankConnectivityHandler.isConnected(world, pos, pos.relative(direction)); return ConnectivityHandler.isConnected(world, pos, pos.relative(direction));
if (state.getBlock() instanceof ItemVaultBlock) if (state.getBlock() instanceof ItemVaultBlock)
return ItemVaultConnectivityHandler.isConnected(world, pos, pos.relative(direction)); return ConnectivityHandler.isConnected(world, pos, pos.relative(direction));
if (AllBlocks.STICKER.has(state) && state.getValue(StickerBlock.EXTENDED)) { if (AllBlocks.STICKER.has(state) && state.getValue(StickerBlock.EXTENDED)) {
return direction == state.getValue(StickerBlock.FACING) return direction == state.getValue(StickerBlock.FACING)
&& !isNotSupportive(world.getBlockState(pos.relative(direction)), direction.getOpposite()); && !isNotSupportive(world.getBlockState(pos.relative(direction)), direction.getOpposite());

View file

@ -35,7 +35,7 @@ public class BearingInstance<B extends KineticTileEntity & IBearingTileEntity> e
PartialModel top = PartialModel top =
bearing.isWoodenTop() ? AllBlockPartials.BEARING_TOP_WOODEN : AllBlockPartials.BEARING_TOP; bearing.isWoodenTop() ? AllBlockPartials.BEARING_TOP_WOODEN : AllBlockPartials.BEARING_TOP;
topInstance = getOrientedMaterial().getModel(top, blockState).createInstance(); topInstance = getOrientedMaterial().getModel(top).createInstance();
topInstance.setPosition(getInstancePosition()).setRotation(blockOrientation); topInstance.setPosition(getInstancePosition()).setRotation(blockOrientation);
} }

View file

@ -38,7 +38,7 @@ public class StabilizedBearingInstance extends ActorInstance {
topInstance = materialManager.defaultSolid() topInstance = materialManager.defaultSolid()
.material(Materials.ORIENTED) .material(Materials.ORIENTED)
.getModel(AllBlockPartials.BEARING_TOP, blockState) .getModel(AllBlockPartials.BEARING_TOP)
.createInstance(); .createInstance();
int blockLight = localBlockLight(); int blockLight = localBlockLight();
@ -48,7 +48,7 @@ public class StabilizedBearingInstance extends ActorInstance {
shaft = materialManager.defaultSolid() shaft = materialManager.defaultSolid()
.material(AllMaterialSpecs.ROTATING) .material(AllMaterialSpecs.ROTATING)
.getModel(AllBlockPartials.SHAFT_HALF, blockState, blockState.getValue(BlockStateProperties.FACING).getOpposite()) .getModel(AllBlockPartials.SHAFT_HALF, blockState.getValue(BlockStateProperties.FACING).getOpposite())
.createInstance(); .createInstance();
// not rotating so no need to set speed, axis, etc. // not rotating so no need to set speed, axis, etc.

View file

@ -17,20 +17,20 @@ public class StickerInstance extends BlockEntityInstance<StickerTileEntity> impl
float lastOffset = Float.NaN; float lastOffset = Float.NaN;
final Direction facing; final Direction facing;
final boolean fakeWorld; final boolean fakeWorld;
final int offset; final int extended;
private final ModelData head; private final ModelData head;
public StickerInstance(MaterialManager modelManager, StickerTileEntity tile) { public StickerInstance(MaterialManager modelManager, StickerTileEntity tile) {
super(modelManager, tile); super(modelManager, tile);
head = getTransformMaterial().getModel(AllBlockPartials.STICKER_HEAD, blockState).createInstance(); head = getTransformMaterial().getModel(AllBlockPartials.STICKER_HEAD).createInstance();
fakeWorld = tile.getLevel() != Minecraft.getInstance().level; fakeWorld = tile.getLevel() != Minecraft.getInstance().level;
facing = blockState.getValue(StickerBlock.FACING); facing = blockState.getValue(StickerBlock.FACING);
offset = blockState.getValue(StickerBlock.EXTENDED) ? 1 : 0; extended = blockState.getValue(StickerBlock.EXTENDED) ? 1 : 0;
animateHead(offset); animateHead(extended);
} }
@Override @Override
@ -38,7 +38,7 @@ public class StickerInstance extends BlockEntityInstance<StickerTileEntity> impl
float offset = blockEntity.piston.getValue(AnimationTickHolder.getPartialTicks()); float offset = blockEntity.piston.getValue(AnimationTickHolder.getPartialTicks());
if (fakeWorld) if (fakeWorld)
offset = this.offset; offset = this.extended;
if (Mth.equal(offset, lastOffset)) if (Mth.equal(offset, lastOffset))
return; return;

View file

@ -30,7 +30,7 @@ public class GantryCarriageInstance extends ShaftInstance implements DynamicInst
super(dispatcher, tile); super(dispatcher, tile);
gantryCogs = getTransformMaterial() gantryCogs = getTransformMaterial()
.getModel(AllBlockPartials.GANTRY_COGS, blockState) .getModel(AllBlockPartials.GANTRY_COGS)
.createInstance(); .createInstance();
facing = blockState.getValue(GantryCarriageBlock.FACING); facing = blockState.getValue(GantryCarriageBlock.FACING);

View file

@ -162,7 +162,7 @@ public class CartAssemblerTileEntity extends SmartTileEntity implements IDisplay
OrientedContraptionEntity entity = OrientedContraptionEntity.create(world, contraption, initialOrientation); OrientedContraptionEntity entity = OrientedContraptionEntity.create(world, contraption, initialOrientation);
if (couplingFound) if (couplingFound)
entity.setCouplingId(cart.getUUID()); entity.setCouplingId(cart.getUUID());
entity.setPos(pos.getX(), pos.getY(), pos.getZ()); entity.setPos(pos.getX() + .5, pos.getY(), pos.getZ() + .5);
world.addFreshEntity(entity); world.addFreshEntity(entity);
entity.startRiding(cart); entity.startRiding(cart);

View file

@ -15,27 +15,27 @@ public class HosePulleyInstance extends AbstractPulleyInstance {
} }
protected Instancer<OrientedData> getRopeModel() { protected Instancer<OrientedData> getRopeModel() {
return getOrientedMaterial().getModel(AllBlockPartials.HOSE, blockState); return getOrientedMaterial().getModel(AllBlockPartials.HOSE);
} }
protected Instancer<OrientedData> getMagnetModel() { protected Instancer<OrientedData> getMagnetModel() {
return materialManager.defaultCutout() return materialManager.defaultCutout()
.material(Materials.ORIENTED) .material(Materials.ORIENTED)
.getModel(AllBlockPartials.HOSE_MAGNET, blockState); .getModel(AllBlockPartials.HOSE_MAGNET);
} }
protected Instancer<OrientedData> getHalfMagnetModel() { protected Instancer<OrientedData> getHalfMagnetModel() {
return materialManager.defaultCutout() return materialManager.defaultCutout()
.material(Materials.ORIENTED) .material(Materials.ORIENTED)
.getModel(AllBlockPartials.HOSE_HALF_MAGNET, blockState); .getModel(AllBlockPartials.HOSE_HALF_MAGNET);
} }
protected Instancer<OrientedData> getCoilModel() { protected Instancer<OrientedData> getCoilModel() {
return getOrientedMaterial().getModel(AllBlockPartials.HOSE_COIL, blockState, rotatingAbout); return getOrientedMaterial().getModel(AllBlockPartials.HOSE_COIL, rotatingAbout);
} }
protected Instancer<OrientedData> getHalfRopeModel() { protected Instancer<OrientedData> getHalfRopeModel() {
return getOrientedMaterial().getModel(AllBlockPartials.HOSE_HALF, blockState); return getOrientedMaterial().getModel(AllBlockPartials.HOSE_HALF);
} }
protected float getOffset() { protected float getOffset() {

View file

@ -22,15 +22,15 @@ public class RopePulleyInstance extends AbstractPulleyInstance {
} }
protected Instancer<OrientedData> getHalfMagnetModel() { protected Instancer<OrientedData> getHalfMagnetModel() {
return getOrientedMaterial().getModel(AllBlockPartials.ROPE_HALF_MAGNET, blockState); return getOrientedMaterial().getModel(AllBlockPartials.ROPE_HALF_MAGNET);
} }
protected Instancer<OrientedData> getCoilModel() { protected Instancer<OrientedData> getCoilModel() {
return getOrientedMaterial().getModel(AllBlockPartials.ROPE_COIL, blockState, rotatingAbout); return getOrientedMaterial().getModel(AllBlockPartials.ROPE_COIL, rotatingAbout);
} }
protected Instancer<OrientedData> getHalfRopeModel() { protected Instancer<OrientedData> getHalfRopeModel() {
return getOrientedMaterial().getModel(AllBlockPartials.ROPE_HALF, blockState); return getOrientedMaterial().getModel(AllBlockPartials.ROPE_HALF);
} }
protected float getOffset() { protected float getOffset() {

View file

@ -4,7 +4,7 @@ import static org.lwjgl.opengl.GL11.glBindTexture;
import static org.lwjgl.opengl.GL12.GL_TEXTURE_3D; import static org.lwjgl.opengl.GL12.GL_TEXTURE_3D;
import com.jozufozu.flywheel.backend.Backend; import com.jozufozu.flywheel.backend.Backend;
import com.jozufozu.flywheel.backend.RenderLayer; import com.jozufozu.flywheel.api.RenderLayer;
import com.jozufozu.flywheel.backend.gl.GlStateTracker; import com.jozufozu.flywheel.backend.gl.GlStateTracker;
import com.jozufozu.flywheel.backend.gl.GlTextureUnit; import com.jozufozu.flywheel.backend.gl.GlTextureUnit;
import com.jozufozu.flywheel.config.BackendType; import com.jozufozu.flywheel.config.BackendType;

View file

@ -32,7 +32,7 @@ public class PumpCogInstance extends SingleRotatingInstance implements DynamicIn
materialManager.defaultSolid() materialManager.defaultSolid()
.material(Materials.TRANSFORMED) .material(Materials.TRANSFORMED)
.getModel(AllBlockPartials.MECHANICAL_PUMP_ARROW, blockState) .getModel(AllBlockPartials.MECHANICAL_PUMP_ARROW)
.createInstances(arrows); .createInstances(arrows);
} }
@ -63,7 +63,7 @@ public class PumpCogInstance extends SingleRotatingInstance implements DynamicIn
protected Instancer<RotatingData> getModel() { protected Instancer<RotatingData> getModel() {
BlockState referenceState = blockEntity.getBlockState(); BlockState referenceState = blockEntity.getBlockState();
Direction facing = referenceState.getValue(BlockStateProperties.FACING); Direction facing = referenceState.getValue(BlockStateProperties.FACING);
return getRotatingMaterial().getModel(AllBlockPartials.MECHANICAL_PUMP_COG, referenceState, facing); return getRotatingMaterial().getModel(AllBlockPartials.MECHANICAL_PUMP_COG, facing);
} }
@Override @Override

View file

@ -30,6 +30,8 @@ import net.minecraftforge.fluids.FluidStack;
public class FluidDrainingBehaviour extends FluidManipulationBehaviour { public class FluidDrainingBehaviour extends FluidManipulationBehaviour {
public static final BehaviourType<FluidDrainingBehaviour> TYPE = new BehaviourType<>();
Fluid fluid; Fluid fluid;
// Execution // Execution
@ -322,8 +324,6 @@ public class FluidDrainingBehaviour extends FluidManipulationBehaviour {
tileEntity.sendData(); tileEntity.sendData();
} }
public static BehaviourType<FluidDrainingBehaviour> TYPE = new BehaviourType<>();
@Override @Override
public BehaviourType<?> getType() { public BehaviourType<?> getType() {
return TYPE; return TYPE;

View file

@ -41,6 +41,8 @@ import net.minecraft.world.ticks.LevelTicks;
public class FluidFillingBehaviour extends FluidManipulationBehaviour { public class FluidFillingBehaviour extends FluidManipulationBehaviour {
public static final BehaviourType<FluidFillingBehaviour> TYPE = new BehaviourType<>();
PriorityQueue<BlockPosEntry> queue; PriorityQueue<BlockPosEntry> queue;
List<BlockPosEntry> infinityCheckFrontier; List<BlockPosEntry> infinityCheckFrontier;
@ -72,7 +74,7 @@ public class FluidFillingBehaviour extends FluidManipulationBehaviour {
(p, d) -> infinityCheckFrontier.add(new BlockPosEntry(p, d)), true); (p, d) -> infinityCheckFrontier.add(new BlockPosEntry(p, d)), true);
int maxBlocks = maxBlocks(); int maxBlocks = maxBlocks();
if (infinityCheckVisited.size() > maxBlocks && maxBlocks != -1) { if (infinityCheckVisited.size() > maxBlocks && maxBlocks != -1 && !fillInfinite()) {
if (!infinite) { if (!infinite) {
reset(); reset();
infinite = true; infinite = true;
@ -163,9 +165,11 @@ public class FluidFillingBehaviour extends FluidManipulationBehaviour {
if (visited.size() >= maxBlocks && maxBlocks != -1) { if (visited.size() >= maxBlocks && maxBlocks != -1) {
infinite = true; infinite = true;
visited.clear(); if (!fillInfinite()) {
queue.clear(); visited.clear();
return false; queue.clear();
return false;
}
} }
SpaceType spaceType = getAtPos(world, currentPos, fluid); SpaceType spaceType = getAtPos(world, currentPos, fluid);
@ -298,8 +302,6 @@ public class FluidFillingBehaviour extends FluidManipulationBehaviour {
infinityCheckVisited.clear(); infinityCheckVisited.clear();
} }
public static BehaviourType<FluidFillingBehaviour> TYPE = new BehaviourType<>();
@Override @Override
public BehaviourType<?> getType() { public BehaviourType<?> getType() {
return TYPE; return TYPE;

View file

@ -76,6 +76,7 @@ public class ItemDrainTileEntity extends SmartTileEntity implements IHaveGoggleI
return returned; return returned;
transportedStack = transportedStack.copy(); transportedStack = transportedStack.copy();
transportedStack.stack = inserted.copy();
transportedStack.beltPosition = side.getAxis() transportedStack.beltPosition = side.getAxis()
.isVertical() ? .5f : 0; .isVertical() ? .5f : 0;
transportedStack.prevSideOffset = transportedStack.sideOffset; transportedStack.prevSideOffset = transportedStack.sideOffset;

View file

@ -40,7 +40,7 @@ public class FluidValveInstance extends ShaftInstance implements DynamicInstance
pointer = materialManager.defaultSolid() pointer = materialManager.defaultSolid()
.material(Materials.TRANSFORMED) .material(Materials.TRANSFORMED)
.getModel(AllBlockPartials.FLUID_VALVE_POINTER, blockState).createInstance(); .getModel(AllBlockPartials.FLUID_VALVE_POINTER).createInstance();
transformPointer(); transformPointer();
} }

View file

@ -1,6 +1,7 @@
package com.simibubi.create.content.contraptions.fluids.tank; package com.simibubi.create.content.contraptions.fluids.tank;
import com.simibubi.create.AllTileEntities; import com.simibubi.create.AllTileEntities;
import com.simibubi.create.api.connectivity.ConnectivityHandler;
import com.simibubi.create.content.contraptions.fluids.actors.GenericItemFilling; import com.simibubi.create.content.contraptions.fluids.actors.GenericItemFilling;
import com.simibubi.create.content.contraptions.fluids.tank.CreativeFluidTankTileEntity.CreativeSmartFluidTank; import com.simibubi.create.content.contraptions.fluids.tank.CreativeFluidTankTileEntity.CreativeSmartFluidTank;
import com.simibubi.create.content.contraptions.processing.EmptyingByBasin; import com.simibubi.create.content.contraptions.processing.EmptyingByBasin;
@ -95,7 +96,7 @@ public class FluidTankBlock extends Block implements IWrenchable, ITE<FluidTankT
@Override @Override
public int getLightEmission(BlockState state, BlockGetter world, BlockPos pos) { public int getLightEmission(BlockState state, BlockGetter world, BlockPos pos) {
FluidTankTileEntity tankAt = FluidTankConnectivityHandler.anyTankAt(world, pos); FluidTankTileEntity tankAt = ConnectivityHandler.partAt(getTileEntityType(), world, pos);
if (tankAt == null) if (tankAt == null)
return 0; return 0;
FluidTankTileEntity controllerTE = tankAt.getControllerTE(); FluidTankTileEntity controllerTE = tankAt.getControllerTE();
@ -130,7 +131,7 @@ public class FluidTankBlock extends Block implements IWrenchable, ITE<FluidTankT
return InteractionResult.PASS; return InteractionResult.PASS;
FluidExchange exchange = null; FluidExchange exchange = null;
FluidTankTileEntity te = FluidTankConnectivityHandler.anyTankAt(world, pos); FluidTankTileEntity te = ConnectivityHandler.partAt(getTileEntityType(), world, pos);
if (te == null) if (te == null)
return InteractionResult.FAIL; return InteractionResult.FAIL;
@ -240,7 +241,7 @@ public class FluidTankBlock extends Block implements IWrenchable, ITE<FluidTankT
return; return;
FluidTankTileEntity tankTE = (FluidTankTileEntity) te; FluidTankTileEntity tankTE = (FluidTankTileEntity) te;
world.removeBlockEntity(pos); world.removeBlockEntity(pos);
FluidTankConnectivityHandler.splitTank(tankTE); ConnectivityHandler.splitMulti(tankTE);
} }
} }

View file

@ -1,5 +1,6 @@
package com.simibubi.create.content.contraptions.fluids.tank; package com.simibubi.create.content.contraptions.fluids.tank;
import com.simibubi.create.api.connectivity.ConnectivityHandler;
import com.simibubi.create.foundation.block.connected.CTSpriteShiftEntry; import com.simibubi.create.foundation.block.connected.CTSpriteShiftEntry;
import com.simibubi.create.foundation.block.connected.HorizontalCTBehaviour; import com.simibubi.create.foundation.block.connected.HorizontalCTBehaviour;
@ -21,6 +22,6 @@ public class FluidTankCTBehaviour extends HorizontalCTBehaviour {
@Override @Override
public boolean connectsTo(BlockState state, BlockState other, BlockAndTintGetter reader, BlockPos pos, BlockPos otherPos, public boolean connectsTo(BlockState state, BlockState other, BlockAndTintGetter reader, BlockPos pos, BlockPos otherPos,
Direction face) { Direction face) {
return state.getBlock() == other.getBlock() && FluidTankConnectivityHandler.isConnected(reader, pos, otherPos); return state.getBlock() == other.getBlock() && ConnectivityHandler.isConnected(reader, pos, otherPos); //FluidTankConnectivityHandler.isConnected(reader, pos, otherPos);
} }
} }

View file

@ -1,376 +0,0 @@
package com.simibubi.create.content.contraptions.fluids.tank;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.PriorityQueue;
import java.util.Set;
import javax.annotation.Nullable;
import org.apache.commons.lang3.tuple.Pair;
import com.simibubi.create.content.contraptions.fluids.tank.CreativeFluidTankTileEntity.CreativeSmartFluidTank;
import com.simibubi.create.foundation.utility.Iterate;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.core.Direction.Axis;
import net.minecraft.core.Direction.AxisDirection;
import net.minecraft.world.level.BlockGetter;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraft.world.level.block.entity.BlockEntityType;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraftforge.fluids.FluidStack;
import net.minecraftforge.fluids.capability.IFluidHandler.FluidAction;
import net.minecraftforge.fluids.capability.templates.FluidTank;
public class FluidTankConnectivityHandler {
public static void formTanks(FluidTankTileEntity te) {
TankSearchCache cache = new TankSearchCache();
List<FluidTankTileEntity> frontier = new ArrayList<>();
frontier.add(te);
formTanks(te.getType(), te.getLevel(), cache, frontier);
}
private static void formTanks(BlockEntityType<?> type, BlockGetter world, TankSearchCache cache,
List<FluidTankTileEntity> frontier) {
PriorityQueue<Pair<Integer, FluidTankTileEntity>> creationQueue = makeCreationQueue();
Set<BlockPos> visited = new HashSet<>();
int minX = Integer.MAX_VALUE;
int minZ = Integer.MAX_VALUE;
for (FluidTankTileEntity fluidTankTileEntity : frontier) {
BlockPos pos = fluidTankTileEntity.getBlockPos();
minX = Math.min(pos.getX(), minX);
minZ = Math.min(pos.getZ(), minZ);
}
minX -= FluidTankTileEntity.getMaxSize();
minZ -= FluidTankTileEntity.getMaxSize();
while (!frontier.isEmpty()) {
FluidTankTileEntity tank = frontier.remove(0);
BlockPos tankPos = tank.getBlockPos();
if (visited.contains(tankPos))
continue;
visited.add(tankPos);
int amount = tryToFormNewTank(tank, cache, true);
if (amount > 1)
creationQueue.add(Pair.of(amount, tank));
for (Axis axis : Iterate.axes) {
Direction d = Direction.get(AxisDirection.NEGATIVE, axis);
BlockPos next = tankPos.relative(d);
if (next.getX() <= minX || next.getZ() <= minZ)
continue;
if (visited.contains(next))
continue;
FluidTankTileEntity nextTank = tankAt(type, world, next);
if (nextTank == null)
continue;
if (nextTank.isRemoved())
continue;
frontier.add(nextTank);
}
}
visited.clear();
while (!creationQueue.isEmpty()) {
Pair<Integer, FluidTankTileEntity> next = creationQueue.poll();
FluidTankTileEntity toCreate = next.getValue();
if (visited.contains(toCreate.getBlockPos()))
continue;
visited.add(toCreate.getBlockPos());
tryToFormNewTank(toCreate, cache, false);
}
}
public static void splitTank(FluidTankTileEntity te) {
splitTankAndInvalidate(te, null, false);
}
private static int tryToFormNewTank(FluidTankTileEntity te, TankSearchCache cache, boolean simulate) {
int bestWidth = 1;
int bestAmount = -1;
if (!te.isController())
return 0;
for (int w = 1; w <= FluidTankTileEntity.getMaxSize(); w++) {
int amount = tryToFormNewTankOfWidth(te, w, cache, true);
if (amount < bestAmount)
continue;
bestWidth = w;
bestAmount = amount;
}
if (!simulate) {
if (te.width == bestWidth && te.width * te.width * te.height == bestAmount)
return bestAmount;
splitTankAndInvalidate(te, cache, false);
te.applyFluidTankSize(bestAmount);
tryToFormNewTankOfWidth(te, bestWidth, cache, simulate);
te.updateConnectivity = false;
te.width = bestWidth;
te.height = bestAmount / bestWidth / bestWidth;
BlockState state = te.getBlockState();
if (FluidTankBlock.isTank(state)) {
state = state.setValue(FluidTankBlock.BOTTOM, true);
state = state.setValue(FluidTankBlock.TOP, te.height == 1);
te.getLevel()
.setBlock(te.getBlockPos(), state, 22);
}
te.setWindows(te.window);
te.onFluidStackChanged(te.tankInventory.getFluid());
te.updateBoilerState();
te.setChanged();
}
return bestAmount;
}
private static int tryToFormNewTankOfWidth(FluidTankTileEntity te, int width, TankSearchCache cache,
boolean simulate) {
int amount = 0;
int height = 0;
BlockEntityType<?> type = te.getType();
Level world = te.getLevel();
BlockPos origin = te.getBlockPos();
FluidTank teTank = te.tankInventory;
FluidStack fluid = te.tankInventory.getFluidInTank(0);
Search:
for (int yOffset = 0; yOffset < FluidTankTileEntity.getMaxHeight(); yOffset++) {
for (int xOffset = 0; xOffset < width; xOffset++) {
for (int zOffset = 0; zOffset < width; zOffset++) {
BlockPos pos = origin.offset(xOffset, yOffset, zOffset);
Optional<FluidTankTileEntity> tank = cache.getOrCache(type, world, pos);
if (!tank.isPresent())
break Search;
FluidTankTileEntity controller = tank.get();
int otherWidth = controller.width;
if (otherWidth > width)
break Search;
BlockPos controllerPos = controller.getBlockPos();
if (!controllerPos.equals(origin)) {
if (controllerPos.getX() < origin.getX())
break Search;
if (controllerPos.getZ() < origin.getZ())
break Search;
if (controllerPos.getX() + otherWidth > origin.getX() + width)
break Search;
if (controllerPos.getZ() + otherWidth > origin.getZ() + width)
break Search;
}
FluidStack otherFluid = controller.getTankInventory()
.getFluid();
if (!fluid.isEmpty() && !otherFluid.isEmpty() && !fluid.isFluidEqual(otherFluid))
break Search;
}
}
amount += width * width;
height++;
}
if (simulate)
return amount;
boolean opaque = false;
for (int yOffset = 0; yOffset < height; yOffset++) {
for (int xOffset = 0; xOffset < width; xOffset++) {
for (int zOffset = 0; zOffset < width; zOffset++) {
BlockPos pos = origin.offset(xOffset, yOffset, zOffset);
FluidTankTileEntity tank = tankAt(type, world, pos);
if (tank == te)
continue;
opaque |= !tank.window;
FluidTank tankTank = tank.tankInventory;
FluidStack fluidInTank = tankTank.getFluid();
if (!fluidInTank.isEmpty()) {
if (teTank.isEmpty() && teTank instanceof CreativeSmartFluidTank)
((CreativeSmartFluidTank) teTank).setContainedFluid(fluidInTank);
teTank.fill(fluidInTank, FluidAction.EXECUTE);
}
tankTank.setFluid(FluidStack.EMPTY);
splitTankAndInvalidate(tank, cache, false);
tank.setController(origin);
tank.updateConnectivity = false;
cache.put(pos, te);
BlockState state = world.getBlockState(pos);
if (!FluidTankBlock.isTank(state))
continue;
state = state.setValue(FluidTankBlock.BOTTOM, yOffset == 0);
state = state.setValue(FluidTankBlock.TOP, yOffset == height - 1);
world.setBlock(pos, state, 22);
}
}
}
te.setWindows(!opaque);
return amount;
}
private static void splitTankAndInvalidate(FluidTankTileEntity te, @Nullable TankSearchCache cache,
boolean tryReconnect) {
// tryReconnect helps whenever only few tanks have been removed
te = te.getControllerTE();
if (te == null)
return;
int height = te.height;
int width = te.width;
if (width == 1 && height == 1)
return;
Level world = te.getLevel();
BlockPos origin = te.getBlockPos();
List<FluidTankTileEntity> frontier = new ArrayList<>();
FluidStack toDistribute = te.tankInventory.getFluid()
.copy();
int maxCapacity = FluidTankTileEntity.getCapacityMultiplier();
if (!toDistribute.isEmpty() && !te.isRemoved())
toDistribute.shrink(maxCapacity);
te.applyFluidTankSize(1);
for (int yOffset = 0; yOffset < height; yOffset++) {
for (int xOffset = 0; xOffset < width; xOffset++) {
for (int zOffset = 0; zOffset < width; zOffset++) {
BlockPos pos = origin.offset(xOffset, yOffset, zOffset);
FluidTankTileEntity tankAt = tankAt(te.getType(), world, pos);
if (tankAt == null)
continue;
if (!tankAt.getController()
.equals(origin))
continue;
FluidTankTileEntity controllerTE = tankAt.getControllerTE();
tankAt.window = controllerTE == null || controllerTE.window;
tankAt.removeController(true);
if (!toDistribute.isEmpty() && tankAt != te) {
FluidStack copy = toDistribute.copy();
FluidTank tankInventory = tankAt.tankInventory;
if (tankInventory.isEmpty() && tankInventory instanceof CreativeSmartFluidTank)
((CreativeSmartFluidTank) tankInventory).setContainedFluid(toDistribute);
else {
int split = Math.min(maxCapacity, toDistribute.getAmount());
copy.setAmount(split);
toDistribute.shrink(split);
tankInventory.fill(copy, FluidAction.EXECUTE);
}
}
if (tryReconnect) {
frontier.add(tankAt);
tankAt.updateConnectivity = false;
}
if (cache != null)
cache.put(pos, tankAt);
}
}
}
te.fluidCapability.invalidate();
if (tryReconnect)
formTanks(te.getType(), world, cache == null ? new TankSearchCache() : cache, frontier);
}
private static PriorityQueue<Pair<Integer, FluidTankTileEntity>> makeCreationQueue() {
return new PriorityQueue<>(new Comparator<Pair<Integer, FluidTankTileEntity>>() {
@Override
public int compare(Pair<Integer, FluidTankTileEntity> o1, Pair<Integer, FluidTankTileEntity> o2) {
return o2.getKey() - o1.getKey();
}
});
}
@Nullable
public static FluidTankTileEntity tankAt(BlockEntityType<?> type, BlockGetter world, BlockPos pos) {
BlockEntity te = world.getBlockEntity(pos);
if (te instanceof FluidTankTileEntity && te.getType() == type)
return (FluidTankTileEntity) te;
return null;
}
@Nullable
public static FluidTankTileEntity anyTankAt(BlockGetter world, BlockPos pos) {
BlockEntity te = world.getBlockEntity(pos);
if (te instanceof FluidTankTileEntity)
return (FluidTankTileEntity) te;
return null;
}
private static class TankSearchCache {
Map<BlockPos, Optional<FluidTankTileEntity>> controllerMap;
public TankSearchCache() {
controllerMap = new HashMap<>();
}
void put(BlockPos pos, FluidTankTileEntity target) {
controllerMap.put(pos, Optional.of(target));
}
void putEmpty(BlockPos pos) {
controllerMap.put(pos, Optional.empty());
}
boolean hasVisited(BlockPos pos) {
return controllerMap.containsKey(pos);
}
Optional<FluidTankTileEntity> getOrCache(BlockEntityType<?> type, BlockGetter world, BlockPos pos) {
if (hasVisited(pos))
return controllerMap.get(pos);
FluidTankTileEntity tankAt = tankAt(type, world, pos);
if (tankAt == null) {
putEmpty(pos);
return Optional.empty();
}
FluidTankTileEntity controller = tankAt.getControllerTE();
if (controller == null) {
putEmpty(pos);
return Optional.empty();
}
put(pos, controller);
return Optional.of(controller);
}
}
public static boolean isConnected(BlockGetter world, BlockPos tankPos, BlockPos otherTankPos) {
BlockEntity te1 = world.getBlockEntity(tankPos);
BlockEntity te2 = world.getBlockEntity(otherTankPos);
if (!(te1 instanceof FluidTankTileEntity) || !(te2 instanceof FluidTankTileEntity))
return false;
return ((FluidTankTileEntity) te1).getController()
.equals(((FluidTankTileEntity) te2).getController());
}
}

View file

@ -1,5 +1,9 @@
package com.simibubi.create.content.contraptions.fluids.tank; package com.simibubi.create.content.contraptions.fluids.tank;
import com.simibubi.create.AllBlocks;
import com.simibubi.create.AllTileEntities;
import com.simibubi.create.api.connectivity.ConnectivityHandler;
import net.minecraft.core.BlockPos; import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction; import net.minecraft.core.Direction;
import net.minecraft.nbt.CompoundTag; import net.minecraft.nbt.CompoundTag;
@ -71,7 +75,10 @@ public class FluidTankItem extends BlockItem {
if (!FluidTankBlock.isTank(placedOnState)) if (!FluidTankBlock.isTank(placedOnState))
return; return;
FluidTankTileEntity tankAt = FluidTankConnectivityHandler.anyTankAt(world, placedOnPos); boolean creative = getBlock().equals(AllBlocks.CREATIVE_FLUID_TANK.get());
FluidTankTileEntity tankAt = ConnectivityHandler.partAt(
creative ? AllTileEntities.CREATIVE_FLUID_TANK.get() : AllTileEntities.FLUID_TANK.get(), world, placedOnPos
);
if (tankAt == null) if (tankAt == null)
return; return;
FluidTankTileEntity controllerTE = tankAt.getControllerTE(); FluidTankTileEntity controllerTE = tankAt.getControllerTE();

View file

@ -7,6 +7,7 @@ import java.util.List;
import java.util.Random; import java.util.Random;
import com.simibubi.create.AllSpriteShifts; import com.simibubi.create.AllSpriteShifts;
import com.simibubi.create.api.connectivity.ConnectivityHandler;
import com.simibubi.create.foundation.block.connected.CTModel; import com.simibubi.create.foundation.block.connected.CTModel;
import com.simibubi.create.foundation.block.connected.CTSpriteShiftEntry; import com.simibubi.create.foundation.block.connected.CTSpriteShiftEntry;
import com.simibubi.create.foundation.utility.Iterate; import com.simibubi.create.foundation.utility.Iterate;
@ -41,7 +42,7 @@ public class FluidTankModel extends CTModel {
protected Builder gatherModelData(Builder builder, BlockAndTintGetter world, BlockPos pos, BlockState state) { protected Builder gatherModelData(Builder builder, BlockAndTintGetter world, BlockPos pos, BlockState state) {
CullData cullData = new CullData(); CullData cullData = new CullData();
for (Direction d : Iterate.horizontalDirections) for (Direction d : Iterate.horizontalDirections)
cullData.setCulled(d, FluidTankConnectivityHandler.isConnected(world, pos, pos.relative(d))); cullData.setCulled(d, ConnectivityHandler.isConnected(world, pos, pos.relative(d))); //FluidTankConnectivityHandler.isConnected(world, pos, pos.relative(d)));
return super.gatherModelData(builder, world, pos, state).withInitial(CULL_PROPERTY, cullData); return super.gatherModelData(builder, world, pos, state).withInitial(CULL_PROPERTY, cullData);
} }

View file

@ -7,6 +7,7 @@ import java.util.List;
import javax.annotation.Nonnull; import javax.annotation.Nonnull;
import javax.annotation.Nullable; import javax.annotation.Nullable;
import com.simibubi.create.api.connectivity.ConnectivityHandler;
import com.simibubi.create.content.contraptions.fluids.tank.FluidTankBlock.Shape; import com.simibubi.create.content.contraptions.fluids.tank.FluidTankBlock.Shape;
import com.simibubi.create.content.contraptions.goggles.IHaveGoggleInformation; import com.simibubi.create.content.contraptions.goggles.IHaveGoggleInformation;
import com.simibubi.create.foundation.config.AllConfigs; import com.simibubi.create.foundation.config.AllConfigs;
@ -36,7 +37,7 @@ import net.minecraftforge.fluids.capability.IFluidHandler;
import net.minecraftforge.fluids.capability.IFluidHandler.FluidAction; import net.minecraftforge.fluids.capability.IFluidHandler.FluidAction;
import net.minecraftforge.fluids.capability.templates.FluidTank; import net.minecraftforge.fluids.capability.templates.FluidTank;
public class FluidTankTileEntity extends SmartTileEntity implements IHaveGoggleInformation, IMultiTileContainer { public class FluidTankTileEntity extends SmartTileEntity implements IHaveGoggleInformation, IMultiTileContainer.Fluid {
private static final int MAX_SIZE = 3; private static final int MAX_SIZE = 3;
@ -83,7 +84,7 @@ public class FluidTankTileEntity extends SmartTileEntity implements IHaveGoggleI
return; return;
if (!isController()) if (!isController())
return; return;
FluidTankConnectivityHandler.formTanks(this); ConnectivityHandler.formMulti(this);
} }
@Override @Override
@ -151,7 +152,7 @@ public class FluidTankTileEntity extends SmartTileEntity implements IHaveGoggleI
for (int xOffset = 0; xOffset < width; xOffset++) { for (int xOffset = 0; xOffset < width; xOffset++) {
for (int zOffset = 0; zOffset < width; zOffset++) { for (int zOffset = 0; zOffset < width; zOffset++) {
BlockPos pos = this.worldPosition.offset(xOffset, yOffset, zOffset); BlockPos pos = this.worldPosition.offset(xOffset, yOffset, zOffset);
FluidTankTileEntity tankAt = FluidTankConnectivityHandler.anyTankAt(level, pos); FluidTankTileEntity tankAt = ConnectivityHandler.partAt(getType(), level, pos);
if (tankAt == null) if (tankAt == null)
continue; continue;
level.updateNeighbourForOutputSignal(pos, tankAt.getBlockState() level.updateNeighbourForOutputSignal(pos, tankAt.getBlockState()
@ -507,4 +508,82 @@ public class FluidTankTileEntity extends SmartTileEntity implements IHaveGoggleI
this.fluidLevel = fluidLevel; this.fluidLevel = fluidLevel;
} }
@Override
public void preventConnectivityUpdate() { updateConnectivity = false; }
@Override
public void notifyMultiUpdated() {
BlockState state = this.getBlockState();
if (FluidTankBlock.isTank(state)) { // safety
state = state.setValue(FluidTankBlock.BOTTOM, getController().getY() == getBlockPos().getY());
state = state.setValue(FluidTankBlock.TOP, getController().getY() + height - 1 == getBlockPos().getY());
level.setBlock(getBlockPos(), state, 22);
}
setWindows(window);
onFluidStackChanged(tankInventory.getFluid());
setChanged();
}
@Override
public void setExtraData(@Nullable Object data) {
if (data instanceof Boolean) window = (boolean)data;
}
@Override
@Nullable
public Object getExtraData() { return window; }
@Override
public Object modifyExtraData(Object data) {
if (data instanceof Boolean windows) {
windows |= window;
return windows;
}
return data;
}
@Override
public Direction.Axis getMainConnectionAxis() { return Direction.Axis.Y; }
@Override
public int getMaxLength(Direction.Axis longAxis, int width) {
if (longAxis == Direction.Axis.Y) return getMaxHeight();
return getMaxWidth();
}
@Override
public int getMaxWidth() { return MAX_SIZE; }
@Override
public int getHeight() { return height; }
@Override
public void setHeight(int height) { this.height = height; }
@Override
public int getWidth() { return width; }
@Override
public void setWidth(int width) { this.width = width; }
@Override
public boolean hasTank() { return true; }
@Override
public int getTankSize(int tank) { return getCapacityMultiplier(); }
@Override
public void setTankSize(int tank, int blocks) {
applyFluidTankSize(blocks);
}
@Override
public IFluidTank getTank(int tank) {
return tankInventory;
}
@Override
public FluidStack getFluid(int tank) {
return tankInventory.getFluid().copy();
}
} }

View file

@ -8,6 +8,8 @@ import java.util.List;
import javax.annotation.Nonnull; import javax.annotation.Nonnull;
import com.simibubi.create.foundation.utility.recipe.IRecipeTypeInfo;
import com.simibubi.create.AllRecipeTypes; import com.simibubi.create.AllRecipeTypes;
import com.simibubi.create.content.contraptions.processing.ProcessingRecipeBuilder.ProcessingRecipeParams; import com.simibubi.create.content.contraptions.processing.ProcessingRecipeBuilder.ProcessingRecipeParams;
import com.simibubi.create.content.contraptions.processing.burner.BlazeBurnerBlock.HeatLevel; import com.simibubi.create.content.contraptions.processing.burner.BlazeBurnerBlock.HeatLevel;
@ -173,7 +175,7 @@ public class BasinRecipe extends ProcessingRecipe<SmartInventory> {
return basinRecipe; return basinRecipe;
} }
protected BasinRecipe(AllRecipeTypes type, ProcessingRecipeParams params) { protected BasinRecipe(IRecipeTypeInfo type, ProcessingRecipeParams params) {
super(type, params); super(type, params);
} }

View file

@ -62,9 +62,9 @@ public class BeltInstance extends KineticTileInstance<BeltTileEntity> {
PartialModel beltPartial = BeltRenderer.getBeltPartial(diagonal, start, end, bottom); PartialModel beltPartial = BeltRenderer.getBeltPartial(diagonal, start, end, bottom);
SpriteShiftEntry spriteShift = BeltRenderer.getSpriteShiftEntry(color, diagonal, bottom); SpriteShiftEntry spriteShift = BeltRenderer.getSpriteShiftEntry(color, diagonal, bottom);
Instancer<BeltData> beltModel = materialManager.defaultSolid() Instancer<BeltData> beltModel = materialManager.defaultSolid()
.material(AllMaterialSpecs.BELTS) .material(AllMaterialSpecs.BELTS)
.getModel(beltPartial, blockState); .getModel(beltPartial);
keys.add(setup(beltModel.createInstance(), bottom, spriteShift)); keys.add(setup(beltModel.createInstance(), bottom, spriteShift));
@ -143,7 +143,7 @@ public class BeltInstance extends KineticTileInstance<BeltTileEntity> {
return modelTransform; return modelTransform;
}; };
return getRotatingMaterial().getModel(AllBlockPartials.BELT_PULLEY, blockState, dir, ms); return getRotatingMaterial().getModel(AllBlockPartials.BELT_PULLEY, dir, ms);
} }
private Direction getOrientation() { private Direction getOrientation() {

View file

@ -38,8 +38,7 @@ public class BracketedKineticTileInstance extends SingleRotatingInstance {
BlockPos pos = blockEntity.getBlockPos(); BlockPos pos = blockEntity.getBlockPos();
float offset = BracketedKineticTileRenderer.getShaftAngleOffset(axis, pos); float offset = BracketedKineticTileRenderer.getShaftAngleOffset(axis, pos);
Direction facing = Direction.fromAxisAndDirection(axis, AxisDirection.POSITIVE); Direction facing = Direction.fromAxisAndDirection(axis, AxisDirection.POSITIVE);
Instancer<RotatingData> half = getRotatingMaterial().getModel(AllBlockPartials.COGWHEEL_SHAFT, blockState, Instancer<RotatingData> half = getRotatingMaterial().getModel(AllBlockPartials.COGWHEEL_SHAFT, facing, () -> this.rotateToAxis(axis));
facing, () -> this.rotateToAxis(axis));
additionalShaft = setup(half.createInstance(), speed); additionalShaft = setup(half.createInstance(), speed);
additionalShaft.setRotationOffset(offset); additionalShaft.setRotationOffset(offset);
@ -52,7 +51,7 @@ public class BracketedKineticTileInstance extends SingleRotatingInstance {
Axis axis = KineticTileEntityRenderer.getRotationAxisOf(blockEntity); Axis axis = KineticTileEntityRenderer.getRotationAxisOf(blockEntity);
Direction facing = Direction.fromAxisAndDirection(axis, AxisDirection.POSITIVE); Direction facing = Direction.fromAxisAndDirection(axis, AxisDirection.POSITIVE);
return getRotatingMaterial().getModel(AllBlockPartials.SHAFTLESS_LARGE_COGWHEEL, blockState, facing, return getRotatingMaterial().getModel(AllBlockPartials.SHAFTLESS_LARGE_COGWHEEL, facing,
() -> this.rotateToAxis(axis)); () -> this.rotateToAxis(axis));
} }

View file

@ -58,7 +58,7 @@ public class EncasedCogInstance extends KineticTileInstance<KineticTileEntity> {
for (Direction d : Iterate.directionsInAxis(axis)) { for (Direction d : Iterate.directionsInAxis(axis)) {
if (!def.hasShaftTowards(blockEntity.getLevel(), blockEntity.getBlockPos(), blockState, d)) if (!def.hasShaftTowards(blockEntity.getLevel(), blockEntity.getBlockPos(), blockState, d))
continue; continue;
RotatingData data = setup(getRotatingMaterial().getModel(AllBlockPartials.SHAFT_HALF, blockState, d) RotatingData data = setup(getRotatingMaterial().getModel(AllBlockPartials.SHAFT_HALF, d)
.createInstance()); .createInstance());
if (d.getAxisDirection() == AxisDirection.POSITIVE) if (d.getAxisDirection() == AxisDirection.POSITIVE)
rotatingTopShaft = Optional.of(data); rotatingTopShaft = Optional.of(data);
@ -94,7 +94,7 @@ public class EncasedCogInstance extends KineticTileInstance<KineticTileEntity> {
Direction.fromAxisAndDirection(referenceState.getValue(BlockStateProperties.AXIS), AxisDirection.POSITIVE); Direction.fromAxisAndDirection(referenceState.getValue(BlockStateProperties.AXIS), AxisDirection.POSITIVE);
PartialModel partial = large ? AllBlockPartials.SHAFTLESS_LARGE_COGWHEEL : AllBlockPartials.SHAFTLESS_COGWHEEL; PartialModel partial = large ? AllBlockPartials.SHAFTLESS_LARGE_COGWHEEL : AllBlockPartials.SHAFTLESS_COGWHEEL;
return getRotatingMaterial().getModel(partial, referenceState, facing, () -> { return getRotatingMaterial().getModel(partial, facing, () -> {
PoseStack poseStack = new PoseStack(); PoseStack poseStack = new PoseStack();
TransformStack.cast(poseStack) TransformStack.cast(poseStack)
.centre() .centre()

View file

@ -30,7 +30,7 @@ public class SplitShaftInstance extends KineticTileInstance<SplitShaftTileEntity
for (Direction dir : Iterate.directionsInAxis(getRotationAxis())) { for (Direction dir : Iterate.directionsInAxis(getRotationAxis())) {
Instancer<RotatingData> half = rotatingMaterial.getModel(AllBlockPartials.SHAFT_HALF, blockState, dir); Instancer<RotatingData> half = rotatingMaterial.getModel(AllBlockPartials.SHAFT_HALF, dir);
float splitSpeed = speed * tile.getRotationSpeedModifier(dir); float splitSpeed = speed * tile.getRotationSpeedModifier(dir);

View file

@ -32,7 +32,7 @@ public abstract class GaugeInstance extends ShaftInstance implements DynamicInst
GaugeTileEntity gaugeTile = (GaugeTileEntity) tile; GaugeTileEntity gaugeTile = (GaugeTileEntity) tile;
GaugeBlock gaugeBlock = (GaugeBlock) blockState.getBlock(); GaugeBlock gaugeBlock = (GaugeBlock) blockState.getBlock();
Instancer<ModelData> dialModel = getTransformMaterial().getModel(AllBlockPartials.GAUGE_DIAL, blockState); Instancer<ModelData> dialModel = getTransformMaterial().getModel(AllBlockPartials.GAUGE_DIAL);
Instancer<ModelData> headModel = getHeadModel(); Instancer<ModelData> headModel = getHeadModel();
ms = new PoseStack(); ms = new PoseStack();
@ -150,7 +150,7 @@ public abstract class GaugeInstance extends ShaftInstance implements DynamicInst
@Override @Override
protected Instancer<ModelData> getHeadModel() { protected Instancer<ModelData> getHeadModel() {
return getTransformMaterial().getModel(AllBlockPartials.GAUGE_HEAD_SPEED, blockState); return getTransformMaterial().getModel(AllBlockPartials.GAUGE_HEAD_SPEED);
} }
} }
@ -161,7 +161,7 @@ public abstract class GaugeInstance extends ShaftInstance implements DynamicInst
@Override @Override
protected Instancer<ModelData> getHeadModel() { protected Instancer<ModelData> getHeadModel() {
return getTransformMaterial().getModel(AllBlockPartials.GAUGE_HEAD_STRESS, blockState); return getTransformMaterial().getModel(AllBlockPartials.GAUGE_HEAD_STRESS);
} }
} }
} }

View file

@ -40,7 +40,7 @@ public class GearboxInstance extends KineticTileInstance<GearboxTileEntity> {
if (boxAxis == axis) if (boxAxis == axis)
continue; continue;
Instancer<RotatingData> shaft = rotatingMaterial.getModel(AllBlockPartials.SHAFT_HALF, blockState, direction); Instancer<RotatingData> shaft = rotatingMaterial.getModel(AllBlockPartials.SHAFT_HALF, direction);
RotatingData key = shaft.createInstance(); RotatingData key = shaft.createInstance();

View file

@ -4,14 +4,18 @@ import com.simibubi.create.foundation.utility.worldWrappers.PlacementSimulationS
import net.minecraft.core.BlockPos; import net.minecraft.core.BlockPos;
import net.minecraft.server.level.ServerLevel; import net.minecraft.server.level.ServerLevel;
import net.minecraft.tags.BlockTags;
import net.minecraft.world.InteractionResult; import net.minecraft.world.InteractionResult;
import net.minecraft.world.item.BoneMealItem; import net.minecraft.world.item.BoneMealItem;
import net.minecraft.world.item.Item; import net.minecraft.world.item.Item;
import net.minecraft.world.item.context.UseOnContext; import net.minecraft.world.item.context.UseOnContext;
import net.minecraft.world.level.block.AzaleaBlock;
import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.Blocks; import net.minecraft.world.level.block.Blocks;
import net.minecraft.world.level.block.BonemealableBlock;
import net.minecraft.world.level.block.SaplingBlock; import net.minecraft.world.level.block.SaplingBlock;
import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.block.state.properties.BlockStateProperties;
public class TreeFertilizerItem extends Item { public class TreeFertilizerItem extends Item {
@ -24,7 +28,7 @@ public class TreeFertilizerItem extends Item {
BlockState state = context.getLevel() BlockState state = context.getLevel()
.getBlockState(context.getClickedPos()); .getBlockState(context.getClickedPos());
Block block = state.getBlock(); Block block = state.getBlock();
if (block instanceof SaplingBlock) { if (block instanceof BonemealableBlock bonemealableBlock && state.is(BlockTags.SAPLINGS)) {
if (context.getLevel().isClientSide) { if (context.getLevel().isClientSide) {
BoneMealItem.addGrowthParticles(context.getLevel(), context.getClickedPos(), 100); BoneMealItem.addGrowthParticles(context.getLevel(), context.getClickedPos(), 100);
@ -38,11 +42,11 @@ public class TreeFertilizerItem extends Item {
if (context.getLevel() if (context.getLevel()
.getBlockState(saplingPos.offset(pos)) .getBlockState(saplingPos.offset(pos))
.getBlock() == block) .getBlock() == block)
world.setBlockAndUpdate(pos.above(10), state.setValue(SaplingBlock.STAGE, 1)); world.setBlockAndUpdate(pos.above(10), withStage(state, 1));
} }
((SaplingBlock) block).performBonemeal(world, world.getRandom(), BlockPos.ZERO.above(10), bonemealableBlock.performBonemeal(world, world.getRandom(), BlockPos.ZERO.above(10),
state.setValue(SaplingBlock.STAGE, 1)); withStage(state, 1));
for (BlockPos pos : world.blocksAdded.keySet()) { for (BlockPos pos : world.blocksAdded.keySet()) {
BlockPos actualPos = pos.offset(saplingPos).below(10); BlockPos actualPos = pos.offset(saplingPos).below(10);
@ -76,6 +80,12 @@ public class TreeFertilizerItem extends Item {
return super.useOn(context); return super.useOn(context);
} }
private BlockState withStage(BlockState original, int stage) {
if (!original.hasProperty(BlockStateProperties.STAGE))
return original;
return original.setValue(BlockStateProperties.STAGE, 1);
}
private static class TreesDreamWorld extends PlacementSimulationServerWorld { private static class TreesDreamWorld extends PlacementSimulationServerWorld {
private final BlockPos saplingPos; private final BlockPos saplingPos;
private final BlockState soil; private final BlockState soil;

View file

@ -15,7 +15,7 @@ public class CopperBacktankInstance extends SingleRotatingInstance {
@Override @Override
protected Instancer<RotatingData> getModel() { protected Instancer<RotatingData> getModel() {
return getRotatingMaterial().getModel(AllBlockPartials.COPPER_BACKTANK_SHAFT, blockState); return getRotatingMaterial().getModel(AllBlockPartials.COPPER_BACKTANK_SHAFT);
} }
} }

View file

@ -32,12 +32,12 @@ public class ToolBoxInstance extends BlockEntityInstance<ToolboxTileEntity> impl
Instancer<ModelData> drawerModel = materialManager.defaultSolid() Instancer<ModelData> drawerModel = materialManager.defaultSolid()
.material(Materials.TRANSFORMED) .material(Materials.TRANSFORMED)
.getModel(AllBlockPartials.TOOLBOX_DRAWER, blockState); .getModel(AllBlockPartials.TOOLBOX_DRAWER);
drawers = new ModelData[]{drawerModel.createInstance(), drawerModel.createInstance()}; drawers = new ModelData[]{drawerModel.createInstance(), drawerModel.createInstance()};
lid = materialManager.defaultCutout() lid = materialManager.defaultCutout()
.material(Materials.TRANSFORMED) .material(Materials.TRANSFORMED)
.getModel(AllBlockPartials.TOOLBOX_LIDS.get(blockEntity.getColor()), blockState) .getModel(AllBlockPartials.TOOLBOX_LIDS.get(blockEntity.getColor()))
.createInstance(); .createInstance();
} }

View file

@ -1,6 +1,7 @@
package com.simibubi.create.content.curiosities.toolbox; package com.simibubi.create.content.curiosities.toolbox;
import java.util.List; import java.util.List;
import java.util.Objects;
import java.util.WeakHashMap; import java.util.WeakHashMap;
import java.util.stream.Collectors; import java.util.stream.Collectors;
@ -111,6 +112,7 @@ public class ToolboxHandler {
.sorted((p1, p2) -> Double.compare(distance(location, p1), distance(location, p2))) .sorted((p1, p2) -> Double.compare(distance(location, p1), distance(location, p2)))
.limit(maxAmount) .limit(maxAmount)
.map(toolboxes.get(world)::get) .map(toolboxes.get(world)::get)
.filter(ToolboxTileEntity::isFullyInitialized)
.collect(Collectors.toList()); .collect(Collectors.toList());
} }

View file

@ -6,6 +6,7 @@ import static com.simibubi.create.foundation.gui.AllGuiTextures.TOOLBELT_SELECTE
import static com.simibubi.create.foundation.gui.AllGuiTextures.TOOLBELT_SELECTED_ON; import static com.simibubi.create.foundation.gui.AllGuiTextures.TOOLBELT_SELECTED_ON;
import java.util.Collections; import java.util.Collections;
import java.util.Comparator;
import java.util.List; import java.util.List;
import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableList;
@ -111,10 +112,7 @@ public class ToolboxHandlerClient {
Level level = player.level; Level level = player.level;
List<ToolboxTileEntity> toolboxes = ToolboxHandler.getNearest(player.level, player, 8); List<ToolboxTileEntity> toolboxes = ToolboxHandler.getNearest(player.level, player, 8);
toolboxes.sort(Comparator.comparing(ToolboxTileEntity::getUniqueId));
if (!toolboxes.isEmpty())
Collections.sort(toolboxes, (te1, te2) -> te1.getUniqueId()
.compareTo(te2.getUniqueId()));
CompoundTag compound = player.getPersistentData() CompoundTag compound = player.getPersistentData()
.getCompound("CreateToolboxData"); .getCompound("CreateToolboxData");

View file

@ -380,6 +380,11 @@ public class ToolboxTileEntity extends SmartTileEntity implements MenuProvider,
return uniqueId; return uniqueId;
} }
public boolean isFullyInitialized() {
// returns true when uniqueId has been initialized
return uniqueId != null;
}
public void setCustomName(Component customName) { public void setCustomName(Component customName) {
this.customName = customName; this.customName = customName;
} }

View file

@ -29,8 +29,8 @@ public class BeltTunnelInstance extends BlockEntityInstance<BeltTunnelTileEntity
tunnelFlaps = new EnumMap<>(Direction.class); tunnelFlaps = new EnumMap<>(Direction.class);
Instancer<FlapData> model = modelManager.defaultSolid() Instancer<FlapData> model = modelManager.defaultSolid()
.material(AllMaterialSpecs.FLAPS) .material(AllMaterialSpecs.FLAPS)
.getModel(AllBlockPartials.BELT_TUNNEL_FLAP, blockState); .getModel(AllBlockPartials.BELT_TUNNEL_FLAP);
int blockLight = world.getBrightness(LightLayer.BLOCK, pos); int blockLight = world.getBrightness(LightLayer.BLOCK, pos);
int skyLight = world.getBrightness(LightLayer.SKY, pos); int skyLight = world.getBrightness(LightLayer.SKY, pos);

View file

@ -41,7 +41,7 @@ import net.minecraftforge.items.ItemStackHandler;
public class DepotBehaviour extends TileEntityBehaviour { public class DepotBehaviour extends TileEntityBehaviour {
public static BehaviourType<DepotBehaviour> TYPE = new BehaviourType<>(); public static final BehaviourType<DepotBehaviour> TYPE = new BehaviourType<>();
TransportedItemStack heldItem; TransportedItemStack heldItem;
List<TransportedItemStack> incoming; List<TransportedItemStack> incoming;

View file

@ -21,7 +21,7 @@ public class EjectorInstance extends ShaftInstance implements DynamicInstance {
super(dispatcher, tile); super(dispatcher, tile);
this.tile = tile; this.tile = tile;
plate = getTransformMaterial().getModel(AllBlockPartials.EJECTOR_TOP, blockState).createInstance(); plate = getTransformMaterial().getModel(AllBlockPartials.EJECTOR_TOP).createInstance();
pivotPlate(); pivotPlate();
} }

View file

@ -19,7 +19,7 @@ public class BrassDiodeInstance extends BlockEntityInstance<BrassDiodeTileEntity
indicator = modelManager.defaultSolid() indicator = modelManager.defaultSolid()
.material(Materials.TRANSFORMED) .material(Materials.TRANSFORMED)
.getModel(AllBlockPartials.FLEXPEATER_INDICATOR, blockState).createInstance(); .getModel(AllBlockPartials.FLEXPEATER_INDICATOR).createInstance();
indicator.loadIdentity() indicator.loadIdentity()
.translate(getInstancePosition()) .translate(getInstancePosition())

View file

@ -30,8 +30,8 @@ public class FunnelInstance extends BlockEntityInstance<FunnelTileEntity> implem
PartialModel flapPartial = (blockState.getBlock() instanceof FunnelBlock ? AllBlockPartials.FUNNEL_FLAP PartialModel flapPartial = (blockState.getBlock() instanceof FunnelBlock ? AllBlockPartials.FUNNEL_FLAP
: AllBlockPartials.BELT_FUNNEL_FLAP); : AllBlockPartials.BELT_FUNNEL_FLAP);
Instancer<FlapData> model = modelManager.defaultSolid() Instancer<FlapData> model = modelManager.defaultSolid()
.material(AllMaterialSpecs.FLAPS) .material(AllMaterialSpecs.FLAPS)
.getModel(flapPartial, blockState); .getModel(flapPartial);
int blockLight = world.getBrightness(LightLayer.BLOCK, pos); int blockLight = world.getBrightness(LightLayer.BLOCK, pos);
int skyLight = world.getBrightness(LightLayer.SKY, pos); int skyLight = world.getBrightness(LightLayer.SKY, pos);

View file

@ -0,0 +1,689 @@
package com.simibubi.create.content.logistics.block.mechanicalArm;
import java.util.Optional;
import java.util.function.Function;
import javax.annotation.Nullable;
import org.apache.commons.lang3.mutable.MutableBoolean;
import com.simibubi.create.AllBlocks;
import com.simibubi.create.Create;
import com.simibubi.create.content.contraptions.base.KineticTileEntity;
import com.simibubi.create.content.contraptions.components.crafter.MechanicalCrafterBlock;
import com.simibubi.create.content.contraptions.components.crafter.MechanicalCrafterTileEntity;
import com.simibubi.create.content.contraptions.components.deployer.DeployerBlock;
import com.simibubi.create.content.contraptions.components.saw.SawBlock;
import com.simibubi.create.content.contraptions.processing.burner.BlazeBurnerBlock;
import com.simibubi.create.content.contraptions.relays.belt.BeltHelper;
import com.simibubi.create.content.contraptions.relays.belt.BeltTileEntity;
import com.simibubi.create.content.logistics.block.belts.tunnel.BeltTunnelBlock;
import com.simibubi.create.content.logistics.block.chute.AbstractChuteBlock;
import com.simibubi.create.content.logistics.block.funnel.AbstractFunnelBlock;
import com.simibubi.create.content.logistics.block.funnel.BeltFunnelBlock;
import com.simibubi.create.content.logistics.block.funnel.BeltFunnelBlock.Shape;
import com.simibubi.create.content.logistics.block.funnel.FunnelBlock;
import com.simibubi.create.content.logistics.block.funnel.FunnelTileEntity;
import com.simibubi.create.foundation.advancement.AllTriggers;
import com.simibubi.create.foundation.item.SmartInventory;
import com.simibubi.create.foundation.tileEntity.TileEntityBehaviour;
import com.simibubi.create.foundation.tileEntity.behaviour.belt.TransportedItemStackHandlerBehaviour;
import com.simibubi.create.foundation.tileEntity.behaviour.belt.TransportedItemStackHandlerBehaviour.TransportedResult;
import com.simibubi.create.foundation.tileEntity.behaviour.filtering.FilteringBehaviour;
import com.simibubi.create.foundation.tileEntity.behaviour.inventory.InvManipulationBehaviour;
import com.simibubi.create.foundation.utility.VecHelper;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.Containers;
import net.minecraft.world.InteractionResultHolder;
import net.minecraft.world.WorldlyContainer;
import net.minecraft.world.item.Item;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.Items;
import net.minecraft.world.item.RecordItem;
import net.minecraft.world.item.crafting.CampfireCookingRecipe;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.Blocks;
import net.minecraft.world.level.block.CampfireBlock;
import net.minecraft.world.level.block.ComposterBlock;
import net.minecraft.world.level.block.JukeboxBlock;
import net.minecraft.world.level.block.RespawnAnchorBlock;
import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraft.world.level.block.entity.CampfireBlockEntity;
import net.minecraft.world.level.block.entity.JukeboxBlockEntity;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.block.state.properties.BlockStateProperties;
import net.minecraft.world.phys.Vec3;
import net.minecraftforge.common.util.LazyOptional;
import net.minecraftforge.items.IItemHandler;
import net.minecraftforge.items.wrapper.CombinedInvWrapper;
import net.minecraftforge.items.wrapper.SidedInvWrapper;
public class AllArmInteractionPointTypes {
public static final BasinType BASIN = register("basin", BasinType::new);
public static final BeltType BELT = register("belt", BeltType::new);
public static final BlazeBurnerType BLAZE_BURNER = register("blaze_burner", BlazeBurnerType::new);
public static final ChuteType CHUTE = register("chute", ChuteType::new);
public static final CrafterType CRAFTER = register("crafter", CrafterType::new);
public static final CrushingWheelsType CRUSHING_WHEELS = register("crushing_wheels", CrushingWheelsType::new);
public static final DeployerType DEPLOYER = register("deployer", DeployerType::new);
public static final DepotType DEPOT = register("depot", DepotType::new);
public static final FunnelType FUNNEL = register("funnel", FunnelType::new);
public static final MillstoneType MILLSTONE = register("millstone", MillstoneType::new);
public static final SawType SAW = register("saw", SawType::new);
public static final CampfireType CAMPFIRE = register("campfire", CampfireType::new);
public static final ComposterType COMPOSTER = register("composter", ComposterType::new);
public static final JukeboxType JUKEBOX = register("jukebox", JukeboxType::new);
public static final RespawnAnchorType RESPAWN_ANCHOR = register("respawn_anchor", RespawnAnchorType::new);
private static <T extends ArmInteractionPointType> T register(String id, Function<ResourceLocation, T> factory) {
T type = factory.apply(Create.asResource(id));
ArmInteractionPointType.register(type);
return type;
}
public static void register() {
}
//
public static class BasinType extends ArmInteractionPointType {
public BasinType(ResourceLocation id) {
super(id);
}
@Override
public boolean canCreatePoint(Level level, BlockPos pos, BlockState state) {
return AllBlocks.BASIN.has(state);
}
@Override
public ArmInteractionPoint createPoint(Level level, BlockPos pos, BlockState state) {
return new ArmInteractionPoint(this, level, pos, state);
}
}
public static class BeltType extends ArmInteractionPointType {
public BeltType(ResourceLocation id) {
super(id);
}
@Override
public boolean canCreatePoint(Level level, BlockPos pos, BlockState state) {
return AllBlocks.BELT.has(state) && !(level.getBlockState(pos.above())
.getBlock() instanceof BeltTunnelBlock);
}
@Override
public ArmInteractionPoint createPoint(Level level, BlockPos pos, BlockState state) {
return new BeltPoint(this, level, pos, state);
}
}
public static class BlazeBurnerType extends ArmInteractionPointType {
public BlazeBurnerType(ResourceLocation id) {
super(id);
}
@Override
public boolean canCreatePoint(Level level, BlockPos pos, BlockState state) {
return AllBlocks.BLAZE_BURNER.has(state);
}
@Override
public ArmInteractionPoint createPoint(Level level, BlockPos pos, BlockState state) {
return new BlazeBurnerPoint(this, level, pos, state);
}
}
public static class ChuteType extends ArmInteractionPointType {
public ChuteType(ResourceLocation id) {
super(id);
}
@Override
public boolean canCreatePoint(Level level, BlockPos pos, BlockState state) {
return AbstractChuteBlock.isChute(state);
}
@Override
public ArmInteractionPoint createPoint(Level level, BlockPos pos, BlockState state) {
return new TopFaceArmInteractionPoint(this, level, pos, state);
}
}
public static class CrafterType extends ArmInteractionPointType {
public CrafterType(ResourceLocation id) {
super(id);
}
@Override
public boolean canCreatePoint(Level level, BlockPos pos, BlockState state) {
return AllBlocks.MECHANICAL_CRAFTER.has(state);
}
@Override
public ArmInteractionPoint createPoint(Level level, BlockPos pos, BlockState state) {
return new CrafterPoint(this, level, pos, state);
}
}
public static class CrushingWheelsType extends ArmInteractionPointType {
public CrushingWheelsType(ResourceLocation id) {
super(id);
}
@Override
public boolean canCreatePoint(Level level, BlockPos pos, BlockState state) {
return AllBlocks.CRUSHING_WHEEL_CONTROLLER.has(state);
}
@Override
public ArmInteractionPoint createPoint(Level level, BlockPos pos, BlockState state) {
return new TopFaceArmInteractionPoint(this, level, pos, state);
}
}
public static class DeployerType extends ArmInteractionPointType {
public DeployerType(ResourceLocation id) {
super(id);
}
@Override
public boolean canCreatePoint(Level level, BlockPos pos, BlockState state) {
return AllBlocks.DEPLOYER.has(state);
}
@Override
public ArmInteractionPoint createPoint(Level level, BlockPos pos, BlockState state) {
return new DeployerPoint(this, level, pos, state);
}
}
public static class DepotType extends ArmInteractionPointType {
public DepotType(ResourceLocation id) {
super(id);
}
@Override
public boolean canCreatePoint(Level level, BlockPos pos, BlockState state) {
return AllBlocks.DEPOT.has(state) || AllBlocks.WEIGHTED_EJECTOR.has(state);
}
@Override
public ArmInteractionPoint createPoint(Level level, BlockPos pos, BlockState state) {
return new DepotPoint(this, level, pos, state);
}
}
public static class FunnelType extends ArmInteractionPointType {
public FunnelType(ResourceLocation id) {
super(id);
}
@Override
public boolean canCreatePoint(Level level, BlockPos pos, BlockState state) {
return state.getBlock() instanceof AbstractFunnelBlock
&& !(state.hasProperty(FunnelBlock.EXTRACTING) && state.getValue(FunnelBlock.EXTRACTING))
&& !(state.hasProperty(BeltFunnelBlock.SHAPE) && state.getValue(BeltFunnelBlock.SHAPE) == Shape.PUSHING);
}
@Override
public ArmInteractionPoint createPoint(Level level, BlockPos pos, BlockState state) {
return new FunnelPoint(this, level, pos, state);
}
}
public static class MillstoneType extends ArmInteractionPointType {
public MillstoneType(ResourceLocation id) {
super(id);
}
@Override
public boolean canCreatePoint(Level level, BlockPos pos, BlockState state) {
return AllBlocks.MILLSTONE.has(state);
}
@Override
public ArmInteractionPoint createPoint(Level level, BlockPos pos, BlockState state) {
return new ArmInteractionPoint(this, level, pos, state);
}
}
public static class SawType extends ArmInteractionPointType {
public SawType(ResourceLocation id) {
super(id);
}
@Override
public boolean canCreatePoint(Level level, BlockPos pos, BlockState state) {
return AllBlocks.MECHANICAL_SAW.has(state) && state.getValue(SawBlock.FACING) == Direction.UP
&& ((KineticTileEntity) level.getBlockEntity(pos)).getSpeed() != 0;
}
@Override
public ArmInteractionPoint createPoint(Level level, BlockPos pos, BlockState state) {
return new DepotPoint(this, level, pos, state);
}
}
public static class CampfireType extends ArmInteractionPointType {
public CampfireType(ResourceLocation id) {
super(id);
}
@Override
public boolean canCreatePoint(Level level, BlockPos pos, BlockState state) {
return state.getBlock() instanceof CampfireBlock;
}
@Override
public ArmInteractionPoint createPoint(Level level, BlockPos pos, BlockState state) {
return new CampfirePoint(this, level, pos, state);
}
}
public static class ComposterType extends ArmInteractionPointType {
public ComposterType(ResourceLocation id) {
super(id);
}
@Override
public boolean canCreatePoint(Level level, BlockPos pos, BlockState state) {
return state.is(Blocks.COMPOSTER);
}
@Override
public ArmInteractionPoint createPoint(Level level, BlockPos pos, BlockState state) {
return new ComposterPoint(this, level, pos, state);
}
}
public static class JukeboxType extends ArmInteractionPointType {
public JukeboxType(ResourceLocation id) {
super(id);
}
@Override
public boolean canCreatePoint(Level level, BlockPos pos, BlockState state) {
return state.is(Blocks.JUKEBOX);
}
@Override
public ArmInteractionPoint createPoint(Level level, BlockPos pos, BlockState state) {
return new JukeboxPoint(this, level, pos, state);
}
}
public static class RespawnAnchorType extends ArmInteractionPointType {
public RespawnAnchorType(ResourceLocation id) {
super(id);
}
@Override
public boolean canCreatePoint(Level level, BlockPos pos, BlockState state) {
return state.is(Blocks.RESPAWN_ANCHOR);
}
@Override
public ArmInteractionPoint createPoint(Level level, BlockPos pos, BlockState state) {
return new RespawnAnchorPoint(this, level, pos, state);
}
}
//
public static class DepositOnlyArmInteractionPoint extends ArmInteractionPoint {
public DepositOnlyArmInteractionPoint(ArmInteractionPointType type, Level level, BlockPos pos, BlockState state) {
super(type, level, pos, state);
}
@Override
public void cycleMode() {
}
@Override
public ItemStack extract(int slot, int amount, boolean simulate) {
return ItemStack.EMPTY;
}
@Override
public int getSlotCount() {
return 0;
}
}
public static class TopFaceArmInteractionPoint extends ArmInteractionPoint {
public TopFaceArmInteractionPoint(ArmInteractionPointType type, Level level, BlockPos pos, BlockState state) {
super(type, level, pos, state);
}
@Override
protected Vec3 getInteractionPositionVector() {
return Vec3.atLowerCornerOf(pos).add(.5f, 1, .5f);
}
}
public static class BeltPoint extends DepotPoint {
public BeltPoint(ArmInteractionPointType type, Level level, BlockPos pos, BlockState state) {
super(type, level, pos, state);
}
@Override
public void keepAlive() {
super.keepAlive();
BeltTileEntity beltTE = BeltHelper.getSegmentTE(level, pos);
if (beltTE == null)
return;
TransportedItemStackHandlerBehaviour transport =
beltTE.getBehaviour(TransportedItemStackHandlerBehaviour.TYPE);
if (transport == null)
return;
MutableBoolean found = new MutableBoolean(false);
transport.handleProcessingOnAllItems(tis -> {
if (found.isTrue())
return TransportedResult.doNothing();
tis.lockedExternally = true;
found.setTrue();
return TransportedResult.doNothing();
});
}
}
public static class BlazeBurnerPoint extends DepositOnlyArmInteractionPoint {
public BlazeBurnerPoint(ArmInteractionPointType type, Level level, BlockPos pos, BlockState state) {
super(type, level, pos, state);
}
@Override
public ItemStack insert(ItemStack stack, boolean simulate) {
ItemStack input = stack.copy();
InteractionResultHolder<ItemStack> res = BlazeBurnerBlock.tryInsert(cachedState, level, pos, input, false, false, simulate);
ItemStack remainder = res.getObject();
if (input.isEmpty()) {
return remainder;
} else {
if (!simulate)
Containers.dropItemStack(level, pos.getX(), pos.getY(), pos.getZ(), remainder);
return input;
}
}
}
public static class CrafterPoint extends ArmInteractionPoint {
public CrafterPoint(ArmInteractionPointType type, Level level, BlockPos pos, BlockState state) {
super(type, level, pos, state);
}
@Override
protected Direction getInteractionDirection() {
return cachedState.getValue(MechanicalCrafterBlock.HORIZONTAL_FACING)
.getOpposite();
}
@Override
protected Vec3 getInteractionPositionVector() {
return super.getInteractionPositionVector()
.add(Vec3.atLowerCornerOf(getInteractionDirection().getNormal()).scale(.5f));
}
@Override
public void updateCachedState() {
BlockState oldState = cachedState;
super.updateCachedState();
if (oldState != cachedState)
cachedAngles = null;
}
@Override
public ItemStack extract(int slot, int amount, boolean simulate) {
BlockEntity te = level.getBlockEntity(pos);
if (!(te instanceof MechanicalCrafterTileEntity))
return ItemStack.EMPTY;
MechanicalCrafterTileEntity crafter = (MechanicalCrafterTileEntity) te;
SmartInventory inventory = crafter.getInventory();
inventory.allowExtraction();
ItemStack extract = super.extract(slot, amount, simulate);
inventory.forbidExtraction();
return extract;
}
}
public static class DeployerPoint extends ArmInteractionPoint {
public DeployerPoint(ArmInteractionPointType type, Level level, BlockPos pos, BlockState state) {
super(type, level, pos, state);
}
@Override
protected Direction getInteractionDirection() {
return cachedState.getValue(DeployerBlock.FACING)
.getOpposite();
}
@Override
protected Vec3 getInteractionPositionVector() {
return super.getInteractionPositionVector()
.add(Vec3.atLowerCornerOf(getInteractionDirection().getNormal()).scale(.65f));
}
@Override
public void updateCachedState() {
BlockState oldState = cachedState;
super.updateCachedState();
if (oldState != cachedState)
cachedAngles = null;
}
}
public static class DepotPoint extends ArmInteractionPoint {
public DepotPoint(ArmInteractionPointType type, Level level, BlockPos pos, BlockState state) {
super(type, level, pos, state);
}
@Override
protected Vec3 getInteractionPositionVector() {
return Vec3.atLowerCornerOf(pos).add(.5f, 14 / 16f, .5f);
}
}
public static class FunnelPoint extends DepositOnlyArmInteractionPoint {
public FunnelPoint(ArmInteractionPointType type, Level level, BlockPos pos, BlockState state) {
super(type, level, pos, state);
}
@Override
protected Vec3 getInteractionPositionVector() {
return VecHelper.getCenterOf(pos)
.add(Vec3.atLowerCornerOf(FunnelBlock.getFunnelFacing(cachedState)
.getNormal()).scale(-.15f));
}
@Override
protected Direction getInteractionDirection() {
return FunnelBlock.getFunnelFacing(cachedState)
.getOpposite();
}
@Override
public void updateCachedState() {
BlockState oldState = cachedState;
super.updateCachedState();
if (oldState != cachedState)
cachedAngles = null;
}
@Override
public ItemStack insert(ItemStack stack, boolean simulate) {
FilteringBehaviour filtering = TileEntityBehaviour.get(level, pos, FilteringBehaviour.TYPE);
InvManipulationBehaviour inserter = TileEntityBehaviour.get(level, pos, InvManipulationBehaviour.TYPE);
if (cachedState.getOptionalValue(BlockStateProperties.POWERED).orElse(false))
return stack;
if (inserter == null)
return stack;
if (filtering != null && !filtering.test(stack))
return stack;
if (simulate)
inserter.simulate();
ItemStack insert = inserter.insert(stack);
if (!simulate && insert.getCount() != stack.getCount()) {
BlockEntity tileEntity = level.getBlockEntity(pos);
if (tileEntity instanceof FunnelTileEntity) {
FunnelTileEntity funnelTileEntity = (FunnelTileEntity) tileEntity;
funnelTileEntity.onTransfer(stack);
if (funnelTileEntity.hasFlap())
funnelTileEntity.flap(true);
}
}
return insert;
}
}
public static class CampfirePoint extends DepositOnlyArmInteractionPoint {
public CampfirePoint(ArmInteractionPointType type, Level level, BlockPos pos, BlockState state) {
super(type, level, pos, state);
}
@Override
public ItemStack insert(ItemStack stack, boolean simulate) {
BlockEntity blockEntity = level.getBlockEntity(pos);
if (!(blockEntity instanceof CampfireBlockEntity campfireBE))
return stack;
Optional<CampfireCookingRecipe> recipe = campfireBE.getCookableRecipe(stack);
if (recipe.isEmpty())
return stack;
if (simulate) {
boolean hasSpace = false;
for (ItemStack campfireStack : campfireBE.getItems()) {
if (campfireStack.isEmpty()) {
hasSpace = true;
break;
}
}
if (!hasSpace)
return stack;
ItemStack remainder = stack.copy();
remainder.shrink(1);
return remainder;
}
ItemStack remainder = stack.copy();
campfireBE.placeFood(remainder, recipe.get().getCookingTime());
return remainder;
}
}
public static class ComposterPoint extends ArmInteractionPoint {
public ComposterPoint(ArmInteractionPointType type, Level level, BlockPos pos, BlockState state) {
super(type, level, pos, state);
}
@Override
protected Vec3 getInteractionPositionVector() {
return Vec3.atLowerCornerOf(pos).add(.5f, 13 / 16f, .5f);
}
@Override
public void updateCachedState() {
BlockState oldState = cachedState;
super.updateCachedState();
if (oldState != cachedState)
cachedHandler.invalidate();
}
@Nullable
@Override
protected IItemHandler getHandler() {
if (!cachedHandler.isPresent()) {
cachedHandler = LazyOptional.of(() -> {
ComposterBlock composterBlock = (ComposterBlock) Blocks.COMPOSTER;
WorldlyContainer container = composterBlock.getContainer(cachedState, level, pos);
SidedInvWrapper insertionHandler = new SidedInvWrapper(container, Direction.UP);
SidedInvWrapper extractionHandler = new SidedInvWrapper(container, Direction.DOWN);
return new CombinedInvWrapper(insertionHandler, extractionHandler);
});
}
return cachedHandler.orElse(null);
}
}
public static class JukeboxPoint extends TopFaceArmInteractionPoint {
public JukeboxPoint(ArmInteractionPointType type, Level level, BlockPos pos, BlockState state) {
super(type, level, pos, state);
}
@Override
public int getSlotCount() {
return 1;
}
@Override
public ItemStack insert(ItemStack stack, boolean simulate) {
Item item = stack.getItem();
if (!(item instanceof RecordItem))
return stack;
if (cachedState.getValue(JukeboxBlock.HAS_RECORD))
return stack;
BlockEntity blockEntity = level.getBlockEntity(pos);
if (!(blockEntity instanceof JukeboxBlockEntity jukeboxBE))
return stack;
if (!jukeboxBE.getRecord()
.isEmpty())
return stack;
ItemStack remainder = stack.copy();
ItemStack toInsert = remainder.split(1);
if (!simulate) {
jukeboxBE.setRecord(toInsert);
level.setBlock(pos, cachedState.setValue(JukeboxBlock.HAS_RECORD, true), 2);
level.levelEvent(null, 1010, pos, Item.getId(item));
AllTriggers.triggerForNearbyPlayers(AllTriggers.MUSICAL_ARM, level, pos, 10);
}
return remainder;
}
@Override
public ItemStack extract(int slot, int amount, boolean simulate) {
if (!cachedState.getValue(JukeboxBlock.HAS_RECORD))
return ItemStack.EMPTY;
BlockEntity blockEntity = level.getBlockEntity(pos);
if (!(blockEntity instanceof JukeboxBlockEntity jukeboxBE))
return ItemStack.EMPTY;
ItemStack record = jukeboxBE.getRecord();
if (record.isEmpty())
return ItemStack.EMPTY;
if (!simulate) {
level.levelEvent(1010, pos, 0);
jukeboxBE.clearContent();
level.setBlock(pos, cachedState.setValue(JukeboxBlock.HAS_RECORD, false), 2);
}
return record;
}
}
public static class RespawnAnchorPoint extends DepositOnlyArmInteractionPoint {
public RespawnAnchorPoint(ArmInteractionPointType type, Level level, BlockPos pos, BlockState state) {
super(type, level, pos, state);
}
@Override
protected Vec3 getInteractionPositionVector() {
return Vec3.atLowerCornerOf(pos).add(.5f, 1, .5f);
}
@Override
public ItemStack insert(ItemStack stack, boolean simulate) {
if (!stack.is(Items.GLOWSTONE))
return stack;
if (cachedState.getValue(RespawnAnchorBlock.CHARGE) == 4)
return stack;
if (!simulate)
RespawnAnchorBlock.charge(level, pos, cachedState);
ItemStack remainder = stack.copy();
remainder.shrink(1);
return remainder;
}
}
}

View file

@ -11,7 +11,7 @@ import net.minecraft.world.phys.Vec3;
public class ArmAngleTarget { public class ArmAngleTarget {
static ArmAngleTarget NO_TARGET = new ArmAngleTarget(); static final ArmAngleTarget NO_TARGET = new ArmAngleTarget();
float baseAngle; float baseAngle;
float lowerArmAngle; float lowerArmAngle;

View file

@ -49,13 +49,13 @@ public class ArmInstance extends SingleRotatingInstance implements DynamicInstan
Material<ModelData> mat = getTransformMaterial(); Material<ModelData> mat = getTransformMaterial();
base = mat.getModel(AllBlockPartials.ARM_BASE, blockState).createInstance(); base = mat.getModel(AllBlockPartials.ARM_BASE).createInstance();
lowerBody = mat.getModel(AllBlockPartials.ARM_LOWER_BODY, blockState).createInstance(); lowerBody = mat.getModel(AllBlockPartials.ARM_LOWER_BODY).createInstance();
upperBody = mat.getModel(AllBlockPartials.ARM_UPPER_BODY, blockState).createInstance(); upperBody = mat.getModel(AllBlockPartials.ARM_UPPER_BODY).createInstance();
head = mat.getModel(AllBlockPartials.ARM_HEAD, blockState).createInstance(); head = mat.getModel(AllBlockPartials.ARM_HEAD).createInstance();
claw = mat.getModel(AllBlockPartials.ARM_CLAW_BASE, blockState).createInstance(); claw = mat.getModel(AllBlockPartials.ARM_CLAW_BASE).createInstance();
Instancer<ModelData> clawHalfModel = mat.getModel(AllBlockPartials.ARM_CLAW_GRIP, blockState); Instancer<ModelData> clawHalfModel = mat.getModel(AllBlockPartials.ARM_CLAW_GRIP);
ModelData clawGrip1 = clawHalfModel.createInstance(); ModelData clawGrip1 = clawHalfModel.createInstance();
ModelData clawGrip2 = clawHalfModel.createInstance(); ModelData clawGrip2 = clawHalfModel.createInstance();
@ -172,7 +172,7 @@ public class ArmInstance extends SingleRotatingInstance implements DynamicInstan
@Override @Override
protected Instancer<RotatingData> getModel() { protected Instancer<RotatingData> getModel() {
return getRotatingMaterial().getModel(AllBlockPartials.ARM_COG, blockEntity.getBlockState()); return getRotatingMaterial().getModel(AllBlockPartials.ARM_COG);
} }
@Override @Override

View file

@ -1,114 +1,66 @@
package com.simibubi.create.content.logistics.block.mechanicalArm; package com.simibubi.create.content.logistics.block.mechanicalArm;
import java.util.HashMap;
import java.util.function.Supplier;
import javax.annotation.Nullable; import javax.annotation.Nullable;
import org.apache.commons.lang3.mutable.MutableBoolean;
import com.mojang.blaze3d.vertex.PoseStack;
import com.simibubi.create.AllBlocks;
import com.simibubi.create.Create;
import com.simibubi.create.content.contraptions.base.KineticTileEntity;
import com.simibubi.create.content.contraptions.components.crafter.MechanicalCrafterBlock;
import com.simibubi.create.content.contraptions.components.crafter.MechanicalCrafterTileEntity;
import com.simibubi.create.content.contraptions.components.deployer.DeployerBlock;
import com.simibubi.create.content.contraptions.components.saw.SawBlock;
import com.simibubi.create.content.contraptions.components.structureMovement.StructureTransform; import com.simibubi.create.content.contraptions.components.structureMovement.StructureTransform;
import com.simibubi.create.content.contraptions.processing.burner.BlazeBurnerBlock;
import com.simibubi.create.content.contraptions.relays.belt.BeltHelper;
import com.simibubi.create.content.contraptions.relays.belt.BeltTileEntity;
import com.simibubi.create.content.logistics.block.belts.tunnel.BeltTunnelBlock;
import com.simibubi.create.content.logistics.block.chute.AbstractChuteBlock;
import com.simibubi.create.content.logistics.block.funnel.AbstractFunnelBlock;
import com.simibubi.create.content.logistics.block.funnel.BeltFunnelBlock;
import com.simibubi.create.content.logistics.block.funnel.BeltFunnelBlock.Shape;
import com.simibubi.create.content.logistics.block.funnel.FunnelBlock;
import com.simibubi.create.content.logistics.block.funnel.FunnelTileEntity;
import com.simibubi.create.foundation.advancement.AllTriggers;
import com.simibubi.create.foundation.item.SmartInventory;
import com.simibubi.create.foundation.tileEntity.TileEntityBehaviour;
import com.simibubi.create.foundation.tileEntity.behaviour.belt.TransportedItemStackHandlerBehaviour;
import com.simibubi.create.foundation.tileEntity.behaviour.belt.TransportedItemStackHandlerBehaviour.TransportedResult;
import com.simibubi.create.foundation.tileEntity.behaviour.filtering.FilteringBehaviour;
import com.simibubi.create.foundation.tileEntity.behaviour.inventory.InvManipulationBehaviour;
import com.simibubi.create.foundation.utility.NBTHelper; import com.simibubi.create.foundation.utility.NBTHelper;
import com.simibubi.create.foundation.utility.VecHelper; import com.simibubi.create.foundation.utility.VecHelper;
import net.minecraft.ChatFormatting;
import net.minecraft.core.BlockPos; import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction; import net.minecraft.core.Direction;
import net.minecraft.nbt.CompoundTag; import net.minecraft.nbt.CompoundTag;
import net.minecraft.nbt.NbtUtils; import net.minecraft.nbt.NbtUtils;
import net.minecraft.world.Containers; import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.InteractionResultHolder;
import net.minecraft.world.item.Item;
import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.RecordItem;
import net.minecraft.world.level.BlockGetter;
import net.minecraft.world.level.Level; import net.minecraft.world.level.Level;
import net.minecraft.world.level.LevelAccessor;
import net.minecraft.world.level.block.Blocks;
import net.minecraft.world.level.block.ComposterBlock;
import net.minecraft.world.level.block.JukeboxBlock;
import net.minecraft.world.level.block.entity.BlockEntity; import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraft.world.level.block.entity.JukeboxBlockEntity;
import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.block.state.properties.BlockStateProperties;
import net.minecraft.world.phys.Vec3; import net.minecraft.world.phys.Vec3;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.api.distmarker.OnlyIn;
import net.minecraftforge.common.util.LazyOptional; import net.minecraftforge.common.util.LazyOptional;
import net.minecraftforge.items.CapabilityItemHandler; import net.minecraftforge.items.CapabilityItemHandler;
import net.minecraftforge.items.IItemHandler; import net.minecraftforge.items.IItemHandler;
import net.minecraftforge.items.ItemHandlerHelper; import net.minecraftforge.items.ItemHandlerHelper;
import net.minecraftforge.items.wrapper.InvWrapper;
public abstract class ArmInteractionPoint { public class ArmInteractionPoint {
public enum Mode {
DEPOSIT, TAKE
}
protected BlockPos pos; protected final ArmInteractionPointType type;
protected BlockState state; protected Level level;
protected Mode mode; protected final BlockPos pos;
protected Mode mode = Mode.DEPOSIT;
protected LazyOptional<IItemHandler> cachedHandler; protected BlockState cachedState;
protected LazyOptional<IItemHandler> cachedHandler = LazyOptional.empty();
protected ArmAngleTarget cachedAngles; protected ArmAngleTarget cachedAngles;
protected static final HashMap<ArmInteractionPoint, Supplier<ArmInteractionPoint>> POINTS = new HashMap<>(); public ArmInteractionPoint(ArmInteractionPointType type, Level level, BlockPos pos, BlockState state) {
this.type = type;
static { this.level = level;
addPoint(new Saw(), Saw::new); this.pos = pos;
addPoint(new Belt(), Belt::new); this.cachedState = state;
addPoint(new Depot(), Depot::new);
addPoint(new Chute(), Chute::new);
addPoint(new Basin(), Basin::new);
addPoint(new Funnel(), Funnel::new);
addPoint(new Jukebox(), Jukebox::new);
addPoint(new Crafter(), Crafter::new);
addPoint(new Deployer(), Deployer::new);
addPoint(new Composter(), Composter::new);
addPoint(new Millstone(), Millstone::new);
addPoint(new BlazeBurner(), BlazeBurner::new);
addPoint(new CrushingWheels(), CrushingWheels::new);
} }
public static void addPoint(ArmInteractionPoint instance, Supplier<ArmInteractionPoint> factory) { public ArmInteractionPointType getType() {
if (POINTS.containsKey(instance)) return type;
Create.LOGGER.warn("Point for " + instance.getClass()
.getSimpleName() + " was overridden");
POINTS.put(instance, factory);
} }
public ArmInteractionPoint() { public Level getLevel() {
cachedHandler = LazyOptional.empty(); return level;
} }
@OnlyIn(Dist.CLIENT) public void setLevel(Level level) {
protected void transformFlag(PoseStack stack) {} this.level = level;
}
protected void cycleMode() { public BlockPos getPos() {
return pos;
}
public Mode getMode() {
return mode;
}
public void cycleMode() {
mode = mode == Mode.DEPOSIT ? Mode.TAKE : Mode.DEPOSIT; mode = mode == Mode.DEPOSIT ? Mode.TAKE : Mode.DEPOSIT;
} }
@ -120,22 +72,7 @@ public abstract class ArmInteractionPoint {
return Direction.DOWN; return Direction.DOWN;
} }
protected boolean isStillValid(BlockGetter reader) { public ArmAngleTarget getTargetAngles(BlockPos armPos, boolean ceiling) {
return isValid(reader, pos, reader.getBlockState(pos));
}
protected void keepAlive(LevelAccessor world) {}
protected abstract boolean isValid(BlockGetter reader, BlockPos pos, BlockState state);
protected static boolean isInteractable(BlockGetter reader, BlockPos pos, BlockState state) {
for (ArmInteractionPoint armInteractionPoint : POINTS.keySet())
if (armInteractionPoint.isValid(reader, pos, state))
return true;
return false;
}
protected ArmAngleTarget getTargetAngles(BlockPos armPos, boolean ceiling) {
if (cachedAngles == null) if (cachedAngles == null)
cachedAngles = cachedAngles =
new ArmAngleTarget(armPos, getInteractionPositionVector(), getInteractionDirection(), ceiling); new ArmAngleTarget(armPos, getInteractionPositionVector(), getInteractionDirection(), ceiling);
@ -143,10 +80,21 @@ public abstract class ArmInteractionPoint {
return cachedAngles; return cachedAngles;
} }
public void updateCachedState() {
cachedState = level.getBlockState(pos);
}
public boolean isValid() {
updateCachedState();
return type.canCreatePoint(level, pos, cachedState);
}
public void keepAlive() {}
@Nullable @Nullable
protected IItemHandler getHandler(Level world) { protected IItemHandler getHandler() {
if (!cachedHandler.isPresent()) { if (!cachedHandler.isPresent()) {
BlockEntity te = world.getBlockEntity(pos); BlockEntity te = level.getBlockEntity(pos);
if (te == null) if (te == null)
return null; return null;
cachedHandler = te.getCapability(CapabilityItemHandler.ITEM_HANDLER_CAPABILITY, Direction.UP); cachedHandler = te.getCapability(CapabilityItemHandler.ITEM_HANDLER_CAPABILITY, Direction.UP);
@ -154,401 +102,106 @@ public abstract class ArmInteractionPoint {
return cachedHandler.orElse(null); return cachedHandler.orElse(null);
} }
protected ItemStack insert(Level world, ItemStack stack, boolean simulate) { public ItemStack insert(ItemStack stack, boolean simulate) {
IItemHandler handler = getHandler(world); IItemHandler handler = getHandler();
if (handler == null) if (handler == null)
return stack; return stack;
return ItemHandlerHelper.insertItem(handler, stack, simulate); return ItemHandlerHelper.insertItem(handler, stack, simulate);
} }
protected ItemStack extract(Level world, int slot, int amount, boolean simulate) { public ItemStack extract(int slot, int amount, boolean simulate) {
IItemHandler handler = getHandler(world); IItemHandler handler = getHandler();
if (handler == null) if (handler == null)
return ItemStack.EMPTY; return ItemStack.EMPTY;
return handler.extractItem(slot, amount, simulate); return handler.extractItem(slot, amount, simulate);
} }
protected ItemStack extract(Level world, int slot, boolean simulate) { public ItemStack extract(int slot, boolean simulate) {
return extract(world, slot, 64, simulate); return extract(slot, 64, simulate);
} }
protected int getSlotCount(Level world) { public int getSlotCount() {
IItemHandler handler = getHandler(world); IItemHandler handler = getHandler();
if (handler == null) if (handler == null)
return 0; return 0;
return handler.getSlots(); return handler.getSlots();
} }
@Nullable protected void serialize(CompoundTag nbt, BlockPos anchor) {
protected static ArmInteractionPoint createAt(BlockGetter world, BlockPos pos) { NBTHelper.writeEnum(nbt, "Mode", mode);
BlockState state = world.getBlockState(pos);
ArmInteractionPoint point = null;
for (ArmInteractionPoint armInteractionPoint : POINTS.keySet())
if (armInteractionPoint.isValid(world, pos, state))
point = POINTS.get(armInteractionPoint)
.get();
if (point != null) {
point.state = state;
point.pos = pos;
point.mode = Mode.DEPOSIT;
}
return point;
} }
protected CompoundTag serialize(BlockPos anchor) { protected void deserialize(CompoundTag nbt, BlockPos anchor) {
mode = NBTHelper.readEnum(nbt, "Mode", Mode.class);
}
public final CompoundTag serialize(BlockPos anchor) {
CompoundTag nbt = new CompoundTag(); CompoundTag nbt = new CompoundTag();
nbt.putString("Type", type.getId().toString());
nbt.put("Pos", NbtUtils.writeBlockPos(pos.subtract(anchor))); nbt.put("Pos", NbtUtils.writeBlockPos(pos.subtract(anchor)));
NBTHelper.writeEnum(nbt, "Mode", mode); serialize(nbt, anchor);
return nbt; return nbt;
} }
protected static ArmInteractionPoint deserialize(BlockGetter world, BlockPos anchor, CompoundTag nbt) { @Nullable
BlockPos pos = NbtUtils.readBlockPos(nbt.getCompound("Pos")); public static ArmInteractionPoint deserialize(CompoundTag nbt, Level level, BlockPos anchor) {
ArmInteractionPoint interactionPoint = createAt(world, pos.offset(anchor)); ResourceLocation id = ResourceLocation.tryParse(nbt.getString("Type"));
if (interactionPoint == null) if (id == null)
return null; return null;
interactionPoint.mode = NBTHelper.readEnum(nbt, "Mode", Mode.class); ArmInteractionPointType type = ArmInteractionPointType.get(id);
return interactionPoint; if (type == null)
return null;
BlockPos pos = NbtUtils.readBlockPos(nbt.getCompound("Pos")).offset(anchor);
ArmInteractionPoint point = type.createPoint(level, pos, level.getBlockState(pos));
if (point == null)
return null;
point.deserialize(nbt, anchor);
return point;
} }
protected static void transformPos(StructureTransform transform, CompoundTag nbt) { public static void transformPos(CompoundTag nbt, StructureTransform transform) {
BlockPos pos = NbtUtils.readBlockPos(nbt.getCompound("Pos")); BlockPos pos = NbtUtils.readBlockPos(nbt.getCompound("Pos"));
pos = transform.applyWithoutOffset(pos); pos = transform.applyWithoutOffset(pos);
nbt.put("Pos", NbtUtils.writeBlockPos(pos)); nbt.put("Pos", NbtUtils.writeBlockPos(pos));
} }
public static abstract class TopFaceArmInteractionPoint extends ArmInteractionPoint { public static boolean isInteractable(Level level, BlockPos pos, BlockState state) {
return ArmInteractionPointType.getPrimaryType(level, pos, state) != null;
@Override
protected Vec3 getInteractionPositionVector() {
return Vec3.atLowerCornerOf(pos)
.add(.5f, 1, .5f);
}
} }
public static class Depot extends ArmInteractionPoint { @Nullable
public static ArmInteractionPoint create(Level level, BlockPos pos, BlockState state) {
@Override ArmInteractionPointType type = ArmInteractionPointType.getPrimaryType(level, pos, state);
protected Vec3 getInteractionPositionVector() { if (type == null)
return Vec3.atLowerCornerOf(pos) return null;
.add(.5f, 14 / 16f, .5f); return type.createPoint(level, pos, state);
}
@Override
protected boolean isValid(BlockGetter reader, BlockPos pos, BlockState state) {
return AllBlocks.DEPOT.has(state) || AllBlocks.WEIGHTED_EJECTOR.has(state)
|| AllBlocks.TRACK_STATION.has(state);
}
} }
public static class Saw extends Depot { public enum Mode {
DEPOSIT("mechanical_arm.deposit_to", ChatFormatting.GOLD, 0xFFCB74),
TAKE("mechanical_arm.extract_from", ChatFormatting.AQUA, 0x4F8A8B);
@Override private final String translationKey;
protected boolean isValid(BlockGetter reader, BlockPos pos, BlockState state) { private final ChatFormatting chatColor;
return AllBlocks.MECHANICAL_SAW.has(state) && state.getValue(SawBlock.FACING) == Direction.UP private final int color;
&& ((KineticTileEntity) reader.getBlockEntity(pos)).getSpeed() != 0;
Mode(String translationKey, ChatFormatting chatColor, int color) {
this.translationKey = translationKey;
this.chatColor = chatColor;
this.color = color;
} }
} public String getTranslationKey() {
return translationKey;
public static class Millstone extends ArmInteractionPoint {
@Override
protected boolean isValid(BlockGetter reader, BlockPos pos, BlockState state) {
return AllBlocks.MILLSTONE.has(state);
} }
} public ChatFormatting getChatColor() {
return chatColor;
public static class CrushingWheels extends TopFaceArmInteractionPoint {
@Override
protected boolean isValid(BlockGetter reader, BlockPos pos, BlockState state) {
return AllBlocks.CRUSHING_WHEEL_CONTROLLER.has(state);
} }
} public int getColor() {
return color;
public static class Composter extends TopFaceArmInteractionPoint {
@Override
protected Vec3 getInteractionPositionVector() {
return Vec3.atLowerCornerOf(pos)
.add(.5f, 13 / 16f, .5f);
}
@Override
protected boolean isValid(BlockGetter reader, BlockPos pos, BlockState state) {
return Blocks.COMPOSTER.equals(state.getBlock());
}
@Nullable
@Override
protected IItemHandler getHandler(Level world) {
return new InvWrapper(
((ComposterBlock) Blocks.COMPOSTER).getContainer(world.getBlockState(pos), world, pos));
} }
} }
public static class Deployer extends ArmInteractionPoint {
@Override
protected boolean isValid(BlockGetter reader, BlockPos pos, BlockState state) {
return AllBlocks.DEPLOYER.has(state);
}
@Override
protected Direction getInteractionDirection() {
return state.getValue(DeployerBlock.FACING)
.getOpposite();
}
@Override
protected Vec3 getInteractionPositionVector() {
return super.getInteractionPositionVector().add(Vec3.atLowerCornerOf(getInteractionDirection().getNormal())
.scale(.65f));
}
}
public static class BlazeBurner extends ArmInteractionPoint {
@Override
protected boolean isValid(BlockGetter reader, BlockPos pos, BlockState state) {
return AllBlocks.BLAZE_BURNER.has(state);
}
@Override
protected ItemStack extract(Level world, int slot, int amount, boolean simulate) {
return ItemStack.EMPTY;
}
@Override
protected ItemStack insert(Level world, ItemStack stack, boolean simulate) {
ItemStack input = stack.copy();
InteractionResultHolder<ItemStack> res =
BlazeBurnerBlock.tryInsert(state, world, pos, input, false, false, simulate);
ItemStack remainder = res.getObject();
if (input.isEmpty()) {
return remainder;
} else {
if (!simulate)
Containers.dropItemStack(world, pos.getX(), pos.getY(), pos.getZ(), remainder);
return input;
}
}
@Override
protected void cycleMode() {}
}
public static class Crafter extends ArmInteractionPoint {
@Override
protected boolean isValid(BlockGetter reader, BlockPos pos, BlockState state) {
return AllBlocks.MECHANICAL_CRAFTER.has(state);
}
@Override
protected Direction getInteractionDirection() {
return state.getValue(MechanicalCrafterBlock.HORIZONTAL_FACING)
.getOpposite();
}
@Override
protected ItemStack extract(Level world, int slot, int amount, boolean simulate) {
BlockEntity te = world.getBlockEntity(pos);
if (!(te instanceof MechanicalCrafterTileEntity))
return ItemStack.EMPTY;
MechanicalCrafterTileEntity crafter = (MechanicalCrafterTileEntity) te;
SmartInventory inventory = crafter.getInventory();
inventory.allowExtraction();
ItemStack extract = super.extract(world, slot, amount, simulate);
inventory.forbidExtraction();
return extract;
}
@Override
protected Vec3 getInteractionPositionVector() {
return super.getInteractionPositionVector().add(Vec3.atLowerCornerOf(getInteractionDirection().getNormal())
.scale(.5f));
}
}
public static class Basin extends ArmInteractionPoint {
@Override
protected boolean isValid(BlockGetter reader, BlockPos pos, BlockState state) {
return AllBlocks.BASIN.has(state);
}
}
public static class Jukebox extends TopFaceArmInteractionPoint {
@Override
protected boolean isValid(BlockGetter reader, BlockPos pos, BlockState state) {
return state.getBlock() instanceof JukeboxBlock;
}
@Override
protected int getSlotCount(Level world) {
return 1;
}
@Override
protected ItemStack insert(Level world, ItemStack stack, boolean simulate) {
BlockEntity tileEntity = world.getBlockEntity(pos);
if (!(tileEntity instanceof JukeboxBlockEntity))
return stack;
if (!(state.getBlock() instanceof JukeboxBlock))
return stack;
JukeboxBlock jukeboxBlock = (JukeboxBlock) state.getBlock();
JukeboxBlockEntity jukeboxTE = (JukeboxBlockEntity) tileEntity;
if (!jukeboxTE.getRecord()
.isEmpty())
return stack;
if (!(stack.getItem() instanceof RecordItem))
return stack;
ItemStack remainder = stack.copy();
ItemStack toInsert = remainder.split(1);
if (!simulate && !world.isClientSide) {
jukeboxBlock.setRecord(world, pos, state, toInsert);
world.levelEvent(null, 1010, pos, Item.getId(toInsert.getItem()));
AllTriggers.triggerForNearbyPlayers(AllTriggers.MUSICAL_ARM, world, pos, 10);
}
return remainder;
}
@Override
protected ItemStack extract(Level world, int slot, int amount, boolean simulate) {
BlockEntity tileEntity = world.getBlockEntity(pos);
if (!(tileEntity instanceof JukeboxBlockEntity))
return ItemStack.EMPTY;
if (!(state.getBlock() instanceof JukeboxBlock))
return ItemStack.EMPTY;
JukeboxBlockEntity jukeboxTE = (JukeboxBlockEntity) tileEntity;
ItemStack itemstack = jukeboxTE.getRecord();
if (itemstack.isEmpty())
return ItemStack.EMPTY;
if (!simulate && !world.isClientSide) {
world.levelEvent(1010, pos, 0);
jukeboxTE.clearContent();
world.setBlock(pos, state.setValue(JukeboxBlock.HAS_RECORD, false), 2);
}
return itemstack;
}
}
public static class Belt extends Depot {
@Override
protected boolean isValid(BlockGetter reader, BlockPos pos, BlockState state) {
return AllBlocks.BELT.has(state) && !(reader.getBlockState(pos.above())
.getBlock() instanceof BeltTunnelBlock);
}
@Override
protected void keepAlive(LevelAccessor world) {
super.keepAlive(world);
BeltTileEntity beltTE = BeltHelper.getSegmentTE(world, pos);
if (beltTE == null)
return;
TransportedItemStackHandlerBehaviour transport =
beltTE.getBehaviour(TransportedItemStackHandlerBehaviour.TYPE);
if (transport == null)
return;
MutableBoolean found = new MutableBoolean(false);
transport.handleProcessingOnAllItems(tis -> {
if (found.isTrue())
return TransportedResult.doNothing();
tis.lockedExternally = true;
found.setTrue();
return TransportedResult.doNothing();
});
}
}
public static class Chute extends TopFaceArmInteractionPoint {
@Override
protected boolean isValid(BlockGetter reader, BlockPos pos, BlockState state) {
return AbstractChuteBlock.isChute(state);
}
}
public static class Funnel extends ArmInteractionPoint {
@Override
protected Vec3 getInteractionPositionVector() {
return VecHelper.getCenterOf(pos)
.add(Vec3.atLowerCornerOf(FunnelBlock.getFunnelFacing(state)
.getNormal())
.scale(-.15f));
}
@Override
protected int getSlotCount(Level world) {
return 0;
}
@Override
protected ItemStack extract(Level world, int slot, int amount, boolean simulate) {
return ItemStack.EMPTY;
}
@Override
protected Direction getInteractionDirection() {
return FunnelBlock.getFunnelFacing(state)
.getOpposite();
}
@Override
protected ItemStack insert(Level world, ItemStack stack, boolean simulate) {
FilteringBehaviour filtering = TileEntityBehaviour.get(world, pos, FilteringBehaviour.TYPE);
InvManipulationBehaviour inserter = TileEntityBehaviour.get(world, pos, InvManipulationBehaviour.TYPE);
BlockState state = world.getBlockState(pos);
if (state.getOptionalValue(BlockStateProperties.POWERED)
.orElse(false))
return stack;
if (inserter == null)
return stack;
if (filtering != null && !filtering.test(stack))
return stack;
if (simulate)
inserter.simulate();
ItemStack insert = inserter.insert(stack);
if (!simulate && insert.getCount() != stack.getCount()) {
BlockEntity tileEntity = world.getBlockEntity(pos);
if (tileEntity instanceof FunnelTileEntity) {
FunnelTileEntity funnelTileEntity = (FunnelTileEntity) tileEntity;
funnelTileEntity.onTransfer(stack);
if (funnelTileEntity.hasFlap())
funnelTileEntity.flap(true);
}
}
return insert;
}
@Override
protected boolean isValid(BlockGetter reader, BlockPos pos, BlockState state) {
return state.getBlock() instanceof AbstractFunnelBlock
&& !(state.hasProperty(FunnelBlock.EXTRACTING) && state.getValue(FunnelBlock.EXTRACTING))
&& !(state.hasProperty(BeltFunnelBlock.SHAPE)
&& state.getValue(BeltFunnelBlock.SHAPE) == Shape.PUSHING);
}
@Override
protected void cycleMode() {}
}
} }

View file

@ -16,7 +16,7 @@ import net.minecraft.ChatFormatting;
import net.minecraft.client.Minecraft; import net.minecraft.client.Minecraft;
import net.minecraft.client.player.LocalPlayer; import net.minecraft.client.player.LocalPlayer;
import net.minecraft.core.BlockPos; import net.minecraft.core.BlockPos;
import net.minecraft.network.chat.TranslatableComponent; import net.minecraft.network.chat.MutableComponent;
import net.minecraft.world.InteractionResult; import net.minecraft.world.InteractionResult;
import net.minecraft.world.entity.player.Player; import net.minecraft.world.entity.player.Player;
import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.ItemStack;
@ -52,9 +52,10 @@ public class ArmInteractionPointHandler {
return; return;
ArmInteractionPoint selected = getSelected(pos); ArmInteractionPoint selected = getSelected(pos);
BlockState state = world.getBlockState(pos);
if (selected == null) { if (selected == null) {
ArmInteractionPoint point = ArmInteractionPoint.createAt(world, pos); ArmInteractionPoint point = ArmInteractionPoint.create(world, pos, state);
if (point == null) if (point == null)
return; return;
selected = point; selected = point;
@ -63,10 +64,9 @@ public class ArmInteractionPointHandler {
selected.cycleMode(); selected.cycleMode();
if (player != null) { if (player != null) {
String key = selected.mode == Mode.DEPOSIT ? "mechanical_arm.deposit_to" : "mechanical_arm.extract_from"; String key = selected.getMode().getTranslationKey();
ChatFormatting colour = selected.mode == Mode.DEPOSIT ? ChatFormatting.GOLD : ChatFormatting.AQUA; ChatFormatting colour = selected.getMode().getChatColor();
TranslatableComponent translatedBlock = new TranslatableComponent(selected.state.getBlock() MutableComponent translatedBlock = state.getBlock().getName();
.getDescriptionId());
player.displayClientMessage((Lang.translate(key, translatedBlock.withStyle(ChatFormatting.WHITE, colour)).withStyle(colour)), player.displayClientMessage((Lang.translate(key, translatedBlock.withStyle(ChatFormatting.WHITE, colour)).withStyle(colour)),
true); true);
} }
@ -95,7 +95,7 @@ public class ArmInteractionPointHandler {
int removed = 0; int removed = 0;
for (Iterator<ArmInteractionPoint> iterator = currentSelection.iterator(); iterator.hasNext();) { for (Iterator<ArmInteractionPoint> iterator = currentSelection.iterator(); iterator.hasNext();) {
ArmInteractionPoint point = iterator.next(); ArmInteractionPoint point = iterator.next();
if (point.pos.closerThan(pos, ArmTileEntity.getRange())) if (point.getPos().closerThan(pos, ArmTileEntity.getRange()))
continue; continue;
iterator.remove(); iterator.remove();
removed++; removed++;
@ -109,7 +109,7 @@ public class ArmInteractionPointHandler {
int inputs = 0; int inputs = 0;
int outputs = 0; int outputs = 0;
for (ArmInteractionPoint armInteractionPoint : currentSelection) { for (ArmInteractionPoint armInteractionPoint : currentSelection) {
if (armInteractionPoint.mode == Mode.DEPOSIT) if (armInteractionPoint.getMode() == Mode.DEPOSIT)
outputs++; outputs++;
else else
inputs++; inputs++;
@ -179,22 +179,22 @@ public class ArmInteractionPointHandler {
} }
private static void drawOutlines(Collection<ArmInteractionPoint> selection) { private static void drawOutlines(Collection<ArmInteractionPoint> selection) {
Level world = Minecraft.getInstance().level;
for (Iterator<ArmInteractionPoint> iterator = selection.iterator(); iterator.hasNext();) { for (Iterator<ArmInteractionPoint> iterator = selection.iterator(); iterator.hasNext();) {
ArmInteractionPoint point = iterator.next(); ArmInteractionPoint point = iterator.next();
BlockPos pos = point.pos;
BlockState state = world.getBlockState(pos);
if (!point.isValid(world, pos, state)) { if (!point.isValid()) {
iterator.remove(); iterator.remove();
continue; continue;
} }
VoxelShape shape = state.getShape(world, pos); Level level = point.getLevel();
BlockPos pos = point.getPos();
BlockState state = level.getBlockState(pos);
VoxelShape shape = state.getShape(level, pos);
if (shape.isEmpty()) if (shape.isEmpty())
continue; continue;
int color = point.mode == Mode.DEPOSIT ? 0xffcb74 : 0x4f8a8b; int color = point.getMode().getColor();
CreateClient.OUTLINER.showAABB(point, shape.bounds() CreateClient.OUTLINER.showAABB(point, shape.bounds()
.move(pos)) .move(pos))
.colored(color) .colored(color)
@ -214,10 +214,9 @@ public class ArmInteractionPointHandler {
} }
private static ArmInteractionPoint getSelected(BlockPos pos) { private static ArmInteractionPoint getSelected(BlockPos pos) {
for (ArmInteractionPoint point : currentSelection) { for (ArmInteractionPoint point : currentSelection)
if (point.pos.equals(pos)) if (point.getPos().equals(pos))
return point; return point;
}
return null; return null;
} }

View file

@ -0,0 +1,66 @@
package com.simibubi.create.content.logistics.block.mechanicalArm;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.function.Consumer;
import javax.annotation.Nullable;
import net.minecraft.core.BlockPos;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.state.BlockState;
public abstract class ArmInteractionPointType {
private static final Map<ResourceLocation, ArmInteractionPointType> TYPES = new HashMap<>();
private static final List<ArmInteractionPointType> SORTED_TYPES = new ArrayList<>();
protected final ResourceLocation id;
public ArmInteractionPointType(ResourceLocation id) {
this.id = id;
}
public static void register(ArmInteractionPointType type) {
ResourceLocation id = type.getId();
if (TYPES.containsKey(id))
throw new IllegalArgumentException("Tried to override ArmInteractionPointType registration for id '" + id + "'. This is not supported!");
TYPES.put(id, type);
SORTED_TYPES.add(type);
SORTED_TYPES.sort((t1, t2) -> t2.getPriority() - t1.getPriority());
}
@Nullable
public static ArmInteractionPointType get(ResourceLocation id) {
return TYPES.get(id);
}
public static void forEach(Consumer<ArmInteractionPointType> action) {
SORTED_TYPES.forEach(action);
}
@Nullable
public static ArmInteractionPointType getPrimaryType(Level level, BlockPos pos, BlockState state) {
for (ArmInteractionPointType type : SORTED_TYPES)
if (type.canCreatePoint(level, pos, state))
return type;
return null;
}
public final ResourceLocation getId() {
return id;
}
public abstract boolean canCreatePoint(Level level, BlockPos pos, BlockState state);
@Nullable
public abstract ArmInteractionPoint createPoint(Level level, BlockPos pos, BlockState state);
public int getPriority() {
return 0;
}
}

View file

@ -9,7 +9,6 @@ import com.simibubi.create.Create;
import com.simibubi.create.content.contraptions.base.KineticTileEntity; import com.simibubi.create.content.contraptions.base.KineticTileEntity;
import com.simibubi.create.content.contraptions.components.structureMovement.ITransformableTE; import com.simibubi.create.content.contraptions.components.structureMovement.ITransformableTE;
import com.simibubi.create.content.contraptions.components.structureMovement.StructureTransform; import com.simibubi.create.content.contraptions.components.structureMovement.StructureTransform;
import com.simibubi.create.content.logistics.block.mechanicalArm.ArmInteractionPoint.Jukebox;
import com.simibubi.create.content.logistics.block.mechanicalArm.ArmInteractionPoint.Mode; import com.simibubi.create.content.logistics.block.mechanicalArm.ArmInteractionPoint.Mode;
import com.simibubi.create.foundation.advancement.AllTriggers; import com.simibubi.create.foundation.advancement.AllTriggers;
import com.simibubi.create.foundation.config.AllConfigs; import com.simibubi.create.foundation.config.AllConfigs;
@ -35,6 +34,7 @@ import net.minecraft.sounds.SoundEvents;
import net.minecraft.sounds.SoundSource; import net.minecraft.sounds.SoundSource;
import net.minecraft.util.Mth; import net.minecraft.util.Mth;
import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.ItemStack;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.JukeboxBlock; import net.minecraft.world.level.block.JukeboxBlock;
import net.minecraft.world.level.block.entity.BlockEntityType; import net.minecraft.world.level.block.entity.BlockEntityType;
import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.block.state.BlockState;
@ -116,7 +116,7 @@ public class ArmTileEntity extends KineticTileEntity implements ITransformableTE
if (phase == Phase.MOVE_TO_INPUT) { if (phase == Phase.MOVE_TO_INPUT) {
ArmInteractionPoint point = getTargetedInteractionPoint(); ArmInteractionPoint point = getTargetedInteractionPoint();
if (point != null) if (point != null)
point.keepAlive(level); point.keepAlive();
} }
return; return;
} }
@ -164,9 +164,9 @@ public class ArmTileEntity extends KineticTileEntity implements ITransformableTE
private boolean checkForMusicAmong(List<ArmInteractionPoint> list) { private boolean checkForMusicAmong(List<ArmInteractionPoint> list) {
for (ArmInteractionPoint armInteractionPoint : list) { for (ArmInteractionPoint armInteractionPoint : list) {
if (!(armInteractionPoint instanceof Jukebox)) if (!(armInteractionPoint instanceof AllArmInteractionPointTypes.JukeboxPoint))
continue; continue;
BlockState state = level.getBlockState(armInteractionPoint.pos); BlockState state = level.getBlockState(armInteractionPoint.getPos());
if (state.getOptionalValue(JukeboxBlock.HAS_RECORD).orElse(false)) if (state.getOptionalValue(JukeboxBlock.HAS_RECORD).orElse(false))
return true; return true;
} }
@ -236,9 +236,9 @@ public class ArmTileEntity extends KineticTileEntity implements ITransformableTE
InteractionPoints: for (int i = startIndex; i < scanRange; i++) { InteractionPoints: for (int i = startIndex; i < scanRange; i++) {
ArmInteractionPoint armInteractionPoint = inputs.get(i); ArmInteractionPoint armInteractionPoint = inputs.get(i);
if (!armInteractionPoint.isStillValid(level)) if (!armInteractionPoint.isValid())
continue; continue;
for (int j = 0; j < armInteractionPoint.getSlotCount(level); j++) { for (int j = 0; j < armInteractionPoint.getSlotCount(); j++) {
if (getDistributableAmount(armInteractionPoint, j) == 0) if (getDistributableAmount(armInteractionPoint, j) == 0)
continue; continue;
@ -274,10 +274,10 @@ public class ArmTileEntity extends KineticTileEntity implements ITransformableTE
for (int i = startIndex; i < scanRange; i++) { for (int i = startIndex; i < scanRange; i++) {
ArmInteractionPoint armInteractionPoint = outputs.get(i); ArmInteractionPoint armInteractionPoint = outputs.get(i);
if (!armInteractionPoint.isStillValid(level)) if (!armInteractionPoint.isValid())
continue; continue;
ItemStack remainder = armInteractionPoint.insert(level, held, true); ItemStack remainder = armInteractionPoint.insert(held, true);
if (remainder.equals(heldItem, false)) if (remainder.equals(heldItem, false))
continue; continue;
@ -311,7 +311,7 @@ public class ArmTileEntity extends KineticTileEntity implements ITransformableTE
} }
protected int getDistributableAmount(ArmInteractionPoint armInteractionPoint, int i) { protected int getDistributableAmount(ArmInteractionPoint armInteractionPoint, int i) {
ItemStack stack = armInteractionPoint.extract(level, i, true); ItemStack stack = armInteractionPoint.extract(i, true);
ItemStack remainder = simulateInsertion(stack); ItemStack remainder = simulateInsertion(stack);
if (stack.sameItem(remainder)) { if (stack.sameItem(remainder)) {
return stack.getCount() - remainder.getCount(); return stack.getCount() - remainder.getCount();
@ -320,11 +320,21 @@ public class ArmTileEntity extends KineticTileEntity implements ITransformableTE
} }
} }
private ItemStack simulateInsertion(ItemStack stack) {
for (ArmInteractionPoint armInteractionPoint : outputs) {
if (armInteractionPoint.isValid())
stack = armInteractionPoint.insert(stack, true);
if (stack.isEmpty())
break;
}
return stack;
}
protected void depositItem() { protected void depositItem() {
ArmInteractionPoint armInteractionPoint = getTargetedInteractionPoint(); ArmInteractionPoint armInteractionPoint = getTargetedInteractionPoint();
if (armInteractionPoint != null) { if (armInteractionPoint != null && armInteractionPoint.isValid()) {
ItemStack toInsert = heldItem.copy(); ItemStack toInsert = heldItem.copy();
ItemStack remainder = armInteractionPoint.insert(level, toInsert, false); ItemStack remainder = armInteractionPoint.insert(toInsert, false);
heldItem = remainder; heldItem = remainder;
} }
phase = heldItem.isEmpty() ? Phase.SEARCH_INPUTS : Phase.SEARCH_OUTPUTS; phase = heldItem.isEmpty() ? Phase.SEARCH_INPUTS : Phase.SEARCH_OUTPUTS;
@ -339,14 +349,14 @@ public class ArmTileEntity extends KineticTileEntity implements ITransformableTE
protected void collectItem() { protected void collectItem() {
ArmInteractionPoint armInteractionPoint = getTargetedInteractionPoint(); ArmInteractionPoint armInteractionPoint = getTargetedInteractionPoint();
if (armInteractionPoint != null) if (armInteractionPoint != null && armInteractionPoint.isValid())
for (int i = 0; i < armInteractionPoint.getSlotCount(level); i++) { for (int i = 0; i < armInteractionPoint.getSlotCount(); i++) {
int amountExtracted = getDistributableAmount(armInteractionPoint, i); int amountExtracted = getDistributableAmount(armInteractionPoint, i);
if (amountExtracted == 0) if (amountExtracted == 0)
continue; continue;
ItemStack prevHeld = heldItem; ItemStack prevHeld = heldItem;
heldItem = armInteractionPoint.extract(level, i, amountExtracted, false); heldItem = armInteractionPoint.extract(i, amountExtracted, false);
phase = Phase.SEARCH_OUTPUTS; phase = Phase.SEARCH_OUTPUTS;
chasedPointProgress = 0; chasedPointProgress = 0;
chasedPointIndex = -1; chasedPointIndex = -1;
@ -366,15 +376,6 @@ public class ArmTileEntity extends KineticTileEntity implements ITransformableTE
setChanged(); setChanged();
} }
private ItemStack simulateInsertion(ItemStack stack) {
for (ArmInteractionPoint armInteractionPoint : outputs) {
stack = armInteractionPoint.insert(level, stack, true);
if (stack.isEmpty())
break;
}
return stack;
}
public void redstoneUpdate() { public void redstoneUpdate() {
if (level.isClientSide) if (level.isClientSide)
return; return;
@ -392,8 +393,8 @@ public class ArmTileEntity extends KineticTileEntity implements ITransformableTE
if (interactionPointTag == null) if (interactionPointTag == null)
return; return;
for (Tag inbt : interactionPointTag) { for (Tag tag : interactionPointTag) {
ArmInteractionPoint.transformPos(transform, (CompoundTag) inbt); ArmInteractionPoint.transformPos((CompoundTag) tag, transform);
} }
notifyUpdate(); notifyUpdate();
@ -408,15 +409,15 @@ public class ArmTileEntity extends KineticTileEntity implements ITransformableTE
outputs.clear(); outputs.clear();
boolean hasBlazeBurner = false; boolean hasBlazeBurner = false;
for (Tag inbt : interactionPointTag) { for (Tag tag : interactionPointTag) {
ArmInteractionPoint point = ArmInteractionPoint.deserialize(level, worldPosition, (CompoundTag) inbt); ArmInteractionPoint point = ArmInteractionPoint.deserialize((CompoundTag) tag, level, worldPosition);
if (point == null) if (point == null)
continue; continue;
if (point.mode == Mode.DEPOSIT) if (point.getMode() == Mode.DEPOSIT)
outputs.add(point); outputs.add(point);
if (point.mode == Mode.TAKE) else if (point.getMode() == Mode.TAKE)
inputs.add(point); inputs.add(point);
hasBlazeBurner |= point instanceof ArmInteractionPoint.BlazeBurner; hasBlazeBurner |= point instanceof AllArmInteractionPointTypes.BlazeBurnerPoint;
} }
if (!level.isClientSide) { if (!level.isClientSide) {
@ -496,6 +497,10 @@ public class ArmTileEntity extends KineticTileEntity implements ITransformableTE
previousPoint == null ? ArmAngleTarget.NO_TARGET : previousPoint.getTargetAngles(worldPosition, ceiling); previousPoint == null ? ArmAngleTarget.NO_TARGET : previousPoint.getTargetAngles(worldPosition, ceiling);
if (previousPoint != null) if (previousPoint != null)
previousBaseAngle = previousPoint.getTargetAngles(worldPosition, ceiling).baseAngle; previousBaseAngle = previousPoint.getTargetAngles(worldPosition, ceiling).baseAngle;
ArmInteractionPoint targetedPoint = getTargetedInteractionPoint();
if (targetedPoint != null)
targetedPoint.updateCachedState();
} }
} }
@ -518,6 +523,16 @@ public class ArmTileEntity extends KineticTileEntity implements ITransformableTE
return true; return true;
} }
public void setLevel(Level level) {
super.setLevel(level);
for (ArmInteractionPoint input : inputs) {
input.setLevel(level);
}
for (ArmInteractionPoint output : outputs) {
output.setLevel(level);
}
}
private class SelectionModeValueBox extends CenteredSideValueBoxTransform { private class SelectionModeValueBox extends CenteredSideValueBoxTransform {
public SelectionModeValueBox() { public SelectionModeValueBox() {

View file

@ -28,8 +28,8 @@ public class AnalogLeverInstance extends BlockEntityInstance<AnalogLeverTileEnti
Material<ModelData> mat = getTransformMaterial(); Material<ModelData> mat = getTransformMaterial();
handle = mat.getModel(AllBlockPartials.ANALOG_LEVER_HANDLE, blockState).createInstance(); handle = mat.getModel(AllBlockPartials.ANALOG_LEVER_HANDLE).createInstance();
indicator = mat.getModel(AllBlockPartials.ANALOG_LEVER_INDICATOR, blockState).createInstance(); indicator = mat.getModel(AllBlockPartials.ANALOG_LEVER_INDICATOR).createInstance();
transform(indicator); transform(indicator);

View file

@ -4,6 +4,7 @@ import javax.annotation.Nullable;
import com.simibubi.create.AllBlocks; import com.simibubi.create.AllBlocks;
import com.simibubi.create.AllTileEntities; import com.simibubi.create.AllTileEntities;
import com.simibubi.create.api.connectivity.ConnectivityHandler;
import com.simibubi.create.content.contraptions.wrench.IWrenchable; import com.simibubi.create.content.contraptions.wrench.IWrenchable;
import com.simibubi.create.foundation.block.ITE; import com.simibubi.create.foundation.block.ITE;
import com.simibubi.create.foundation.item.ItemHelper; import com.simibubi.create.foundation.item.ItemHelper;
@ -85,7 +86,7 @@ public class ItemVaultBlock extends Block implements IWrenchable, ITE<ItemVaultT
.getBlockEntity(context.getClickedPos()); .getBlockEntity(context.getClickedPos());
if (te instanceof ItemVaultTileEntity) { if (te instanceof ItemVaultTileEntity) {
ItemVaultTileEntity vault = (ItemVaultTileEntity) te; ItemVaultTileEntity vault = (ItemVaultTileEntity) te;
ItemVaultConnectivityHandler.splitVault(vault); ConnectivityHandler.splitMulti(vault);
vault.removeController(true); vault.removeController(true);
} }
state = state.setValue(LARGE, false); state = state.setValue(LARGE, false);
@ -100,10 +101,10 @@ public class ItemVaultBlock extends Block implements IWrenchable, ITE<ItemVaultT
BlockEntity te = world.getBlockEntity(pos); BlockEntity te = world.getBlockEntity(pos);
if (!(te instanceof ItemVaultTileEntity)) if (!(te instanceof ItemVaultTileEntity))
return; return;
ItemVaultTileEntity tankTE = (ItemVaultTileEntity) te; ItemVaultTileEntity vaultTE = (ItemVaultTileEntity) te;
ItemHelper.dropContents(world, pos, tankTE.inventory); ItemHelper.dropContents(world, pos, vaultTE.inventory);
world.removeBlockEntity(pos); world.removeBlockEntity(pos);
ItemVaultConnectivityHandler.splitVault(tankTE); ConnectivityHandler.splitMulti(vaultTE);
} }
} }

View file

@ -1,6 +1,7 @@
package com.simibubi.create.content.logistics.block.vault; package com.simibubi.create.content.logistics.block.vault;
import com.simibubi.create.AllSpriteShifts; import com.simibubi.create.AllSpriteShifts;
import com.simibubi.create.api.connectivity.ConnectivityHandler;
import com.simibubi.create.foundation.block.connected.CTSpriteShiftEntry; import com.simibubi.create.foundation.block.connected.CTSpriteShiftEntry;
import com.simibubi.create.foundation.block.connected.ConnectedTextureBehaviour; import com.simibubi.create.foundation.block.connected.ConnectedTextureBehaviour;
@ -62,7 +63,7 @@ public class ItemVaultCTBehaviour extends ConnectedTextureBehaviour {
@Override @Override
public boolean connectsTo(BlockState state, BlockState other, BlockAndTintGetter reader, BlockPos pos, public boolean connectsTo(BlockState state, BlockState other, BlockAndTintGetter reader, BlockPos pos,
BlockPos otherPos, Direction face) { BlockPos otherPos, Direction face) {
return state == other && ItemVaultConnectivityHandler.isConnected(reader, pos, otherPos); return state == other && ConnectivityHandler.isConnected(reader, pos, otherPos); //ItemVaultConnectivityHandler.isConnected(reader, pos, otherPos);
} }
} }

View file

@ -1,329 +0,0 @@
package com.simibubi.create.content.logistics.block.vault;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.PriorityQueue;
import java.util.Set;
import javax.annotation.Nullable;
import org.apache.commons.lang3.tuple.Pair;
import com.simibubi.create.foundation.utility.Iterate;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.core.Direction.Axis;
import net.minecraft.core.Direction.AxisDirection;
import net.minecraft.world.level.BlockGetter;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraft.world.level.block.entity.BlockEntityType;
import net.minecraft.world.level.block.state.BlockState;
public class ItemVaultConnectivityHandler {
public static void formVaults(ItemVaultTileEntity te) {
VaultSearchCache cache = new VaultSearchCache();
List<ItemVaultTileEntity> frontier = new ArrayList<>();
frontier.add(te);
formVaults(te.getType(), te.getLevel(), cache, frontier);
}
private static void formVaults(BlockEntityType<?> type, BlockGetter world, VaultSearchCache cache,
List<ItemVaultTileEntity> frontier) {
PriorityQueue<Pair<Integer, ItemVaultTileEntity>> creationQueue = makeCreationQueue();
Set<BlockPos> visited = new HashSet<>();
int minY = Integer.MAX_VALUE;
for (ItemVaultTileEntity fluidTankTileEntity : frontier) {
BlockPos pos = fluidTankTileEntity.getBlockPos();
minY = Math.min(pos.getY(), minY);
}
minY -= 3;
while (!frontier.isEmpty()) {
ItemVaultTileEntity tank = frontier.remove(0);
BlockPos tankPos = tank.getBlockPos();
if (visited.contains(tankPos))
continue;
visited.add(tankPos);
int amount = tryToFormNewVault(tank, cache, true);
if (amount > 1)
creationQueue.add(Pair.of(amount, tank));
for (Axis axis : Iterate.axes) {
Direction d = Direction.fromAxisAndDirection(axis, AxisDirection.NEGATIVE);
BlockPos next = tankPos.relative(d);
if (next.getY() <= minY)
continue;
if (visited.contains(next))
continue;
ItemVaultTileEntity nextTank = vaultAt(type, world, next);
if (nextTank == null)
continue;
if (nextTank.isRemoved())
continue;
frontier.add(nextTank);
}
}
visited.clear();
while (!creationQueue.isEmpty()) {
Pair<Integer, ItemVaultTileEntity> next = creationQueue.poll();
ItemVaultTileEntity toCreate = next.getValue();
if (visited.contains(toCreate.getBlockPos()))
continue;
visited.add(toCreate.getBlockPos());
tryToFormNewVault(toCreate, cache, false);
}
}
public static void splitVault(ItemVaultTileEntity te) {
splitVaultAndInvalidate(te, null, false);
}
private static int tryToFormNewVault(ItemVaultTileEntity te, VaultSearchCache cache, boolean simulate) {
int bestWidth = 1;
int bestAmount = -1;
if (!te.isController())
return 0;
for (int w = 1; w <= 3; w++) {
int amount = tryToFormNewVaultOfRadius(te, w, cache, true);
if (amount < bestAmount)
continue;
bestWidth = w;
bestAmount = amount;
}
if (!simulate) {
if (te.radius == bestWidth && te.radius * te.radius * te.length == bestAmount)
return bestAmount;
splitVaultAndInvalidate(te, cache, false);
tryToFormNewVaultOfRadius(te, bestWidth, cache, simulate);
te.updateConnectivity = false;
te.radius = bestWidth;
te.length = bestAmount / bestWidth / bestWidth;
BlockState state = te.getBlockState();
if (ItemVaultBlock.isVault(state))
te.getLevel()
.setBlock(te.getBlockPos(), state.setValue(ItemVaultBlock.LARGE, te.radius > 2), 22);
te.itemCapability.invalidate();
te.setChanged();
}
return bestAmount;
}
private static int tryToFormNewVaultOfRadius(ItemVaultTileEntity te, int width, VaultSearchCache cache,
boolean simulate) {
int amount = 0;
int height = 0;
BlockEntityType<?> type = te.getType();
Level world = te.getLevel();
BlockPos origin = te.getBlockPos();
boolean alongZ = ItemVaultBlock.getVaultBlockAxis(te.getBlockState()) == Axis.Z;
Search:
for (int yOffset = 0; yOffset < ItemVaultTileEntity.getMaxLength(width); yOffset++) {
for (int xOffset = 0; xOffset < width; xOffset++) {
for (int zOffset = 0; zOffset < width; zOffset++) {
BlockPos pos =
alongZ ? origin.offset(xOffset, zOffset, yOffset) : origin.offset(yOffset, xOffset, zOffset);
Optional<ItemVaultTileEntity> tank = cache.getOrCache(type, world, pos);
if (!tank.isPresent())
break Search;
ItemVaultTileEntity controller = tank.get();
int otherWidth = controller.radius;
if (otherWidth > width)
break Search;
if (otherWidth == width && controller.length == ItemVaultTileEntity.getMaxLength(width))
break Search;
if ((ItemVaultBlock.getVaultBlockAxis(controller.getBlockState()) == Axis.Z) != alongZ)
break Search;
BlockPos controllerPos = controller.getBlockPos();
if (!controllerPos.equals(origin)) {
if (alongZ && controllerPos.getX() < origin.getX())
break Search;
if (controllerPos.getY() < origin.getY())
break Search;
if (!alongZ && controllerPos.getZ() < origin.getZ())
break Search;
if (alongZ && controllerPos.getX() + otherWidth > origin.getX() + width)
break Search;
if (controllerPos.getY() + otherWidth > origin.getY() + width)
break Search;
if (!alongZ && controllerPos.getZ() + otherWidth > origin.getZ() + width)
break Search;
}
}
}
amount += width * width;
height++;
}
if (simulate)
return amount;
for (int yOffset = 0; yOffset < height; yOffset++) {
for (int xOffset = 0; xOffset < width; xOffset++) {
for (int zOffset = 0; zOffset < width; zOffset++) {
BlockPos pos =
alongZ ? origin.offset(xOffset, zOffset, yOffset) : origin.offset(yOffset, xOffset, zOffset);
ItemVaultTileEntity tank = vaultAt(type, world, pos);
if (tank == te)
continue;
splitVaultAndInvalidate(tank, cache, false);
tank.setController(origin);
tank.updateConnectivity = false;
cache.put(pos, te);
BlockState state = world.getBlockState(pos);
if (!ItemVaultBlock.isVault(state))
continue;
state = state.setValue(ItemVaultBlock.LARGE, width > 2);
world.setBlock(pos, state, 22);
}
}
}
return amount;
}
private static void splitVaultAndInvalidate(ItemVaultTileEntity te, @Nullable VaultSearchCache cache,
boolean tryReconnect) {
// tryReconnect helps whenever only few tanks have been removed
te = te.getControllerTE();
if (te == null)
return;
int height = te.length;
int width = te.radius;
BlockState state = te.getBlockState();
boolean alongZ = ItemVaultBlock.getVaultBlockAxis(state) == Axis.Z;
if (width == 1 && height == 1)
return;
Level world = te.getLevel();
BlockPos origin = te.getBlockPos();
List<ItemVaultTileEntity> frontier = new ArrayList<>();
for (int yOffset = 0; yOffset < height; yOffset++) {
for (int xOffset = 0; xOffset < width; xOffset++) {
for (int zOffset = 0; zOffset < width; zOffset++) {
BlockPos pos =
alongZ ? origin.offset(xOffset, zOffset, yOffset) : origin.offset(yOffset, xOffset, zOffset);
ItemVaultTileEntity tankAt = vaultAt(te.getType(), world, pos);
if (tankAt == null)
continue;
if (!tankAt.getController()
.equals(origin))
continue;
tankAt.removeController(true);
if (tryReconnect) {
frontier.add(tankAt);
tankAt.updateConnectivity = false;
}
if (cache != null)
cache.put(pos, tankAt);
}
}
}
te.itemCapability.invalidate();
if (tryReconnect)
formVaults(te.getType(), world, cache == null ? new VaultSearchCache() : cache, frontier);
}
private static PriorityQueue<Pair<Integer, ItemVaultTileEntity>> makeCreationQueue() {
return new PriorityQueue<>(new Comparator<Pair<Integer, ItemVaultTileEntity>>() {
@Override
public int compare(Pair<Integer, ItemVaultTileEntity> o1, Pair<Integer, ItemVaultTileEntity> o2) {
return o2.getKey() - o1.getKey();
}
});
}
@Nullable
public static ItemVaultTileEntity vaultAt(BlockEntityType<?> type, BlockGetter world, BlockPos pos) {
BlockEntity te = world.getBlockEntity(pos);
if (te instanceof ItemVaultTileEntity && te.getType() == type)
return (ItemVaultTileEntity) te;
return null;
}
private static class VaultSearchCache {
Map<BlockPos, Optional<ItemVaultTileEntity>> controllerMap;
public VaultSearchCache() {
controllerMap = new HashMap<>();
}
void put(BlockPos pos, ItemVaultTileEntity target) {
controllerMap.put(pos, Optional.of(target));
}
void putEmpty(BlockPos pos) {
controllerMap.put(pos, Optional.empty());
}
boolean hasVisited(BlockPos pos) {
return controllerMap.containsKey(pos);
}
Optional<ItemVaultTileEntity> getOrCache(BlockEntityType<?> type, BlockGetter world, BlockPos pos) {
if (hasVisited(pos))
return controllerMap.get(pos);
ItemVaultTileEntity tankAt = vaultAt(type, world, pos);
if (tankAt == null) {
putEmpty(pos);
return Optional.empty();
}
ItemVaultTileEntity controller = tankAt.getControllerTE();
if (controller == null) {
putEmpty(pos);
return Optional.empty();
}
put(pos, controller);
return Optional.of(controller);
}
}
public static boolean isConnected(BlockGetter world, BlockPos tankPos, BlockPos otherTankPos) {
BlockEntity te1 = world.getBlockEntity(tankPos);
BlockEntity te2 = world.getBlockEntity(otherTankPos);
if (!(te1 instanceof ItemVaultTileEntity) || !(te2 instanceof ItemVaultTileEntity))
return false;
return ((ItemVaultTileEntity) te1).getController()
.equals(((ItemVaultTileEntity) te2).getController());
}
}

View file

@ -1,6 +1,7 @@
package com.simibubi.create.content.logistics.block.vault; package com.simibubi.create.content.logistics.block.vault;
import com.simibubi.create.AllTileEntities; import com.simibubi.create.AllTileEntities;
import com.simibubi.create.api.connectivity.ConnectivityHandler;
import com.simibubi.create.foundation.utility.VecHelper; import com.simibubi.create.foundation.utility.VecHelper;
import net.minecraft.core.BlockPos; import net.minecraft.core.BlockPos;
@ -64,7 +65,7 @@ public class ItemVaultItem extends BlockItem {
if (!ItemVaultBlock.isVault(placedOnState)) if (!ItemVaultBlock.isVault(placedOnState))
return; return;
ItemVaultTileEntity tankAt = ItemVaultConnectivityHandler.vaultAt(AllTileEntities.ITEM_VAULT.get(), world, placedOnPos); ItemVaultTileEntity tankAt = ConnectivityHandler.partAt(AllTileEntities.ITEM_VAULT.get(), world, placedOnPos);
if (tankAt == null) if (tankAt == null)
return; return;
ItemVaultTileEntity controllerTE = tankAt.getControllerTE(); ItemVaultTileEntity controllerTE = tankAt.getControllerTE();

View file

@ -3,6 +3,7 @@ package com.simibubi.create.content.logistics.block.vault;
import java.util.List; import java.util.List;
import com.simibubi.create.AllTileEntities; import com.simibubi.create.AllTileEntities;
import com.simibubi.create.api.connectivity.ConnectivityHandler;
import com.simibubi.create.foundation.config.AllConfigs; import com.simibubi.create.foundation.config.AllConfigs;
import com.simibubi.create.foundation.tileEntity.IMultiTileContainer; import com.simibubi.create.foundation.tileEntity.IMultiTileContainer;
import com.simibubi.create.foundation.tileEntity.SmartTileEntity; import com.simibubi.create.foundation.tileEntity.SmartTileEntity;
@ -25,7 +26,7 @@ import net.minecraftforge.items.IItemHandlerModifiable;
import net.minecraftforge.items.ItemStackHandler; import net.minecraftforge.items.ItemStackHandler;
import net.minecraftforge.items.wrapper.CombinedInvWrapper; import net.minecraftforge.items.wrapper.CombinedInvWrapper;
public class ItemVaultTileEntity extends SmartTileEntity implements IMultiTileContainer { public class ItemVaultTileEntity extends SmartTileEntity implements IMultiTileContainer.Inventory {
protected LazyOptional<IItemHandler> itemCapability; protected LazyOptional<IItemHandler> itemCapability;
@ -62,7 +63,7 @@ public class ItemVaultTileEntity extends SmartTileEntity implements IMultiTileCo
return; return;
if (!isController()) if (!isController())
return; return;
ItemVaultConnectivityHandler.formVaults(this); ConnectivityHandler.formMulti(this);
} }
protected void updateComparators() { protected void updateComparators() {
@ -248,7 +249,7 @@ public class ItemVaultTileEntity extends SmartTileEntity implements IMultiTileCo
BlockPos vaultPos = alongZ ? worldPosition.offset(xOffset, zOffset, yOffset) BlockPos vaultPos = alongZ ? worldPosition.offset(xOffset, zOffset, yOffset)
: worldPosition.offset(yOffset, xOffset, zOffset); : worldPosition.offset(yOffset, xOffset, zOffset);
ItemVaultTileEntity vaultAt = ItemVaultTileEntity vaultAt =
ItemVaultConnectivityHandler.vaultAt(AllTileEntities.ITEM_VAULT.get(), level, vaultPos); ConnectivityHandler.partAt(AllTileEntities.ITEM_VAULT.get(), level, vaultPos);
invs[yOffset * radius * radius + xOffset * radius + zOffset] = invs[yOffset * radius * radius + xOffset * radius + zOffset] =
vaultAt != null ? vaultAt.inventory : new ItemStackHandler(); vaultAt != null ? vaultAt.inventory : new ItemStackHandler();
} }
@ -263,4 +264,45 @@ public class ItemVaultTileEntity extends SmartTileEntity implements IMultiTileCo
return radius * 3; return radius * 3;
} }
@Override
public void preventConnectivityUpdate() { updateConnectivity = false; }
@Override
public void notifyMultiUpdated() {
BlockState state = this.getBlockState();
if (ItemVaultBlock.isVault(state)) { // safety
level.setBlock(getBlockPos(), state.setValue(ItemVaultBlock.LARGE, radius > 2), 22);
}
itemCapability.invalidate();
setChanged();
}
@Override
public Direction.Axis getMainConnectionAxis() { return getMainAxisOf(this); }
@Override
public int getMaxLength(Direction.Axis longAxis, int width) {
if (longAxis == Direction.Axis.Y) return getMaxWidth();
return getMaxLength(width);
}
@Override
public int getMaxWidth() {
return 3;
}
@Override
public int getHeight() { return length; }
@Override
public int getWidth() { return radius; }
@Override
public void setHeight(int height) { this.length = height; }
@Override
public void setWidth(int width) { this.radius = width; }
@Override
public boolean hasInventory() { return true; }
} }

View file

@ -77,6 +77,13 @@ public interface ItemAttribute {
return attributeType; return attributeType;
} }
static ItemAttribute fromNBT(CompoundTag nbt) {
for (ItemAttribute itemAttribute : types)
if (itemAttribute.canRead(nbt))
return itemAttribute.readNBT(nbt.getCompound(itemAttribute.getNBTKey()));
return null;
}
default boolean appliesTo(ItemStack stack, Level world) { default boolean appliesTo(ItemStack stack, Level world) {
return appliesTo(stack); return appliesTo(stack);
} }
@ -87,29 +94,20 @@ public interface ItemAttribute {
return listAttributesOf(stack); return listAttributesOf(stack);
} }
public List<ItemAttribute> listAttributesOf(ItemStack stack); List<ItemAttribute> listAttributesOf(ItemStack stack);
public String getTranslationKey(); String getTranslationKey();
void writeNBT(CompoundTag nbt); void writeNBT(CompoundTag nbt);
ItemAttribute readNBT(CompoundTag nbt); ItemAttribute readNBT(CompoundTag nbt);
public default void serializeNBT(CompoundTag nbt) { default void serializeNBT(CompoundTag nbt) {
CompoundTag compound = new CompoundTag(); CompoundTag compound = new CompoundTag();
writeNBT(compound); writeNBT(compound);
nbt.put(getNBTKey(), compound); nbt.put(getNBTKey(), compound);
} }
public static ItemAttribute fromNBT(CompoundTag nbt) {
for (ItemAttribute itemAttribute : types) {
if (!itemAttribute.canRead(nbt))
continue;
return itemAttribute.readNBT(nbt.getCompound(itemAttribute.getNBTKey()));
}
return null;
}
default Object[] getTranslationParameters() { default Object[] getTranslationParameters() {
return new String[0]; return new String[0];
} }

View file

@ -22,8 +22,8 @@ public class SchematicannonInstance extends BlockEntityInstance<SchematicannonTi
Material<ModelData> mat = getTransformMaterial(); Material<ModelData> mat = getTransformMaterial();
connector = mat.getModel(AllBlockPartials.SCHEMATICANNON_CONNECTOR, blockState).createInstance(); connector = mat.getModel(AllBlockPartials.SCHEMATICANNON_CONNECTOR).createInstance();
pipe = mat.getModel(AllBlockPartials.SCHEMATICANNON_PIPE, blockState).createInstance(); pipe = mat.getModel(AllBlockPartials.SCHEMATICANNON_PIPE).createInstance();
} }
@Override @Override

View file

@ -1,6 +1,6 @@
package com.simibubi.create.content.schematics.client; package com.simibubi.create.content.schematics.client;
import java.util.HashMap; import java.util.LinkedHashMap;
import java.util.Map; import java.util.Map;
import java.util.Random; import java.util.Random;
@ -33,7 +33,7 @@ public class SchematicRenderer {
private static final ThreadLocal<ThreadLocalObjects> THREAD_LOCAL_OBJECTS = ThreadLocal.withInitial(ThreadLocalObjects::new); private static final ThreadLocal<ThreadLocalObjects> THREAD_LOCAL_OBJECTS = ThreadLocal.withInitial(ThreadLocalObjects::new);
private final Map<RenderType, SuperByteBuffer> bufferCache = new HashMap<>(getLayerCount()); private final Map<RenderType, SuperByteBuffer> bufferCache = new LinkedHashMap<>(getLayerCount());
private boolean active; private boolean active;
private boolean changed; private boolean changed;
protected SchematicWorld schematic; protected SchematicWorld schematic;

View file

@ -30,6 +30,7 @@ import com.tterrag.registrate.util.nullness.NonNullFunction;
import com.tterrag.registrate.util.nullness.NonNullSupplier; import com.tterrag.registrate.util.nullness.NonNullSupplier;
import net.minecraft.client.resources.model.BakedModel; import net.minecraft.client.resources.model.BakedModel;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.tags.BlockTags; import net.minecraft.tags.BlockTags;
import net.minecraft.world.entity.Entity; import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.EntityType; import net.minecraft.world.entity.EntityType;
@ -168,12 +169,26 @@ public class CreateRegistrate extends AbstractRegistrate<CreateRegistrate> {
Create.asResource("fluid/" + name + "_flow"), attributesFactory, factory)); Create.asResource("fluid/" + name + "_flow"), attributesFactory, factory));
} }
public <T extends ForgeFlowingFluid> FluidBuilder<T, CreateRegistrate> virtualFluid(String name, ResourceLocation still, ResourceLocation flow,
BiFunction<FluidAttributes.Builder, Fluid, FluidAttributes> attributesFactory,
NonNullFunction<ForgeFlowingFluid.Properties, T> factory) {
return entry(name,
c -> new VirtualFluidBuilder<>(self(), self(), name, c, still,
flow, attributesFactory, factory));
}
public FluidBuilder<VirtualFluid, CreateRegistrate> virtualFluid(String name) { public FluidBuilder<VirtualFluid, CreateRegistrate> virtualFluid(String name) {
return entry(name, return entry(name,
c -> new VirtualFluidBuilder<>(self(), self(), name, c, Create.asResource("fluid/" + name + "_still"), c -> new VirtualFluidBuilder<>(self(), self(), name, c, Create.asResource("fluid/" + name + "_still"),
Create.asResource("fluid/" + name + "_flow"), null, VirtualFluid::new)); Create.asResource("fluid/" + name + "_flow"), null, VirtualFluid::new));
} }
public FluidBuilder<VirtualFluid, CreateRegistrate> virtualFluid(String name, ResourceLocation still, ResourceLocation flow) {
return entry(name,
c -> new VirtualFluidBuilder<>(self(), self(), name, c, still,
flow, null, VirtualFluid::new));
}
public FluidBuilder<ForgeFlowingFluid.Flowing, CreateRegistrate> standardFluid(String name) { public FluidBuilder<ForgeFlowingFluid.Flowing, CreateRegistrate> standardFluid(String name) {
return fluid(name, Create.asResource("fluid/" + name + "_still"), Create.asResource("fluid/" + name + "_flow")); return fluid(name, Create.asResource("fluid/" + name + "_still"), Create.asResource("fluid/" + name + "_flow"));
} }

View file

@ -95,7 +95,7 @@ public class CrushingRecipeGen extends ProcessingRecipeGen {
DEEP_REDSTONE_ORE = deepslateOre(() -> Items.DEEPSLATE_REDSTONE_ORE, () -> Items.REDSTONE, 7.5f, 350), DEEP_REDSTONE_ORE = deepslateOre(() -> Items.DEEPSLATE_REDSTONE_ORE, () -> Items.REDSTONE, 7.5f, 350),
DEEP_LAPIS_ORE = deepslateOre(() -> Items.DEEPSLATE_LAPIS_ORE, () -> Items.LAPIS_LAZULI, 12.5f, 350), DEEP_LAPIS_ORE = deepslateOre(() -> Items.DEEPSLATE_LAPIS_ORE, () -> Items.LAPIS_LAZULI, 12.5f, 350),
NETHER_GOLD_ORE = netherOre(() -> Items.NETHER_GOLD_ORE, () -> Items.GOLD_NUGGET, 7.5f, 350), NETHER_GOLD_ORE = netherOre(() -> Items.NETHER_GOLD_ORE, () -> Items.GOLD_NUGGET, 18, 350),
NETHER_QUARTZ_ORE = netherOre(() -> Items.NETHER_QUARTZ_ORE, () -> Items.QUARTZ, 2.25f, 350), NETHER_QUARTZ_ORE = netherOre(() -> Items.NETHER_QUARTZ_ORE, () -> Items.QUARTZ, 2.25f, 350),
RAW_COPPER_ORE = rawOre(() -> Items.RAW_COPPER, AllItems.CRUSHED_COPPER::get, 1), RAW_COPPER_ORE = rawOre(() -> Items.RAW_COPPER, AllItems.CRUSHED_COPPER::get, 1),

View file

@ -229,7 +229,7 @@ public class ItemHelper {
for (int slot = 0; slot < inv.getSlots(); slot++) { for (int slot = 0; slot < inv.getSlots(); slot++) {
if (extracting.isEmpty()) { if (extracting.isEmpty()) {
ItemStack stackInSlot = inv.getStackInSlot(slot); ItemStack stackInSlot = inv.getStackInSlot(slot);
if (stackInSlot.isEmpty()) if (stackInSlot.isEmpty() || !test.test(stackInSlot))
continue; continue;
int maxExtractionCountForItem = amountFunction.apply(stackInSlot); int maxExtractionCountForItem = amountFunction.apply(stackInSlot);
if (maxExtractionCountForItem == 0) if (maxExtractionCountForItem == 0)

View file

@ -1,12 +1,75 @@
package com.simibubi.create.foundation.tileEntity; package com.simibubi.create.foundation.tileEntity;
import net.minecraft.core.BlockPos; import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.block.state.properties.BlockStateProperties;
import net.minecraftforge.fluids.FluidStack;
import net.minecraftforge.fluids.IFluidTank;
import javax.annotation.Nullable;
public interface IMultiTileContainer { public interface IMultiTileContainer {
public BlockPos getController(); BlockPos getController();
public boolean isController(); <T extends BlockEntity & IMultiTileContainer> T getControllerTE ();
public void setController(BlockPos pos); boolean isController();
public BlockPos getLastKnownPos(); void setController(BlockPos pos);
void removeController (boolean keepContents);
BlockPos getLastKnownPos();
void preventConnectivityUpdate ();
void notifyMultiUpdated ();
// only used for FluidTank windows at present. Might be useful for similar properties on other things?
default void setExtraData (@Nullable Object data) {}
@Nullable
default Object getExtraData () { return null; }
default Object modifyExtraData (Object data) { return data; }
// multiblock structural information
Direction.Axis getMainConnectionAxis();
default Direction.Axis getMainAxisOf (BlockEntity be) { // this feels redundant, but it gives us a default to use when defining ::getMainConnectionAxis
BlockState state = be.getBlockState();
Direction.Axis axis;
if (state.hasProperty(BlockStateProperties.HORIZONTAL_AXIS)) {
axis = state.getValue(BlockStateProperties.HORIZONTAL_AXIS);
}
else if (state.hasProperty(BlockStateProperties.FACING)) {
axis = state.getValue(BlockStateProperties.FACING).getAxis();
}
else if (state.hasProperty(BlockStateProperties.HORIZONTAL_FACING)) {
axis = state.getValue(BlockStateProperties.HORIZONTAL_FACING).getAxis();
}
else axis = Direction.Axis.Y;
return axis;
}
int getMaxLength (Direction.Axis longAxis, int width);
int getMaxWidth ();
int getHeight ();
void setHeight (int height);
int getWidth ();
void setWidth (int width);
public interface Inventory extends IMultiTileContainer {
default boolean hasInventory() { return false; }
}
public interface Fluid extends IMultiTileContainer {
// done here rather than through the Capability to allow greater flexibility
default boolean hasTank() { return false; }
default int getTankSize(int tank) { return 0; }
default void setTankSize(int tank, int blocks) {}
default IFluidTank getTank(int tank) { return null; }
default FluidStack getFluid(int tank) { return FluidStack.EMPTY; }
}
} }

View file

@ -17,7 +17,8 @@ import net.minecraft.world.phys.Vec3;
public class TransportedItemStackHandlerBehaviour extends TileEntityBehaviour { public class TransportedItemStackHandlerBehaviour extends TileEntityBehaviour {
public static BehaviourType<TransportedItemStackHandlerBehaviour> TYPE = new BehaviourType<>(); public static final BehaviourType<TransportedItemStackHandlerBehaviour> TYPE = new BehaviourType<>();
private ProcessingCallback processingCallback; private ProcessingCallback processingCallback;
private PositionGetter positionGetter; private PositionGetter positionGetter;

View file

@ -25,7 +25,7 @@ import net.minecraftforge.items.ItemHandlerHelper;
public class FilteringBehaviour extends TileEntityBehaviour { public class FilteringBehaviour extends TileEntityBehaviour {
public static BehaviourType<FilteringBehaviour> TYPE = new BehaviourType<>(); public static final BehaviourType<FilteringBehaviour> TYPE = new BehaviourType<>();
ValueBoxTransform slotPositioning; ValueBoxTransform slotPositioning;
boolean showCount; boolean showCount;

View file

@ -22,7 +22,7 @@ import net.minecraftforge.fluids.capability.IFluidHandler;
public class SmartFluidTankBehaviour extends TileEntityBehaviour { public class SmartFluidTankBehaviour extends TileEntityBehaviour {
public static BehaviourType<SmartFluidTankBehaviour> public static final BehaviourType<SmartFluidTankBehaviour>
TYPE = new BehaviourType<>(), INPUT = new BehaviourType<>("Input"), OUTPUT = new BehaviourType<>("Output"); TYPE = new BehaviourType<>(), INPUT = new BehaviourType<>("Input"), OUTPUT = new BehaviourType<>("Output");

View file

@ -15,7 +15,7 @@ import net.minecraftforge.fluids.capability.IFluidHandler.FluidAction;
public class TankManipulationBehaviour extends CapManipulationBehaviourBase<IFluidHandler, TankManipulationBehaviour> { public class TankManipulationBehaviour extends CapManipulationBehaviourBase<IFluidHandler, TankManipulationBehaviour> {
public static BehaviourType<TankManipulationBehaviour> OBSERVE = new BehaviourType<>(); public static final BehaviourType<TankManipulationBehaviour> OBSERVE = new BehaviourType<>();
private BehaviourType<TankManipulationBehaviour> behaviourType; private BehaviourType<TankManipulationBehaviour> behaviourType;
public TankManipulationBehaviour(SmartTileEntity te, InterfaceProvider target) { public TankManipulationBehaviour(SmartTileEntity te, InterfaceProvider target) {

View file

@ -23,7 +23,7 @@ import net.minecraft.world.phys.Vec3;
public class LinkBehaviour extends TileEntityBehaviour implements IRedstoneLinkable { public class LinkBehaviour extends TileEntityBehaviour implements IRedstoneLinkable {
public static BehaviourType<LinkBehaviour> TYPE = new BehaviourType<>(); public static final BehaviourType<LinkBehaviour> TYPE = new BehaviourType<>();
enum Mode { enum Mode {
TRANSMIT, RECEIVE TRANSMIT, RECEIVE

View file

@ -18,7 +18,7 @@ import net.minecraft.world.phys.Vec3;
public class ScrollValueBehaviour extends TileEntityBehaviour { public class ScrollValueBehaviour extends TileEntityBehaviour {
public static BehaviourType<ScrollValueBehaviour> TYPE = new BehaviourType<>(); public static final BehaviourType<ScrollValueBehaviour> TYPE = new BehaviourType<>();
ValueBoxTransform slotPositioning; ValueBoxTransform slotPositioning;
Vec3 textShift; Vec3 textShift;

View file

@ -10,7 +10,7 @@ import net.minecraft.nbt.CompoundTag;
public class DeferralBehaviour extends TileEntityBehaviour { public class DeferralBehaviour extends TileEntityBehaviour {
public static BehaviourType<DeferralBehaviour> TYPE = new BehaviourType<>(); public static final BehaviourType<DeferralBehaviour> TYPE = new BehaviourType<>();
private boolean needsUpdate; private boolean needsUpdate;
private Supplier<Boolean> callback; private Supplier<Boolean> callback;

View file

@ -18,7 +18,7 @@ Technology that empowers the player.'''
[[dependencies.create]] [[dependencies.create]]
modId="forge" modId="forge"
mandatory=true mandatory=true
versionRange="[40.0.0,)" versionRange="[40.1.0,)"
ordering="NONE" ordering="NONE"
side="BOTH" side="BOTH"
@ -32,6 +32,6 @@ Technology that empowers the player.'''
[[dependencies.create]] [[dependencies.create]]
modId="flywheel" modId="flywheel"
mandatory=true mandatory=true
versionRange="[1.18-0.6.2,1.18-0.6.3)" versionRange="[1.18-0.7.0,1.18-0.7.1)"
ordering="AFTER" ordering="AFTER"
side="CLIENT" side="CLIENT"

File diff suppressed because it is too large Load diff

View file

@ -1,5 +1,4 @@
{ {
"_": "Missing Localizations: 330",
"_": "->------------------------] Game Elements [------------------------<-", "_": "->------------------------] Game Elements [------------------------<-",
@ -567,11 +566,12 @@
"item.create.chromatic_compound": "Compuesto cromático", "item.create.chromatic_compound": "Compuesto cromático",
"item.create.cinder_flour": "Harina del Nether", "item.create.cinder_flour": "Harina del Nether",
"item.create.copper_backtank": "Depósito trasero de cobre", "item.create.copper_backtank": "Depósito trasero de cobre",
"item.create.copper_backtank_placeable": "Depósito de cobre colocable",
"item.create.copper_nugget": "Pepita de cobre", "item.create.copper_nugget": "Pepita de cobre",
"item.create.copper_sheet": "Lámina de cobre", "item.create.copper_sheet": "Lámina de cobre",
"item.create.crafter_slot_cover": "Tapa de ranura del ensamblador mecánico", "item.create.crafter_slot_cover": "Tapa de ranura del ensamblador mecánico",
"item.create.crafting_blueprint": "Plano de elaboración", "item.create.crafting_blueprint": "Plano de elaboración",
"item.create.creative_blaze_cake": "´Pastel de blaze creativo", "item.create.creative_blaze_cake": "Pastel de blaze creativo",
"item.create.crushed_aluminum_ore": "Mineral de aluminio molido", "item.create.crushed_aluminum_ore": "Mineral de aluminio molido",
"item.create.crushed_copper_ore": "Mineral de cobre molido", "item.create.crushed_copper_ore": "Mineral de cobre molido",
"item.create.crushed_gold_ore": "Mineral de oro molido", "item.create.crushed_gold_ore": "Mineral de oro molido",
@ -636,7 +636,7 @@
"advancement.create.root": "Bienvenido a Create", "advancement.create.root": "Bienvenido a Create",
"advancement.create.root.desc": "¡Es hora de empezar a construir increíbles artefactos animados!", "advancement.create.root.desc": "¡Es hora de empezar a construir increíbles artefactos animados!",
"advancement.creatse.andesite_alloy": "Aleaciones en abundancia", "advancement.create.andesite_alloy": "Aliteraciones a montones",
"advancement.create.andesite_alloy.desc": "Los materiales de Create tienen nombres extraños, la aleación de andesita es uno de ellos.", "advancement.create.andesite_alloy.desc": "Los materiales de Create tienen nombres extraños, la aleación de andesita es uno de ellos.",
"advancement.create.its_alive": "¡Está vivo!", "advancement.create.its_alive": "¡Está vivo!",
"advancement.create.its_alive.desc": "Mira cómo gira tu primer componente cinético.", "advancement.create.its_alive.desc": "Mira cómo gira tu primer componente cinético.",
@ -821,6 +821,8 @@
"create.recipe.fan_washing.fan": "Ventilador detrás del agua fluyente", "create.recipe.fan_washing.fan": "Ventilador detrás del agua fluyente",
"create.recipe.fan_smoking": "Ahumador a granel", "create.recipe.fan_smoking": "Ahumador a granel",
"create.recipe.fan_smoking.fan": "Ventilador detrás del fuego", "create.recipe.fan_smoking.fan": "Ventilador detrás del fuego",
"create.recipe.fan_haunting": "Maldecidor a granel",
"create.recipe.fan_haunting.fan": "Ventilador detrás del fuego de alma",
"create.recipe.fan_blasting": "Voladuras a granel", "create.recipe.fan_blasting": "Voladuras a granel",
"create.recipe.fan_blasting.fan": "Ventilador detrás de la lava", "create.recipe.fan_blasting.fan": "Ventilador detrás de la lava",
"create.recipe.pressing": "Prensando", "create.recipe.pressing": "Prensando",
@ -1163,6 +1165,8 @@
"create.item_attributes.furnace_fuel.inverted": "no es combustible para hornos", "create.item_attributes.furnace_fuel.inverted": "no es combustible para hornos",
"create.item_attributes.washable": "se puede lavar", "create.item_attributes.washable": "se puede lavar",
"create.item_attributes.washable.inverted": "no se puede lavar", "create.item_attributes.washable.inverted": "no se puede lavar",
"create.item_attributes.hauntable": "puede ser maldito",
"create.item_attributes.hauntable.inverted": "no puede ser maldito",
"create.item_attributes.crushable": "puede ser molido", "create.item_attributes.crushable": "puede ser molido",
"create.item_attributes.crushable.inverted": "no puede ser molido", "create.item_attributes.crushable.inverted": "no puede ser molido",
"create.item_attributes.smeltable": "se puede fundir", "create.item_attributes.smeltable": "se puede fundir",
@ -1227,6 +1231,7 @@
"create.tooltip.keyCtrl": "Ctrl", "create.tooltip.keyCtrl": "Ctrl",
"create.tooltip.speedRequirement": "Requisitos de velocidad: %1$s", "create.tooltip.speedRequirement": "Requisitos de velocidad: %1$s",
"create.tooltip.speedRequirement.none": "Ninguno", "create.tooltip.speedRequirement.none": "Ninguno",
"create.tooltip.speedRequirement.slow": "Lento",
"create.tooltip.speedRequirement.medium": "Moderado", "create.tooltip.speedRequirement.medium": "Moderado",
"create.tooltip.speedRequirement.fast": "Rápido", "create.tooltip.speedRequirement.fast": "Rápido",
"create.tooltip.stressImpact": "Impacto de estrés: %1$s", "create.tooltip.stressImpact": "Impacto de estrés: %1$s",
@ -2438,6 +2443,6 @@
"create.ponder.windmill_structure.header": "Artefactos estacionarios de molinos de viento", "create.ponder.windmill_structure.header": "Artefactos estacionarios de molinos de viento",
"create.ponder.windmill_structure.text_1": "Cualquier estructura puede contar como un molino de viento válido, siempre que contenga al menos 8 velas.", "create.ponder.windmill_structure.text_1": "Cualquier estructura puede contar como un molino de viento válido, siempre que contenga al menos 8 velas.",
"_": "¡Gracias por traducir Create!" "_": "Thank you for translating Create!"
} }

View file

@ -803,6 +803,16 @@
"death.attack.create.cuckoo_clock_explosion": "%1$s foi explodido por relógio cuco adulterado", "death.attack.create.cuckoo_clock_explosion": "%1$s foi explodido por relógio cuco adulterado",
"death.attack.create.cuckoo_clock_explosion.player": "%1$s foi explodido por relógio cuco adulterado", "death.attack.create.cuckoo_clock_explosion.player": "%1$s foi explodido por relógio cuco adulterado",
"create.block.deployer.damage_source_name": "Implantador rebelde",
"create.block.cart_assembler.invalid": "Coloque o seu montador de carrinho de minas num trilho",
"create.menu.return": "Retornar ao menu",
"create.menu.configure": "Configurar...",
"create.menu.ponder_index": "Tabela do ponderamento",
"create.menu.only_ingame": "Disponível no menu de pausa",
"create.menu.project_page": "Página do projeto",
"create.menu.report_bugs": "Informar um erro",
"create.menu.support": "Suporte nós",
"create.recipe.crushing": "Triturando", "create.recipe.crushing": "Triturando",
"create.recipe.milling": "Moendo", "create.recipe.milling": "Moendo",
@ -818,6 +828,7 @@
"create.recipe.mixing": "Misturando", "create.recipe.mixing": "Misturando",
"create.recipe.deploying": "Implantando", "create.recipe.deploying": "Implantando",
"create.recipe.automatic_shapeless": "Fabricação sem forma automático", "create.recipe.automatic_shapeless": "Fabricação sem forma automático",
"create.recipe.automatic_brewing": "Produção de poções",
"create.recipe.packing": "Compactando", "create.recipe.packing": "Compactando",
"create.recipe.automatic_packing": "Compactamento automático", "create.recipe.automatic_packing": "Compactamento automático",
"create.recipe.sawing": "Serrando", "create.recipe.sawing": "Serrando",
@ -869,18 +880,22 @@
"create.action.discard": "Descartar", "create.action.discard": "Descartar",
"create.keyinfo.toolmenu": "Menu Focal da Ferramenta", "create.keyinfo.toolmenu": "Menu Focal da Ferramenta",
"create.keyinfo.toolbelt": "Acessa caixas de ferramenta próximas",
"create.keyinfo.scrollup": "Simular a roda do mouse (para cima) (no mundo)",
"create.keyinfo.scrolldown": "Simular a roda do mouse (para baixo) (no mundo)",
"create.gui.scrollInput.defaultTitle": "Escolha uma Opção:", "create.gui.scrollInput.defaultTitle": "Escolha uma Opção:",
"create.gui.scrollInput.scrollToModify": "Role o mouse para Modificar", "create.gui.scrollInput.scrollToModify": "Role o mouse para Modificar",
"create.gui.scrollInput.scrollToAdjustAmount": "Role o mouse para ajustar a quantidade", "create.gui.scrollInput.scrollToAdjustAmount": "Role o mouse para ajustar a quantidade",
"create.gui.scrollInput.scrollToSelect": "Role o mouse para Selecionar", "create.gui.scrollInput.scrollToSelect": "Role o mouse para Selecionar",
"create.gui.scrollInput.shiftScrollsFaster": "Shift para rolar o mouse mais rapido",
"create.gui.toolmenu.focusKey": "Segure [%1$s] para Focar", "create.gui.toolmenu.focusKey": "Segure [%1$s] para Focar",
"create.gui.toolmenu.cycle": "[SCROLL] para Circular", "create.gui.toolmenu.cycle": "[SCROLL] para Circular",
"create.toolbox.unequip": "Desequipar: %1$s", "create.toolbox.unequip": "Desequipar: %1$s",
"create.toolbox.outOfRange": "Caixa de ferramentas do item segurado fora de alcance", "create.toolbox.outOfRange": "Caixa de ferramentas do item segurado fora de alcance",
"create.toolbox.detach": "Parar de rastrear e manter item", "create.toolbox.detach": "Parar de rastrear e manter item",
"create.toolbox.depositAll": "Retornar itens para caixa de ferramenta próxima", "create.toolbox.depositAll": "Retorna itens para caixa de ferramenta próxima",
"create.toolbox.depositBox": "Retornar itens para caixa de ferramenta", "create.toolbox.depositBox": "Retornar itens para caixa de ferramenta",
"create.gui.symmetryWand.mirrorType": "Espelhar", "create.gui.symmetryWand.mirrorType": "Espelhar",
@ -895,17 +910,90 @@
"create.orientation.horizontal": "Horizontal", "create.orientation.horizontal": "Horizontal",
"create.orientation.alongZ": "Através de Z", "create.orientation.alongZ": "Através de Z",
"create.orientation.alongX": "Através de X", "create.orientation.alongX": "Através de X",
"create.minecart_coupling.two_couplings_max": "Carrinhos de mina não podem ter mais de dois acoplamentos cada",
"create.minecart_coupling.unloaded": "Partes do seu trem aparentam estar em um chunk descarregado",
"create.minecart_coupling.no_loops": "Acoplamentos não podem formar um loop",
"create.minecart_coupling.removed": "Removeu todos os acoplamentos do carrinho de mina",
"create.minecart_coupling.too_far": "Carrinhos de mina estão muito distanciados",
"create.contraptions.movement_mode": "Modo de movimento",
"create.contraptions.movement_mode.move_place": "Sempre colocar quando parado",
"create.contraptions.movement_mode.move_place_returned": "Colocar apenas na posição inicial",
"create.contraptions.movement_mode.move_never_place": "Colocar apenas caso a âncora seja destruída",
"create.contraptions.movement_mode.rotate_place": "Sempre colocar quando parado",
"create.contraptions.movement_mode.rotate_place_returned": "Apenas colocar perto do angulo inicial",
"create.contraptions.movement_mode.rotate_never_place": "Colocar apenas caso a âncora seja destruída",
"create.contraptions.cart_movement_mode": "Modo de movimento do carrinho",
"create.contraptions.cart_movement_mode.rotate": "Sempre apontar para a direção do movimento",
"create.contraptions.cart_movement_mode.rotate_paused": "Pausar atores quando girando",
"create.contraptions.cart_movement_mode.rotation_locked": "Travar a rotação",
"create.contraptions.windmill.rotation_direction": "Direção da rotação",
"create.contraptions.clockwork.clock_hands": "Ponteiros do relogio",
"create.contraptions.clockwork.hour_first": "Ponteiro da hora primeiro",
"create.contraptions.clockwork.minute_first": "Ponteiro do minuto primeiro",
"create.contraptions.clockwork.hour_first_24": "Ponteiro das 24 horas primeiro",
"create.logistics.filter": "Filtro",
"create.logistics.recipe_filter": "Filtro de receitas",
"create.logistics.fluid_filter": "Filtro de fluido",
"create.logistics.firstFrequency": "Freq. #1",
"create.logistics.secondFrequency": "Freq. #2",
"create.logistics.filter.apply": "Aplicou filtro para %1$s.",
"create.logistics.filter.apply_click_again": "Aplicou filtro para %1$s, Clique denovo para copiar quantidade.",
"create.logistics.filter.apply_count": "Aplicou quantidade de extração para o filtro.",
"create.gui.goggles.generator_stats": "Estatísticas do gerador:", "create.gui.goggles.generator_stats": "Estatísticas do gerador:",
"create.gui.goggles.kinetic_stats": "Estatísticas cinéticas:", "create.gui.goggles.kinetic_stats": "Estatísticas cinéticas:",
"create.gui.goggles.at_current_speed": "Na velocidade atual", "create.gui.goggles.at_current_speed": "Na velocidade atual",
"create.gui.goggles.pole_length": "Comprimento da vara:", "create.gui.goggles.pole_length": "Comprimento da vara:",
"create.gui.goggles.fluid_container": "Informação do recipiente de fluido:",
"create.gui.goggles.fluid_container.capacity": "Capacidade: ",
"create.gui.assembly.exception": "Não foi possível montar essa engenhoca:",
"create.gui.assembly.exception.unmovableBlock": "Bloco imovel (%4$s) em [%1$s,%2$s,%3$s]",
"create.gui.assembly.exception.chunkNotLoaded": "O bloco em [%1$s,%2$s,%3$s] não estava em um chunk carregado",
"create.gui.assembly.exception.structureTooLarge": "Tem muitos blocos incluídos na engenhoca. O limite configurado é: %1$s",
"create.gui.assembly.exception.tooManyPistonPoles": "Tem muitas varetas de extensão colocadas nesse pistão. O limite configurado é: %1$s",
"create.gui.assembly.exception.noPistonPoles": "O pistão esta faltando algumas varetas de extensão",
"create.gui.assembly.exception.not_enough_sails": "A estrutura conectada não possui o número suficiente de blocos tipo vela: %1$s\nUm mínimo de %2$s são requeridos",
"create.gui.gauge.info_header": "Informação do medidor:",
"create.gui.speedometer.title": "Velocidade de rotação",
"create.gui.stressometer.title": "Estresse do sistema",
"create.gui.stressometer.capacity": "Capacidade restante",
"create.gui.stressometer.overstressed": "Sobre estressado",
"create.gui.stressometer.no_rotation": "Nenhuma rotação",
"create.gui.contraptions.not_fast_enough": "Aparenta que esse %1$s não _está_ girando com _a velocidade_ _necessária_.",
"create.gui.contraptions.network_overstressed": "Aparenta que essa engenhoca está _sobre estressada_. Adicione mais fontes ou _desacelere_ __ os componentes que tem um _impacto de_ _stress alto_.",
"create.gui.adjustable_crate.title": "UNLOCALIZED: Adjustable Crate",
"create.gui.adjustable_crate.storageSpace": "UNLOCALIZED: Storage Space",
"create.gui.stockpile_switch.title": "Dijuntor de armazenamento",
"create.gui.stockpile_switch.invert_signal": "Inverter sinal",
"create.gui.stockpile_switch.move_to_lower_at": "Mover para a faixa mais baixa %1$s%%",
"create.gui.stockpile_switch.move_to_upper_at": "Mover para a faixa mais alta %1$s%%",
"create.gui.sequenced_gearshift.title": "Câmbio sequenciado",
"create.gui.sequenced_gearshift.instruction": "Instruções",
"create.gui.sequenced_gearshift.instruction.turn_angle.descriptive": "Rotacionar por angulo",
"create.gui.sequenced_gearshift.instruction.turn_angle": "Giro",
"create.gui.sequenced_gearshift.instruction.turn_angle.angle": "Angulo",
"create.gui.sequenced_gearshift.instruction.turn_distance.descriptive": "Rotacionar par mover Pistão/Polia/Portico",
"create.gui.sequenced_gearshift.instruction.turn_distance": "Pistão",
"create.gui.sequenced_gearshift.instruction.turn_distance.distance": "Distancia",
"create.gui.sequenced_gearshift.instruction.delay.descriptive": "Espera",
"create.gui.sequenced_gearshift.instruction.delay": "Esperar",
"create.gui.sequenced_gearshift.instruction.delay.duration": "Duração",
"create.gui.sequenced_gearshift.instruction.end.descriptive": "Terminar",
"create.gui.sequenced_gearshift.instruction.end": "Termino",
"create.gui.sequenced_gearshift.instruction.await.descriptive": "Esperar novo pulso de redstone",
"create.gui.sequenced_gearshift.instruction.await": "Espera",
"create.gui.sequenced_gearshift.speed": "Velocidade, Direção",
"create.gui.sequenced_gearshift.speed.forward": "Velocidade inicial, Para frente",
"create.gui.sequenced_gearshift.speed.forward_fast": "Dobro da velocidade, Para frente",
"create.gui.sequenced_gearshift.speed.back": "Velocidade inicial, Para trás",
"create.gui.sequenced_gearshift.speed.back_fast": "Dobro da velocidade, Para trás",
"create.schematicAndQuill.dimensions": "Tamanho Esquema: %1$sx%2$sx%3$s", "create.schematicAndQuill.dimensions": "Tamanho Esquema: %1$sx%2$sx%3$s",
"create.schematicAndQuill.firstPos": "Primeira posição feita.", "create.schematicAndQuill.firstPos": "Primeira posição feita.",
"create.schematicAndQuill.secondPos": "Segunda posição feita.", "create.schematicAndQuill.secondPos": "Segunda posição feita.",
"create.schematicAndQuill.noTarget": "Seguro [Ctrl] para selecionar Blocos de Ar.", "create.schematicAndQuill.noTarget": "Seguro [Ctrl] para seleccionar Blocos de Ar.",
"create.schematicAndQuill.abort": "Seleção removida.", "create.schematicAndQuill.abort": "Seleção removida.",
"create.schematicAndQuill.title": "Nome do esquema:", "create.schematicAndQuill.title": "Nome do esquema:",
"create.schematicAndQuill.convert": "Salvar e carregar arquivo imediatamente", "create.schematicAndQuill.convert": "Salvar e carregar arquivo imediatamente",
@ -945,7 +1033,7 @@
"create.schematic.tool.rotate.description.1": "[CTRL]-Rolar para rolar 90 Graus", "create.schematic.tool.rotate.description.1": "[CTRL]-Rolar para rolar 90 Graus",
"create.schematic.tool.rotate.description.2": "", "create.schematic.tool.rotate.description.2": "",
"create.schematic.tool.rotate.description.3": "", "create.schematic.tool.rotate.description.3": "",
"create.schematic.tool.print.description.0": "Coloca estrutura no mundo instantaneamente", "create.schematic.tool.print.description.0": "Colocá estrutura no mundo instantaneamente",
"create.schematic.tool.print.description.1": "[Botão-Direito] para confirmar a posição atual.", "create.schematic.tool.print.description.1": "[Botão-Direito] para confirmar a posição atual.",
"create.schematic.tool.print.description.2": "Esta ferramenta é para o Modo Criativo apenas.", "create.schematic.tool.print.description.2": "Esta ferramenta é para o Modo Criativo apenas.",
"create.schematic.tool.print.description.3": "", "create.schematic.tool.print.description.3": "",
@ -957,7 +1045,12 @@
"create.schematics.synchronizing": "Sincronizando...", "create.schematics.synchronizing": "Sincronizando...",
"create.schematics.uploadTooLarge": "Seu esquema é muito grande", "create.schematics.uploadTooLarge": "Seu esquema é muito grande",
"create.schematics.maxAllowedSize": "O tamanho máximo permitido para o esquema é:", "create.schematics.maxAllowedSize": "O tamanho máximo permitido para o esquema é:",
"create.gui.schematicTable.refresh": "atualizar arquivos",
"create.gui.schematicTable.open_folder": "Abrir pasta",
"create.gui.schematicTable.title": "Mesa de Desenho", "create.gui.schematicTable.title": "Mesa de Desenho",
"create.gui.schematicTable.availableSchematics": "Esquema disponíveis",
"create.gui.schematicTable.noSchematics": "Nenhum esquema salvo",
"create.gui.schematicTable.uploading": "Importando...", "create.gui.schematicTable.uploading": "Importando...",
"create.gui.schematicTable.finished": "Envio Concluído!", "create.gui.schematicTable.finished": "Envio Concluído!",
"create.gui.schematicannon.title": "Canhão de esquema", "create.gui.schematicannon.title": "Canhão de esquema",
@ -967,14 +1060,18 @@
"create.gui.schematicannon.shotsRemainingWithBackup": "Com backup: %1$s", "create.gui.schematicannon.shotsRemainingWithBackup": "Com backup: %1$s",
"create.gui.schematicannon.optionEnabled": "Habilitado Atualmente", "create.gui.schematicannon.optionEnabled": "Habilitado Atualmente",
"create.gui.schematicannon.optionDisabled": "Desabilitado Atualmente", "create.gui.schematicannon.optionDisabled": "Desabilitado Atualmente",
"create.gui.schematicannon.showOptions": "Mostrar as configurações da impressora",
"create.gui.schematicannon.option.dontReplaceSolid": "Não Substituir Blocos Sólidos", "create.gui.schematicannon.option.dontReplaceSolid": "Não Substituir Blocos Sólidos",
"create.gui.schematicannon.option.replaceWithSolid": "Substituir Blocos Sólidos", "create.gui.schematicannon.option.replaceWithSolid": "Substituir Blocos Sólidos",
"create.gui.schematicannon.option.replaceWithAny": "Substituir Sólidos com Qualquer", "create.gui.schematicannon.option.replaceWithAny": "Substituir Sólidos com Qualquer",
"create.gui.schematicannon.option.replaceWithEmpty": "Substituir Sólidos com Vazio", "create.gui.schematicannon.option.replaceWithEmpty": "Substituir Sólidos com Vazio",
"create.gui.schematicannon.option.skipMissing": "Pulando Blocos faltantes", "create.gui.schematicannon.option.skipMissing": "Pulando Blocos faltantes",
"create.gui.schematicannon.option.skipTileEntities": "Proteger Entidades Entalhadas", "create.gui.schematicannon.option.skipTileEntities": "Proteger tile entities",
"create.gui.schematicannon.option.skipMissing.description": "Se o Canhão de esquema não encontrar o Bloco para colocar, ele irá continuar para a próx. Posição.", "create.gui.schematicannon.slot.gunpowder": "Adicionar pólvora para carregar o canhão",
"create.gui.schematicannon.option.skipTileEntities.description": "O Canhão de esquema vai evitar substituir blocos que contêm dados como Baus.", "create.gui.schematicannon.slot.listPrinter": "Coloque livros aqui para imprimir uma lista para o seu esquema",
"create.gui.schematicannon.slot.schematic": "Adicione o seu esquema aqui. Tenha certeza que ele está colocado em um lugar especifico.",
"create.gui.schematicannon.option.skipMissing.description": "Se o Canhão de esquema não encontrar o Bloco para colocar, ele irá continuar para a próxima. Posição.",
"create.gui.schematicannon.option.skipTileEntities.description": "O Canhão de esquema vai evitar substituir blocos que contêm dados como Baús.",
"create.gui.schematicannon.option.dontReplaceSolid.description": "O Canhão de esquema nunca irá substituir Blocos sólidos na área em trabalho, apenas não-Sólidos e Ar.", "create.gui.schematicannon.option.dontReplaceSolid.description": "O Canhão de esquema nunca irá substituir Blocos sólidos na área em trabalho, apenas não-Sólidos e Ar.",
"create.gui.schematicannon.option.replaceWithSolid.description": "O Canhão de esquema irá apenas substituir Blocos sólidos na área de trabalho, se o Esquema conter um bloco Sólido naquela posição.", "create.gui.schematicannon.option.replaceWithSolid.description": "O Canhão de esquema irá apenas substituir Blocos sólidos na área de trabalho, se o Esquema conter um bloco Sólido naquela posição.",
"create.gui.schematicannon.option.replaceWithAny.description": "O Canhão de esquema irá substituir Blocos sólidos na área de trabalho, se o Esquema conter qualquer Bloco naquela posição.", "create.gui.schematicannon.option.replaceWithAny.description": "O Canhão de esquema irá substituir Blocos sólidos na área de trabalho, se o Esquema conter qualquer Bloco naquela posição.",
@ -998,10 +1095,239 @@
"create.schematicannon.status.schematicNotPlaced": "Esquema não Colocado", "create.schematicannon.status.schematicNotPlaced": "Esquema não Colocado",
"create.schematicannon.status.schematicExpired": "Arquivo de Esquema Expirado", "create.schematicannon.status.schematicExpired": "Arquivo de Esquema Expirado",
"create.materialChecklist": "Lista de materiais",
"create.gui.filter.deny_list": "Lista de negação",
"create.gui.filter.deny_list.description": "Itens passam se eles não encaixam em nenhum dos acima. Uma lista de negação vazia aceita tudo.",
"create.gui.filter.allow_list": "Lista de permissão",
"create.gui.filter.allow_list.description": "Itens passam se eles se encaixam em algum dos acima. Uma lista de permissão vazia rejeita tudo.",
"create.gui.filter.respect_data": "Respeitar informação",
"create.gui.filter.respect_data.description": "Itens apenas se encaixam caso a durabilidade, encantamentos e outros atributos se encaixam também.",
"create.gui.filter.ignore_data": "Ignorar informação",
"create.gui.filter.ignore_data.description": "Itens se enquadram não importa os seus atributos.",
"create.item_attributes.placeable": "É colocavel",
"create.item_attributes.placeable.inverted": "Não é colocavel",
"create.item_attributes.consumable": "É comestivel",
"create.item_attributes.consumable.inverted": "Não é comestivel",
"create.item_attributes.fluid_container": "Pode armazenar fluidos",
"create.item_attributes.fluid_container.inverted": "Não pode armazenar fluidos",
"create.item_attributes.enchanted": "Está encantado",
"create.item_attributes.enchanted.inverted": "Não está encantado",
"create.item_attributes.max_enchanted": "Está encantado no nível máximo",
"create.item_attributes.max_enchanted.inverted": "Não está encantado no nível maximo",
"create.item_attributes.renamed": "Tem nome customizado",
"create.item_attributes.renamed.inverted": "Não tem nome customizado",
"create.item_attributes.damaged": "Está danificado",
"create.item_attributes.damaged.inverted": "Não está danificado",
"create.item_attributes.badly_damaged": "Está severamente danificado",
"create.item_attributes.badly_damaged.inverted": "Não esta severamente danificado",
"create.item_attributes.not_stackable": "Não pode ser empilhado",
"create.item_attributes.not_stackable.inverted": "Pode ser empilhado",
"create.item_attributes.equipable": "Pode ser equipado",
"create.item_attributes.equipable.inverted": "Não pode ser equipado",
"create.item_attributes.furnace_fuel": "è combustivel",
"create.item_attributes.furnace_fuel.inverted": "Não é combustivel",
"create.item_attributes.washable": "Pode ser lavado",
"create.item_attributes.washable.inverted": "Não pode ser lavado",
"create.item_attributes.hauntable": "Pode ser amaldiçoado",
"create.item_attributes.hauntable.inverted": "Não pode ser amaldiçoado",
"create.item_attributes.crushable": "Pode ser triturado",
"create.item_attributes.crushable.inverted": "Não pode ser triturado",
"create.item_attributes.smeltable": "Pode ser fundido",
"create.item_attributes.smeltable.inverted": "Não pode ser fundido",
"create.item_attributes.smokable": "Pode ser defumado",
"create.item_attributes.smokable.inverted": "Não pode ser defumado",
"create.item_attributes.blastable": "È fundível no alto-forno",
"create.item_attributes.blastable.inverted": "Não é fundível no alto-forno",
"create.item_attributes.shulker_level": "O shulker é %1$s",
"create.item_attributes.shulker_level.inverted": "O shulker não é %1$s",
"create.item_attributes.shulker_level.full": "Cheio",
"create.item_attributes.shulker_level.empty": "Vazio",
"create.item_attributes.shulker_level.partial": "Parcialmente cheio",
"create.item_attributes.in_tag": "è marcado %1$s",
"create.item_attributes.in_tag.inverted": "Não é marcado %1$s",
"create.item_attributes.in_item_group": "Está no grupo '%1$s'",
"create.item_attributes.in_item_group.inverted": "Não esta no grupo '%1$s'",
"create.item_attributes.added_by": "Foi adicionado por %1$s",
"create.item_attributes.added_by.inverted": "Não foi adicionado por %1$s",
"create.item_attributes.has_enchant": "Está encantado com %1$s",
"create.item_attributes.has_enchant.inverted": "Não esta encantado com %1$s",
"create.item_attributes.color": "Esta tingido de %1$s",
"create.item_attributes.color.inverted": "Não está tingido de %1$s",
"create.item_attributes.has_fluid": "Contem %1$s",
"create.item_attributes.has_fluid.inverted": "Não contem %1$s",
"create.item_attributes.has_name": "Tem o nome %1$s",
"create.item_attributes.has_name.inverted": "Não tem o nome %1$s",
"create.item_attributes.book_author": "Tem a autoria de %1$s",
"create.item_attributes.book_author.inverted": "Não tem a autoria de %1$s",
"create.item_attributes.book_copy_original": "É original",
"create.item_attributes.book_copy_original.inverted": "Não é original",
"create.item_attributes.book_copy_first": "É uma cópia da primeira geração",
"create.item_attributes.book_copy_first.inverted": "Não é uma copia de primeira geração",
"create.item_attributes.book_copy_second": "É uma cópia de segunda geração",
"create.item_attributes.book_copy_second.inverted": "Não é uma copia de segunda geração",
"create.item_attributes.book_copy_tattered": "É uma bagunça esfarrapada",
"create.item_attributes.book_copy_tattered.inverted": "Não é uma bagunça esfarrapada",
"create.item_attributes.astralsorcery_amulet": "Melhora %1$s",
"create.item_attributes.astralsorcery_amulet.inverted": "Não melhora %1$s",
"create.item_attributes.astralsorcery_constellation": "Esta sintonizado a %1$s",
"create.item_attributes.astralsorcery_constellation.inverted": "Não esta sintonizado a %1$s",
"create.item_attributes.astralsorcery_crystal": "Tem atributos de cristais %1$s",
"create.item_attributes.astralsorcery_crystal.inverted": "Não tem atributos de cristais %1$s",
"create.item_attributes.astralsorcery_perk_gem": " %1$s Tem um atributo de benefio",
"create.item_attributes.astralsorcery_perk_gem.inverted": "%1$s Não tem um atributo de benefio",
"create.gui.attribute_filter.no_selected_attributes": "Nenhum atributo selecionado",
"create.gui.attribute_filter.selected_attributes": "Atributos selecionados:",
"create.gui.attribute_filter.add_attribute": "Adicionar atributo a lista",
"create.gui.attribute_filter.add_inverted_attribute": "Adicionar atributo oposto a lista",
"create.gui.attribute_filter.allow_list_disjunctive": "Lista de permissão (Qualquer)",
"create.gui.attribute_filter.allow_list_disjunctive.description": "Itens passam se eles tiverem qualquer atributo selecionado.",
"create.gui.attribute_filter.allow_list_conjunctive": "Lista de permissão (Todos)",
"create.gui.attribute_filter.allow_list_conjunctive.description": "Itens passam se eles tiverem TODOS atributos selecionados.",
"create.gui.attribute_filter.deny_list": "lista de negação",
"create.gui.attribute_filter.deny_list.description": "Itens passam se eles NÃO tiverem qualquer atributo selecionado.",
"create.gui.attribute_filter.add_reference_item": "Adicionar item referência",
"create.tooltip.holdForDescription": "Segure [%1$s] para o sumário",
"create.tooltip.holdForControls": "Segure [%1$s] para os controles",
"create.tooltip.keyShift": "Shift",
"create.tooltip.keyCtrl": "Ctrl",
"create.tooltip.speedRequirement": "Requerimento de velocidade: %1$s",
"create.tooltip.speedRequirement.none": "Nenhum",
"create.tooltip.speedRequirement.slow": "Devagar",
"create.tooltip.speedRequirement.medium": "Modereado",
"create.tooltip.speedRequirement.fast": "Rapido",
"create.tooltip.stressImpact": "Impacto de stress: %1$s",
"create.tooltip.stressImpact.low": " Baixo",
"create.tooltip.stressImpact.medium": " Moderado",
"create.tooltip.stressImpact.high": " Alto",
"create.tooltip.stressImpact.overstressed": ": Sobre estresse",
"create.tooltip.capacityProvided": "Capacidade de stress cinético: %1$s",
"create.tooltip.capacityProvided.low": " Pequeno",
"create.tooltip.capacityProvided.medium": " Médio",
"create.tooltip.capacityProvided.high": " Grande",
"create.tooltip.generationSpeed": " Gera em %1$s %2$s",
"create.tooltip.analogStrength": " Força analogica: %1$s/15",
"create.mechanical_arm.extract_from": " Pegar itens de %1$s",
"create.mechanical_arm.deposit_to": " Depositar itens para %1$s",
"create.mechanical_arm.summary": "Braço mecânico tem %1$s entrada(s) e %2$s saida(s).",
"create.mechanical_arm.points_outside_range": "%1$s Ponto(s) de interação removidos pelas limitações de alcance.",
"create.weighted_ejector.target_set": "Alvo selecionado",
"create.weighted_ejector.target_not_valid": "Ejetando para o bloco adjacente (Alvo não foi valido)",
"create.weighted_ejector.no_target": "Ejetando para o bloco adjacente (Nenhum alvo foi selecionado)",
"create.weighted_ejector.targeting": "Ejetando para [%1$s,%2$s,%3$s]",
"create.weighted_ejector.stack_size": "Tamanho da pilha ejetada",
"create.logistics.when_multiple_outputs_available": "Quando multiplas saidas selecionadas",
"create.mechanical_arm.selection_mode.round_robin": "Rodízio",
"create.mechanical_arm.selection_mode.forced_round_robin": "Rodízio forçado",
"create.mechanical_arm.selection_mode.prefer_first": "Preferir primeiro alvo",
"create.tunnel.selection_mode.split": "Dividir",
"create.tunnel.selection_mode.forced_split": "Divisão forçada",
"create.tunnel.selection_mode.round_robin": "Rodízio",
"create.tunnel.selection_mode.forced_round_robin": "Rodízio forçado",
"create.tunnel.selection_mode.prefer_nearest": "Preferir o mais perto",
"create.tunnel.selection_mode.randomize": "Aleatorizar",
"create.tunnel.selection_mode.synchronize": "Sincronizar as entradas",
"create.tooltip.chute.header": "Informação da calha",
"create.tooltip.chute.items_move_down": "Itens movimentam para baixo",
"create.tooltip.chute.items_move_up": "Itens movem para cima",
"create.tooltip.chute.no_fans_attached": "Não conectado com um ventilador",
"create.tooltip.chute.fans_push_up": "Ventiladores sopram de baixo",
"create.tooltip.chute.fans_push_down": "Ventiladores sopram de cima",
"create.tooltip.chute.fans_pull_up": "Ventiladores sugam de cima",
"create.tooltip.chute.fans_pull_down": "Ventiladores sugam de baixo",
"create.tooltip.chute.contains": "Contem: %1$s x%2$s",
"create.tooltip.brass_tunnel.contains": "Distribuindo:",
"create.tooltip.brass_tunnel.contains_entry": " > %1$s x%2$s",
"create.tooltip.brass_tunnel.retrieve": "Clique direito para recuperar item",
"create.linked_controller.bind_mode": "Modo de vinculação",
"create.linked_controller.press_keybind": "Aperte %1$s, %2$s, %3$s, %4$s, %5$s or %6$s, para vincular essa frequencia para tecla respectiva",
"create.linked_controller.key_bound": "Frequência vinculada com %1$s",
"create.linked_controller.frequency_slot_1": "Tecla: %1$s, Freq. #1",
"create.linked_controller.frequency_slot_2": "Tecla: %1$s, Freq. #2",
"create.crafting_blueprint.crafting_slot": "Slot de ingrediente",
"create.crafting_blueprint.filter_items_viable": "Filtros avançados são viaveis",
"create.crafting_blueprint.display_slot": "Slot de exibição",
"create.crafting_blueprint.inferred": "Deduzido pela receita",
"create.crafting_blueprint.manually_assigned": "Designado manualmente",
"create.crafting_blueprint.secondary_display_slot": "Slot de exibição secundario",
"create.crafting_blueprint.optional": "Opcional",
"create.potato_cannon.ammo.attack_damage": " %1$s Dano de ataque",
"create.potato_cannon.ammo.reload_ticks": " %1$s Velocidade de recarregamento",
"create.potato_cannon.ammo.knockback": " %1$s Repulsão do projetil",
"create.hint.hose_pulley.title": "Abastecimento sem fundo",
"create.hint.hose_pulley": "O corpo de fluido selecionado é considerado infinito.",
"create.hint.mechanical_arm_no_targets.title": "Sem alvos",
"create.hint.mechanical_arm_no_targets": "Aparentemente esse _Braço_ _Mecânico_ não foi designado nenhum _alvo._ Selecione esteiras, depósitos, funis e outros blocos com o _botão direito do mouse_ enquanto _segurando_ o _Braço_ _Mecanico_ na sua _mão_.",
"create.hint.empty_bearing.title": "Atualizar o rolamento",
"create.hint.empty_bearing": " _clique com o botão direito_ o rolamento com a _mão_ _vazia_ para _conectar_ a estrutura que você construiu não frente disso.",
"create.hint.full_deployer.title": "Implantador transbordando de itens",
"create.hint.full_deployer": "Aparenta que esse _inplantador_ contém _itens_ em _excesso_ que precisam ser _extraídos._ Use um _funil,_ _funil de andesito/latão_ ou outros meios para extrair os itens excedentes.",
"create.gui.config.overlay1": "Oi :)",
"create.command.killTPSCommand": " killtps",
"create.command.killTPSCommand.status.slowed_by.0": " [Create]: Server tick is currently slowed by %s ms :o",
"create.command.killTPSCommand.status.slowed_by.1": " [Create]: Server tick is slowed by %s ms now >:)",
"create.command.killTPSCommand.status.slowed_by.2": " [Create]: Server tick is back to regular speed :D",
"create.command.killTPSCommand.status.usage.0": " [Create]: use /killtps stop to bring back server tick to regular speed",
"create.command.killTPSCommand.status.usage.1": " [Create]: use /killtps start <tickTime> to artificially slow down the server tick",
"create.command.killTPSCommand.argument.tickTime": "tickTime",
"create.contraption.minecart_contraption_too_big": "Essa engenhoca de carrinho aparenta ser muita grande para pegar",
"create.contraption.minecart_contraption_illegal_pickup": "Uma força mistica esta segurando esta engenhoca de carrinho",
"_": "->------------------------] Subtitles [------------------------<-", "_": "->------------------------] Subtitles [------------------------<-",
"create.subtitle.contraption_disassemble": "Engenhoca para",
"create.subtitle.peculiar_bell_use": "Sino peculiar toca",
"create.subtitle.mixing": "Sons de mistura",
"create.subtitle.mechanical_press_activation_belt": "Bonks da prensa mecanica",
"create.subtitle.fwoomp": "Fwoomps do canhão de batata",
"create.subtitle.worldshaper_place": "Zaps do terraformador",
"create.subtitle.sanding_long": "Sons de lixa",
"create.subtitle.crushing_1": "Sons de trituração",
"create.subtitle.depot_slide": "Item escorrega",
"create.subtitle.saw_activate_stone": "Serra mecânica ativa",
"create.subtitle.blaze_munch": "Queimador de blazer mastiga",
"create.subtitle.funnel_flap": "Abas do funil batendo",
"create.subtitle.schematicannon_finish": "Ding do canhão de esquema",
"create.subtitle.haunted_bell_use": "Sino assombrado toca",
"create.subtitle.scroll_value": "click do scroll",
"create.subtitle.crafter_craft": "Fabricador fábrica",
"create.subtitle.controller_put": "Thumps do controle",
"create.subtitle.cranking": "Manivela gira",
"create.subtitle.wrench_remove": "Componente quebra",
"create.subtitle.sanding_short": "Sons de lixa",
"create.subtitle.cogs": "tremer da rodas dentadas",
"create.subtitle.slime_added": "Slime sendo espremido",
"create.subtitle.wrench_rotate": "Chave inglesa usada",
"create.subtitle.potato_hit": "Impacto vegetal",
"create.subtitle.saw_activate_wood": "Serra mecânica ativa",
"create.subtitle.haunted_bell_convert": "Sino assombrado acorda",
"create.subtitle.deny": "Boop de negação",
"create.subtitle.controller_click": "Clicks do controle",
"create.subtitle.schematicannon_launch_block": "Canhão de esquema atira",
"create.subtitle.copper_armor_equip": "Tilintar dos equipamentos de mergulho",
"create.subtitle.controller_take": "Atril esvaziado",
"create.subtitle.mechanical_press_activation": "Clang da prensa mecânica",
"create.subtitle.contraption_assemble": "Engenhoca move",
"create.subtitle.crafter_click": "Clicks do fabricador",
"create.subtitle.depot_plop": "Item pousa",
"create.subtitle.confirm": "Ding afirmativo",
"_": "->------------------------] Item Descriptions [------------------------<-", "_": "->------------------------] Item Descriptions [------------------------<-",

File diff suppressed because it is too large Load diff

Some files were not shown because too many files have changed in this diff Show more