diff --git a/src/generated/resources/assets/gtmutils/blockstates/expanded_me_pattern_buffer.json b/src/generated/resources/assets/gtmutils/blockstates/expanded_me_pattern_buffer.json new file mode 100644 index 0000000..a2d1ea1 --- /dev/null +++ b/src/generated/resources/assets/gtmutils/blockstates/expanded_me_pattern_buffer.json @@ -0,0 +1,28 @@ +{ + "variants": { + "facing=down": { + "model": "gtmutils:block/machine/expanded_me_pattern_buffer", + "x": 90 + }, + "facing=east": { + "model": "gtmutils:block/machine/expanded_me_pattern_buffer", + "y": 90 + }, + "facing=north": { + "model": "gtmutils:block/machine/expanded_me_pattern_buffer" + }, + "facing=south": { + "model": "gtmutils:block/machine/expanded_me_pattern_buffer", + "y": 180 + }, + "facing=up": { + "gtceu:z": 180, + "model": "gtmutils:block/machine/expanded_me_pattern_buffer", + "x": 270 + }, + "facing=west": { + "model": "gtmutils:block/machine/expanded_me_pattern_buffer", + "y": 270 + } + } +} \ No newline at end of file diff --git a/src/generated/resources/assets/gtmutils/blockstates/expanded_me_pattern_buffer_proxy.json b/src/generated/resources/assets/gtmutils/blockstates/expanded_me_pattern_buffer_proxy.json new file mode 100644 index 0000000..4618990 --- /dev/null +++ b/src/generated/resources/assets/gtmutils/blockstates/expanded_me_pattern_buffer_proxy.json @@ -0,0 +1,28 @@ +{ + "variants": { + "facing=down": { + "model": "gtmutils:block/machine/expanded_me_pattern_buffer_proxy", + "x": 90 + }, + "facing=east": { + "model": "gtmutils:block/machine/expanded_me_pattern_buffer_proxy", + "y": 90 + }, + "facing=north": { + "model": "gtmutils:block/machine/expanded_me_pattern_buffer_proxy" + }, + "facing=south": { + "model": "gtmutils:block/machine/expanded_me_pattern_buffer_proxy", + "y": 180 + }, + "facing=up": { + "gtceu:z": 180, + "model": "gtmutils:block/machine/expanded_me_pattern_buffer_proxy", + "x": 270 + }, + "facing=west": { + "model": "gtmutils:block/machine/expanded_me_pattern_buffer_proxy", + "y": 270 + } + } +} \ No newline at end of file diff --git a/src/generated/resources/assets/gtmutils/lang/en_ud.json b/src/generated/resources/assets/gtmutils/lang/en_ud.json index 10da7e8..7bcb3db 100644 --- a/src/generated/resources/assets/gtmutils/lang/en_ud.json +++ b/src/generated/resources/assets/gtmutils/lang/en_ud.json @@ -1,6 +1,8 @@ { "block.gtmutils.ev_64a_energy_converter": "ɹǝʇɹǝʌuoƆ ʎbɹǝuƎ ɹ§Ɐǝ§ㄣ9 ɹ§ΛƎϛ§", "block.gtmutils.ev_auto_charger_4x": "ɹǝbɹɐɥƆ oqɹn⟘ oʇnⱯ xㄣ ɹ§ǝbɐʇןoΛ ǝɯǝɹʇxƎϛ§", + "block.gtmutils.expanded_me_pattern_buffer": "ɹǝɟɟnᗺ uɹǝʇʇɐԀ ƎW pǝpuɐdxƎ", + "block.gtmutils.expanded_me_pattern_buffer_proxy": "ʎxoɹԀ ɹǝɟɟnᗺ uɹǝʇʇɐԀ ƎW pǝpuɐdxƎ", "block.gtmutils.hv_64a_energy_converter": "ɹǝʇɹǝʌuoƆ ʎbɹǝuƎ ɹ§Ɐǝ§ㄣ9 ɹ§ΛH9§", "block.gtmutils.hv_auto_charger_4x": "ɹǝbɹɐɥƆ oqɹn⟘ oʇnⱯ xㄣ ɹ§ǝbɐʇןoΛ ɥbıH9§", "block.gtmutils.iv_64a_energy_converter": "ɹǝʇɹǝʌuoƆ ʎbɹǝuƎ ɹ§Ɐǝ§ㄣ9 ɹ§ΛI6§", @@ -14,6 +16,9 @@ "block.gtmutils.mv_auto_charger_4x": "ɹǝbɹɐɥƆ oqɹn⟘ oʇnⱯ xㄣ ɹ§ǝbɐʇןoΛ ɯnıpǝWq§", "block.gtmutils.opv_64a_energy_converter": "ɹǝʇɹǝʌuoƆ ʎbɹǝuƎ ɹ§Ɐǝ§ㄣ9 ɹ§ΛdOן§6§", "block.gtmutils.opv_auto_charger_4x": "ɹǝbɹɐɥƆ oqɹn⟘ oʇnⱯ xㄣ ɹ§ǝbɐʇןoΛ pǝɹǝʍodɹǝʌOן§6§", + "block.gtmutils.pattern_buffer.desc.0": "˙sʞɔoןqıʇןnW ɥɔǝ⟘bǝɹ⅁ ɹoɟɟ§ ǝbɐɹoʇs uɹǝʇʇɐd ᄅƎⱯ9§ ʇɔǝɹıp pǝpuɐdxǝ sʍoןןⱯɟ§", + "block.gtmutils.pattern_buffer.desc.2": "¡ɹǝɥʇǝboʇ sǝuıɥɔɐɯ ʞuıן oʇɟ§ ʞɔıʇsɐʇɐpq§ ɐ ɥʇıʍɟ§ sǝıxoɹԀ ɹǝɟɟnᗺ uɹǝʇʇɐԀ pǝpuɐdxƎ9§ ʞuıꞀɟ§", + "block.gtmutils.pattern_buffer_proxy.desc.0": "˙ɟ§ɹǝɟɟnᗺ uɹǝʇʇɐԀ ƎW pǝpuɐdxƎ9§ ɹɐןnbuıs ɐ oʇ sǝuıɥɔɐɯ ʎuɐɯ buıʞuıן sʍoןןⱯɟ§", "block.gtmutils.pterb_machine": "ɹǝɯɹoɟsuɐɹ⟘ ǝʌıʇɔⱯ ssǝןǝɹıM", "block.gtmutils.sterile_cleaning_maintenance_hatch": "ɥɔʇɐH ǝɔuɐuǝʇuıɐW buıuɐǝןƆ ǝןıɹǝʇS", "block.gtmutils.uev_64a_energy_converter": "ɹǝʇɹǝʌuoƆ ʎbɹǝuƎ ɹ§Ɐǝ§ㄣ9 ɹ§ΛƎ∩ɐ§", @@ -39,6 +44,7 @@ "config.gtmutils.option.customLuVToolsEnabled": "pǝןqɐuƎsןoo⟘ΛnꞀɯoʇsnɔ", "config.gtmutils.option.customMVToolsEnabled": "pǝןqɐuƎsןoo⟘ΛWɯoʇsnɔ", "config.gtmutils.option.customZPMToolsEnabled": "pǝןqɐuƎsןoo⟘WԀZɯoʇsnɔ", + "config.gtmutils.option.expandedBuffersEnabled": "pǝןqɐuƎsɹǝɟɟnᗺpǝpuɐdxǝ", "config.gtmutils.option.features": "sǝɹnʇɐǝɟ", "config.gtmutils.option.omnibreakerEnabled": "pǝןqɐuƎɹǝʞɐǝɹqıuɯo", "config.gtmutils.option.omnibreakerEnergyCapacity": "ʎʇıɔɐdɐƆʎbɹǝuƎɹǝʞɐǝɹqıuɯo", diff --git a/src/generated/resources/assets/gtmutils/lang/en_us.json b/src/generated/resources/assets/gtmutils/lang/en_us.json index e38bca1..bd3556d 100644 --- a/src/generated/resources/assets/gtmutils/lang/en_us.json +++ b/src/generated/resources/assets/gtmutils/lang/en_us.json @@ -1,6 +1,8 @@ { "block.gtmutils.ev_64a_energy_converter": "§5EV§r 64§eA§r Energy Converter", "block.gtmutils.ev_auto_charger_4x": "§5Extreme Voltage§r 4x Auto Turbo Charger", + "block.gtmutils.expanded_me_pattern_buffer": "Expanded ME Pattern Buffer", + "block.gtmutils.expanded_me_pattern_buffer_proxy": "Expanded ME Pattern Buffer Proxy", "block.gtmutils.hv_64a_energy_converter": "§6HV§r 64§eA§r Energy Converter", "block.gtmutils.hv_auto_charger_4x": "§6High Voltage§r 4x Auto Turbo Charger", "block.gtmutils.iv_64a_energy_converter": "§9IV§r 64§eA§r Energy Converter", @@ -14,6 +16,9 @@ "block.gtmutils.mv_auto_charger_4x": "§bMedium Voltage§r 4x Auto Turbo Charger", "block.gtmutils.opv_64a_energy_converter": "§9§lOpV§r 64§eA§r Energy Converter", "block.gtmutils.opv_auto_charger_4x": "§9§lOverpowered Voltage§r 4x Auto Turbo Charger", + "block.gtmutils.pattern_buffer.desc.0": "§fAllows expanded direct §6AE2 pattern storage §ffor GregTech Multiblocks.", + "block.gtmutils.pattern_buffer.desc.2": "§fLink §6Expanded Pattern Buffer Proxies §fwith a §bdatastick §fto link machines together!", + "block.gtmutils.pattern_buffer_proxy.desc.0": "§fAllows linking many machines to a singular §6Expanded ME Pattern Buffer§f.", "block.gtmutils.pterb_machine": "Wireless Active Transformer", "block.gtmutils.sterile_cleaning_maintenance_hatch": "Sterile Cleaning Maintenance Hatch", "block.gtmutils.uev_64a_energy_converter": "§aUEV§r 64§eA§r Energy Converter", @@ -39,6 +44,7 @@ "config.gtmutils.option.customLuVToolsEnabled": "customLuVToolsEnabled", "config.gtmutils.option.customMVToolsEnabled": "customMVToolsEnabled", "config.gtmutils.option.customZPMToolsEnabled": "customZPMToolsEnabled", + "config.gtmutils.option.expandedBuffersEnabled": "expandedBuffersEnabled", "config.gtmutils.option.features": "features", "config.gtmutils.option.omnibreakerEnabled": "omnibreakerEnabled", "config.gtmutils.option.omnibreakerEnergyCapacity": "omnibreakerEnergyCapacity", diff --git a/src/generated/resources/assets/gtmutils/models/block/machine/expanded_me_pattern_buffer.json b/src/generated/resources/assets/gtmutils/models/block/machine/expanded_me_pattern_buffer.json new file mode 100644 index 0000000..3d32505 --- /dev/null +++ b/src/generated/resources/assets/gtmutils/models/block/machine/expanded_me_pattern_buffer.json @@ -0,0 +1,56 @@ +{ + "parent": "minecraft:block/block", + "loader": "gtceu:machine", + "machine": "gtmutils:expanded_me_pattern_buffer", + "replaceable_textures": [ + "bottom", + "top", + "side" + ], + "variants": { + "is_formed=false,is_painted=false": { + "model": { + "parent": "gtceu:block/machine/template/part/hatch_machine", + "textures": { + "bottom": "gtceu:block/casings/voltage/zpm/bottom", + "overlay": "gtceu:block/overlay/appeng/me_buffer_hatch", + "side": "gtceu:block/casings/voltage/zpm/side", + "top": "gtceu:block/casings/voltage/zpm/top" + } + } + }, + "is_formed=false,is_painted=true": { + "model": { + "parent": "gtceu:block/machine/template/part/hatch_machine_color_ring", + "textures": { + "bottom": "gtceu:block/casings/voltage/zpm/bottom", + "overlay": "gtceu:block/overlay/appeng/me_buffer_hatch", + "side": "gtceu:block/casings/voltage/zpm/side", + "top": "gtceu:block/casings/voltage/zpm/top" + } + } + }, + "is_formed=true,is_painted=false": { + "model": { + "parent": "gtceu:block/machine/template/part/hatch_machine", + "textures": { + "bottom": "gtceu:block/casings/voltage/zpm/bottom", + "overlay": "gtceu:block/overlay/appeng/me_buffer_hatch", + "side": "gtceu:block/casings/voltage/zpm/side", + "top": "gtceu:block/casings/voltage/zpm/top" + } + } + }, + "is_formed=true,is_painted=true": { + "model": { + "parent": "gtceu:block/machine/template/part/hatch_machine_color_ring", + "textures": { + "bottom": "gtceu:block/casings/voltage/zpm/bottom", + "overlay": "gtceu:block/overlay/appeng/me_buffer_hatch", + "side": "gtceu:block/casings/voltage/zpm/side", + "top": "gtceu:block/casings/voltage/zpm/top" + } + } + } + } +} \ No newline at end of file diff --git a/src/generated/resources/assets/gtmutils/models/block/machine/expanded_me_pattern_buffer_proxy.json b/src/generated/resources/assets/gtmutils/models/block/machine/expanded_me_pattern_buffer_proxy.json new file mode 100644 index 0000000..505e302 --- /dev/null +++ b/src/generated/resources/assets/gtmutils/models/block/machine/expanded_me_pattern_buffer_proxy.json @@ -0,0 +1,56 @@ +{ + "parent": "minecraft:block/block", + "loader": "gtceu:machine", + "machine": "gtmutils:expanded_me_pattern_buffer_proxy", + "replaceable_textures": [ + "bottom", + "top", + "side" + ], + "variants": { + "is_formed=false,is_painted=false": { + "model": { + "parent": "gtceu:block/machine/template/part/hatch_machine", + "textures": { + "bottom": "gtceu:block/casings/voltage/zpm/bottom", + "overlay": "gtceu:block/overlay/appeng/me_buffer_hatch_proxy", + "side": "gtceu:block/casings/voltage/zpm/side", + "top": "gtceu:block/casings/voltage/zpm/top" + } + } + }, + "is_formed=false,is_painted=true": { + "model": { + "parent": "gtceu:block/machine/template/part/hatch_machine_color_ring", + "textures": { + "bottom": "gtceu:block/casings/voltage/zpm/bottom", + "overlay": "gtceu:block/overlay/appeng/me_buffer_hatch_proxy", + "side": "gtceu:block/casings/voltage/zpm/side", + "top": "gtceu:block/casings/voltage/zpm/top" + } + } + }, + "is_formed=true,is_painted=false": { + "model": { + "parent": "gtceu:block/machine/template/part/hatch_machine", + "textures": { + "bottom": "gtceu:block/casings/voltage/zpm/bottom", + "overlay": "gtceu:block/overlay/appeng/me_buffer_hatch_proxy", + "side": "gtceu:block/casings/voltage/zpm/side", + "top": "gtceu:block/casings/voltage/zpm/top" + } + } + }, + "is_formed=true,is_painted=true": { + "model": { + "parent": "gtceu:block/machine/template/part/hatch_machine_color_ring", + "textures": { + "bottom": "gtceu:block/casings/voltage/zpm/bottom", + "overlay": "gtceu:block/overlay/appeng/me_buffer_hatch_proxy", + "side": "gtceu:block/casings/voltage/zpm/side", + "top": "gtceu:block/casings/voltage/zpm/top" + } + } + } + } +} \ No newline at end of file diff --git a/src/generated/resources/assets/gtmutils/models/item/expanded_me_pattern_buffer.json b/src/generated/resources/assets/gtmutils/models/item/expanded_me_pattern_buffer.json new file mode 100644 index 0000000..9760df5 --- /dev/null +++ b/src/generated/resources/assets/gtmutils/models/item/expanded_me_pattern_buffer.json @@ -0,0 +1,3 @@ +{ + "parent": "gtmutils:block/machine/expanded_me_pattern_buffer" +} \ No newline at end of file diff --git a/src/generated/resources/assets/gtmutils/models/item/expanded_me_pattern_buffer_proxy.json b/src/generated/resources/assets/gtmutils/models/item/expanded_me_pattern_buffer_proxy.json new file mode 100644 index 0000000..490d730 --- /dev/null +++ b/src/generated/resources/assets/gtmutils/models/item/expanded_me_pattern_buffer_proxy.json @@ -0,0 +1,3 @@ +{ + "parent": "gtmutils:block/machine/expanded_me_pattern_buffer_proxy" +} \ No newline at end of file diff --git a/src/main/java/net/neganote/gtutilities/GregTechModernUtilities.java b/src/main/java/net/neganote/gtutilities/GregTechModernUtilities.java index b7dba01..00346f1 100644 --- a/src/main/java/net/neganote/gtutilities/GregTechModernUtilities.java +++ b/src/main/java/net/neganote/gtutilities/GregTechModernUtilities.java @@ -28,6 +28,7 @@ import net.neganote.gtutilities.common.data.UtilPlaceholders; import net.neganote.gtutilities.common.item.UtilItems; import net.neganote.gtutilities.common.item.UtilToolItems; +import net.neganote.gtutilities.common.machine.UtilAEMachines; import net.neganote.gtutilities.common.machine.UtilMachines; import net.neganote.gtutilities.common.materials.UtilMaterials; import net.neganote.gtutilities.common.tools.UtilToolConnection; @@ -154,5 +155,6 @@ private void registerRecipeTypes(GTCEuAPI.RegisterEvent event) { UtilMachines.init(); + UtilAEMachines.init(); } } diff --git a/src/main/java/net/neganote/gtutilities/common/machine/UtilAEMachines.java b/src/main/java/net/neganote/gtutilities/common/machine/UtilAEMachines.java new file mode 100644 index 0000000..ceda9b6 --- /dev/null +++ b/src/main/java/net/neganote/gtutilities/common/machine/UtilAEMachines.java @@ -0,0 +1,55 @@ +package net.neganote.gtutilities.common.machine; + +import com.gregtechceu.gtceu.GTCEu; +import com.gregtechceu.gtceu.api.data.RotationState; +import com.gregtechceu.gtceu.api.machine.MachineDefinition; +import com.gregtechceu.gtceu.api.machine.multiblock.PartAbility; + +import net.minecraft.network.chat.Component; +import net.neganote.gtutilities.config.UtilConfig; +import net.neganote.gtutilities.integration.ae2.machine.ExpandedPatternBufferPartMachine; +import net.neganote.gtutilities.integration.ae2.machine.ExpandedPatternBufferProxyPartMachine; + +import static com.gregtechceu.gtceu.api.GTValues.ZPM; +import static net.neganote.gtutilities.GregTechModernUtilities.REGISTRATE; + +public class UtilAEMachines { + + public static MachineDefinition EXPANDED_ME_PATTERN_BUFFER = null; + public static MachineDefinition EXPANDED_ME_PATTERN_BUFFER_PROXY = null; + + static { + if (UtilConfig.INSTANCE.features.expandedBuffersEnabled && GTCEu.Mods.isAE2Loaded() || GTCEu.isDataGen()) { + EXPANDED_ME_PATTERN_BUFFER = REGISTRATE + .machine("expanded_me_pattern_buffer", ExpandedPatternBufferPartMachine::new) + .tier(ZPM) + .rotationState(RotationState.ALL) + .abilities(PartAbility.IMPORT_ITEMS, PartAbility.IMPORT_FLUIDS, PartAbility.EXPORT_FLUIDS, + PartAbility.EXPORT_ITEMS) + .colorOverlayTieredHullModel(GTCEu.id("block/overlay/appeng/me_buffer_hatch")) + .langValue("Expanded ME Pattern Buffer") + .tooltips( + Component.translatable("block.gtmutils.pattern_buffer.desc.0"), + Component.translatable("block.gtceu.pattern_buffer.desc.1"), + Component.translatable("block.gtmutils.pattern_buffer.desc.2"), + Component.translatable("gtceu.part_sharing.enabled")) + .register(); + + EXPANDED_ME_PATTERN_BUFFER_PROXY = REGISTRATE + .machine("expanded_me_pattern_buffer_proxy", ExpandedPatternBufferProxyPartMachine::new) + .tier(ZPM) + .rotationState(RotationState.ALL) + .abilities(PartAbility.IMPORT_ITEMS, PartAbility.IMPORT_FLUIDS, PartAbility.EXPORT_FLUIDS, + PartAbility.EXPORT_ITEMS) + .colorOverlayTieredHullModel(GTCEu.id("block/overlay/appeng/me_buffer_hatch_proxy")) + .langValue("Expanded ME Pattern Buffer Proxy") + .tooltips( + Component.translatable("block.gtmutils.pattern_buffer_proxy.desc.0"), + Component.translatable("block.gtceu.pattern_buffer_proxy.desc.2"), + Component.translatable("gtceu.part_sharing.enabled")) + .register(); + } + } + + public static void init() {} +} diff --git a/src/main/java/net/neganote/gtutilities/config/UtilConfig.java b/src/main/java/net/neganote/gtutilities/config/UtilConfig.java index 658e3e9..6147bf7 100644 --- a/src/main/java/net/neganote/gtutilities/config/UtilConfig.java +++ b/src/main/java/net/neganote/gtutilities/config/UtilConfig.java @@ -90,6 +90,11 @@ public static class FeatureConfigs { @Configurable @Configurable.Comment({ "Whether the Auto Turbo Chargers are enabled." }) public boolean autoChargersEnabled = false; + + @Configurable + @Configurable.Comment({ + "Whether the Expanded Pattern Buffer and Expanded Pattern Buffer Proxy are enabled. If AE2 is not loaded, this config will not load the machines regardless. " }) + public boolean expandedBuffersEnabled = true; } public static boolean coolantEnabled() { diff --git a/src/main/java/net/neganote/gtutilities/datagen/lang/UtilLangHandler.java b/src/main/java/net/neganote/gtutilities/datagen/lang/UtilLangHandler.java index 3f0a84a..53c6887 100644 --- a/src/main/java/net/neganote/gtutilities/datagen/lang/UtilLangHandler.java +++ b/src/main/java/net/neganote/gtutilities/datagen/lang/UtilLangHandler.java @@ -83,6 +83,13 @@ public static void init(RegistrateLangProvider provider) { "Usage:", " {watfrequency} -> Current frequency: (insert frequency here)"); + provider.add("block.gtmutils.pattern_buffer.desc.0", + "§fAllows expanded direct §6AE2 pattern storage §ffor GregTech Multiblocks."); + provider.add("block.gtmutils.pattern_buffer.desc.2", + "§fLink §6Expanded Pattern Buffer Proxies §fwith a §bdatastick §fto link machines together!"); + provider.add("block.gtmutils.pattern_buffer_proxy.desc.0", + "§fAllows linking many machines to a singular §6Expanded ME Pattern Buffer§f."); + dfs(provider, new HashSet<>(), UtilConfig.CONFIG_HOLDER.getValueMap()); } diff --git a/src/main/java/net/neganote/gtutilities/integration/ae2/machine/ExpandedPatternBufferPartMachine.java b/src/main/java/net/neganote/gtutilities/integration/ae2/machine/ExpandedPatternBufferPartMachine.java new file mode 100644 index 0000000..97a8995 --- /dev/null +++ b/src/main/java/net/neganote/gtutilities/integration/ae2/machine/ExpandedPatternBufferPartMachine.java @@ -0,0 +1,617 @@ +package net.neganote.gtutilities.integration.ae2.machine; + +import com.gregtechceu.gtceu.api.capability.recipe.IO; +import com.gregtechceu.gtceu.api.gui.GuiTextures; +import com.gregtechceu.gtceu.api.gui.fancy.ConfiguratorPanel; +import com.gregtechceu.gtceu.api.machine.IMachineBlockEntity; +import com.gregtechceu.gtceu.api.machine.MetaMachine; +import com.gregtechceu.gtceu.api.machine.MultiblockMachineDefinition; +import com.gregtechceu.gtceu.api.machine.TickableSubscription; +import com.gregtechceu.gtceu.api.machine.fancyconfigurator.ButtonConfigurator; +import com.gregtechceu.gtceu.api.machine.fancyconfigurator.CircuitFancyConfigurator; +import com.gregtechceu.gtceu.api.machine.fancyconfigurator.FancyInvConfigurator; +import com.gregtechceu.gtceu.api.machine.fancyconfigurator.FancyTankConfigurator; +import com.gregtechceu.gtceu.api.machine.feature.IDataStickInteractable; +import com.gregtechceu.gtceu.api.machine.feature.multiblock.IMultiController; +import com.gregtechceu.gtceu.api.machine.trait.NotifiableFluidTank; +import com.gregtechceu.gtceu.api.machine.trait.NotifiableItemStackHandler; +import com.gregtechceu.gtceu.api.machine.trait.RecipeHandlerList; +import com.gregtechceu.gtceu.api.recipe.ingredient.FluidIngredient; +import com.gregtechceu.gtceu.api.recipe.ingredient.SizedIngredient; +import com.gregtechceu.gtceu.api.transfer.item.CustomItemStackHandler; +import com.gregtechceu.gtceu.common.data.machines.GTAEMachines; +import com.gregtechceu.gtceu.common.item.IntCircuitBehaviour; +import com.gregtechceu.gtceu.integration.ae2.gui.widget.AETextInputButtonWidget; +import com.gregtechceu.gtceu.integration.ae2.gui.widget.slot.AEPatternViewSlotWidget; +import com.gregtechceu.gtceu.integration.ae2.machine.MEBusPartMachine; +import com.gregtechceu.gtceu.utils.GTMath; +import com.gregtechceu.gtceu.utils.ItemStackHashStrategy; + +import com.lowdragmc.lowdraglib.gui.texture.GuiTextureGroup; +import com.lowdragmc.lowdraglib.gui.util.ClickData; +import com.lowdragmc.lowdraglib.gui.widget.LabelWidget; +import com.lowdragmc.lowdraglib.gui.widget.Widget; +import com.lowdragmc.lowdraglib.gui.widget.WidgetGroup; +import com.lowdragmc.lowdraglib.syncdata.IContentChangeAware; +import com.lowdragmc.lowdraglib.syncdata.ITagSerializable; +import com.lowdragmc.lowdraglib.syncdata.annotation.DescSynced; +import com.lowdragmc.lowdraglib.syncdata.annotation.Persisted; +import com.lowdragmc.lowdraglib.syncdata.field.ManagedFieldHolder; + +import net.minecraft.MethodsReturnNonnullByDefault; +import net.minecraft.core.BlockPos; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.nbt.ListTag; +import net.minecraft.nbt.Tag; +import net.minecraft.network.chat.Component; +import net.minecraft.server.TickTask; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.world.InteractionResult; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.crafting.Ingredient; +import net.minecraftforge.fluids.FluidStack; +import net.minecraftforge.fluids.FluidType; +import net.neganote.gtutilities.integration.ae2.machine.trait.ExpandedInternalSlotRecipeHandler; + +import appeng.api.crafting.IPatternDetails; +import appeng.api.crafting.PatternDetailsHelper; +import appeng.api.implementations.blockentities.PatternContainerGroup; +import appeng.api.inventories.InternalInventory; +import appeng.api.networking.IGrid; +import appeng.api.networking.IGridNodeListener; +import appeng.api.networking.crafting.ICraftingProvider; +import appeng.api.stacks.*; +import appeng.api.storage.MEStorage; +import appeng.api.storage.StorageHelper; +import appeng.crafting.pattern.EncodedPatternItem; +import appeng.crafting.pattern.ProcessingPatternItem; +import appeng.helpers.patternprovider.PatternContainer; +import com.google.common.collect.BiMap; +import com.google.common.collect.HashBiMap; +import it.unimi.dsi.fastutil.objects.*; +import lombok.Getter; +import lombok.Setter; +import org.jetbrains.annotations.Nullable; +import org.jetbrains.annotations.UnmodifiableView; + +import java.util.*; + +import javax.annotation.ParametersAreNonnullByDefault; + +@ParametersAreNonnullByDefault +@MethodsReturnNonnullByDefault +public class ExpandedPatternBufferPartMachine extends MEBusPartMachine + implements ICraftingProvider, PatternContainer, IDataStickInteractable { + + protected static final ManagedFieldHolder MANAGED_FIELD_HOLDER = new ManagedFieldHolder( + ExpandedPatternBufferPartMachine.class, MEBusPartMachine.MANAGED_FIELD_HOLDER); + + protected static final int MAX_PATTERN_COUNT = 72; + + private final InternalInventory internalPatternInventory = new InternalInventory() { + + @Override + public int size() { + return MAX_PATTERN_COUNT; + } + + @Override + public ItemStack getStackInSlot(int slotIndex) { + return patternInventory.getStackInSlot(slotIndex); + } + + @Override + public void setItemDirect(int slotIndex, ItemStack stack) { + patternInventory.setStackInSlot(slotIndex, stack); + patternInventory.onContentsChanged(slotIndex); + onPatternChange(slotIndex); + } + }; + + @Getter + @Persisted + @DescSynced + private final CustomItemStackHandler patternInventory = new CustomItemStackHandler(MAX_PATTERN_COUNT); + + @Getter + @Persisted + protected final NotifiableItemStackHandler shareInventory; + + @Getter + @Persisted + protected final NotifiableFluidTank shareTank; + + @Getter + @Persisted + protected final InternalSlot[] internalInventory = new InternalSlot[MAX_PATTERN_COUNT]; + + private final BiMap detailsSlotMap = HashBiMap.create(MAX_PATTERN_COUNT); + + @DescSynced + @Persisted + @Setter + private String customName = ""; + + private boolean needPatternSync; + + @Persisted + private final Set proxies = new ObjectOpenHashSet<>(); + + private final Set proxyMachines = new ReferenceOpenHashSet<>(); + + @Getter + protected final ExpandedInternalSlotRecipeHandler internalRecipeHandler; + + @Nullable + protected TickableSubscription updateSubs; + + public ExpandedPatternBufferPartMachine(IMachineBlockEntity holder, Object... args) { + super(holder, IO.IN, args); + this.patternInventory.setFilter(stack -> stack.getItem() instanceof ProcessingPatternItem); + for (int i = 0; i < this.internalInventory.length; i++) { + this.internalInventory[i] = new InternalSlot(); + } + getMainNode().addService(ICraftingProvider.class, this); + this.shareInventory = new NotifiableItemStackHandler(this, 9, IO.IN, IO.NONE); + this.shareTank = new NotifiableFluidTank(this, 9, 8 * FluidType.BUCKET_VOLUME, IO.IN, IO.NONE); + this.internalRecipeHandler = new ExpandedInternalSlotRecipeHandler(this, internalInventory); + } + + @Override + public void onLoad() { + super.onLoad(); + if (getLevel() instanceof ServerLevel serverLevel) { + serverLevel.getServer().tell(new TickTask(1, () -> { + for (int i = 0; i < patternInventory.getSlots(); i++) { + var pattern = patternInventory.getStackInSlot(i); + var patternDetails = PatternDetailsHelper.decodePattern(pattern, getLevel()); + if (patternDetails != null) { + this.detailsSlotMap.put(patternDetails, this.internalInventory[i]); + } + } + needPatternSync = true; + })); + } + } + + @Override + public List getRecipeHandlers() { + return internalRecipeHandler.getSlotHandlers(); + } + + public void addProxy(ExpandedPatternBufferProxyPartMachine proxy) { + proxies.add(proxy.getPos()); + proxyMachines.add(proxy); + } + + public void removeProxy(ExpandedPatternBufferProxyPartMachine proxy) { + proxies.remove(proxy.getPos()); + proxyMachines.remove(proxy); + } + + @UnmodifiableView + public Set getProxies() { + if (proxyMachines.size() != proxies.size()) { + proxyMachines.clear(); + for (var pos : proxies) { + if (MetaMachine.getMachine(getLevel(), pos) instanceof ExpandedPatternBufferProxyPartMachine proxy) { + proxyMachines.add(proxy); + } + } + } + return Collections.unmodifiableSet(proxyMachines); + } + + @Override + public Widget createUIWidget() { + int rowSize = 9; + int colSize = 8; + var group = new WidgetGroup(0, 0, 18 * rowSize + 16, 18 * colSize + 16); + int index = 0; + for (int y = 0; y < colSize; ++y) { + for (int x = 0; x < rowSize; ++x) { + int finalI = index; + var slot = new AEPatternViewSlotWidget(patternInventory, index++, 8 + x * 18, 14 + y * 18) + .setOccupiedTexture(GuiTextures.SLOT) + .setItemHook(stack -> { + if (!stack.isEmpty() && stack.getItem() instanceof EncodedPatternItem iep) { + final ItemStack out = iep.getOutput(stack); + if (!out.isEmpty()) return out; + } + return stack; + }) + .setChangeListener(() -> onPatternChange(finalI)) + .setBackground(GuiTextures.SLOT, GuiTextures.PATTERN_OVERLAY); + group.addWidget(slot); + } + } + group.addWidget(new LabelWidget(8, 2, + () -> this.isOnline ? "gtceu.gui.me_network.online" : "gtceu.gui.me_network.offline")); + group.addWidget(new AETextInputButtonWidget(18 * rowSize + 8 - 70, 2, 70, 10) + .setText(customName) + .setOnConfirm(this::setCustomName) + .setButtonTooltips(Component.translatable("gui.gtceu.rename.desc"))); + return group; + } + + @Override + public boolean isWorkingEnabled() { + return true; + } + + @Override + public void setWorkingEnabled(boolean ignored) {} + + @Override + public boolean isDistinct() { + return true; + } + + @Override + public void setDistinct(boolean ignored) {} + + @Override + public void onMainNodeStateChanged(IGridNodeListener.State reason) { + super.onMainNodeStateChanged(reason); + this.updateSubscription(); + } + + protected void updateSubscription() { + if (getMainNode().isOnline()) { + updateSubs = subscribeServerTick(updateSubs, this::update); + } else if (updateSubs != null) { + updateSubs.unsubscribe(); + updateSubs = null; + } + } + + protected void update() { + if (needPatternSync) { + ICraftingProvider.requestUpdate(getMainNode()); + this.needPatternSync = false; + } + } + + private void refundAll(ClickData clickData) { + if (!clickData.isRemote) { + for (InternalSlot internalSlot : internalInventory) { + internalSlot.refund(); + } + } + } + + private void onPatternChange(int index) { + if (isRemote()) return; + var internalInv = internalInventory[index]; + var newPattern = patternInventory.getStackInSlot(index); + var newPatternDetails = PatternDetailsHelper.decodePattern(newPattern, getLevel()); + var oldPatternDetails = detailsSlotMap.inverse().get(internalInv); + detailsSlotMap.forcePut(newPatternDetails, internalInv); + if (oldPatternDetails != null && !oldPatternDetails.equals(newPatternDetails)) { + internalInv.refund(); + } + needPatternSync = true; + } + + @Override + public void attachConfigurators(ConfiguratorPanel configuratorPanel) { + configuratorPanel.attachConfigurators(new ButtonConfigurator( + new GuiTextureGroup(GuiTextures.BUTTON, GuiTextures.REFUND_OVERLAY), this::refundAll) + .setTooltips(List.of(Component.translatable("gui.gtceu.refund_all.desc")))); + if (isHasCircuitSlot() && isCircuitSlotEnabled()) { + configuratorPanel.attachConfigurators(new CircuitFancyConfigurator(circuitInventory.storage)); + } + configuratorPanel.attachConfigurators(new FancyInvConfigurator( + shareInventory.storage, Component.translatable("gui.gtceu.share_inventory.title")) + .setTooltips(List.of( + Component.translatable("gui.gtceu.share_inventory.desc.0"), + Component.translatable("gui.gtceu.share_inventory.desc.1")))); + configuratorPanel.attachConfigurators(new FancyTankConfigurator( + shareTank.getStorages(), Component.translatable("gui.gtceu.share_tank.title")) + .setTooltips(List.of( + Component.translatable("gui.gtceu.share_tank.desc.0"), + Component.translatable("gui.gtceu.share_inventory.desc.1")))); + } + + @Override + public List getAvailablePatterns() { + return detailsSlotMap.keySet().stream().filter(Objects::nonNull).toList(); + } + + @Override + public boolean pushPattern(IPatternDetails patternDetails, KeyCounter[] inputHolder) { + if (!isFormed() || !getMainNode().isActive() || !detailsSlotMap.containsKey(patternDetails) || + !checkInput(inputHolder)) { + return false; + } + var slot = detailsSlotMap.get(patternDetails); + if (slot != null) { + slot.pushPattern(patternDetails, inputHolder); + return true; + } + return false; + } + + @Override + public boolean isBusy() { + return false; + } + + private boolean checkInput(KeyCounter[] inputHolder) { + for (KeyCounter input : inputHolder) { + var illegal = input.keySet().stream() + .map(AEKey::getType) + .map(AEKeyType::getId) + .anyMatch(id -> !id.equals(AEKeyType.items().getId()) && !id.equals(AEKeyType.fluids().getId())); + if (illegal) return false; + } + return true; + } + + @Override + public ManagedFieldHolder getFieldHolder() { + return MANAGED_FIELD_HOLDER; + } + + @Override + public @Nullable IGrid getGrid() { + return getMainNode().getGrid(); + } + + @Override + public InternalInventory getTerminalPatternInventory() { + return internalPatternInventory; + } + + @Override + public PatternContainerGroup getTerminalGroup() { + if (isFormed()) { + IMultiController controller = getControllers().first(); + MultiblockMachineDefinition controllerDefinition = controller.self().getDefinition(); + if (!customName.isEmpty()) { + return new PatternContainerGroup(AEItemKey.of(controllerDefinition.asStack()), + Component.literal(customName), Collections.emptyList()); + } else { + ItemStack circuitStack = isHasCircuitSlot() ? circuitInventory.storage.getStackInSlot(0) : + ItemStack.EMPTY; + int circuitConfiguration = circuitStack.isEmpty() ? -1 : + IntCircuitBehaviour.getCircuitConfiguration(circuitStack); + Component groupName = circuitConfiguration != -1 ? + Component.translatable(controllerDefinition.getDescriptionId()) + .append(" - " + circuitConfiguration) : + Component.translatable(controllerDefinition.getDescriptionId()); + return new PatternContainerGroup(AEItemKey.of(controllerDefinition.asStack()), groupName, + Collections.emptyList()); + } + } else { + return new PatternContainerGroup(AEItemKey.of(GTAEMachines.ME_PATTERN_BUFFER.getItem()), + customName.isEmpty() ? + GTAEMachines.ME_PATTERN_BUFFER.get().getDefinition().getItem().getDescription() : + Component.literal(customName), + Collections.emptyList()); + } + } + + @Override + public void onMachineRemoved() { + clearInventory(patternInventory); + clearInventory(shareInventory); + } + + @Override + public InteractionResult onDataStickShiftUse(Player player, ItemStack dataStick) { + dataStick.getOrCreateTag().putIntArray("pos", new int[] { getPos().getX(), getPos().getY(), getPos().getZ() }); + return InteractionResult.SUCCESS; + } + + public record BufferData(Object2LongMap items, Object2LongMap fluids) {} + + public BufferData mergeInternalSlots() { + var items = new Object2LongOpenCustomHashMap<>(ItemStackHashStrategy.comparingAllButCount()); + var fluids = new Object2LongOpenHashMap(); + for (InternalSlot slot : internalInventory) { + slot.itemInventory.object2LongEntrySet().fastForEach(e -> items.addTo(e.getKey(), e.getLongValue())); + slot.fluidInventory.object2LongEntrySet().fastForEach(e -> fluids.addTo(e.getKey(), e.getLongValue())); + } + return new BufferData(items, fluids); + } + + public class InternalSlot implements ITagSerializable, IContentChangeAware { + + @Getter + @Setter + private Runnable onContentsChanged = () -> {}; + private final Object2LongOpenCustomHashMap itemInventory = new Object2LongOpenCustomHashMap<>( + ItemStackHashStrategy.comparingAllButCount()); + private final Object2LongOpenHashMap fluidInventory = new Object2LongOpenHashMap<>(); + private List itemStacks = null; + private List fluidStacks = null; + + public InternalSlot() {} + + public boolean isItemEmpty() { + return itemInventory.isEmpty(); + } + + public boolean isFluidEmpty() { + return fluidInventory.isEmpty(); + } + + public void onContentsChanged() { + itemStacks = null; + fluidStacks = null; + onContentsChanged.run(); + } + + private void add(AEKey what, long amount) { + if (amount <= 0L) return; + if (what instanceof AEItemKey itemKey) { + itemInventory.addTo(itemKey.toStack(), amount); + } else if (what instanceof AEFluidKey fluidKey) { + fluidInventory.addTo(fluidKey.toStack(1), amount); + } + } + + public List getItems() { + if (itemStacks == null) { + itemStacks = new ArrayList<>(); + itemInventory.object2LongEntrySet().stream().map(e -> GTMath.splitStacks(e.getKey(), e.getLongValue())) + .forEach(itemStacks::addAll); + } + return itemStacks; + } + + public List getFluids() { + if (fluidStacks == null) { + fluidStacks = new ArrayList<>(); + fluidInventory.object2LongEntrySet().stream() + .map(e -> GTMath.splitFluidStacks(e.getKey(), e.getLongValue())).forEach(fluidStacks::addAll); + } + return fluidStacks; + } + + public void refund() { + var network = getMainNode().getGrid(); + if (network != null) { + MEStorage networkInv = network.getStorageService().getInventory(); + var energy = network.getEnergyService(); + for (var it = itemInventory.object2LongEntrySet().iterator(); it.hasNext();) { + var entry = it.next(); + var key = AEItemKey.of(entry.getKey()); + if (key == null) continue; + long inserted = StorageHelper.poweredInsert(energy, networkInv, key, entry.getLongValue(), + actionSource); + if (inserted > 0) { + long count = entry.getLongValue() - inserted; + if (count == 0) it.remove(); + else entry.setValue(count); + } + } + for (var it = fluidInventory.object2LongEntrySet().iterator(); it.hasNext();) { + var entry = it.next(); + var key = AEFluidKey.of(entry.getKey()); + if (key == null) continue; + long inserted = StorageHelper.poweredInsert(energy, networkInv, key, entry.getLongValue(), + actionSource); + if (inserted > 0) { + long amount = entry.getLongValue() - inserted; + if (amount == 0) it.remove(); + else entry.setValue(amount); + } + } + onContentsChanged(); + } + } + + public void pushPattern(IPatternDetails patternDetails, KeyCounter[] inputHolder) { + patternDetails.pushInputsToExternalInventory(inputHolder, this::add); + onContentsChanged(); + } + + public @Nullable List handleItemInternal(List left, boolean simulate) { + boolean changed = false; + for (var it = left.listIterator(); it.hasNext();) { + var ingredient = it.next(); + var items = ingredient.getItems(); + if (items.length == 0 || items[0].isEmpty()) { + it.remove(); + continue; + } + int amount = items[0].getCount(); + for (var it2 = itemInventory.object2LongEntrySet().iterator(); it2.hasNext();) { + var entry = it2.next(); + if (!ingredient.test(entry.getKey())) continue; + int extracted = Math.min(GTMath.saturatedCast(entry.getLongValue()), amount); + if (!simulate && extracted > 0) { + changed = true; + long count = entry.getLongValue() - extracted; + if (count == 0) it2.remove(); + else entry.setValue(count); + } + amount -= extracted; + if (amount <= 0) { + it.remove(); + break; + } + } + if (amount > 0) { + if (ingredient instanceof SizedIngredient si) si.setAmount(amount); + else items[0].setCount(amount); + } + } + if (changed) onContentsChanged(); + return left.isEmpty() ? null : left; + } + + public @Nullable List handleFluidInternal(List left, boolean simulate) { + boolean changed = false; + for (var it = left.listIterator(); it.hasNext();) { + var ingredient = it.next(); + var fluids = ingredient.getStacks(); + if (fluids.length == 0 || fluids[0].isEmpty()) { + it.remove(); + continue; + } + int amount = fluids[0].getAmount(); + for (var it2 = fluidInventory.object2LongEntrySet().iterator(); it2.hasNext();) { + var entry = it2.next(); + if (!ingredient.test(entry.getKey())) continue; + int extracted = Math.min(GTMath.saturatedCast(entry.getLongValue()), amount); + if (!simulate && extracted > 0) { + changed = true; + long count = entry.getLongValue() - extracted; + if (count == 0) it2.remove(); + else entry.setValue(count); + } + amount -= extracted; + if (amount <= 0) { + it.remove(); + break; + } + } + if (amount > 0) ingredient.setAmount(amount); + } + if (changed) onContentsChanged(); + return left.isEmpty() ? null : left; + } + + @Override + public CompoundTag serializeNBT() { + CompoundTag tag = new CompoundTag(); + ListTag itemsTag = new ListTag(); + for (var entry : itemInventory.object2LongEntrySet()) { + var ct = entry.getKey().serializeNBT(); + ct.putLong("real", entry.getLongValue()); + itemsTag.add(ct); + } + if (!itemsTag.isEmpty()) tag.put("inventory", itemsTag); + ListTag fluidsTag = new ListTag(); + for (var entry : fluidInventory.object2LongEntrySet()) { + var ct = entry.getKey().writeToNBT(new CompoundTag()); + ct.putLong("real", entry.getLongValue()); + fluidsTag.add(ct); + } + if (!fluidsTag.isEmpty()) tag.put("fluidInventory", fluidsTag); + return tag; + } + + @Override + public void deserializeNBT(CompoundTag tag) { + ListTag items = tag.getList("inventory", Tag.TAG_COMPOUND); + for (Tag t : items) { + if (!(t instanceof CompoundTag ct)) continue; + var stack = ItemStack.of(ct); + var count = ct.getLong("real"); + if (!stack.isEmpty() && count > 0) itemInventory.put(stack, count); + } + ListTag fluids = tag.getList("fluidInventory", Tag.TAG_COMPOUND); + for (Tag t : fluids) { + if (!(t instanceof CompoundTag ct)) continue; + var stack = FluidStack.loadFluidStackFromNBT(ct); + var amount = ct.getLong("real"); + if (!stack.isEmpty() && amount > 0) fluidInventory.put(stack, amount); + } + } + } +} diff --git a/src/main/java/net/neganote/gtutilities/integration/ae2/machine/ExpandedPatternBufferProxyPartMachine.java b/src/main/java/net/neganote/gtutilities/integration/ae2/machine/ExpandedPatternBufferProxyPartMachine.java new file mode 100644 index 0000000..afad4e2 --- /dev/null +++ b/src/main/java/net/neganote/gtutilities/integration/ae2/machine/ExpandedPatternBufferProxyPartMachine.java @@ -0,0 +1,133 @@ +package net.neganote.gtutilities.integration.ae2.machine; + +import com.gregtechceu.gtceu.api.GTValues; +import com.gregtechceu.gtceu.api.capability.recipe.IO; +import com.gregtechceu.gtceu.api.machine.IMachineBlockEntity; +import com.gregtechceu.gtceu.api.machine.MetaMachine; +import com.gregtechceu.gtceu.api.machine.feature.IDataStickInteractable; +import com.gregtechceu.gtceu.api.machine.feature.IMachineLife; +import com.gregtechceu.gtceu.api.machine.multiblock.part.TieredIOPartMachine; +import com.gregtechceu.gtceu.api.machine.trait.RecipeHandlerList; + +import com.lowdragmc.lowdraglib.gui.modular.ModularUI; +import com.lowdragmc.lowdraglib.syncdata.annotation.DescSynced; +import com.lowdragmc.lowdraglib.syncdata.annotation.Persisted; +import com.lowdragmc.lowdraglib.syncdata.field.ManagedFieldHolder; + +import net.minecraft.MethodsReturnNonnullByDefault; +import net.minecraft.core.BlockPos; +import net.minecraft.nbt.Tag; +import net.minecraft.server.TickTask; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.world.InteractionHand; +import net.minecraft.world.InteractionResult; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.phys.BlockHitResult; +import net.neganote.gtutilities.integration.ae2.machine.trait.ExpandedProxySlotRecipeHandler; + +import lombok.Getter; +import org.jetbrains.annotations.Nullable; + +import java.util.List; + +import javax.annotation.ParametersAreNonnullByDefault; + +@MethodsReturnNonnullByDefault +@ParametersAreNonnullByDefault +public class ExpandedPatternBufferProxyPartMachine extends TieredIOPartMachine + implements IMachineLife, IDataStickInteractable { + + protected static final ManagedFieldHolder MANAGED_FIELD_HOLDER = new ManagedFieldHolder( + ExpandedPatternBufferProxyPartMachine.class, TieredIOPartMachine.MANAGED_FIELD_HOLDER); + + @Getter + private final ExpandedProxySlotRecipeHandler proxySlotRecipeHandler; + + @Persisted + @Getter + @DescSynced + private @Nullable BlockPos bufferPos; + + private @Nullable ExpandedPatternBufferPartMachine buffer = null; + private boolean bufferResolved = false; + + public ExpandedPatternBufferProxyPartMachine(IMachineBlockEntity holder) { + super(holder, GTValues.LuV, IO.IN); + this.proxySlotRecipeHandler = new ExpandedProxySlotRecipeHandler(this, 72); + } + + @Override + public void onLoad() { + super.onLoad(); + if (getLevel() instanceof ServerLevel level) { + level.getServer().tell(new TickTask(0, () -> this.setBuffer(bufferPos))); + } + } + + @Override + public List getRecipeHandlers() { + return proxySlotRecipeHandler.getProxySlotHandlers(); + } + + public void setBuffer(@Nullable BlockPos pos) { + this.bufferResolved = true; + var level = getLevel(); + if (level == null || pos == null) { + this.buffer = null; + } else if (MetaMachine.getMachine(level, pos) instanceof ExpandedPatternBufferPartMachine machine) { + this.bufferPos = pos; + this.buffer = machine; + machine.addProxy(this); + if (!isRemote()) proxySlotRecipeHandler.updateProxy(machine); + } else { + this.buffer = null; + } + } + + @Nullable + public ExpandedPatternBufferPartMachine getBuffer() { + if (!bufferResolved) setBuffer(bufferPos); + return buffer; + } + + @Override + public boolean shouldOpenUI(Player player, InteractionHand hand, BlockHitResult hit) { + return getBuffer() != null; + } + + @Override + public ModularUI createUI(Player entityPlayer) { + var buf = getBuffer(); + assert buf != null; + return buf.createUI(entityPlayer); + } + + @Override + public ManagedFieldHolder getFieldHolder() { + return MANAGED_FIELD_HOLDER; + } + + @Override + public void onMachineRemoved() { + var buf = getBuffer(); + if (buf != null) { + buf.removeProxy(this); + proxySlotRecipeHandler.clearProxy(); + } + } + + @Override + public InteractionResult onDataStickUse(Player player, ItemStack dataStick) { + if (dataStick.hasTag()) { + assert dataStick.getTag() != null; + if (dataStick.getTag().contains("pos", Tag.TAG_INT_ARRAY)) { + var posArray = dataStick.getOrCreateTag().getIntArray("pos"); + var newBufferPos = new BlockPos(posArray[0], posArray[1], posArray[2]); + setBuffer(newBufferPos); + return InteractionResult.SUCCESS; + } + } + return InteractionResult.PASS; + } +} diff --git a/src/main/java/net/neganote/gtutilities/integration/ae2/machine/trait/ExpandedInternalSlotRecipeHandler.java b/src/main/java/net/neganote/gtutilities/integration/ae2/machine/trait/ExpandedInternalSlotRecipeHandler.java new file mode 100644 index 0000000..5dac071 --- /dev/null +++ b/src/main/java/net/neganote/gtutilities/integration/ae2/machine/trait/ExpandedInternalSlotRecipeHandler.java @@ -0,0 +1,130 @@ +package net.neganote.gtutilities.integration.ae2.machine.trait; + +import com.gregtechceu.gtceu.api.capability.recipe.*; +import com.gregtechceu.gtceu.api.machine.trait.NotifiableRecipeHandlerTrait; +import com.gregtechceu.gtceu.api.machine.trait.RecipeHandlerGroupDistinctness; +import com.gregtechceu.gtceu.api.machine.trait.RecipeHandlerList; +import com.gregtechceu.gtceu.api.recipe.GTRecipe; +import com.gregtechceu.gtceu.api.recipe.ingredient.FluidIngredient; + +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.crafting.Ingredient; +import net.minecraftforge.fluids.FluidStack; +import net.neganote.gtutilities.integration.ae2.machine.ExpandedPatternBufferPartMachine; + +import lombok.Getter; +import org.jetbrains.annotations.NotNull; + +import java.util.ArrayList; +import java.util.List; + +public final class ExpandedInternalSlotRecipeHandler { + + @Getter + private final List slotHandlers; + + public ExpandedInternalSlotRecipeHandler(ExpandedPatternBufferPartMachine buffer, + ExpandedPatternBufferPartMachine.InternalSlot[] slots) { + this.slotHandlers = new ArrayList<>(slots.length); + for (int i = 0; i < slots.length; i++) { + var rhl = new SlotRHL(buffer, slots[i], i); + slotHandlers.add(rhl); + } + } + + @Getter + protected static class SlotRHL extends RecipeHandlerList { + + private final SlotItemRecipeHandler itemRecipeHandler; + private final SlotFluidRecipeHandler fluidRecipeHandler; + + public SlotRHL(ExpandedPatternBufferPartMachine buffer, ExpandedPatternBufferPartMachine.InternalSlot slot, + int idx) { + super(IO.IN); + itemRecipeHandler = new SlotItemRecipeHandler(buffer, slot, idx); + fluidRecipeHandler = new SlotFluidRecipeHandler(buffer, slot, idx); + addHandlers(buffer.getCircuitInventory(), buffer.getShareInventory(), buffer.getShareTank(), + itemRecipeHandler, fluidRecipeHandler); + this.setGroup(RecipeHandlerGroupDistinctness.BUS_DISTINCT); + } + + @Override + public boolean isDistinct() { + return true; + } + + @Override + public void setDistinct(boolean ignored, boolean notify) {} + } + + @Getter + private static class SlotItemRecipeHandler extends NotifiableRecipeHandlerTrait { + + private final ExpandedPatternBufferPartMachine.InternalSlot slot; + private final int priority; + private final int size = 81; + private final RecipeCapability capability = ItemRecipeCapability.CAP; + private final IO handlerIO = IO.IN; + private final boolean isDistinct = true; + + private SlotItemRecipeHandler(ExpandedPatternBufferPartMachine buffer, + ExpandedPatternBufferPartMachine.InternalSlot slot, int index) { + super(buffer); + this.slot = slot; + this.priority = IFilteredHandler.HIGH + index + 1; + slot.setOnContentsChanged(this::notifyListeners); + } + + @Override + public List handleRecipeInner(IO io, GTRecipe recipe, List left, boolean simulate) { + if (io != IO.IN || slot.isItemEmpty()) return left; + return slot.handleItemInternal(left, simulate); + } + + @Override + public @NotNull List getContents() { + return new ArrayList<>(slot.getItems()); + } + + @Override + public double getTotalContentAmount() { + return slot.getItems().stream().mapToLong(ItemStack::getCount).sum(); + } + } + + @Getter + private static class SlotFluidRecipeHandler extends NotifiableRecipeHandlerTrait { + + private final ExpandedPatternBufferPartMachine.InternalSlot slot; + private final int priority; + private final int size = 81; + private final RecipeCapability capability = FluidRecipeCapability.CAP; + private final IO handlerIO = IO.IN; + private final boolean isDistinct = true; + + private SlotFluidRecipeHandler(ExpandedPatternBufferPartMachine buffer, + ExpandedPatternBufferPartMachine.InternalSlot slot, int index) { + super(buffer); + this.slot = slot; + this.priority = IFilteredHandler.HIGH + index + 1; + slot.setOnContentsChanged(this::notifyListeners); + } + + @Override + public List handleRecipeInner(IO io, GTRecipe recipe, List left, + boolean simulate) { + if (io != IO.IN || slot.isFluidEmpty()) return left; + return slot.handleFluidInternal(left, simulate); + } + + @Override + public @NotNull List getContents() { + return new ArrayList<>(slot.getFluids()); + } + + @Override + public double getTotalContentAmount() { + return slot.getFluids().stream().mapToLong(FluidStack::getAmount).sum(); + } + } +} diff --git a/src/main/java/net/neganote/gtutilities/integration/ae2/machine/trait/ExpandedProxySlotRecipeHandler.java b/src/main/java/net/neganote/gtutilities/integration/ae2/machine/trait/ExpandedProxySlotRecipeHandler.java new file mode 100644 index 0000000..07462ee --- /dev/null +++ b/src/main/java/net/neganote/gtutilities/integration/ae2/machine/trait/ExpandedProxySlotRecipeHandler.java @@ -0,0 +1,198 @@ +package net.neganote.gtutilities.integration.ae2.machine.trait; + +import com.gregtechceu.gtceu.api.capability.recipe.*; +import com.gregtechceu.gtceu.api.machine.MetaMachine; +import com.gregtechceu.gtceu.api.machine.trait.IRecipeHandlerTrait; +import com.gregtechceu.gtceu.api.machine.trait.NotifiableRecipeHandlerTrait; +import com.gregtechceu.gtceu.api.machine.trait.RecipeHandlerGroupDistinctness; +import com.gregtechceu.gtceu.api.machine.trait.RecipeHandlerList; +import com.gregtechceu.gtceu.api.recipe.GTRecipe; +import com.gregtechceu.gtceu.api.recipe.ingredient.FluidIngredient; + +import com.lowdragmc.lowdraglib.syncdata.ISubscription; + +import net.minecraft.world.item.crafting.Ingredient; +import net.neganote.gtutilities.integration.ae2.machine.ExpandedPatternBufferPartMachine; +import net.neganote.gtutilities.integration.ae2.machine.ExpandedPatternBufferProxyPartMachine; + +import lombok.Getter; +import org.jetbrains.annotations.NotNull; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +public final class ExpandedProxySlotRecipeHandler { + + @Getter + private final List proxySlotHandlers; + + public ExpandedProxySlotRecipeHandler(ExpandedPatternBufferProxyPartMachine machine, int slots) { + proxySlotHandlers = new ArrayList<>(slots); + for (int i = 0; i < slots; ++i) { + proxySlotHandlers.add(new ProxyRHL(machine)); + } + } + + public void updateProxy(ExpandedPatternBufferPartMachine patternBuffer) { + var slotHandlers = patternBuffer.getInternalRecipeHandler().getSlotHandlers(); + for (int i = 0; i < proxySlotHandlers.size(); ++i) { + ProxyRHL proxyRHL = (ProxyRHL) proxySlotHandlers.get(i); + ExpandedInternalSlotRecipeHandler.SlotRHL slotRHL = (ExpandedInternalSlotRecipeHandler.SlotRHL) slotHandlers + .get(i); + proxyRHL.setBuffer(patternBuffer, slotRHL); + } + } + + public void clearProxy() { + for (var slotHandler : proxySlotHandlers) { + ((ProxyRHL) slotHandler).clearBuffer(); + } + } + + private static class ProxyRHL extends RecipeHandlerList { + + private final ProxyItemRecipeHandler circuit; + private final ProxyItemRecipeHandler sharedItem; + private final ProxyItemRecipeHandler slotItem; + private final ProxyFluidRecipeHandler sharedFluid; + private final ProxyFluidRecipeHandler slotFluid; + + public ProxyRHL(ExpandedPatternBufferProxyPartMachine machine) { + super(IO.IN); + circuit = new ProxyItemRecipeHandler(machine); + sharedItem = new ProxyItemRecipeHandler(machine); + slotItem = new ProxyItemRecipeHandler(machine); + sharedFluid = new ProxyFluidRecipeHandler(machine); + slotFluid = new ProxyFluidRecipeHandler(machine); + addHandlers(circuit, sharedItem, slotItem, sharedFluid, slotFluid); + this.setGroup(RecipeHandlerGroupDistinctness.BUS_DISTINCT); + } + + public void setBuffer(ExpandedPatternBufferPartMachine buffer, + ExpandedInternalSlotRecipeHandler.SlotRHL slotRHL) { + circuit.setProxy(buffer.getCircuitInventory()); + sharedItem.setProxy(buffer.getShareInventory()); + sharedFluid.setProxy(buffer.getShareTank()); + slotItem.setProxy(slotRHL.getItemRecipeHandler()); + slotFluid.setProxy(slotRHL.getFluidRecipeHandler()); + } + + public void clearBuffer() { + circuit.setProxy(null); + sharedItem.setProxy(null); + sharedFluid.setProxy(null); + slotItem.setProxy(null); + slotFluid.setProxy(null); + } + + @Override + public boolean isDistinct() { + return true; + } + + @Override + public void setDistinct(boolean ignored, boolean notify) {} + } + + @Getter + private static class ProxyItemRecipeHandler extends NotifiableRecipeHandlerTrait { + + private IRecipeHandlerTrait proxy = null; + private ISubscription proxySub = null; + private final IO handlerIO = IO.IN; + private final RecipeCapability capability = ItemRecipeCapability.CAP; + private final boolean isDistinct = true; + + public ProxyItemRecipeHandler(MetaMachine machine) { + super(machine); + } + + public void setProxy(IRecipeHandlerTrait proxy) { + this.proxy = proxy; + if (proxySub != null) { + proxySub.unsubscribe(); + proxySub = null; + } + if (proxy != null) { + proxySub = proxy.addChangedListener(this::notifyListeners); + } + } + + @Override + public List handleRecipeInner(IO io, GTRecipe recipe, List left, boolean simulate) { + if (proxy == null) return left; + return proxy.handleRecipeInner(io, recipe, left, simulate); + } + + @Override + public int getSize() { + return proxy == null ? 0 : proxy.getSize(); + } + + @Override + public @NotNull List getContents() { + return proxy == null ? Collections.emptyList() : proxy.getContents(); + } + + @Override + public double getTotalContentAmount() { + return proxy == null ? 0 : proxy.getTotalContentAmount(); + } + + public int getPriority() { + return proxy == null ? IFilteredHandler.LOW : proxy.getPriority(); + } + } + + @Getter + private static class ProxyFluidRecipeHandler extends NotifiableRecipeHandlerTrait { + + private IRecipeHandlerTrait proxy = null; + private ISubscription proxySub = null; + private final IO handlerIO = IO.IN; + private final RecipeCapability capability = FluidRecipeCapability.CAP; + private final boolean isDistinct = true; + + public ProxyFluidRecipeHandler(MetaMachine machine) { + super(machine); + } + + public void setProxy(IRecipeHandlerTrait proxy) { + this.proxy = proxy; + if (proxySub != null) { + proxySub.unsubscribe(); + proxySub = null; + } + if (proxy != null) { + proxySub = proxy.addChangedListener(this::notifyListeners); + } + } + + @Override + public List handleRecipeInner(IO io, GTRecipe recipe, List left, + boolean simulate) { + if (proxy == null) return left; + return proxy.handleRecipeInner(io, recipe, left, simulate); + } + + @Override + public int getSize() { + return proxy == null ? 0 : proxy.getSize(); + } + + @Override + public @NotNull List getContents() { + return proxy == null ? Collections.emptyList() : proxy.getContents(); + } + + @Override + public double getTotalContentAmount() { + return proxy == null ? 0 : proxy.getTotalContentAmount(); + } + + public int getPriority() { + return proxy == null ? IFilteredHandler.LOW : proxy.getPriority(); + } + } +} diff --git a/src/main/java/net/neganote/gtutilities/recipe/UtilRecipes.java b/src/main/java/net/neganote/gtutilities/recipe/UtilRecipes.java index 5f7b320..d423762 100644 --- a/src/main/java/net/neganote/gtutilities/recipe/UtilRecipes.java +++ b/src/main/java/net/neganote/gtutilities/recipe/UtilRecipes.java @@ -1,5 +1,6 @@ package net.neganote.gtutilities.recipe; +import com.gregtechceu.gtceu.GTCEu; import com.gregtechceu.gtceu.api.GTCEuAPI; import com.gregtechceu.gtceu.api.GTValues; import com.gregtechceu.gtceu.api.data.tag.TagPrefix; @@ -7,6 +8,7 @@ import com.gregtechceu.gtceu.common.data.GTItems; import com.gregtechceu.gtceu.common.data.GTMachines; import com.gregtechceu.gtceu.common.data.GTMaterials; +import com.gregtechceu.gtceu.common.data.machines.GTAEMachines; import com.gregtechceu.gtceu.common.data.machines.GTMultiMachines; import com.gregtechceu.gtceu.config.ConfigHolder; import com.gregtechceu.gtceu.data.recipe.CustomTags; @@ -14,12 +16,22 @@ import net.minecraft.data.recipes.FinishedRecipe; import net.minecraft.world.item.ItemStack; +import net.neganote.gtutilities.common.machine.UtilAEMachines; import net.neganote.gtutilities.common.machine.UtilMachines; import net.neganote.gtutilities.config.UtilConfig; +import appeng.core.definitions.AEBlocks; +import appeng.core.definitions.AEItems; + import java.util.function.Consumer; +import static com.gregtechceu.gtceu.api.GTValues.*; +import static com.gregtechceu.gtceu.api.GTValues.ZPM; +import static com.gregtechceu.gtceu.api.data.tag.TagPrefix.wireFine; import static com.gregtechceu.gtceu.common.data.GTBlocks.LASER_PIPES; +import static com.gregtechceu.gtceu.common.data.GTItems.*; +import static com.gregtechceu.gtceu.common.data.GTMachines.DUAL_IMPORT_HATCH; +import static com.gregtechceu.gtceu.common.data.GTMaterials.*; import static com.gregtechceu.gtceu.common.data.GTRecipeTypes.ASSEMBLER_RECIPES; import static com.gregtechceu.gtceu.common.data.GTRecipeTypes.ASSEMBLY_LINE_RECIPES; import static com.gregtechceu.gtceu.data.recipe.GTCraftingComponents.*; @@ -60,6 +72,43 @@ public static void init(Consumer provider) { .save(provider); } + if (UtilConfig.INSTANCE.features.expandedBuffersEnabled && GTCEu.Mods.isAE2Loaded()) { + ASSEMBLY_LINE_RECIPES.recipeBuilder("expanded_me_pattern_buffer") + .inputItems(DUAL_IMPORT_HATCH[ZPM], 1) + .inputItems(EMITTER_ZPM, 4) + .inputItems(CustomTags.ZPM_CIRCUITS, 4) + .inputItems(AEBlocks.PATTERN_PROVIDER.asItem(), 4) + .inputItems(AEBlocks.INTERFACE.asItem(), 4) + .inputItems(AEItems.SPEED_CARD.asItem(), 8) + .inputItems(AEItems.CAPACITY_CARD.asItem(), 4) + .inputItems(wireFine, UraniumRhodiumDinaquadide, 48) + .inputItems(wireFine, UraniumRhodiumDinaquadide, 48) + .inputItems(wireFine, UraniumRhodiumDinaquadide, 48) + .inputItems(wireFine, UraniumRhodiumDinaquadide, 48) + .inputFluids(SolderingAlloy, L * 8) + .inputFluids(Lubricant, 4000) + .outputItems(UtilAEMachines.EXPANDED_ME_PATTERN_BUFFER) + .stationResearch(b -> b.researchStack(DUAL_IMPORT_HATCH[ZPM].asStack()) + .CWUt(16, 32000)) + .duration(4000).EUt(VA[ZPM]).save(provider); + ASSEMBLY_LINE_RECIPES.recipeBuilder("expanded_me_pattern_buffer_proxy") + .inputItems(GTMachines.HULL[ZPM], 1) + .inputItems(SENSOR_ZPM, 4) + .inputItems(CustomTags.ZPM_CIRCUITS, 2) + .inputItems(AEBlocks.QUANTUM_LINK.asItem(), 2) + .inputItems(AEBlocks.QUANTUM_RING.asItem(), 4) + .inputItems(wireFine, UraniumRhodiumDinaquadide, 48) + .inputItems(wireFine, UraniumRhodiumDinaquadide, 48) + .inputItems(wireFine, UraniumRhodiumDinaquadide, 48) + .inputItems(wireFine, UraniumRhodiumDinaquadide, 48) + .inputFluids(SolderingAlloy, L * 8) + .inputFluids(Lubricant, 2000) + .outputItems(UtilAEMachines.EXPANDED_ME_PATTERN_BUFFER_PROXY) + .stationResearch(b -> b.researchStack(GTAEMachines.ME_PATTERN_BUFFER_PROXY.asStack()) + .CWUt(32)) + .duration(600).EUt(VA[ZPM]).save(provider); + } + if (UtilConfig.INSTANCE.features.autoChargersEnabled) { for (MachineDefinition autoChargerDef : AUTO_CHARGER_4) { if (autoChargerDef == null) {