diff --git a/src/main/java/com/gregtechceu/gtceu/api/machine/fancyconfigurator/AutoStockingFancyConfigurator.java b/src/main/java/com/gregtechceu/gtceu/api/machine/fancyconfigurator/AutoStockingFancyConfigurator.java deleted file mode 100644 index 94620e8736c..00000000000 --- a/src/main/java/com/gregtechceu/gtceu/api/machine/fancyconfigurator/AutoStockingFancyConfigurator.java +++ /dev/null @@ -1,53 +0,0 @@ -package com.gregtechceu.gtceu.api.machine.fancyconfigurator; - -import com.gregtechceu.gtceu.api.gui.fancy.IFancyConfigurator; -import com.gregtechceu.gtceu.api.gui.widget.IntInputWidget; -import com.gregtechceu.gtceu.common.data.GTItems; -import com.gregtechceu.gtceu.config.ConfigHolder; -import com.gregtechceu.gtceu.integration.ae2.machine.MEStockingBusPartMachine; -import com.gregtechceu.gtceu.integration.ae2.machine.feature.multiblock.IMEStockingPart; - -import com.lowdragmc.lowdraglib.gui.texture.IGuiTexture; -import com.lowdragmc.lowdraglib.gui.texture.ItemStackTexture; -import com.lowdragmc.lowdraglib.gui.widget.LabelWidget; -import com.lowdragmc.lowdraglib.gui.widget.Widget; -import com.lowdragmc.lowdraglib.gui.widget.WidgetGroup; - -import net.minecraft.network.chat.Component; - -public class AutoStockingFancyConfigurator implements IFancyConfigurator { - - private IMEStockingPart machine; - - public AutoStockingFancyConfigurator(IMEStockingPart machine) { - this.machine = machine; - } - - @Override - public Component getTitle() { - return Component.translatable("gtceu.gui.adv_stocking_config.title"); - } - - @Override - public IGuiTexture getIcon() { - return new ItemStackTexture(GTItems.TOOL_DATA_STICK.asStack()); - } - - @Override - public Widget createConfigurator() { - var group = new WidgetGroup(0, 0, 90, 70); - - String suffix = machine instanceof MEStockingBusPartMachine ? "min_item_count" : "min_fluid_count"; - - group.addWidget(new LabelWidget(4, 2, "gtceu.gui.title.adv_stocking_config." + suffix)); - group.addWidget(new IntInputWidget(4, 12, 81, 14, machine::getMinStackSize, - machine::setMinStackSize).setMin(1) - .appendHoverTooltips(Component.translatable("gtceu.gui.adv_stocking_config." + suffix))); - group.addWidget(new LabelWidget(4, 36, "gtceu.gui.title.adv_stocking_config.ticks_per_cycle")); - group.addWidget(new IntInputWidget(4, 46, 81, 14, machine::getTicksPerCycle, - machine::setTicksPerCycle).setMin(ConfigHolder.INSTANCE.compat.ae2.updateIntervals) - .setHoverTooltips(Component.translatable("gtceu.gui.adv_stocking_config.ticks_per_cycle"))); - - return group; - } -} diff --git a/src/main/java/com/gregtechceu/gtceu/api/machine/feature/IDataStickConfigurable.java b/src/main/java/com/gregtechceu/gtceu/api/machine/feature/IDataStickConfigurable.java new file mode 100644 index 00000000000..e12409f027c --- /dev/null +++ b/src/main/java/com/gregtechceu/gtceu/api/machine/feature/IDataStickConfigurable.java @@ -0,0 +1,49 @@ +package com.gregtechceu.gtceu.api.machine.feature; + +import net.minecraft.nbt.CompoundTag; +import net.minecraft.network.chat.Component; +import net.minecraft.world.InteractionResult; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.item.ItemStack; + +public interface IDataStickConfigurable extends IMachineFeature, IDataStickInteractable { + + @Override + default InteractionResult onDataStickShiftUse(Player player, ItemStack dataStick) { + if (!self().isRemote()) { + CompoundTag root = dataStick.getOrCreateTag(); + CompoundTag config = new CompoundTag(); + writeConfig(config); + root.put(getConfigKey(), config); + dataStick.setHoverName(getConfigName()); + player.sendSystemMessage(Component.translatable("gtceu.machine.me.import_copy_settings")); + } + return InteractionResult.SUCCESS; + } + + @Override + default InteractionResult onDataStickUse(Player player, ItemStack dataStick) { + String tagKey = getConfigKey(); + CompoundTag root = dataStick.getTag(); + if (root == null || !root.contains(tagKey)) { + return InteractionResult.PASS; + } + if (!self().isRemote()) { + readConfig(root.getCompound(tagKey)); + player.sendSystemMessage(Component.translatable("gtceu.machine.me.import_paste_settings")); + } + return InteractionResult.sidedSuccess(self().isRemote()); + } + + default String getConfigKey() { + return getClass().getSimpleName(); + } + + default Component getConfigName() { + return Component.literal(getConfigKey()); + } + + void writeConfig(CompoundTag tag); + + void readConfig(CompoundTag tag); +} diff --git a/src/main/java/com/gregtechceu/gtceu/common/data/machines/GTAEMachines.java b/src/main/java/com/gregtechceu/gtceu/common/data/machines/GTAEMachines.java index 72abe4159a2..a27361f816d 100644 --- a/src/main/java/com/gregtechceu/gtceu/common/data/machines/GTAEMachines.java +++ b/src/main/java/com/gregtechceu/gtceu/common/data/machines/GTAEMachines.java @@ -16,7 +16,7 @@ public class GTAEMachines { public final static MachineDefinition ITEM_IMPORT_BUS_ME = REGISTRATE - .machine("me_input_bus", MEInputBusPartMachine::new) + .machine("me_input_bus", be -> new MEInputBusPartMachine(be, EV, 16)) .langValue("ME Input Bus") .tier(EV) .rotationState(RotationState.ALL) @@ -30,7 +30,7 @@ public class GTAEMachines { .register(); public final static MachineDefinition STOCKING_IMPORT_BUS_ME = REGISTRATE - .machine("me_stocking_input_bus", MEStockingBusPartMachine::new) + .machine("me_stocking_input_bus", be -> new MEStockingBusPartMachine(be, LuV, 16)) .langValue("ME Stocking Input Bus") .tier(LuV) .rotationState(RotationState.ALL) @@ -46,7 +46,7 @@ public class GTAEMachines { .register(); public final static MachineDefinition ITEM_EXPORT_BUS_ME = REGISTRATE - .machine("me_output_bus", MEOutputBusPartMachine::new) + .machine("me_output_bus", be -> new MEOutputBusPartMachine(be, EV)) .langValue("ME Output Bus") .tier(EV) .rotationState(RotationState.ALL) @@ -60,7 +60,7 @@ public class GTAEMachines { .register(); public final static MachineDefinition FLUID_IMPORT_HATCH_ME = REGISTRATE - .machine("me_input_hatch", MEInputHatchPartMachine::new) + .machine("me_input_hatch", be -> new MEInputHatchPartMachine(be, EV, 16)) .langValue("ME Input Hatch") .tier(EV) .rotationState(RotationState.ALL) @@ -74,7 +74,7 @@ public class GTAEMachines { .register(); public final static MachineDefinition STOCKING_IMPORT_HATCH_ME = REGISTRATE - .machine("me_stocking_input_hatch", MEStockingHatchPartMachine::new) + .machine("me_stocking_input_hatch", be -> new MEStockingHatchPartMachine(be, LuV, 16)) .langValue("ME Stocking Input Hatch") .tier(LuV) .rotationState(RotationState.ALL) @@ -90,7 +90,7 @@ public class GTAEMachines { .register(); public final static MachineDefinition FLUID_EXPORT_HATCH_ME = REGISTRATE - .machine("me_output_hatch", MEOutputHatchPartMachine::new) + .machine("me_output_hatch", be -> new MEOutputHatchPartMachine(be, EV)) .langValue("ME Output Hatch") .tier(EV) .rotationState(RotationState.ALL) @@ -118,7 +118,7 @@ public class GTAEMachines { Component.translatable("gtceu.part_sharing.enabled")) .register(); public static final MachineDefinition ME_PATTERN_BUFFER_PROXY = REGISTRATE - .machine("me_pattern_buffer_proxy", MEPatternBufferProxyPartMachine::new) + .machine("me_pattern_buffer_proxy", MEPatternProxyPartMachine::new) .tier(LuV) .rotationState(RotationState.ALL) .abilities(PartAbility.IMPORT_ITEMS, PartAbility.IMPORT_FLUIDS, PartAbility.EXPORT_FLUIDS, diff --git a/src/main/java/com/gregtechceu/gtceu/common/machine/electric/HullMachine.java b/src/main/java/com/gregtechceu/gtceu/common/machine/electric/HullMachine.java index 4f5c9d06f9e..98dd8b36091 100644 --- a/src/main/java/com/gregtechceu/gtceu/common/machine/electric/HullMachine.java +++ b/src/main/java/com/gregtechceu/gtceu/common/machine/electric/HullMachine.java @@ -7,21 +7,17 @@ import com.gregtechceu.gtceu.api.machine.IMachineBlockEntity; import com.gregtechceu.gtceu.api.machine.multiblock.part.MultiblockPartMachine; import com.gregtechceu.gtceu.api.machine.multiblock.part.TieredPartMachine; +import com.gregtechceu.gtceu.api.machine.trait.MachineTrait; import com.gregtechceu.gtceu.api.machine.trait.NotifiableEnergyContainer; -import com.gregtechceu.gtceu.integration.ae2.machine.trait.GridNodeHostTrait; +import com.gregtechceu.gtceu.integration.ae2.machine.trait.GridNodeHost; import com.lowdragmc.lowdraglib.gui.texture.IGuiTexture; import com.lowdragmc.lowdraglib.syncdata.annotation.Persisted; import com.lowdragmc.lowdraglib.syncdata.field.ManagedFieldHolder; import net.minecraft.MethodsReturnNonnullByDefault; -import net.minecraft.core.Direction; -import net.minecraft.nbt.CompoundTag; -import net.minecraft.server.TickTask; -import net.minecraft.server.level.ServerLevel; -import appeng.me.helpers.IGridConnectedBlockEntity; -import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import javax.annotation.ParametersAreNonnullByDefault; @@ -32,14 +28,14 @@ public class HullMachine extends TieredPartMachine implements IMonitorComponent protected static final ManagedFieldHolder MANAGED_FIELD_HOLDER = new ManagedFieldHolder(HullMachine.class, MultiblockPartMachine.MANAGED_FIELD_HOLDER); - private final Object gridNodeHost; + private final @Nullable MachineTrait gridNodeHost; @Persisted protected NotifiableEnergyContainer energyContainer; public HullMachine(IMachineBlockEntity holder, int tier) { super(holder, tier); if (GTCEu.Mods.isAE2Loaded()) { - this.gridNodeHost = new GridNodeHostTrait(this); + this.gridNodeHost = new GridNodeHost(this); } else { this.gridNodeHost = null; } @@ -52,56 +48,11 @@ protected void reinitializeEnergyContainer() { this.energyContainer.setSideOutputCondition(s -> s == getFrontFacing()); } - @Override - public void onLoad() { - super.onLoad(); - if (GTCEu.Mods.isAE2Loaded() && gridNodeHost instanceof GridNodeHostTrait connectedBlockEntity && - getLevel() instanceof ServerLevel level) { - level.getServer().tell(new TickTask(0, connectedBlockEntity::init)); - } - } - - @Override - public void onUnload() { - super.onUnload(); - if (GTCEu.Mods.isAE2Loaded() && gridNodeHost instanceof GridNodeHostTrait connectedBlockEntity) { - connectedBlockEntity.getMainNode().destroy(); - } - } - - @Override - public void setFrontFacing(Direction facing) { - super.setFrontFacing(facing); - if (isFacingValid(facing)) { - if (GTCEu.Mods.isAE2Loaded() && gridNodeHost instanceof GridNodeHostTrait connectedBlockEntity) { - connectedBlockEntity.init(); - } - } - } - @Override public ManagedFieldHolder getFieldHolder() { return MANAGED_FIELD_HOLDER; } - @Override - public void saveCustomPersistedData(@NotNull CompoundTag tag, boolean forDrop) { - super.saveCustomPersistedData(tag, forDrop); - if (GTCEu.Mods.isAE2Loaded() && gridNodeHost instanceof IGridConnectedBlockEntity connectedBlockEntity) { - CompoundTag nbt = new CompoundTag(); - connectedBlockEntity.getMainNode().saveToNBT(nbt); - tag.put("grid_node", nbt); - } - } - - @Override - public void loadCustomPersistedData(@NotNull CompoundTag tag) { - super.loadCustomPersistedData(tag); - if (GTCEu.Mods.isAE2Loaded() && gridNodeHost instanceof IGridConnectedBlockEntity connectedBlockEntity) { - connectedBlockEntity.getMainNode().loadFromNBT(tag.getCompound("grid_node")); - } - } - ////////////////////////////////////// // ********** Misc **********// ////////////////////////////////////// diff --git a/src/main/java/com/gregtechceu/gtceu/data/lang/MachineLang.java b/src/main/java/com/gregtechceu/gtceu/data/lang/MachineLang.java index 0efc336ac21..05a5cfa75a0 100644 --- a/src/main/java/com/gregtechceu/gtceu/data/lang/MachineLang.java +++ b/src/main/java/com/gregtechceu/gtceu/data/lang/MachineLang.java @@ -810,10 +810,6 @@ protected static void init(RegistrateLangProvider provider) { "Minimum Item Stack Size for Automated Pulling"); provider.add("gtceu.gui.adv_stocking_config.min_fluid_count", "Minimum Fluid Stack Size for Automated Pulling"); - provider.add("gtceu.gui.title.adv_stocking_config.ticks_per_cycle", - "Ticks Per Cycle"); - provider.add("gtceu.gui.adv_stocking_config.ticks_per_cycle", - "Delay between item list updates"); provider.add("gtceu.gui.adv_stocking_config.title", "Configure Automatic Stocking"); diff --git a/src/main/java/com/gregtechceu/gtceu/integration/ae2/gui/AEFluidConfigWidget.java b/src/main/java/com/gregtechceu/gtceu/integration/ae2/gui/AEFluidConfigWidget.java new file mode 100644 index 00000000000..9564013ddf6 --- /dev/null +++ b/src/main/java/com/gregtechceu/gtceu/integration/ae2/gui/AEFluidConfigWidget.java @@ -0,0 +1,39 @@ +package com.gregtechceu.gtceu.integration.ae2.gui; + +import com.gregtechceu.gtceu.integration.ae2.gui.slot.AEFluidConfigSlotWidget; +import com.gregtechceu.gtceu.integration.ae2.slot.ConfigurableFluidList; +import com.gregtechceu.gtceu.integration.ae2.slot.ConfigurableFluidSlot; +import com.gregtechceu.gtceu.integration.ae2.slot.ConfigurableSlot; + +import appeng.api.stacks.GenericStack; + +public class AEFluidConfigWidget extends ConfigWidget { + + private final ConfigurableFluidList fluidList; + + public AEFluidConfigWidget(int x, int y, ConfigurableFluidList list) { + super(x, y, list.getInventory(), list.isStocking()); + this.fluidList = list; + } + + @Override + void init() { + int line; + this.displayList = new ConfigurableSlot[this.config.length]; + this.cached = new ConfigurableSlot[this.config.length]; + for (int index = 0; index < this.config.length; index++) { + this.displayList[index] = new ConfigurableFluidSlot(); + this.cached[index] = new ConfigurableFluidSlot(); + line = index / 8; + this.addWidget(new AEFluidConfigSlotWidget((index - line * 8) * 18, line * (18 * 2 + 2), this, index)); + } + } + + public boolean hasStackInConfig(GenericStack stack) { + return fluidList.isStackConfigured(stack, true); + } + + public boolean isAutoPull() { + return fluidList.isAutoPull(); + } +} diff --git a/src/main/java/com/gregtechceu/gtceu/integration/ae2/gui/AEItemConfigWidget.java b/src/main/java/com/gregtechceu/gtceu/integration/ae2/gui/AEItemConfigWidget.java new file mode 100644 index 00000000000..d905eacb0a4 --- /dev/null +++ b/src/main/java/com/gregtechceu/gtceu/integration/ae2/gui/AEItemConfigWidget.java @@ -0,0 +1,44 @@ +package com.gregtechceu.gtceu.integration.ae2.gui; + +import com.gregtechceu.gtceu.integration.ae2.gui.slot.AEItemConfigSlotWidget; +import com.gregtechceu.gtceu.integration.ae2.slot.ConfigurableItemList; +import com.gregtechceu.gtceu.integration.ae2.slot.ConfigurableItemSlot; +import com.gregtechceu.gtceu.integration.ae2.slot.ConfigurableSlot; + +import appeng.api.stacks.GenericStack; + +public class AEItemConfigWidget extends ConfigWidget { + + private static final int SLOTS_PER_ROW = 8; + private static final int SLOT_SIZE = 18; + private static final int ROW_SPACING = 2; + + private final ConfigurableItemList itemList; + + public AEItemConfigWidget(int x, int y, ConfigurableItemList list) { + super(x, y, list.getInventory(), list.isStocking()); + this.itemList = list; + } + + @Override + void init() { + int line; + this.displayList = new ConfigurableSlot[this.config.length]; + this.cached = new ConfigurableSlot[this.config.length]; + for (int index = 0; index < this.config.length; index++) { + this.displayList[index] = new ConfigurableItemSlot(); + this.cached[index] = new ConfigurableItemSlot(); + line = index / SLOTS_PER_ROW; + this.addWidget(new AEItemConfigSlotWidget((index - line * SLOTS_PER_ROW) * SLOT_SIZE, + line * (SLOT_SIZE * 2 + ROW_SPACING), this, index)); + } + } + + public boolean hasStackInConfig(GenericStack stack) { + return itemList.isStackConfigured(stack, true); + } + + public boolean isAutoPull() { + return itemList.isAutoPull(); + } +} diff --git a/src/main/java/com/gregtechceu/gtceu/integration/ae2/gui/widget/AETextInputButtonWidget.java b/src/main/java/com/gregtechceu/gtceu/integration/ae2/gui/AETextInputButtonWidget.java similarity index 97% rename from src/main/java/com/gregtechceu/gtceu/integration/ae2/gui/widget/AETextInputButtonWidget.java rename to src/main/java/com/gregtechceu/gtceu/integration/ae2/gui/AETextInputButtonWidget.java index 2baeffb5d8b..8cc537fa304 100644 --- a/src/main/java/com/gregtechceu/gtceu/integration/ae2/gui/widget/AETextInputButtonWidget.java +++ b/src/main/java/com/gregtechceu/gtceu/integration/ae2/gui/AETextInputButtonWidget.java @@ -1,4 +1,4 @@ -package com.gregtechceu.gtceu.integration.ae2.gui.widget; +package com.gregtechceu.gtceu.integration.ae2.gui; import com.gregtechceu.gtceu.api.gui.GuiTextures; import com.gregtechceu.gtceu.api.gui.widget.ToggleButtonWidget; diff --git a/src/main/java/com/gregtechceu/gtceu/integration/ae2/gui/widget/AmountSetWidget.java b/src/main/java/com/gregtechceu/gtceu/integration/ae2/gui/AmountSetWidget.java similarity index 90% rename from src/main/java/com/gregtechceu/gtceu/integration/ae2/gui/widget/AmountSetWidget.java rename to src/main/java/com/gregtechceu/gtceu/integration/ae2/gui/AmountSetWidget.java index 1139bd36c2f..41097f275e6 100644 --- a/src/main/java/com/gregtechceu/gtceu/integration/ae2/gui/widget/AmountSetWidget.java +++ b/src/main/java/com/gregtechceu/gtceu/integration/ae2/gui/AmountSetWidget.java @@ -1,7 +1,7 @@ -package com.gregtechceu.gtceu.integration.ae2.gui.widget; +package com.gregtechceu.gtceu.integration.ae2.gui; import com.gregtechceu.gtceu.api.gui.GuiTextures; -import com.gregtechceu.gtceu.integration.ae2.slot.IConfigurableSlot; +import com.gregtechceu.gtceu.integration.ae2.slot.ConfigurableSlot; import com.lowdragmc.lowdraglib.gui.widget.TextFieldWidget; import com.lowdragmc.lowdraglib.gui.widget.Widget; @@ -47,7 +47,7 @@ public String getAmountStr() { if (this.index < 0) { return "0"; } - IConfigurableSlot slot = this.parentWidget.getConfig(this.index); + ConfigurableSlot slot = this.parentWidget.getConfig(this.index); if (slot.getConfig() != null) { return String.valueOf(slot.getConfig().amount()); } @@ -60,7 +60,7 @@ public void setNewAmount(String amount) { if (this.index < 0) { return; } - IConfigurableSlot slot = this.parentWidget.getConfig(this.index); + ConfigurableSlot slot = this.parentWidget.getConfig(this.index); if (newAmount > 0 && slot.getConfig() != null) { slot.setConfig(new GenericStack(slot.getConfig().what(), newAmount)); } diff --git a/src/main/java/com/gregtechceu/gtceu/integration/ae2/gui/widget/ConfigWidget.java b/src/main/java/com/gregtechceu/gtceu/integration/ae2/gui/ConfigWidget.java similarity index 87% rename from src/main/java/com/gregtechceu/gtceu/integration/ae2/gui/widget/ConfigWidget.java rename to src/main/java/com/gregtechceu/gtceu/integration/ae2/gui/ConfigWidget.java index 69198688a73..4c0f2592584 100644 --- a/src/main/java/com/gregtechceu/gtceu/integration/ae2/gui/widget/ConfigWidget.java +++ b/src/main/java/com/gregtechceu/gtceu/integration/ae2/gui/ConfigWidget.java @@ -1,7 +1,7 @@ -package com.gregtechceu.gtceu.integration.ae2.gui.widget; +package com.gregtechceu.gtceu.integration.ae2.gui; -import com.gregtechceu.gtceu.integration.ae2.gui.widget.slot.AEConfigSlotWidget; -import com.gregtechceu.gtceu.integration.ae2.slot.IConfigurableSlot; +import com.gregtechceu.gtceu.integration.ae2.gui.slot.AEConfigSlotWidget; +import com.gregtechceu.gtceu.integration.ae2.slot.ConfigurableSlot; import com.lowdragmc.lowdraglib.gui.widget.Widget; import com.lowdragmc.lowdraglib.gui.widget.WidgetGroup; @@ -19,17 +19,17 @@ public abstract class ConfigWidget extends WidgetGroup { - protected final IConfigurableSlot[] config; - protected IConfigurableSlot[] cached; - protected Int2ObjectMap changeMap = new Int2ObjectOpenHashMap<>(); - protected IConfigurableSlot[] displayList; + protected final ConfigurableSlot[] config; + protected ConfigurableSlot[] cached; + protected Int2ObjectMap changeMap = new Int2ObjectOpenHashMap<>(); + protected ConfigurableSlot[] displayList; protected AmountSetWidget amountSetWidget; protected final static int UPDATE_ID = 1000; @Getter protected final boolean isStocking; - public ConfigWidget(int x, int y, IConfigurableSlot[] config, boolean isStocking) { + public ConfigWidget(int x, int y, ConfigurableSlot[] config, boolean isStocking) { super(new Position(x, y), new Size(config.length / 2 * 18, 18 * 4 + 2)); this.isStocking = isStocking; this.config = config; @@ -95,8 +95,8 @@ public void detectAndSendChanges() { super.detectAndSendChanges(); this.changeMap.clear(); for (int index = 0; index < this.config.length; index++) { - IConfigurableSlot newSlot = this.config[index]; - IConfigurableSlot oldSlot = this.cached[index]; + ConfigurableSlot newSlot = this.config[index]; + ConfigurableSlot oldSlot = this.cached[index]; GenericStack nConfig = newSlot.getConfig(); GenericStack nStock = newSlot.getStock(); GenericStack oConfig = oldSlot.getConfig(); @@ -139,7 +139,7 @@ public void readUpdateInfo(int id, FriendlyByteBuf buffer) { int size = buffer.readVarInt(); for (int i = 0; i < size; i++) { int index = buffer.readVarInt(); - IConfigurableSlot slot = this.displayList[index]; + ConfigurableSlot slot = this.displayList[index]; if (buffer.readBoolean()) { slot.setConfig(GenericStack.readBuffer(buffer)); } else { @@ -154,11 +154,11 @@ public void readUpdateInfo(int id, FriendlyByteBuf buffer) { } } - public final IConfigurableSlot getConfig(int index) { + public final ConfigurableSlot getConfig(int index) { return this.config[index]; } - public final IConfigurableSlot getDisplay(int index) { + public final ConfigurableSlot getDisplay(int index) { return this.displayList[index]; } diff --git a/src/main/java/com/gregtechceu/gtceu/integration/ae2/gui/fancyconfigurator/StockingFancyConfigurator.java b/src/main/java/com/gregtechceu/gtceu/integration/ae2/gui/fancyconfigurator/StockingFancyConfigurator.java new file mode 100644 index 00000000000..edafb8a72f2 --- /dev/null +++ b/src/main/java/com/gregtechceu/gtceu/integration/ae2/gui/fancyconfigurator/StockingFancyConfigurator.java @@ -0,0 +1,58 @@ +package com.gregtechceu.gtceu.integration.ae2.gui.fancyconfigurator; + +import com.gregtechceu.gtceu.api.gui.fancy.IFancyConfigurator; +import com.gregtechceu.gtceu.api.gui.widget.IntInputWidget; +import com.gregtechceu.gtceu.common.data.GTItems; + +import com.lowdragmc.lowdraglib.gui.texture.IGuiTexture; +import com.lowdragmc.lowdraglib.gui.texture.ItemStackTexture; +import com.lowdragmc.lowdraglib.gui.widget.LabelWidget; +import com.lowdragmc.lowdraglib.gui.widget.Widget; +import com.lowdragmc.lowdraglib.gui.widget.WidgetGroup; + +import net.minecraft.network.chat.Component; + +import java.util.function.Consumer; +import java.util.function.Supplier; + +public class StockingFancyConfigurator implements IFancyConfigurator { + + private final String minSizeLabel; + private final String minSizeTooltip; + private final Supplier minSizeGetter; + private final Consumer minSizeSetter; + + public StockingFancyConfigurator( + String minSizeLabel, + String minSizeTooltip, + Supplier minSizeGetter, + Consumer minSizeSetter + ) { + this.minSizeLabel = minSizeLabel; + this.minSizeTooltip = minSizeTooltip; + this.minSizeGetter = minSizeGetter; + this.minSizeSetter = minSizeSetter; + } + + @Override + public Component getTitle() { + return Component.translatable("gtceu.gui.adv_stocking_config.title"); + } + + @Override + public IGuiTexture getIcon() { + return new ItemStackTexture(GTItems.TOOL_DATA_STICK.asStack()); + } + + @Override + public Widget createConfigurator() { + var group = new WidgetGroup(0, 0, 90, 30); + + group.addWidget(new LabelWidget(4, 2, minSizeLabel)); + group.addWidget(new IntInputWidget(4, 12, 81, 14, minSizeGetter, minSizeSetter) + .setMin(1) + .appendHoverTooltips(Component.translatable(minSizeTooltip))); + + return group; + } +} diff --git a/src/main/java/com/gregtechceu/gtceu/integration/ae2/gui/widget/list/AEFluidDisplayWidget.java b/src/main/java/com/gregtechceu/gtceu/integration/ae2/gui/list/AEFluidDisplayWidget.java similarity index 95% rename from src/main/java/com/gregtechceu/gtceu/integration/ae2/gui/widget/list/AEFluidDisplayWidget.java rename to src/main/java/com/gregtechceu/gtceu/integration/ae2/gui/list/AEFluidDisplayWidget.java index 08dd66ce998..c65e6443810 100644 --- a/src/main/java/com/gregtechceu/gtceu/integration/ae2/gui/widget/list/AEFluidDisplayWidget.java +++ b/src/main/java/com/gregtechceu/gtceu/integration/ae2/gui/list/AEFluidDisplayWidget.java @@ -1,4 +1,4 @@ -package com.gregtechceu.gtceu.integration.ae2.gui.widget.list; +package com.gregtechceu.gtceu.integration.ae2.gui.list; import com.gregtechceu.gtceu.api.gui.GuiTextures; import com.gregtechceu.gtceu.client.TooltipsHandler; @@ -24,7 +24,7 @@ import java.util.List; import java.util.Optional; -import static com.gregtechceu.gtceu.integration.ae2.gui.widget.slot.AEConfigSlotWidget.drawSelectionOverlay; +import static com.gregtechceu.gtceu.integration.ae2.gui.slot.AEConfigSlotWidget.drawSelectionOverlay; import static com.lowdragmc.lowdraglib.gui.util.DrawerHelper.drawText; /** diff --git a/src/main/java/com/gregtechceu/gtceu/integration/ae2/gui/widget/list/AEItemDisplayWidget.java b/src/main/java/com/gregtechceu/gtceu/integration/ae2/gui/list/AEItemDisplayWidget.java similarity index 93% rename from src/main/java/com/gregtechceu/gtceu/integration/ae2/gui/widget/list/AEItemDisplayWidget.java rename to src/main/java/com/gregtechceu/gtceu/integration/ae2/gui/list/AEItemDisplayWidget.java index 3c28a821248..d6b1d6d2231 100644 --- a/src/main/java/com/gregtechceu/gtceu/integration/ae2/gui/widget/list/AEItemDisplayWidget.java +++ b/src/main/java/com/gregtechceu/gtceu/integration/ae2/gui/list/AEItemDisplayWidget.java @@ -1,4 +1,4 @@ -package com.gregtechceu.gtceu.integration.ae2.gui.widget.list; +package com.gregtechceu.gtceu.integration.ae2.gui.list; import com.gregtechceu.gtceu.api.gui.GuiTextures; @@ -14,7 +14,7 @@ import appeng.api.stacks.GenericStack; import org.jetbrains.annotations.NotNull; -import static com.gregtechceu.gtceu.integration.ae2.gui.widget.slot.AEConfigSlotWidget.drawSelectionOverlay; +import static com.gregtechceu.gtceu.integration.ae2.gui.slot.AEConfigSlotWidget.drawSelectionOverlay; import static com.lowdragmc.lowdraglib.gui.util.DrawerHelper.drawItemStack; import static com.lowdragmc.lowdraglib.gui.util.DrawerHelper.drawText; diff --git a/src/main/java/com/gregtechceu/gtceu/integration/ae2/gui/widget/list/AEListGridWidget.java b/src/main/java/com/gregtechceu/gtceu/integration/ae2/gui/list/AEListGridWidget.java similarity index 93% rename from src/main/java/com/gregtechceu/gtceu/integration/ae2/gui/widget/list/AEListGridWidget.java rename to src/main/java/com/gregtechceu/gtceu/integration/ae2/gui/list/AEListGridWidget.java index fe52076fd63..ff2c9c480f7 100644 --- a/src/main/java/com/gregtechceu/gtceu/integration/ae2/gui/widget/list/AEListGridWidget.java +++ b/src/main/java/com/gregtechceu/gtceu/integration/ae2/gui/list/AEListGridWidget.java @@ -1,6 +1,6 @@ -package com.gregtechceu.gtceu.integration.ae2.gui.widget.list; +package com.gregtechceu.gtceu.integration.ae2.gui.list; -import com.gregtechceu.gtceu.integration.ae2.utils.KeyStorage; +import com.gregtechceu.gtceu.integration.ae2.utils.AEKeyStorage; import com.lowdragmc.lowdraglib.gui.widget.DraggableScrollableWidgetGroup; import com.lowdragmc.lowdraglib.gui.widget.Widget; @@ -20,21 +20,21 @@ import java.util.List; /** - * A display only widget for {@link KeyStorage} + * A display only widget for {@link AEKeyStorage} */ public abstract class AEListGridWidget extends DraggableScrollableWidgetGroup { - protected final KeyStorage list; + protected final AEKeyStorage list; private final int slotAmountY; private int slotRowsAmount; protected final static int ROW_CHANGE_ID = 2; protected final static int CONTENT_CHANGE_ID = 3; protected final Object2LongMap changeMap = new Object2LongOpenHashMap<>(); - protected final KeyStorage cached = new KeyStorage(); + protected final AEKeyStorage cached = new AEKeyStorage(); protected final List displayList = new ArrayList<>(); - public AEListGridWidget(int x, int y, int slotsY, KeyStorage internalList) { + public AEListGridWidget(int x, int y, int slotsY, AEKeyStorage internalList) { super(x, y, 18 + 140, slotsY * 18); this.list = internalList; this.slotAmountY = slotsY; @@ -189,7 +189,7 @@ public void readInitialData(FriendlyByteBuf buffer) { public static class Item extends AEListGridWidget { - public Item(int x, int y, int slotsY, KeyStorage internalList) { + public Item(int x, int y, int slotsY, AEKeyStorage internalList) { super(x, y, slotsY, internalList); } @@ -211,7 +211,7 @@ protected Widget createDisplayWidget(int x, int y, int index) { public static class Fluid extends AEListGridWidget { - public Fluid(int x, int y, int slotsY, KeyStorage internalList) { + public Fluid(int x, int y, int slotsY, AEKeyStorage internalList) { super(x, y, slotsY, internalList); } diff --git a/src/main/java/com/gregtechceu/gtceu/integration/ae2/gui/widget/slot/AEConfigSlotWidget.java b/src/main/java/com/gregtechceu/gtceu/integration/ae2/gui/slot/AEConfigSlotWidget.java similarity index 93% rename from src/main/java/com/gregtechceu/gtceu/integration/ae2/gui/widget/slot/AEConfigSlotWidget.java rename to src/main/java/com/gregtechceu/gtceu/integration/ae2/gui/slot/AEConfigSlotWidget.java index b6d04d492ce..9c412638333 100644 --- a/src/main/java/com/gregtechceu/gtceu/integration/ae2/gui/widget/slot/AEConfigSlotWidget.java +++ b/src/main/java/com/gregtechceu/gtceu/integration/ae2/gui/slot/AEConfigSlotWidget.java @@ -1,7 +1,7 @@ -package com.gregtechceu.gtceu.integration.ae2.gui.widget.slot; +package com.gregtechceu.gtceu.integration.ae2.gui.slot; -import com.gregtechceu.gtceu.integration.ae2.gui.widget.ConfigWidget; -import com.gregtechceu.gtceu.integration.ae2.slot.IConfigurableSlot; +import com.gregtechceu.gtceu.integration.ae2.gui.ConfigWidget; +import com.gregtechceu.gtceu.integration.ae2.slot.ConfigurableSlot; import com.lowdragmc.lowdraglib.gui.widget.Widget; import com.lowdragmc.lowdraglib.utils.Position; @@ -43,7 +43,7 @@ public AEConfigSlotWidget(Position pos, Size size, ConfigWidget widget, int inde @Override public void drawInForeground(@NotNull GuiGraphics graphics, int mouseX, int mouseY, float partialTicks) { super.drawInForeground(graphics, mouseX, mouseY, partialTicks); - IConfigurableSlot slot = this.parentWidget.getDisplay(this.index); + ConfigurableSlot slot = this.parentWidget.getDisplay(this.index); if (slot.getConfig() == null) { if (mouseOverConfig(mouseX, mouseY)) { List hoverStringList = new ArrayList<>(); diff --git a/src/main/java/com/gregtechceu/gtceu/integration/ae2/gui/widget/slot/AEFluidConfigSlotWidget.java b/src/main/java/com/gregtechceu/gtceu/integration/ae2/gui/slot/AEFluidConfigSlotWidget.java similarity index 92% rename from src/main/java/com/gregtechceu/gtceu/integration/ae2/gui/widget/slot/AEFluidConfigSlotWidget.java rename to src/main/java/com/gregtechceu/gtceu/integration/ae2/gui/slot/AEFluidConfigSlotWidget.java index bbf171ffbe9..c5b3f16ebe4 100644 --- a/src/main/java/com/gregtechceu/gtceu/integration/ae2/gui/widget/slot/AEFluidConfigSlotWidget.java +++ b/src/main/java/com/gregtechceu/gtceu/integration/ae2/gui/slot/AEFluidConfigSlotWidget.java @@ -1,12 +1,10 @@ -package com.gregtechceu.gtceu.integration.ae2.gui.widget.slot; +package com.gregtechceu.gtceu.integration.ae2.gui.slot; import com.gregtechceu.gtceu.api.gui.GuiTextures; import com.gregtechceu.gtceu.api.gui.misc.IGhostFluidTarget; -import com.gregtechceu.gtceu.integration.ae2.gui.widget.ConfigWidget; -import com.gregtechceu.gtceu.integration.ae2.slot.ExportOnlyAEFluidSlot; -import com.gregtechceu.gtceu.integration.ae2.slot.ExportOnlyAESlot; -import com.gregtechceu.gtceu.integration.ae2.slot.IConfigurableSlot; -import com.gregtechceu.gtceu.integration.ae2.utils.AEUtil; +import com.gregtechceu.gtceu.integration.ae2.gui.ConfigWidget; +import com.gregtechceu.gtceu.integration.ae2.slot.ConfigurableFluidSlot; +import com.gregtechceu.gtceu.integration.ae2.slot.ConfigurableSlot; import com.gregtechceu.gtceu.utils.FormattingUtil; import com.gregtechceu.gtceu.utils.GTMath; @@ -49,7 +47,7 @@ public AEFluidConfigSlotWidget(int x, int y, ConfigWidget widget, int index) { public void drawInBackground(@NotNull GuiGraphics graphics, int mouseX, int mouseY, float partialTicks) { super.drawInBackground(graphics, mouseX, mouseY, partialTicks); Position position = getPosition(); - IConfigurableSlot slot = this.parentWidget.getDisplay(this.index); + ConfigurableSlot slot = this.parentWidget.getDisplay(this.index); GenericStack config = slot.getConfig(); GenericStack stock = slot.getStock(); drawSlots(graphics, mouseX, mouseY, position.x, position.y, parentWidget.isAutoPull()); @@ -148,7 +146,7 @@ public boolean mouseClicked(double mouseX, double mouseY, int button) { @Override public void handleClientAction(int id, FriendlyByteBuf buffer) { super.handleClientAction(id, buffer); - IConfigurableSlot slot = this.parentWidget.getConfig(this.index); + ConfigurableSlot slot = this.parentWidget.getConfig(this.index); if (id == REMOVE_ID) { slot.setConfig(null); this.parentWidget.disableAmount(); @@ -167,7 +165,7 @@ public void handleClientAction(int id, FriendlyByteBuf buffer) { if (id == AMOUNT_CHANGE_ID) { if (slot.getConfig() != null) { int amt = buffer.readInt(); - slot.setConfig(ExportOnlyAESlot.copy(slot.getConfig(), amt)); + slot.setConfig(ConfigurableSlot.copy(slot.getConfig(), amt)); writeUpdateInfo(AMOUNT_CHANGE_ID, buf -> buf.writeInt(amt)); } } @@ -186,7 +184,7 @@ public void handleClientAction(int id, FriendlyByteBuf buffer) { @Override public void readUpdateInfo(int id, FriendlyByteBuf buffer) { super.readUpdateInfo(id, buffer); - IConfigurableSlot slot = this.parentWidget.getDisplay(this.index); + ConfigurableSlot slot = this.parentWidget.getDisplay(this.index); if (id == REMOVE_ID) { slot.setConfig(null); } @@ -198,7 +196,7 @@ public void readUpdateInfo(int id, FriendlyByteBuf buffer) { if (id == AMOUNT_CHANGE_ID) { if (slot.getConfig() != null) { int amt = buffer.readInt(); - slot.setConfig(ExportOnlyAESlot.copy(slot.getConfig(), amt)); + slot.setConfig(ConfigurableSlot.copy(slot.getConfig(), amt)); } } if (id == PICK_UP_ID) { @@ -212,7 +210,7 @@ public void readUpdateInfo(int id, FriendlyByteBuf buffer) { if (key.hasTag()) { stack.setTag(key.getTag().copy()); } - GenericStack stack1 = ExportOnlyAESlot.copy(slot.getStock(), + GenericStack stack1 = ConfigurableSlot.copy(slot.getStock(), Math.max(0, (slot.getStock().amount() - stack.getAmount()))); slot.setStock(stack1.amount() == 0 ? null : stack1); } @@ -244,7 +242,7 @@ public void acceptFluid(FluidStack fluidStack) { public boolean mouseWheelMove(double mouseX, double mouseY, double wheelDelta) { // Only allow the amount scrolling if not stocking, as amount is useless for stocking if (parentWidget.isStocking()) return false; - IConfigurableSlot slot = this.parentWidget.getDisplay(this.index); + ConfigurableSlot slot = this.parentWidget.getDisplay(this.index); Rect2i rectangle = toRectangleBox(); rectangle.setHeight(rectangle.getHeight() / 2); if (slot.getConfig() == null || wheelDelta == 0 || !rectangle.contains((int) mouseX, (int) mouseY)) { @@ -270,8 +268,8 @@ public boolean mouseWheelMove(double mouseX, double mouseY, double wheelDelta) { } private int tryClickContainer(boolean isShiftKeyDown) { - ExportOnlyAEFluidSlot fluidTank = this.parentWidget - .getConfig(this.index) instanceof ExportOnlyAEFluidSlot fluid ? fluid : null; + ConfigurableFluidSlot fluidTank = this.parentWidget + .getConfig(this.index) instanceof ConfigurableFluidSlot fluid ? fluid : null; if (fluidTank == null) return -1; Player player = gui.entityPlayer; ItemStack currentStack = gui.getModularUIContainer().getCarried(); diff --git a/src/main/java/com/gregtechceu/gtceu/integration/ae2/gui/widget/slot/AEItemConfigSlotWidget.java b/src/main/java/com/gregtechceu/gtceu/integration/ae2/gui/slot/AEItemConfigSlotWidget.java similarity index 93% rename from src/main/java/com/gregtechceu/gtceu/integration/ae2/gui/widget/slot/AEItemConfigSlotWidget.java rename to src/main/java/com/gregtechceu/gtceu/integration/ae2/gui/slot/AEItemConfigSlotWidget.java index 574b4fdf276..8f34487a238 100644 --- a/src/main/java/com/gregtechceu/gtceu/integration/ae2/gui/widget/slot/AEItemConfigSlotWidget.java +++ b/src/main/java/com/gregtechceu/gtceu/integration/ae2/gui/slot/AEItemConfigSlotWidget.java @@ -1,10 +1,9 @@ -package com.gregtechceu.gtceu.integration.ae2.gui.widget.slot; +package com.gregtechceu.gtceu.integration.ae2.gui.slot; import com.gregtechceu.gtceu.api.gui.GuiTextures; import com.gregtechceu.gtceu.api.gui.misc.IGhostItemTarget; -import com.gregtechceu.gtceu.integration.ae2.gui.widget.ConfigWidget; -import com.gregtechceu.gtceu.integration.ae2.slot.ExportOnlyAESlot; -import com.gregtechceu.gtceu.integration.ae2.slot.IConfigurableSlot; +import com.gregtechceu.gtceu.integration.ae2.gui.ConfigWidget; +import com.gregtechceu.gtceu.integration.ae2.slot.ConfigurableSlot; import com.lowdragmc.lowdraglib.gui.util.TextFormattingUtil; import com.lowdragmc.lowdraglib.utils.Position; @@ -35,7 +34,7 @@ public AEItemConfigSlotWidget(int x, int y, ConfigWidget widget, int index) { public void drawInBackground(@NotNull GuiGraphics graphics, int mouseX, int mouseY, float partialTicks) { super.drawInBackground(graphics, mouseX, mouseY, partialTicks); Position position = getPosition(); - IConfigurableSlot slot = this.parentWidget.getDisplay(this.index); + ConfigurableSlot slot = this.parentWidget.getDisplay(this.index); GenericStack config = slot.getConfig(); GenericStack stock = slot.getStock(); drawSlots(graphics, mouseX, mouseY, position.x, position.y, parentWidget.isAutoPull()); @@ -127,7 +126,7 @@ public boolean mouseClicked(double mouseX, double mouseY, int button) { @Override public void handleClientAction(int id, FriendlyByteBuf buffer) { super.handleClientAction(id, buffer); - IConfigurableSlot slot = this.parentWidget.getConfig(this.index); + ConfigurableSlot slot = this.parentWidget.getConfig(this.index); if (id == REMOVE_ID) { slot.setConfig(null); this.parentWidget.disableAmount(); @@ -159,7 +158,7 @@ public void handleClientAction(int id, FriendlyByteBuf buffer) { stack.setTag(key.getTag().copy()); } this.gui.getModularUIContainer().setCarried(stack); - GenericStack stack1 = ExportOnlyAESlot.copy(slot.getStock(), + GenericStack stack1 = ConfigurableSlot.copy(slot.getStock(), Math.max(0, (slot.getStock().amount() - stack.getCount()))); slot.setStock(stack1.amount() == 0 ? null : stack1); writeUpdateInfo(PICK_UP_ID, buf -> {}); @@ -171,7 +170,7 @@ public void handleClientAction(int id, FriendlyByteBuf buffer) { @Override public void readUpdateInfo(int id, FriendlyByteBuf buffer) { super.readUpdateInfo(id, buffer); - IConfigurableSlot slot = this.parentWidget.getDisplay(this.index); + ConfigurableSlot slot = this.parentWidget.getDisplay(this.index); if (id == REMOVE_ID) { slot.setConfig(null); } @@ -193,7 +192,7 @@ public void readUpdateInfo(int id, FriendlyByteBuf buffer) { stack.setTag(key.getTag().copy()); } this.gui.getModularUIContainer().setCarried(stack); - GenericStack stack1 = ExportOnlyAESlot.copy(slot.getStock(), + GenericStack stack1 = ConfigurableSlot.copy(slot.getStock(), Math.max(0, (slot.getStock().amount() - stack.getCount()))); slot.setStock(stack1.amount() == 0 ? null : stack1); } @@ -219,7 +218,7 @@ public void acceptItem(ItemStack itemStack) { public boolean mouseWheelMove(double mouseX, double mouseY, double wheelDelta) { // Only allow the amount scrolling if not stocking, as amount is useless for stocking if (parentWidget.isStocking()) return false; - IConfigurableSlot slot = this.parentWidget.getDisplay(this.index); + ConfigurableSlot slot = this.parentWidget.getDisplay(this.index); Rect2i rectangle = toRectangleBox(); rectangle.setHeight(rectangle.getHeight() / 2); if (slot.getConfig() == null || wheelDelta == 0 || !rectangle.contains((int) mouseX, (int) mouseY)) { diff --git a/src/main/java/com/gregtechceu/gtceu/integration/ae2/gui/widget/slot/AEPatternViewSlotWidget.java b/src/main/java/com/gregtechceu/gtceu/integration/ae2/gui/slot/AEPatternViewSlotWidget.java similarity index 98% rename from src/main/java/com/gregtechceu/gtceu/integration/ae2/gui/widget/slot/AEPatternViewSlotWidget.java rename to src/main/java/com/gregtechceu/gtceu/integration/ae2/gui/slot/AEPatternViewSlotWidget.java index a3d0f477b93..465e9271be6 100644 --- a/src/main/java/com/gregtechceu/gtceu/integration/ae2/gui/widget/slot/AEPatternViewSlotWidget.java +++ b/src/main/java/com/gregtechceu/gtceu/integration/ae2/gui/slot/AEPatternViewSlotWidget.java @@ -1,4 +1,4 @@ -package com.gregtechceu.gtceu.integration.ae2.gui.widget.slot; +package com.gregtechceu.gtceu.integration.ae2.gui.slot; import com.gregtechceu.gtceu.api.gui.widget.SlotWidget; diff --git a/src/main/java/com/gregtechceu/gtceu/integration/ae2/gui/widget/AEFluidConfigWidget.java b/src/main/java/com/gregtechceu/gtceu/integration/ae2/gui/widget/AEFluidConfigWidget.java deleted file mode 100644 index 2ebe1b3164e..00000000000 --- a/src/main/java/com/gregtechceu/gtceu/integration/ae2/gui/widget/AEFluidConfigWidget.java +++ /dev/null @@ -1,39 +0,0 @@ -package com.gregtechceu.gtceu.integration.ae2.gui.widget; - -import com.gregtechceu.gtceu.integration.ae2.gui.widget.slot.AEFluidConfigSlotWidget; -import com.gregtechceu.gtceu.integration.ae2.slot.ExportOnlyAEFluidList; -import com.gregtechceu.gtceu.integration.ae2.slot.ExportOnlyAEFluidSlot; -import com.gregtechceu.gtceu.integration.ae2.slot.IConfigurableSlot; - -import appeng.api.stacks.GenericStack; - -public class AEFluidConfigWidget extends ConfigWidget { - - private final ExportOnlyAEFluidList fluidList; - - public AEFluidConfigWidget(int x, int y, ExportOnlyAEFluidList list) { - super(x, y, list.getInventory(), list.isStocking()); - this.fluidList = list; - } - - @Override - void init() { - int line; - this.displayList = new IConfigurableSlot[this.config.length]; - this.cached = new IConfigurableSlot[this.config.length]; - for (int index = 0; index < this.config.length; index++) { - this.displayList[index] = new ExportOnlyAEFluidSlot(); - this.cached[index] = new ExportOnlyAEFluidSlot(); - line = index / 8; - this.addWidget(new AEFluidConfigSlotWidget((index - line * 8) * 18, line * (18 * 2 + 2), this, index)); - } - } - - public boolean hasStackInConfig(GenericStack stack) { - return fluidList.hasStackInConfig(stack, true); - } - - public boolean isAutoPull() { - return fluidList.isAutoPull(); - } -} diff --git a/src/main/java/com/gregtechceu/gtceu/integration/ae2/gui/widget/AEItemConfigWidget.java b/src/main/java/com/gregtechceu/gtceu/integration/ae2/gui/widget/AEItemConfigWidget.java deleted file mode 100644 index 167afbb34a5..00000000000 --- a/src/main/java/com/gregtechceu/gtceu/integration/ae2/gui/widget/AEItemConfigWidget.java +++ /dev/null @@ -1,39 +0,0 @@ -package com.gregtechceu.gtceu.integration.ae2.gui.widget; - -import com.gregtechceu.gtceu.integration.ae2.gui.widget.slot.AEItemConfigSlotWidget; -import com.gregtechceu.gtceu.integration.ae2.slot.ExportOnlyAEItemList; -import com.gregtechceu.gtceu.integration.ae2.slot.ExportOnlyAEItemSlot; -import com.gregtechceu.gtceu.integration.ae2.slot.IConfigurableSlot; - -import appeng.api.stacks.GenericStack; - -public class AEItemConfigWidget extends ConfigWidget { - - private final ExportOnlyAEItemList itemList; - - public AEItemConfigWidget(int x, int y, ExportOnlyAEItemList list) { - super(x, y, list.getInventory(), list.isStocking()); - this.itemList = list; - } - - @Override - void init() { - int line; - this.displayList = new IConfigurableSlot[this.config.length]; - this.cached = new IConfigurableSlot[this.config.length]; - for (int index = 0; index < this.config.length; index++) { - this.displayList[index] = new ExportOnlyAEItemSlot(); - this.cached[index] = new ExportOnlyAEItemSlot(); - line = index / 8; - this.addWidget(new AEItemConfigSlotWidget((index - line * 8) * 18, line * (18 * 2 + 2), this, index)); - } - } - - public boolean hasStackInConfig(GenericStack stack) { - return itemList.hasStackInConfig(stack, true); - } - - public boolean isAutoPull() { - return itemList.isAutoPull(); - } -} diff --git a/src/main/java/com/gregtechceu/gtceu/integration/ae2/machine/MEBusPartMachine.java b/src/main/java/com/gregtechceu/gtceu/integration/ae2/machine/MEBusPartMachine.java index 7bd09427d3b..2404d8fd227 100644 --- a/src/main/java/com/gregtechceu/gtceu/integration/ae2/machine/MEBusPartMachine.java +++ b/src/main/java/com/gregtechceu/gtceu/integration/ae2/machine/MEBusPartMachine.java @@ -1,70 +1,63 @@ package com.gregtechceu.gtceu.integration.ae2.machine; -import com.gregtechceu.gtceu.api.GTValues; +import appeng.api.networking.GridFlags; +import appeng.api.networking.IGridNode; +import appeng.api.networking.security.IActionHost; +import appeng.api.networking.security.IActionSource; import com.gregtechceu.gtceu.api.capability.recipe.IO; import com.gregtechceu.gtceu.api.machine.IMachineBlockEntity; import com.gregtechceu.gtceu.common.machine.multiblock.part.ItemBusPartMachine; +import com.gregtechceu.gtceu.config.ConfigHolder; import com.gregtechceu.gtceu.integration.ae2.machine.feature.IGridConnectedMachine; -import com.gregtechceu.gtceu.integration.ae2.machine.trait.GridNodeHolder; - -import com.lowdragmc.lowdraglib.syncdata.annotation.DescSynced; -import com.lowdragmc.lowdraglib.syncdata.annotation.Persisted; +import com.gregtechceu.gtceu.integration.ae2.machine.trait.GridNodeHost; +import com.gregtechceu.gtceu.utils.GTTransferUtils; import com.lowdragmc.lowdraglib.syncdata.field.ManagedFieldHolder; - -import net.minecraft.MethodsReturnNonnullByDefault; import net.minecraft.core.Direction; - -import appeng.api.networking.*; -import appeng.api.networking.security.IActionSource; -import lombok.Getter; -import lombok.Setter; +import org.jetbrains.annotations.Nullable; import java.util.EnumSet; -import javax.annotation.ParametersAreNonnullByDefault; - -@Getter -@ParametersAreNonnullByDefault -@MethodsReturnNonnullByDefault -public abstract class MEBusPartMachine extends ItemBusPartMachine implements IGridConnectedMachine { - - protected static final ManagedFieldHolder MANAGED_FIELD_HOLDER = new ManagedFieldHolder(MEBusPartMachine.class, - ItemBusPartMachine.MANAGED_FIELD_HOLDER); +public abstract class MEBusPartMachine extends ItemBusPartMachine implements IGridConnectedMachine, IActionHost { - @Persisted - protected final GridNodeHolder nodeHolder; + protected static final ManagedFieldHolder MANAGED_FIELD_HOLDER = new ManagedFieldHolder( + MEBusPartMachine.class, + ItemBusPartMachine.MANAGED_FIELD_HOLDER + ); - @DescSynced - @Getter - @Setter - protected boolean isOnline; + protected final GridNodeHost nodeHost; + protected final IActionSource actionSource = IActionSource.ofMachine(this); - protected final IActionSource actionSource; - - public MEBusPartMachine(IMachineBlockEntity holder, IO io, Object... args) { - super(holder, GTValues.LuV, io, args); - this.nodeHolder = createNodeHolder(); - this.actionSource = IActionSource.ofMachine(nodeHolder.getMainNode()::getNode); + // bus LuV + // UHV FluidHatchPartMachine.INITIAL_TANK_CAPACITY_1X 16 + public MEBusPartMachine(IMachineBlockEntity holder, int tier, IO io, Object... args) { + super(holder, tier, io, args); + this.nodeHost = createNodeHost(); } - protected GridNodeHolder createNodeHolder() { - return new GridNodeHolder(this); + protected GridNodeHost createNodeHost() { + GridNodeHost host = new GridNodeHost(this); + host.getMainNode() + .setFlags(GridFlags.REQUIRE_CHANNEL) + .setIdlePowerUsage(ConfigHolder.INSTANCE.compat.ae2.meHatchEnergyUsage) + .setExposedOnSides( + hasFrontFacing() ? EnumSet.of(getFrontFacing()) : EnumSet.allOf(Direction.class) + ); + return host; } - @Override - public IManagedGridNode getMainNode() { - return nodeHolder.getMainNode(); + protected boolean isMESyncTick() { + int interval = ConfigHolder.INSTANCE.compat.ae2.updateIntervals; + return getOffsetTimer() % interval == 0; } - @Override - public void onMainNodeStateChanged(IGridNodeListener.State reason) { - IGridConnectedMachine.super.onMainNodeStateChanged(reason); - this.updateInventorySubscription(); + protected boolean shouldUpdateSubscription(Direction newFacing) { + return isWorkingEnabled() && ((io.support(IO.OUT) && !getInventory().isEmpty()) || io.support(IO.IN)) && + GTTransferUtils.hasAdjacentItemHandler(getLevel(), getPos(), newFacing); } @Override - protected void updateInventorySubscription() { - if (shouldSubscribe()) { + protected void updateInventorySubscription(Direction newFacing) { + if (shouldUpdateSubscription(newFacing)) { autoIOSubs = subscribeServerTick(autoIOSubs, this::autoIO); } else if (autoIOSubs != null) { autoIOSubs.unsubscribe(); @@ -72,25 +65,19 @@ protected void updateInventorySubscription() { } } - protected boolean shouldSubscribe() { - return isWorkingEnabled() && isOnline(); + @Override + public @Nullable IGridNode getActionableNode() { + return nodeHost.getMainNode().getNode(); } @Override public void onRotated(Direction oldFacing, Direction newFacing) { super.onRotated(oldFacing, newFacing); - getMainNode().setExposedOnSides(EnumSet.of(newFacing)); + nodeHost.getMainNode().setExposedOnSides(EnumSet.of(newFacing)); } @Override public ManagedFieldHolder getFieldHolder() { return MANAGED_FIELD_HOLDER; } - - // By returning false here, we don't allow shift-clicking - // with a screwdriver to swap the IO. - @Override - public boolean swapIO() { - return false; - } } diff --git a/src/main/java/com/gregtechceu/gtceu/integration/ae2/machine/MEHatchPartMachine.java b/src/main/java/com/gregtechceu/gtceu/integration/ae2/machine/MEHatchPartMachine.java index c7237baaf41..cfc417ba558 100644 --- a/src/main/java/com/gregtechceu/gtceu/integration/ae2/machine/MEHatchPartMachine.java +++ b/src/main/java/com/gregtechceu/gtceu/integration/ae2/machine/MEHatchPartMachine.java @@ -1,71 +1,61 @@ package com.gregtechceu.gtceu.integration.ae2.machine; -import com.gregtechceu.gtceu.api.GTValues; +import appeng.api.networking.GridFlags; +import appeng.api.networking.IGridNode; +import appeng.api.networking.security.IActionHost; +import appeng.api.networking.security.IActionSource; import com.gregtechceu.gtceu.api.capability.recipe.IO; import com.gregtechceu.gtceu.api.machine.IMachineBlockEntity; import com.gregtechceu.gtceu.common.machine.multiblock.part.FluidHatchPartMachine; +import com.gregtechceu.gtceu.config.ConfigHolder; import com.gregtechceu.gtceu.integration.ae2.machine.feature.IGridConnectedMachine; -import com.gregtechceu.gtceu.integration.ae2.machine.trait.GridNodeHolder; - -import com.lowdragmc.lowdraglib.syncdata.annotation.DescSynced; -import com.lowdragmc.lowdraglib.syncdata.annotation.Persisted; +import com.gregtechceu.gtceu.integration.ae2.machine.trait.GridNodeHost; +import com.gregtechceu.gtceu.utils.GTTransferUtils; import com.lowdragmc.lowdraglib.syncdata.field.ManagedFieldHolder; - -import net.minecraft.MethodsReturnNonnullByDefault; import net.minecraft.core.Direction; - -import appeng.api.networking.*; -import appeng.api.networking.security.IActionSource; -import lombok.Getter; -import lombok.Setter; +import org.jetbrains.annotations.Nullable; import java.util.EnumSet; -import javax.annotation.ParametersAreNonnullByDefault; - -@ParametersAreNonnullByDefault -@MethodsReturnNonnullByDefault -public abstract class MEHatchPartMachine extends FluidHatchPartMachine implements IGridConnectedMachine { - - protected static final ManagedFieldHolder MANAGED_FIELD_HOLDER = new ManagedFieldHolder(MEHatchPartMachine.class, - FluidHatchPartMachine.MANAGED_FIELD_HOLDER); - - protected final static int CONFIG_SIZE = 16; +public abstract class MEHatchPartMachine extends FluidHatchPartMachine implements IGridConnectedMachine, IActionHost { - @Persisted - protected final GridNodeHolder nodeHolder; + protected static final ManagedFieldHolder MANAGED_FIELD_HOLDER = new ManagedFieldHolder( + MEHatchPartMachine.class, + FluidHatchPartMachine.MANAGED_FIELD_HOLDER + ); - @DescSynced - @Getter - @Setter - protected boolean isOnline; + protected final GridNodeHost nodeHost; + protected final IActionSource actionSource = IActionSource.ofMachine(this); - protected final IActionSource actionSource; - - public MEHatchPartMachine(IMachineBlockEntity holder, IO io, Object... args) { - super(holder, GTValues.UHV, io, FluidHatchPartMachine.INITIAL_TANK_CAPACITY_1X, CONFIG_SIZE, args); - this.nodeHolder = createNodeHolder(); - this.actionSource = IActionSource.ofMachine(nodeHolder.getMainNode()::getNode); + public MEHatchPartMachine(IMachineBlockEntity holder, int tier, IO io, int initialCapacity, int slots, Object... args) { + super(holder, tier, io, initialCapacity, slots, args); + this.nodeHost = createNodeHost(); } - protected GridNodeHolder createNodeHolder() { - return new GridNodeHolder(this); + protected GridNodeHost createNodeHost() { + GridNodeHost host = new GridNodeHost(this); + host.getMainNode() + .setFlags(GridFlags.REQUIRE_CHANNEL) + .setIdlePowerUsage(ConfigHolder.INSTANCE.compat.ae2.meHatchEnergyUsage) + .setExposedOnSides( + hasFrontFacing() ? EnumSet.of(getFrontFacing()) : EnumSet.allOf(Direction.class) + ); + return host; } - @Override - public IManagedGridNode getMainNode() { - return nodeHolder.getMainNode(); + protected boolean isMESyncTick() { + int interval = ConfigHolder.INSTANCE.compat.ae2.updateIntervals; + return getOffsetTimer() % interval == 0; } - @Override - public void onMainNodeStateChanged(IGridNodeListener.State reason) { - IGridConnectedMachine.super.onMainNodeStateChanged(reason); - this.updateTankSubscription(); + protected boolean shouldUpdateSubscription(Direction newFacing) { + return isWorkingEnabled() && ((io.support(IO.OUT) && !tank.isEmpty()) || io.support(IO.IN)) && + GTTransferUtils.hasAdjacentFluidHandler(getLevel(), getPos(), newFacing); } @Override - protected void updateTankSubscription() { - if (shouldSubscribe()) { + protected void updateTankSubscription(Direction newFacing) { + if (shouldUpdateSubscription(newFacing)) { autoIOSubs = subscribeServerTick(autoIOSubs, this::autoIO); } else if (autoIOSubs != null) { autoIOSubs.unsubscribe(); @@ -73,25 +63,19 @@ protected void updateTankSubscription() { } } - protected boolean shouldSubscribe() { - return isWorkingEnabled() && isOnline(); + @Override + public @Nullable IGridNode getActionableNode() { + return nodeHost.getMainNode().getNode(); } @Override public void onRotated(Direction oldFacing, Direction newFacing) { super.onRotated(oldFacing, newFacing); - getMainNode().setExposedOnSides(EnumSet.of(newFacing)); + nodeHost.getMainNode().setExposedOnSides(EnumSet.of(newFacing)); } @Override public ManagedFieldHolder getFieldHolder() { return MANAGED_FIELD_HOLDER; } - - // By returning false here, we don't allow shift-clicking - // with a screwdriver to swap the IO. - @Override - public boolean swapIO() { - return false; - } } diff --git a/src/main/java/com/gregtechceu/gtceu/integration/ae2/machine/MEInputBusPartMachine.java b/src/main/java/com/gregtechceu/gtceu/integration/ae2/machine/MEInputBusPartMachine.java index d1c45b4f5c8..ec958c61558 100644 --- a/src/main/java/com/gregtechceu/gtceu/integration/ae2/machine/MEInputBusPartMachine.java +++ b/src/main/java/com/gregtechceu/gtceu/integration/ae2/machine/MEInputBusPartMachine.java @@ -1,217 +1,185 @@ package com.gregtechceu.gtceu.integration.ae2.machine; +import appeng.api.config.Actionable; +import appeng.api.networking.IGrid; +import appeng.api.networking.IGridNodeListener; +import appeng.api.networking.IManagedGridNode; +import appeng.api.stacks.AEItemKey; +import appeng.api.stacks.GenericStack; +import appeng.api.storage.MEStorage; import com.gregtechceu.gtceu.api.capability.recipe.IO; import com.gregtechceu.gtceu.api.machine.IMachineBlockEntity; -import com.gregtechceu.gtceu.api.machine.feature.IDataStickInteractable; -import com.gregtechceu.gtceu.api.machine.feature.IHasCircuitSlot; -import com.gregtechceu.gtceu.api.machine.feature.IMachineLife; +import com.gregtechceu.gtceu.api.machine.feature.IDataStickConfigurable; import com.gregtechceu.gtceu.api.machine.trait.NotifiableItemStackHandler; -import com.gregtechceu.gtceu.common.item.IntCircuitBehaviour; -import com.gregtechceu.gtceu.integration.ae2.gui.widget.AEItemConfigWidget; -import com.gregtechceu.gtceu.integration.ae2.slot.ExportOnlyAEItemList; -import com.gregtechceu.gtceu.integration.ae2.slot.ExportOnlyAEItemSlot; -import com.gregtechceu.gtceu.utils.GTMath; - -import com.lowdragmc.lowdraglib.gui.widget.LabelWidget; -import com.lowdragmc.lowdraglib.gui.widget.Widget; -import com.lowdragmc.lowdraglib.gui.widget.WidgetGroup; +import com.gregtechceu.gtceu.api.transfer.item.CustomItemStackHandler; +import com.gregtechceu.gtceu.integration.ae2.utils.GenericStackHandler; +import com.gregtechceu.gtceu.integration.ae2.utils.MEConfigUtil; +import com.lowdragmc.lowdraglib.syncdata.annotation.Persisted; import com.lowdragmc.lowdraglib.syncdata.field.ManagedFieldHolder; -import com.lowdragmc.lowdraglib.utils.Position; - -import net.minecraft.MethodsReturnNonnullByDefault; +import net.minecraft.core.Direction; import net.minecraft.nbt.CompoundTag; import net.minecraft.network.chat.Component; -import net.minecraft.world.InteractionResult; -import net.minecraft.world.entity.player.Player; import net.minecraft.world.item.ItemStack; -import appeng.api.config.Actionable; -import appeng.api.stacks.GenericStack; -import appeng.api.storage.MEStorage; +public class MEInputBusPartMachine extends MEBusPartMachine implements IDataStickConfigurable { -import javax.annotation.ParametersAreNonnullByDefault; + static final String CONFIG_KEY = "MEInputBus"; + static final Component CONFIG_NAME = Component.translatable("gtceu.machine.me.item_import.data_stick.name"); -@ParametersAreNonnullByDefault -@MethodsReturnNonnullByDefault -public class MEInputBusPartMachine extends MEBusPartMachine - implements IDataStickInteractable, IMachineLife, IHasCircuitSlot { + protected static final ManagedFieldHolder MANAGED_FIELD_HOLDER = new ManagedFieldHolder( + MEInputBusPartMachine.class, + MEBusPartMachine.MANAGED_FIELD_HOLDER + ); - protected static final ManagedFieldHolder MANAGED_FIELD_HOLDER = new ManagedFieldHolder(MEInputBusPartMachine.class, - MEBusPartMachine.MANAGED_FIELD_HOLDER); - protected final static int CONFIG_SIZE = 16; + @Persisted + protected final GenericStackHandler configHandler; + protected final int slots; - protected ExportOnlyAEItemList aeItemHandler; - - public MEInputBusPartMachine(IMachineBlockEntity holder, Object... args) { - super(holder, IO.IN, args); + public MEInputBusPartMachine(IMachineBlockEntity holder, int tier, int slots, Object... args) { + super(holder, tier, IO.IN, args); + this.configHandler = new GenericStackHandler(slots); + this.slots = slots; } - ///////////////////////////////// - // ***** Machine LifeCycle ****// - ///////////////////////////////// - @Override - public void onMachineRemoved() { - flushInventory(); + protected NotifiableItemStackHandler createInventory(Object... args) { + return new NotifiableItemStackHandler( + this, + getInventorySize(), + IO.IN, + IO.NONE, + slots -> new CustomItemStackHandler(slots) { + @Override + public int getSlotLimit(int slot) { + return Integer.MAX_VALUE; + } + + @Override + protected int getStackLimit(int slot, ItemStack stack) { + return Integer.MAX_VALUE; + } + } + ); } @Override - protected NotifiableItemStackHandler createInventory(Object... args) { - this.aeItemHandler = new ExportOnlyAEItemList(this, CONFIG_SIZE); - return this.aeItemHandler; + protected boolean shouldUpdateSubscription(Direction newFacing) { + IManagedGridNode node = nodeHost.getMainNode(); + return isWorkingEnabled() && node.isActive(); } @Override - public ManagedFieldHolder getFieldHolder() { - return MANAGED_FIELD_HOLDER; + protected int getInventorySize() { + return slots; } - ///////////////////////////////// - // ********** Sync ME *********// - ///////////////////////////////// + @Override + public boolean swapIO() { + return false; + } @Override - public void autoIO() { - if (!this.isWorkingEnabled()) return; - if (!this.shouldSyncME()) return; + protected void autoIO() { + if (!isMESyncTick()) return; - if (this.updateMEStatus()) { - this.syncME(); - this.updateInventorySubscription(); - } - } + IGrid grid = nodeHost.getMainNode().getGrid(); + if (grid == null) return; - protected void syncME() { - MEStorage networkInv = this.getMainNode().getGrid().getStorageService().getInventory(); - for (ExportOnlyAEItemSlot aeSlot : this.aeItemHandler.getInventory()) { - // Try to clear the wrong item - GenericStack exceedItem = aeSlot.exceedStack(); - if (exceedItem != null) { - long total = exceedItem.amount(); - long inserted = networkInv.insert(exceedItem.what(), exceedItem.amount(), Actionable.MODULATE, - this.actionSource); - if (inserted > 0) { - aeSlot.extractItem(0, GTMath.saturatedCast(inserted), false); - continue; - } else { - aeSlot.extractItem(0, GTMath.saturatedCast(total), false); - } - } - // Fill it - GenericStack reqItem = aeSlot.requestStack(); - if (reqItem != null) { - long extracted = networkInv.extract(reqItem.what(), reqItem.amount(), Actionable.MODULATE, - this.actionSource); - if (extracted != 0) { - aeSlot.addStack(new GenericStack(reqItem.what(), extracted)); - } + MEStorage networkInv = grid.getStorageService().getInventory(); + NotifiableItemStackHandler inventory = getInventory(); + + for (int i = 0; i < configHandler.getSlots(); i++) { + GenericStack configStack = configHandler.getStackInSlot(i); + if (configStack == null) continue; + AEItemKey configKey = (AEItemKey) configStack.what(); + long configAmount = configStack.amount(); + + // Ensure config amount does not exceed slot limit + if (configAmount > inventory.getSlotLimit(i)) { + throw new IllegalArgumentException("Config amount exceeds slot capacity!"); } - } - } - protected void flushInventory() { - var grid = getMainNode().getGrid(); - if (grid != null) { - for (var aeSlot : aeItemHandler.getInventory()) { - GenericStack stock = aeSlot.getStock(); - if (stock != null) { - grid.getStorageService().getInventory().insert(stock.what(), stock.amount(), Actionable.MODULATE, - actionSource); - } + // Ensure item in slot matches the config key + ItemStack stackInSlot = inventory.getStackInSlot(i); + if (!stackInSlot.isEmpty() && !configKey.matches(stackInSlot)) continue; + // Ensure slot has enough space + int actualAmount = stackInSlot.getCount(); + if (actualAmount >= configAmount) continue; + + ItemStack requestedStack = configKey.toStack(Math.toIntExact(configAmount - actualAmount)); + int inserted = requestedStack.getCount() - inventory.insertItem(i, requestedStack, true).getCount(); + if (inserted <= 0) continue; + + int extracted = Math.toIntExact( + networkInv.extract(configKey, inserted, Actionable.MODULATE, actionSource) + ); + if (extracted > 0) { + requestedStack.setCount(extracted); + inventory.insertItem(i, requestedStack, false); } } } - /////////////////////////////// - // ********** GUI ***********// - /////////////////////////////// - @Override - public Widget createUIWidget() { - WidgetGroup group = new WidgetGroup(new Position(0, 0)); - // ME Network status - group.addWidget(new LabelWidget(3, 0, () -> this.isOnline ? - "gtceu.gui.me_network.online" : - "gtceu.gui.me_network.offline")); - - // Config slots - group.addWidget(new AEItemConfigWidget(3, 10, this.aeItemHandler)); + public void onMainNodeStateChanged(IGridNodeListener.State reason) { + super.onMainNodeStateChanged(reason); + updateInventorySubscription(); + } - return group; + @Override + public void onMachineRemoved() { + nodeHost.getMainNode().ifPresent(grid -> { + var networkInv = grid.getStorageService().getInventory(); + NotifiableItemStackHandler inventory = getInventory(); + for (int i = 0; i < inventory.getSlots(); i++) { + ItemStack stack = inventory.getStackInSlot(i); + if (stack.isEmpty()) continue; + networkInv.insert(AEItemKey.of(stack), stack.getCount(), Actionable.MODULATE, actionSource); + } + }); + super.onMachineRemoved(); } - //////////////////////////////// - // ******* Interaction *******// - //////////////////////////////// +// @Override +// public Widget createUIWidget() { +// WidgetGroup group = new WidgetGroup(new Position(0, 0)); +// // ME Network status +// group.addWidget(new LabelWidget(3, 0, () -> this.isOnline ? +// "gtceu.gui.me_network.online" : +// "gtceu.gui.me_network.offline")); +// +// // Config slots +// group.addWidget(new AEItemConfigWidget(3, 10, this.aeItemHandler)); +// +// return group; +// } @Override - public final InteractionResult onDataStickShiftUse(Player player, ItemStack dataStick) { - if (!isRemote()) { - CompoundTag tag = new CompoundTag(); - tag.put("MEInputBus", writeConfigToTag()); - dataStick.setTag(tag); - dataStick.setHoverName(Component.translatable("gtceu.machine.me.item_import.data_stick.name")); - player.sendSystemMessage(Component.translatable("gtceu.machine.me.import_copy_settings")); - } - return InteractionResult.SUCCESS; + public String getConfigKey() { + return CONFIG_KEY; } @Override - public final InteractionResult onDataStickUse(Player player, ItemStack dataStick) { - CompoundTag tag = dataStick.getTag(); - if (tag == null || !tag.contains("MEInputBus")) { - return InteractionResult.PASS; - } + public Component getConfigName() { + return CONFIG_NAME; + } - if (!isRemote()) { - readConfigFromTag(tag.getCompound("MEInputBus")); - this.updateInventorySubscription(); - player.sendSystemMessage(Component.translatable("gtceu.machine.me.import_paste_settings")); - } - return InteractionResult.sidedSuccess(isRemote()); + @Override + public void writeConfig(CompoundTag tag) { + MEConfigUtil.writeConfigHandler(tag, configHandler); + MEConfigUtil.writeGhostCircuit(tag, circuitInventory); + MEConfigUtil.writeDistinctBuses(tag, isDistinct()); } - //////////////////////////////// - // ****** Configuration ******// - //////////////////////////////// - - protected CompoundTag writeConfigToTag() { - CompoundTag tag = new CompoundTag(); - CompoundTag configStacks = new CompoundTag(); - tag.put("ConfigStacks", configStacks); - for (int i = 0; i < CONFIG_SIZE; i++) { - var slot = this.aeItemHandler.getInventory()[i]; - GenericStack config = slot.getConfig(); - if (config == null) { - continue; - } - CompoundTag stackTag = GenericStack.writeTag(config); - configStacks.put(Integer.toString(i), stackTag); - } - tag.putByte("GhostCircuit", - (byte) IntCircuitBehaviour.getCircuitConfiguration(circuitInventory.getStackInSlot(0))); - tag.putBoolean("DistinctBuses", isDistinct()); - return tag; + @Override + public void readConfig(CompoundTag tag) { + MEConfigUtil.readConfigHandler(tag, configHandler); + MEConfigUtil.readGhostCircuit(tag, circuitInventory); + MEConfigUtil.readDistinctBuses(tag, this::setDistinct); } - protected void readConfigFromTag(CompoundTag tag) { - if (tag.contains("ConfigStacks")) { - CompoundTag configStacks = tag.getCompound("ConfigStacks"); - for (int i = 0; i < CONFIG_SIZE; i++) { - String key = Integer.toString(i); - if (configStacks.contains(key)) { - CompoundTag configTag = configStacks.getCompound(key); - this.aeItemHandler.getInventory()[i].setConfig(GenericStack.readTag(configTag)); - } else { - this.aeItemHandler.getInventory()[i].setConfig(null); - } - } - } - if (tag.contains("GhostCircuit")) { - circuitInventory.setStackInSlot(0, IntCircuitBehaviour.stack(tag.getByte("GhostCircuit"))); - } - if (tag.contains("DistinctBuses")) { - setDistinct(tag.getBoolean("DistinctBuses")); - } + @Override + public ManagedFieldHolder getFieldHolder() { + return MANAGED_FIELD_HOLDER; } } diff --git a/src/main/java/com/gregtechceu/gtceu/integration/ae2/machine/MEInputHatchPartMachine.java b/src/main/java/com/gregtechceu/gtceu/integration/ae2/machine/MEInputHatchPartMachine.java index 14b821bf6dc..f5212c4a339 100644 --- a/src/main/java/com/gregtechceu/gtceu/integration/ae2/machine/MEInputHatchPartMachine.java +++ b/src/main/java/com/gregtechceu/gtceu/integration/ae2/machine/MEInputHatchPartMachine.java @@ -1,214 +1,163 @@ package com.gregtechceu.gtceu.integration.ae2.machine; +import appeng.api.config.Actionable; +import appeng.api.networking.IGrid; +import appeng.api.networking.IGridNodeListener; +import appeng.api.networking.IManagedGridNode; +import appeng.api.stacks.AEFluidKey; +import appeng.api.stacks.GenericStack; +import appeng.api.storage.MEStorage; import com.gregtechceu.gtceu.api.capability.recipe.IO; import com.gregtechceu.gtceu.api.machine.IMachineBlockEntity; -import com.gregtechceu.gtceu.api.machine.feature.IDataStickInteractable; -import com.gregtechceu.gtceu.api.machine.feature.IHasCircuitSlot; -import com.gregtechceu.gtceu.api.machine.feature.IMachineLife; +import com.gregtechceu.gtceu.api.machine.feature.IDataStickConfigurable; import com.gregtechceu.gtceu.api.machine.trait.NotifiableFluidTank; -import com.gregtechceu.gtceu.common.item.IntCircuitBehaviour; -import com.gregtechceu.gtceu.integration.ae2.gui.widget.AEFluidConfigWidget; -import com.gregtechceu.gtceu.integration.ae2.slot.ExportOnlyAEFluidList; -import com.gregtechceu.gtceu.integration.ae2.slot.ExportOnlyAEFluidSlot; -import com.gregtechceu.gtceu.utils.GTMath; - -import com.lowdragmc.lowdraglib.gui.widget.LabelWidget; -import com.lowdragmc.lowdraglib.gui.widget.Widget; -import com.lowdragmc.lowdraglib.gui.widget.WidgetGroup; +import com.gregtechceu.gtceu.integration.ae2.utils.GenericStackHandler; +import com.gregtechceu.gtceu.integration.ae2.utils.MEConfigUtil; +import com.lowdragmc.lowdraglib.syncdata.annotation.Persisted; import com.lowdragmc.lowdraglib.syncdata.field.ManagedFieldHolder; -import com.lowdragmc.lowdraglib.utils.Position; - -import net.minecraft.MethodsReturnNonnullByDefault; +import net.minecraft.core.Direction; import net.minecraft.nbt.CompoundTag; import net.minecraft.network.chat.Component; -import net.minecraft.world.InteractionResult; -import net.minecraft.world.entity.player.Player; -import net.minecraft.world.item.ItemStack; +import net.minecraftforge.fluids.FluidStack; import net.minecraftforge.fluids.capability.IFluidHandler; +import net.minecraftforge.fluids.capability.templates.FluidTank; -import appeng.api.config.Actionable; -import appeng.api.stacks.GenericStack; -import appeng.api.storage.MEStorage; - -import javax.annotation.ParametersAreNonnullByDefault; +public class MEInputHatchPartMachine extends MEHatchPartMachine implements IDataStickConfigurable { -@ParametersAreNonnullByDefault -@MethodsReturnNonnullByDefault -public class MEInputHatchPartMachine extends MEHatchPartMachine - implements IDataStickInteractable, IMachineLife, IHasCircuitSlot { + static final String CONFIG_KEY = "MEInputHatch"; + static final Component CONFIG_NAME = Component.translatable("gtceu.machine.me.fluid_import.data_stick.name"); protected static final ManagedFieldHolder MANAGED_FIELD_HOLDER = new ManagedFieldHolder( - MEInputHatchPartMachine.class, MEHatchPartMachine.MANAGED_FIELD_HOLDER); - - protected ExportOnlyAEFluidList aeFluidHandler; - - public MEInputHatchPartMachine(IMachineBlockEntity holder, Object... args) { - super(holder, IO.IN, args); - } + MEInputHatchPartMachine.class, + MEHatchPartMachine.MANAGED_FIELD_HOLDER + ); - ///////////////////////////////// - // ***** Machine LifeCycle ****// - ///////////////////////////////// + @Persisted + protected final GenericStackHandler configHandler; - @Override - public void onMachineRemoved() { - flushInventory(); + public MEInputHatchPartMachine(IMachineBlockEntity holder, int tier, int slots, Object... args) { + super(holder, tier, IO.IN, -1, slots, args); + this.configHandler = new GenericStackHandler(slots); } @Override protected NotifiableFluidTank createTank(int initialCapacity, int slots, Object... args) { - this.aeFluidHandler = new ExportOnlyAEFluidList(this, slots); - return aeFluidHandler; + return new NotifiableFluidTank(this, slots, Integer.MAX_VALUE, IO.IN, IO.NONE); } @Override - public ManagedFieldHolder getFieldHolder() { - return MANAGED_FIELD_HOLDER; + protected boolean shouldUpdateSubscription(Direction newFacing) { + IManagedGridNode node = nodeHost.getMainNode(); + return isWorkingEnabled() && node.isActive(); } - ///////////////////////////////// - // ********** Sync ME *********// - ///////////////////////////////// - @Override protected void autoIO() { - if (!this.isWorkingEnabled()) return; - if (!this.shouldSyncME()) return; + if (!isMESyncTick()) return; - if (this.updateMEStatus()) { - this.syncME(); - this.updateTankSubscription(); - } - } + IGrid grid = nodeHost.getMainNode().getGrid(); + if (grid == null) return; - protected void syncME() { - MEStorage networkInv = this.getMainNode().getGrid().getStorageService().getInventory(); - for (ExportOnlyAEFluidSlot aeTank : this.aeFluidHandler.getInventory()) { - // Try to clear the wrong fluid - GenericStack exceedFluid = aeTank.exceedStack(); - if (exceedFluid != null) { - int total = GTMath.saturatedCast(exceedFluid.amount()); - int inserted = GTMath - .saturatedCast(networkInv.insert(exceedFluid.what(), exceedFluid.amount(), Actionable.MODULATE, - this.actionSource)); - if (inserted > 0) { - aeTank.drain(inserted, IFluidHandler.FluidAction.EXECUTE); - continue; - } else { - aeTank.drain(total, IFluidHandler.FluidAction.EXECUTE); - } - } - // Fill it - GenericStack reqFluid = aeTank.requestStack(); - if (reqFluid != null) { - long extracted = networkInv.extract(reqFluid.what(), reqFluid.amount(), Actionable.MODULATE, - this.actionSource); - if (extracted > 0) { - aeTank.addStack(new GenericStack(reqFluid.what(), extracted)); - } + MEStorage networkInv = grid.getStorageService().getInventory(); + FluidTank[] tanks = tank.getStorages(); + + for (int i = 0; i < configHandler.getSlots(); i++) { + GenericStack configStack = configHandler.getStackInSlot(i); + if (configStack == null) continue; + AEFluidKey configKey = (AEFluidKey) configStack.what(); + long configAmount = configStack.amount(); + + FluidTank tank = tanks[i]; + // Ensure config amount does not exceed tank capacity + if (configAmount > tank.getCapacity()) { + throw new IllegalArgumentException("Config amount exceeds tank capacity!"); } - } - } - protected void flushInventory() { - var grid = getMainNode().getGrid(); - if (grid != null) { - for (var aeSlot : aeFluidHandler.getInventory()) { - GenericStack stock = aeSlot.getStock(); - if (stock != null) { - grid.getStorageService().getInventory().insert(stock.what(), stock.amount(), Actionable.MODULATE, - actionSource); - } + // Ensure fluid in tank matches the config key + if (!tank.isEmpty() && !configKey.matches(tank.getFluid())) continue; + // Ensure tank has enough space + int actualAmount = tank.getFluidAmount(); + if (actualAmount >= configAmount) continue; + + FluidStack requestedStack = configKey.toStack(Math.toIntExact(configAmount - actualAmount)); + int inserted = tank.fill( + requestedStack, + IFluidHandler.FluidAction.SIMULATE + ); + if (inserted <= 0) continue; + + int extracted = Math.toIntExact( + networkInv.extract(configKey, inserted, Actionable.MODULATE, actionSource) + ); + if (extracted > 0) { + requestedStack.setAmount(extracted); + tank.fill(requestedStack, IFluidHandler.FluidAction.EXECUTE); } } } - /////////////////////////////// - // ********** GUI ***********// - /////////////////////////////// - @Override - public Widget createUIWidget() { - WidgetGroup group = new WidgetGroup(new Position(0, 0)); - // ME Network status - group.addWidget(new LabelWidget(3, 0, () -> this.isOnline ? - "gtceu.gui.me_network.online" : - "gtceu.gui.me_network.offline")); + public boolean swapIO() { + return false; + } - // Config slots - group.addWidget(new AEFluidConfigWidget(3, 10, this.aeFluidHandler)); + @Override + public void onMainNodeStateChanged(IGridNodeListener.State reason) { + super.onMainNodeStateChanged(reason); + updateTankSubscription(); + } - return group; + @Override + public void onMachineRemoved() { + nodeHost.getMainNode().ifPresent(grid -> { + for (var storage : tank.getStorages()) { + FluidStack stack = storage.getFluid(); + if (stack.isEmpty()) continue; + grid.getStorageService().getInventory().insert( + AEFluidKey.of(stack), stack.getAmount(), Actionable.MODULATE, actionSource + ); + } + }); + super.onMachineRemoved(); } - //////////////////////////////// - // ******* Interaction *******// - //////////////////////////////// +// @Override +// public Widget createUIWidget() { +// WidgetGroup group = new WidgetGroup(new Position(0, 0)); +// // ME Network status +// group.addWidget(new LabelWidget(3, 0, () -> this.isOnline ? +// "gtceu.gui.me_network.online" : +// "gtceu.gui.me_network.offline")); +// +// // Config slots +// group.addWidget(new AEFluidConfigWidget(3, 10, this.aeFluidHandler)); +// return group; +// } @Override - public final InteractionResult onDataStickShiftUse(Player player, ItemStack dataStick) { - if (!isRemote()) { - CompoundTag tag = new CompoundTag(); - tag.put("MEInputHatch", writeConfigToTag()); - dataStick.setTag(tag); - dataStick.setHoverName(Component.translatable("gtceu.machine.me.fluid_import.data_stick.name")); - player.sendSystemMessage(Component.translatable("gtceu.machine.me.import_copy_settings")); - } - return InteractionResult.SUCCESS; + public String getConfigKey() { + return CONFIG_KEY; } @Override - public final InteractionResult onDataStickUse(Player player, ItemStack dataStick) { - CompoundTag tag = dataStick.getTag(); - if (tag == null || !tag.contains("MEInputHatch")) { - return InteractionResult.PASS; - } + public Component getConfigName() { + return CONFIG_NAME; + } - if (!isRemote()) { - readConfigFromTag(tag.getCompound("MEInputHatch")); - this.updateTankSubscription(); - player.sendSystemMessage(Component.translatable("gtceu.machine.me.import_paste_settings")); - } - return InteractionResult.sidedSuccess(isRemote()); + @Override + public void writeConfig(CompoundTag tag) { + MEConfigUtil.writeConfigHandler(tag, configHandler); + MEConfigUtil.writeGhostCircuit(tag, circuitInventory); } - //////////////////////////////// - // ****** Configuration ******// - //////////////////////////////// - - protected CompoundTag writeConfigToTag() { - CompoundTag tag = new CompoundTag(); - CompoundTag configStacks = new CompoundTag(); - tag.put("ConfigStacks", configStacks); - for (int i = 0; i < CONFIG_SIZE; i++) { - var slot = this.aeFluidHandler.getInventory()[i]; - GenericStack config = slot.getConfig(); - if (config == null) { - continue; - } - CompoundTag stackTag = GenericStack.writeTag(config); - configStacks.put(Integer.toString(i), stackTag); - } - tag.putByte("GhostCircuit", - (byte) IntCircuitBehaviour.getCircuitConfiguration(circuitInventory.getStackInSlot(0))); - return tag; + @Override + public void readConfig(CompoundTag tag) { + MEConfigUtil.readConfigHandler(tag, configHandler); + MEConfigUtil.readGhostCircuit(tag, circuitInventory); } - protected void readConfigFromTag(CompoundTag tag) { - if (tag.contains("ConfigStacks")) { - CompoundTag configStacks = tag.getCompound("ConfigStacks"); - for (int i = 0; i < CONFIG_SIZE; i++) { - String key = Integer.toString(i); - if (configStacks.contains(key)) { - CompoundTag configTag = configStacks.getCompound(key); - this.aeFluidHandler.getInventory()[i].setConfig(GenericStack.readTag(configTag)); - } else { - this.aeFluidHandler.getInventory()[i].setConfig(null); - } - } - } - if (tag.contains("GhostCircuit")) { - circuitInventory.setStackInSlot(0, IntCircuitBehaviour.stack(tag.getByte("GhostCircuit"))); - } + @Override + public ManagedFieldHolder getFieldHolder() { + return MANAGED_FIELD_HOLDER; } } diff --git a/src/main/java/com/gregtechceu/gtceu/integration/ae2/machine/MEOutputBusPartMachine.java b/src/main/java/com/gregtechceu/gtceu/integration/ae2/machine/MEOutputBusPartMachine.java index 6914f7782a3..f91cc226380 100644 --- a/src/main/java/com/gregtechceu/gtceu/integration/ae2/machine/MEOutputBusPartMachine.java +++ b/src/main/java/com/gregtechceu/gtceu/integration/ae2/machine/MEOutputBusPartMachine.java @@ -1,187 +1,100 @@ package com.gregtechceu.gtceu.integration.ae2.machine; +import appeng.api.networking.IGrid; +import appeng.api.networking.IGridNodeListener; +import appeng.api.networking.IManagedGridNode; +import appeng.api.storage.MEStorage; 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.IInteractedMachine; -import com.gregtechceu.gtceu.api.machine.feature.IMachineLife; import com.gregtechceu.gtceu.api.machine.trait.NotifiableItemStackHandler; -import com.gregtechceu.gtceu.api.transfer.item.CustomItemStackHandler; -import com.gregtechceu.gtceu.integration.ae2.gui.widget.list.AEListGridWidget; -import com.gregtechceu.gtceu.integration.ae2.utils.KeyStorage; - +import com.gregtechceu.gtceu.config.ConfigHolder; +import com.gregtechceu.gtceu.integration.ae2.gui.list.AEListGridWidget; +import com.gregtechceu.gtceu.integration.ae2.machine.trait.KeyStorageBackedHandler; +import com.gregtechceu.gtceu.integration.ae2.utils.AEKeyStorage; +import com.gregtechceu.gtceu.integration.ae2.utils.AEUtil; 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.annotation.Persisted; import com.lowdragmc.lowdraglib.syncdata.field.ManagedFieldHolder; +import net.minecraft.core.Direction; +import net.minecraft.world.level.Level; +import org.apache.commons.lang3.ArrayUtils; -import net.minecraft.MethodsReturnNonnullByDefault; -import net.minecraft.world.item.ItemStack; - -import appeng.api.config.Actionable; -import appeng.api.stacks.AEItemKey; -import lombok.NoArgsConstructor; -import org.jetbrains.annotations.NotNull; - -import java.util.Collections; -import java.util.List; - -import javax.annotation.ParametersAreNonnullByDefault; - -/** - * The Output Bus that can directly send its contents to ME storage network. - */ -@MethodsReturnNonnullByDefault -@ParametersAreNonnullByDefault -public class MEOutputBusPartMachine extends MEBusPartMachine implements IMachineLife, IInteractedMachine { +public class MEOutputBusPartMachine extends MEBusPartMachine { protected static final ManagedFieldHolder MANAGED_FIELD_HOLDER = new ManagedFieldHolder( - MEOutputBusPartMachine.class, MEBusPartMachine.MANAGED_FIELD_HOLDER); + MEOutputBusPartMachine.class, + MEBusPartMachine.MANAGED_FIELD_HOLDER + ); @Persisted - private KeyStorage internalBuffer; // Do not use KeyCounter, use our simple implementation + protected final AEKeyStorage keyStorage; - public MEOutputBusPartMachine(IMachineBlockEntity holder, Object... args) { - super(holder, IO.OUT, args); + public MEOutputBusPartMachine(IMachineBlockEntity holder, int tier, Object... args) { + super(holder, tier, IO.OUT, args = ArrayUtils.addAll(args, new AEKeyStorage())); + this.keyStorage = (AEKeyStorage) args[args.length - 1]; } - ///////////////////////////////// - // ***** Machine LifeCycle ****// - ///////////////////////////////// - @Override protected NotifiableItemStackHandler createInventory(Object... args) { - this.internalBuffer = new KeyStorage(); - return new InaccessibleInfiniteHandler(this); + return new KeyStorageBackedHandler(this, (AEKeyStorage) args[args.length - 1]); } @Override - public void onMachineRemoved() { - var grid = getMainNode().getGrid(); - if (grid != null && !internalBuffer.isEmpty()) { - for (var entry : internalBuffer) { - grid.getStorageService().getInventory().insert(entry.getKey(), entry.getLongValue(), - Actionable.MODULATE, actionSource); - } - } + protected boolean shouldUpdateSubscription(Direction newFacing) { + IManagedGridNode mainNode = nodeHost.getMainNode(); + return isWorkingEnabled() && mainNode.isActive() && !keyStorage.isEmpty(); } @Override - public ManagedFieldHolder getFieldHolder() { - return MANAGED_FIELD_HOLDER; - } + protected void autoIO() { + if (!isMESyncTick()) return; - ///////////////////////////////// - // ********** Sync ME *********// - ///////////////////////////////// + IGrid grid = nodeHost.getMainNode().getGrid(); + if (grid == null) return; + + AEUtil.transferTo(keyStorage, grid.getStorageService().getInventory(), actionSource, true); + } @Override - protected boolean shouldSubscribe() { - return super.shouldSubscribe() && !internalBuffer.storage.isEmpty(); + public void onMainNodeStateChanged(IGridNodeListener.State reason) { + super.onMainNodeStateChanged(reason); + updateInventorySubscription(); } @Override - public void autoIO() { - if (!this.shouldSyncME()) return; - if (this.updateMEStatus()) { - var grid = getMainNode().getGrid(); - if (grid != null && !internalBuffer.isEmpty()) { - internalBuffer.insertInventory(grid.getStorageService().getInventory(), actionSource); - } - this.updateInventorySubscription(); + public void onMachineRemoved() { + IManagedGridNode mainNode = nodeHost.getMainNode(); + if (!keyStorage.isEmpty() && mainNode.isActive()) { + assert mainNode.getGrid() != null; + MEStorage networkInv = mainNode.getGrid().getStorageService().getInventory(); + AEUtil.transferTo(keyStorage, networkInv, actionSource, false); } - } - /////////////////////////////// - // ********** GUI ***********// - /////////////////////////////// + Level level = getLevel(); + if (level != null && !level.isClientSide) { + AEUtil.dropAllItems(level, getPos(), keyStorage); + } + + if (!ConfigHolder.INSTANCE.machines.ghostCircuit) { + clearInventory(circuitInventory.storage); + } + } @Override public Widget createUIWidget() { WidgetGroup group = new WidgetGroup(0, 0, 170, 65); - // ME Network status - group.addWidget(new LabelWidget(5, 0, () -> this.isOnline ? - "gtceu.gui.me_network.online" : - "gtceu.gui.me_network.offline")); + group.addWidget(new LabelWidget(5, 0, () -> nodeHost.getMainNode().isActive() ? + "gtceu.gui.me_network.online" : "gtceu.gui.me_network.offline")); group.addWidget(new LabelWidget(5, 10, "gtceu.gui.waiting_list")); - // display list - group.addWidget(new AEListGridWidget.Item(5, 20, 3, this.internalBuffer)); - + group.addWidget(new AEListGridWidget.Item(5, 20, 3, this.keyStorage)); return group; } - private class InaccessibleInfiniteHandler extends NotifiableItemStackHandler { - - public InaccessibleInfiniteHandler(MetaMachine holder) { - super(holder, 1, IO.OUT, IO.NONE, ItemStackHandlerDelegate::new); - internalBuffer.setOnContentsChanged(this::onContentsChanged); - } - - @Override - public @NotNull List getContents() { - return Collections.emptyList(); - } - - @Override - public double getTotalContentAmount() { - return 0; - } - - @Override - public boolean isEmpty() { - return true; - } + @Override + public ManagedFieldHolder getFieldHolder() { + return MANAGED_FIELD_HOLDER; } - @NoArgsConstructor - private class ItemStackHandlerDelegate extends CustomItemStackHandler { - - // Necessary for InaccessibleInfiniteHandler - public ItemStackHandlerDelegate(Integer integer) { - super(); - } - - @Override - public int getSlots() { - return Short.MAX_VALUE; - } - - @Override - public int getSlotLimit(int slot) { - return Integer.MAX_VALUE; - } - - @Override - public ItemStack getStackInSlot(int slot) { - return ItemStack.EMPTY; - } - - @Override - public void setStackInSlot(int slot, ItemStack stack) { - // NO-OP - } - - @Override - public ItemStack insertItem(int slot, ItemStack stack, boolean simulate) { - var key = AEItemKey.of(stack); - int count = stack.getCount(); - long oldValue = internalBuffer.storage.getOrDefault(key, 0); - long changeValue = Math.min(Long.MAX_VALUE - oldValue, count); - if (changeValue > 0) { - if (!simulate) { - internalBuffer.storage.put(key, oldValue + changeValue); - internalBuffer.onChanged(); - } - return stack.copyWithCount((int) (count - changeValue)); - } else { - return ItemStack.EMPTY; - } - } - - @Override - public ItemStack extractItem(int slot, int amount, boolean simulate) { - return ItemStack.EMPTY; - } - } } diff --git a/src/main/java/com/gregtechceu/gtceu/integration/ae2/machine/MEOutputHatchPartMachine.java b/src/main/java/com/gregtechceu/gtceu/integration/ae2/machine/MEOutputHatchPartMachine.java index 560cf98d83a..8ffd40c01ec 100644 --- a/src/main/java/com/gregtechceu/gtceu/integration/ae2/machine/MEOutputHatchPartMachine.java +++ b/src/main/java/com/gregtechceu/gtceu/integration/ae2/machine/MEOutputHatchPartMachine.java @@ -1,234 +1,94 @@ package com.gregtechceu.gtceu.integration.ae2.machine; +import appeng.api.networking.IGrid; +import appeng.api.networking.IGridNodeListener; +import appeng.api.networking.IManagedGridNode; +import appeng.api.storage.MEStorage; 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.IMachineLife; import com.gregtechceu.gtceu.api.machine.trait.NotifiableFluidTank; -import com.gregtechceu.gtceu.api.recipe.GTRecipe; -import com.gregtechceu.gtceu.api.recipe.ingredient.FluidIngredient; -import com.gregtechceu.gtceu.api.transfer.fluid.CustomFluidTank; -import com.gregtechceu.gtceu.integration.ae2.gui.widget.list.AEListGridWidget; -import com.gregtechceu.gtceu.integration.ae2.utils.KeyStorage; -import com.gregtechceu.gtceu.utils.GTMath; - +import com.gregtechceu.gtceu.config.ConfigHolder; +import com.gregtechceu.gtceu.integration.ae2.gui.list.AEListGridWidget; +import com.gregtechceu.gtceu.integration.ae2.machine.trait.KeyStorageBackedTank; +import com.gregtechceu.gtceu.integration.ae2.utils.AEKeyStorage; +import com.gregtechceu.gtceu.integration.ae2.utils.AEUtil; 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.annotation.Persisted; import com.lowdragmc.lowdraglib.syncdata.field.ManagedFieldHolder; +import net.minecraft.core.Direction; +import org.apache.commons.lang3.ArrayUtils; -import net.minecraft.MethodsReturnNonnullByDefault; -import net.minecraftforge.fluids.FluidStack; - -import appeng.api.config.Actionable; -import appeng.api.stacks.AEFluidKey; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -import java.util.Collections; -import java.util.List; - -import javax.annotation.ParametersAreNonnullByDefault; - -@MethodsReturnNonnullByDefault -@ParametersAreNonnullByDefault -public class MEOutputHatchPartMachine extends MEHatchPartMachine implements IMachineLife { +public class MEOutputHatchPartMachine extends MEHatchPartMachine { protected static final ManagedFieldHolder MANAGED_FIELD_HOLDER = new ManagedFieldHolder( - MEOutputHatchPartMachine.class, MEHatchPartMachine.MANAGED_FIELD_HOLDER); + MEOutputHatchPartMachine.class, + MEHatchPartMachine.MANAGED_FIELD_HOLDER + ); @Persisted - private KeyStorage internalBuffer; // Do not use KeyCounter, use our simple implementation + protected final AEKeyStorage keyStorage; - public MEOutputHatchPartMachine(IMachineBlockEntity holder, Object... args) { - super(holder, IO.OUT, args); + public MEOutputHatchPartMachine(IMachineBlockEntity holder, int tier, Object... args) { + super(holder, tier, IO.OUT, 0, 0, args = ArrayUtils.addAll(args, new AEKeyStorage())); + this.keyStorage = (AEKeyStorage) args[args.length - 1]; } - ///////////////////////////////// - // ***** Machine LifeCycle ****// - ///////////////////////////////// - @Override protected NotifiableFluidTank createTank(int initialCapacity, int slots, Object... args) { - this.internalBuffer = new KeyStorage(); - return new InaccessibleInfiniteTank(this); + return new KeyStorageBackedTank(this, (AEKeyStorage) args[args.length - 1]); } @Override - public void onLoad() { - super.onLoad(); - if (isRemote()) return; + protected boolean shouldUpdateSubscription(Direction newFacing) { + IManagedGridNode mainNode = nodeHost.getMainNode(); + return isWorkingEnabled() && mainNode.isActive() && !keyStorage.isEmpty(); } @Override - public void onMachineRemoved() { - var grid = getMainNode().getGrid(); - if (grid != null && !internalBuffer.isEmpty()) { - for (var entry : internalBuffer) { - grid.getStorageService().getInventory().insert(entry.getKey(), entry.getLongValue(), - Actionable.MODULATE, actionSource); - } - } - } + protected void autoIO() { + if (!isMESyncTick()) return; - @Override - public ManagedFieldHolder getFieldHolder() { - return MANAGED_FIELD_HOLDER; - } + IGrid grid = nodeHost.getMainNode().getGrid(); + if (grid == null) return; - ///////////////////////////////// - // ********** Sync ME *********// - ///////////////////////////////// + AEUtil.transferTo(keyStorage, grid.getStorageService().getInventory(), actionSource, true); + } @Override - protected boolean shouldSubscribe() { - return super.shouldSubscribe() && !internalBuffer.storage.isEmpty(); + public void onMainNodeStateChanged(IGridNodeListener.State reason) { + super.onMainNodeStateChanged(reason); + updateTankSubscription(); } @Override - protected void autoIO() { - if (!this.shouldSyncME()) return; - if (this.updateMEStatus()) { - var grid = getMainNode().getGrid(); - if (grid != null && !internalBuffer.isEmpty()) { - internalBuffer.insertInventory(grid.getStorageService().getInventory(), actionSource); - } - this.updateTankSubscription(); + public void onMachineRemoved() { + IManagedGridNode mainNode = nodeHost.getMainNode(); + if (!keyStorage.isEmpty() && mainNode.isActive()) { + assert mainNode.getGrid() != null; + MEStorage networkInv = mainNode.getGrid().getStorageService().getInventory(); + AEUtil.transferTo(keyStorage, networkInv, actionSource, false); } - } - /////////////////////////////// - // ********** GUI ***********// - /////////////////////////////// + if (!ConfigHolder.INSTANCE.machines.ghostCircuit) { + clearInventory(circuitInventory.storage); + } + } @Override public Widget createUIWidget() { WidgetGroup group = new WidgetGroup(0, 0, 170, 65); - // ME Network status - group.addWidget(new LabelWidget(5, 0, () -> this.isOnline ? - "gtceu.gui.me_network.online" : - "gtceu.gui.me_network.offline")); + group.addWidget(new LabelWidget(5, 0, () -> nodeHost.getMainNode().isActive() ? + "gtceu.gui.me_network.online" : "gtceu.gui.me_network.offline")); group.addWidget(new LabelWidget(5, 10, "gtceu.gui.waiting_list")); - // display list - group.addWidget(new AEListGridWidget.Fluid(5, 20, 3, this.internalBuffer)); - + group.addWidget(new AEListGridWidget.Fluid(5, 20, 3, this.keyStorage)); return group; } - private class InaccessibleInfiniteTank extends NotifiableFluidTank { - - FluidStorageDelegate storage; - - public InaccessibleInfiniteTank(MetaMachine holder) { - super(holder, List.of(new FluidStorageDelegate()), IO.OUT, IO.NONE); - internalBuffer.setOnContentsChanged(this::onContentsChanged); - storage = (FluidStorageDelegate) getStorages()[0]; - allowSameFluids = true; - } - - @Override - public int getTanks() { - return 128; - } - - @Override - public @NotNull List getContents() { - return Collections.emptyList(); - } - - @Override - public double getTotalContentAmount() { - return 0; - } - - @Override - public boolean isEmpty() { - return true; - } - - @Override - public @NotNull FluidStack getFluidInTank(int tank) { - return FluidStack.EMPTY; - } - - @Override - public void setFluidInTank(int tank, @NotNull FluidStack fluidStack) {} - - @Override - public int getTankCapacity(int tank) { - return storage.getCapacity(); - } - - @Override - public boolean isFluidValid(int tank, @NotNull FluidStack stack) { - return true; - } - - @Override - @Nullable - public List handleRecipeInner(IO io, GTRecipe recipe, List left, - boolean simulate) { - if (io != IO.OUT) return left; - FluidAction action = simulate ? FluidAction.SIMULATE : FluidAction.EXECUTE; - for (var it = left.iterator(); it.hasNext();) { - var ingredient = it.next(); - if (ingredient.isEmpty()) { - it.remove(); - continue; - } - - var fluids = ingredient.getStacks(); - if (fluids.length == 0 || fluids[0].isEmpty()) { - it.remove(); - continue; - } - - FluidStack output = fluids[0]; - ingredient.shrink(storage.fill(output, action)); - if (ingredient.getAmount() <= 0) it.remove(); - } - return left.isEmpty() ? null : left; - } + @Override + public ManagedFieldHolder getFieldHolder() { + return MANAGED_FIELD_HOLDER; } - private class FluidStorageDelegate extends CustomFluidTank { - - public FluidStorageDelegate() { - super(0); - } - - @Override - public int getCapacity() { - return Integer.MAX_VALUE; - } - - @Override - public void setFluid(FluidStack fluid) { - // NO-OP - } - - @Override - public int fill(FluidStack resource, FluidAction action) { - var key = AEFluidKey.of(resource.getFluid(), resource.getTag()); - int amount = resource.getAmount(); - int oldValue = GTMath.saturatedCast(internalBuffer.storage.getOrDefault(key, 0)); - int changeValue = Math.min(Integer.MAX_VALUE - oldValue, amount); - if (changeValue > 0 && action.execute()) { - internalBuffer.storage.put(key, oldValue + changeValue); - internalBuffer.onChanged(); - } - return changeValue; - } - - @Override - public boolean supportsFill(int tank) { - return false; - } - - @Override - public boolean supportsDrain(int tank) { - return false; - } - } } diff --git a/src/main/java/com/gregtechceu/gtceu/integration/ae2/machine/MEPatternBufferPartMachine.java b/src/main/java/com/gregtechceu/gtceu/integration/ae2/machine/MEPatternBufferPartMachine.java index f8c5e49e6f9..636d6e03772 100644 --- a/src/main/java/com/gregtechceu/gtceu/integration/ae2/machine/MEPatternBufferPartMachine.java +++ b/src/main/java/com/gregtechceu/gtceu/integration/ae2/machine/MEPatternBufferPartMachine.java @@ -11,8 +11,9 @@ 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.IDataStickConfigurable; import com.gregtechceu.gtceu.api.machine.feature.multiblock.IMultiController; +import com.gregtechceu.gtceu.api.machine.multiblock.part.TieredIOPartMachine; import com.gregtechceu.gtceu.api.machine.trait.NotifiableFluidTank; import com.gregtechceu.gtceu.api.machine.trait.NotifiableItemStackHandler; import com.gregtechceu.gtceu.api.machine.trait.RecipeHandlerList; @@ -21,9 +22,9 @@ 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.trait.InternalSlotRecipeHandler; +import com.gregtechceu.gtceu.integration.ae2.gui.AETextInputButtonWidget; +import com.gregtechceu.gtceu.integration.ae2.gui.slot.AEPatternViewSlotWidget; +import com.gregtechceu.gtceu.integration.ae2.utils.InternalSlotRecipeHandler; import com.gregtechceu.gtceu.utils.GTMath; import com.gregtechceu.gtceu.utils.ItemStackHashStrategy; @@ -38,7 +39,6 @@ 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; @@ -80,15 +80,13 @@ import java.util.Objects; import java.util.Set; -import javax.annotation.ParametersAreNonnullByDefault; - -@ParametersAreNonnullByDefault -@MethodsReturnNonnullByDefault -public class MEPatternBufferPartMachine extends MEBusPartMachine - implements ICraftingProvider, PatternContainer, IDataStickInteractable { +public class MEPatternBufferPartMachine extends TieredIOPartMachine implements ICraftingProvider, PatternContainer, IDataStickConfigurable { protected static final ManagedFieldHolder MANAGED_FIELD_HOLDER = new ManagedFieldHolder( - MEPatternBufferPartMachine.class, MEBusPartMachine.MANAGED_FIELD_HOLDER); + MEPatternBufferPartMachine.class, + MEBusPartMachine.MANAGED_FIELD_HOLDER + ); + protected static final int MAX_PATTERN_COUNT = 27; private final InternalInventory internalPatternInventory = new InternalInventory() { @@ -139,7 +137,7 @@ public void setItemDirect(int slotIndex, ItemStack stack) { @Persisted private final Set proxies = new ObjectOpenHashSet<>(); - private final Set proxyMachines = new ReferenceOpenHashSet<>(); + private final Set proxyMachines = new ReferenceOpenHashSet<>(); @Getter protected final InternalSlotRecipeHandler internalRecipeHandler; @@ -219,22 +217,22 @@ protected void update() { } } - public void addProxy(MEPatternBufferProxyPartMachine proxy) { + public void addProxy(MEPatternProxyPartMachine proxy) { proxies.add(proxy.getPos()); proxyMachines.add(proxy); } - public void removeProxy(MEPatternBufferProxyPartMachine proxy) { + public void removeProxy(MEPatternProxyPartMachine proxy) { proxies.remove(proxy.getPos()); proxyMachines.remove(proxy); } @UnmodifiableView - public Set getProxies() { + public Set getProxies() { if (proxyMachines.size() != proxies.size()) { proxyMachines.clear(); for (var pos : proxies) { - if (MetaMachine.getMachine(getLevel(), pos) instanceof MEPatternBufferProxyPartMachine proxy) { + if (MetaMachine.getMachine(getLevel(), pos) instanceof MEPatternProxyPartMachine proxy) { proxyMachines.add(proxy); } } @@ -318,7 +316,7 @@ public Widget createUIWidget() { group.addWidget(new LabelWidget( 8, 2, - () -> this.isOnline ? "gtceu.gui.me_network.online" : "gtceu.gui.me_network.offline")); + () -> this.online ? "gtceu.gui.me_network.online" : "gtceu.gui.me_network.offline")); group.addWidget(new AETextInputButtonWidget(18 * rowSize + 8 - 70, 2, 70, 10) .setText(customName) diff --git a/src/main/java/com/gregtechceu/gtceu/integration/ae2/machine/MEPatternBufferProxyPartMachine.java b/src/main/java/com/gregtechceu/gtceu/integration/ae2/machine/MEPatternProxyPartMachine.java similarity index 90% rename from src/main/java/com/gregtechceu/gtceu/integration/ae2/machine/MEPatternBufferProxyPartMachine.java rename to src/main/java/com/gregtechceu/gtceu/integration/ae2/machine/MEPatternProxyPartMachine.java index 1e8901b2b8b..5c36d6c5d10 100644 --- a/src/main/java/com/gregtechceu/gtceu/integration/ae2/machine/MEPatternBufferProxyPartMachine.java +++ b/src/main/java/com/gregtechceu/gtceu/integration/ae2/machine/MEPatternProxyPartMachine.java @@ -8,14 +8,13 @@ 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.gregtechceu.gtceu.integration.ae2.machine.trait.ProxySlotRecipeHandler; +import com.gregtechceu.gtceu.integration.ae2.utils.ProxySlotRecipeHandler; 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; @@ -33,13 +32,11 @@ import javax.annotation.ParametersAreNonnullByDefault; -@MethodsReturnNonnullByDefault -@ParametersAreNonnullByDefault -public class MEPatternBufferProxyPartMachine extends TieredIOPartMachine +public class MEPatternProxyPartMachine extends TieredIOPartMachine implements IMachineLife, IDataStickInteractable { protected static final ManagedFieldHolder MANAGED_FIELD_HOLDER = new ManagedFieldHolder( - MEPatternBufferProxyPartMachine.class, TieredIOPartMachine.MANAGED_FIELD_HOLDER); + MEPatternProxyPartMachine.class, TieredIOPartMachine.MANAGED_FIELD_HOLDER); @Getter private final ProxySlotRecipeHandler proxySlotRecipeHandler; @@ -52,7 +49,7 @@ public class MEPatternBufferProxyPartMachine extends TieredIOPartMachine private @Nullable MEPatternBufferPartMachine buffer = null; private boolean bufferResolved = false; - public MEPatternBufferProxyPartMachine(IMachineBlockEntity holder) { + public MEPatternProxyPartMachine(IMachineBlockEntity holder) { super(holder, GTValues.LuV, IO.IN); proxySlotRecipeHandler = new ProxySlotRecipeHandler(this, MEPatternBufferPartMachine.MAX_PATTERN_COUNT); } diff --git a/src/main/java/com/gregtechceu/gtceu/integration/ae2/machine/MEStockingBusPartMachine.java b/src/main/java/com/gregtechceu/gtceu/integration/ae2/machine/MEStockingBusPartMachine.java index 288dac498f5..f6ff5166e7e 100644 --- a/src/main/java/com/gregtechceu/gtceu/integration/ae2/machine/MEStockingBusPartMachine.java +++ b/src/main/java/com/gregtechceu/gtceu/integration/ae2/machine/MEStockingBusPartMachine.java @@ -1,27 +1,32 @@ package com.gregtechceu.gtceu.integration.ae2.machine; +import appeng.api.config.Actionable; +import appeng.api.networking.IGrid; +import appeng.api.networking.IGridNodeListener; +import appeng.api.networking.IManagedGridNode; +import appeng.api.networking.storage.IStorageWatcherNode; +import appeng.api.stacks.AEItemKey; +import appeng.api.stacks.KeyCounter; +import appeng.api.storage.MEStorage; +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.gui.fancy.IFancyConfiguratorButton; import com.gregtechceu.gtceu.api.gui.fancy.TabsWidget; import com.gregtechceu.gtceu.api.machine.IMachineBlockEntity; -import com.gregtechceu.gtceu.api.machine.MetaMachine; -import com.gregtechceu.gtceu.api.machine.fancyconfigurator.AutoStockingFancyConfigurator; -import com.gregtechceu.gtceu.api.machine.feature.multiblock.IMultiController; -import com.gregtechceu.gtceu.api.machine.feature.multiblock.IMultiPart; +import com.gregtechceu.gtceu.api.machine.feature.IDataStickConfigurable; import com.gregtechceu.gtceu.api.machine.trait.NotifiableItemStackHandler; -import com.gregtechceu.gtceu.common.item.IntCircuitBehaviour; +import com.gregtechceu.gtceu.api.transfer.item.CustomItemStackHandler; import com.gregtechceu.gtceu.config.ConfigHolder; -import com.gregtechceu.gtceu.integration.ae2.machine.feature.multiblock.IMEStockingPart; -import com.gregtechceu.gtceu.integration.ae2.slot.ExportOnlyAEItemList; -import com.gregtechceu.gtceu.integration.ae2.slot.ExportOnlyAEItemSlot; -import com.gregtechceu.gtceu.integration.ae2.slot.ExportOnlyAESlot; -import com.gregtechceu.gtceu.integration.ae2.slot.IConfigurableSlotList; - +import com.gregtechceu.gtceu.integration.ae2.gui.fancyconfigurator.StockingFancyConfigurator; +import com.gregtechceu.gtceu.integration.ae2.utils.MEConfigUtil; +import com.gregtechceu.gtceu.integration.ae2.utils.StockingConfigHandler; +import com.gregtechceu.gtceu.utils.GTMath; import com.lowdragmc.lowdraglib.syncdata.annotation.DescSynced; -import com.lowdragmc.lowdraglib.syncdata.annotation.DropSaved; import com.lowdragmc.lowdraglib.syncdata.annotation.Persisted; import com.lowdragmc.lowdraglib.syncdata.field.ManagedFieldHolder; - -import net.minecraft.MethodsReturnNonnullByDefault; +import lombok.Getter; +import lombok.Setter; import net.minecraft.core.Direction; import net.minecraft.nbt.CompoundTag; import net.minecraft.network.chat.Component; @@ -30,377 +35,222 @@ import net.minecraft.world.entity.player.Player; import net.minecraft.world.item.ItemStack; import net.minecraft.world.phys.BlockHitResult; - -import appeng.api.config.Actionable; -import appeng.api.networking.IGrid; -import appeng.api.stacks.AEItemKey; -import appeng.api.stacks.AEKey; -import appeng.api.stacks.GenericStack; -import appeng.api.storage.MEStorage; -import it.unimi.dsi.fastutil.objects.Object2LongMap; -import lombok.Getter; -import lombok.Setter; import org.jetbrains.annotations.Nullable; -import java.util.Comparator; -import java.util.PriorityQueue; -import java.util.function.Predicate; - -import javax.annotation.ParametersAreNonnullByDefault; +import java.util.List; -@ParametersAreNonnullByDefault -@MethodsReturnNonnullByDefault -public class MEStockingBusPartMachine extends MEInputBusPartMachine implements IMEStockingPart { +public class MEStockingBusPartMachine extends MEBusPartMachine implements IDataStickConfigurable { protected static final ManagedFieldHolder MANAGED_FIELD_HOLDER = new ManagedFieldHolder( - MEStockingBusPartMachine.class, MEInputBusPartMachine.MANAGED_FIELD_HOLDER); + MEStockingBusPartMachine.class, + MEBusPartMachine.MANAGED_FIELD_HOLDER + ); + + private final int slots; + @Getter @DescSynced @Persisted - @Getter private boolean autoPull; @Getter @Setter @Persisted - @DropSaved private int minStackSize = 1; - @Getter - @Setter - @Persisted - @DropSaved - private int ticksPerCycle = 40; - @Setter - private Predicate autoPullTest; - - public MEStockingBusPartMachine(IMachineBlockEntity holder, Object... args) { - super(holder, args); - this.autoPullTest = $ -> false; - } - - ///////////////////////////////// - // ***** Machine LifeCycle ****// - ///////////////////////////////// - - @Override - public void addedToController(IMultiController controller) { - super.addedToController(controller); - IMEStockingPart.super.addedToController(controller); - } + @Persisted + protected final StockingConfigHandler configHandler; - @Override - public void removedFromController(IMultiController controller) { - IMEStockingPart.super.removedFromController(controller); - super.removedFromController(controller); + public MEStockingBusPartMachine(IMachineBlockEntity holder, int tier, int slots, Object... args) { + super(holder, tier, IO.IN, args); + this.slots = slots; + this.configHandler = new StockingConfigHandler(slots, () -> getInventory().onContentsChanged()); + nodeHost.getMainNode().addService(IStorageWatcherNode.class, configHandler); } @Override protected NotifiableItemStackHandler createInventory(Object... args) { - this.aeItemHandler = new ExportOnlyAEStockingItemList(this, CONFIG_SIZE); - return this.aeItemHandler; + return new NotifiableItemStackHandler( + this, + getInventorySize(), + IO.IN, + IO.NONE, + MEStorageBackedItemHandler::new + ); } @Override - public ManagedFieldHolder getFieldHolder() { - return MANAGED_FIELD_HOLDER; + protected boolean shouldUpdateSubscription(Direction newFacing) { + IManagedGridNode node = nodeHost.getMainNode(); + return isWorkingEnabled() && node.isActive() && isAutoPull(); } - ///////////////////////////////// - // ********** Sync ME *********// - ///////////////////////////////// - @Override public void autoIO() { - super.autoIO(); - if (ticksPerCycle == 0) ticksPerCycle = ConfigHolder.INSTANCE.compat.ae2.updateIntervals; // Emergency Check to - // Avoid Crash loops. - if (getOffsetTimer() % ticksPerCycle == 0) { - if (autoPull) { - refreshList(); - } - syncME(); - } - } + if (!isMESyncTick()) return; - @Override - protected void syncME() { - // Update the visual display for the fake items. This also is important for the item handler's - // getStackInSlot() method, as it uses the cached items set here. - MEStorage networkInv = this.getMainNode().getGrid().getStorageService().getInventory(); - for (ExportOnlyAEItemSlot slot : this.aeItemHandler.getInventory()) { - var config = slot.getConfig(); - if (config != null) { - // Try to fill the slot - var key = config.what(); - long extracted = networkInv.extract(key, Long.MAX_VALUE, Actionable.SIMULATE, actionSource); - if (extracted >= minStackSize) { - slot.setStock(new GenericStack(key, extracted)); - continue; - } - } - slot.setStock(null); - } - } + IGrid grid = nodeHost.getMainNode().getGrid(); + if (grid == null) return; - @Override - public void attachSideTabs(TabsWidget sideTabs) { - sideTabs.setMainTab(this); // removes the cover configurator, it's pointless and clashes with layout. + KeyCounter cachedInv = grid.getStorageService().getCachedInventory(); + configHandler.autoPull(cachedInv, (key, amount) -> amount >= minStackSize && key instanceof AEItemKey); } @Override - protected void flushInventory() { - // no-op, nothing to send back to the network + public void onMainNodeStateChanged(IGridNodeListener.State reason) { + super.onMainNodeStateChanged(reason); + updateInventorySubscription(); } @Override - public void setDistinct(boolean isDistinct) { - super.setDistinct(isDistinct); - if (!isRemote() && !isDistinct) { - // Ensure that our configured items won't match any other buses in the multiblock. - // Needed since we allow duplicates in distinct mode on, but not off - validateConfig(); + public void onMachineRemoved() { + // nothing to drop + if (!ConfigHolder.INSTANCE.machines.ghostCircuit) { + clearInventory(circuitInventory.storage); } } @Override - public IConfigurableSlotList getSlotList() { - return aeItemHandler; + protected int getInventorySize() { + return slots; } - @Override - public boolean testConfiguredInOtherPart(@Nullable GenericStack config) { - if (config == null) return false; - // In distinct mode, we don't need to check other buses since only one bus can run a recipe at a time. - if (!isFormed() || isDistinct()) return false; - - // Otherwise, we need to test for if the item is configured - // in any stocking bus in the multi (besides ourselves). - for (IMultiController controller : getControllers()) { - for (IMultiPart part : controller.getParts()) { - if (part instanceof MEStockingBusPartMachine bus) { - // We don't need to check for ourselves, as this case is handled elsewhere. - if (bus == this || bus.isDistinct()) continue; - if (bus.aeItemHandler.hasStackInConfig(config, false)) { - return true; - } - } - } - } - return false; - } - - @Override public void setAutoPull(boolean autoPull) { this.autoPull = autoPull; - if (!isRemote()) { - if (!this.autoPull) { - this.aeItemHandler.clearInventory(0); - } else if (updateMEStatus()) { - this.refreshList(); - updateInventorySubscription(); - } - } + updateInventorySubscription(); } - /** - * Refresh the configuration list in auto-pull mode. - * Sets the config to the CONFIG_SIZE items with the highest amount in the ME system. - */ - private void refreshList() { - IGrid grid = this.getMainNode().getGrid(); - if (grid == null) { - aeItemHandler.clearInventory(0); - return; - } - - MEStorage networkStorage = grid.getStorageService().getInventory(); - var counter = networkStorage.getAvailableStacks(); - - // Use a PriorityQueue to sort the stacks on size, take the first CONFIG_SIZE - // biggest stacks. - PriorityQueue> topItems = new PriorityQueue<>( - Comparator.comparingLong(Object2LongMap.Entry::getLongValue)); - - for (Object2LongMap.Entry entry : counter) { - long amount = entry.getLongValue(); - AEKey what = entry.getKey(); - - if (amount <= 0) continue; - if (!(what instanceof AEItemKey itemKey)) continue; - - long request = networkStorage.extract(what, amount, Actionable.SIMULATE, actionSource); - if (request == 0) continue; - - // Ensure that it is valid to configure with this stack - if (autoPullTest != null && !autoPullTest.test(new GenericStack(itemKey, amount))) continue; - if (amount >= minStackSize) { - if (topItems.size() < CONFIG_SIZE) { - topItems.offer(entry); - } else if (amount > topItems.peek().getLongValue()) { - topItems.poll(); - topItems.offer(entry); - } - } - } - - // Now, topItems is a PQ with CONFIG_SIZE highest amount items in the system. - int index; - int itemAmount = topItems.size(); - for (index = 0; index < CONFIG_SIZE; index++) { - if (topItems.isEmpty()) break; - Object2LongMap.Entry entry = topItems.poll(); - - AEKey what = entry.getKey(); - long amount = entry.getLongValue(); - - // If we get here, the item has already been checked by the PQ. - long request = networkStorage.extract(what, amount, Actionable.SIMULATE, actionSource); - - // Since we want our items to be displayed from highest to lowest, but poll() returns - // the lowest first, we fill in the slots starting at itemAmount-1 - var slot = this.aeItemHandler.getInventory()[itemAmount - index - 1]; - slot.setConfig(new GenericStack(what, 1)); - slot.setStock(new GenericStack(what, request)); - } - - aeItemHandler.clearInventory(index); + @Override + public void attachSideTabs(TabsWidget sideTabs) { + sideTabs.setMainTab(this); // removes the cover configurator, it's pointless and clashes with layout. } - /////////////////////////////// - // ********** GUI ***********// - /////////////////////////////// - @Override public void attachConfigurators(ConfiguratorPanel configuratorPanel) { - IMEStockingPart.super.attachConfigurators(configuratorPanel); super.attachConfigurators(configuratorPanel); - configuratorPanel.attachConfigurators(new AutoStockingFancyConfigurator(this)); + configuratorPanel.attachConfigurators(new IFancyConfiguratorButton.Toggle( + GuiTextures.BUTTON_AUTO_PULL.getSubTexture(0, 0, 1, 0.5), + GuiTextures.BUTTON_AUTO_PULL.getSubTexture(0, 0.5, 1, 0.5), + this::isAutoPull, + (clickData, pressed) -> setAutoPull(pressed)) + .setTooltipsSupplier(pressed -> List.of(Component.translatable("gtceu.gui.me_bus.auto_pull_button")))); + configuratorPanel.attachConfigurators(new StockingFancyConfigurator( + "gtceu.gui.title.adv_stocking_config.min_item_count", + "gtceu.gui.adv_stocking_config.min_item_count", + this::getMinStackSize, + this::setMinStackSize) + ); } @Override - protected InteractionResult onScrewdriverClick(Player playerIn, InteractionHand hand, Direction gridSide, - BlockHitResult hitResult) { + protected InteractionResult onScrewdriverClick(Player playerIn, InteractionHand hand, Direction gridSide, BlockHitResult hitResult) { if (!isRemote()) { setAutoPull(!autoPull); - if (autoPull) { - playerIn.sendSystemMessage( - Component.translatable("gtceu.machine.me.stocking_auto_pull_enabled")); - } else { - playerIn.sendSystemMessage( - Component.translatable("gtceu.machine.me.stocking_auto_pull_disabled")); - } + playerIn.sendSystemMessage(autoPull + ? Component.translatable("gtceu.machine.me.stocking_auto_pull_enabled") + : Component.translatable("gtceu.machine.me.stocking_auto_pull_disabled") + ); } return InteractionResult.sidedSuccess(isRemote()); } - //////////////////////////////// - // ****** Configuration ******// - //////////////////////////////// + @Override + public String getConfigKey() { + return MEInputBusPartMachine.CONFIG_KEY; + } + + @Override + public Component getConfigName() { + return MEInputBusPartMachine.CONFIG_NAME; + } @Override - protected CompoundTag writeConfigToTag() { + public void writeConfig(CompoundTag tag) { + MEConfigUtil.writeGhostCircuit(tag, circuitInventory); + MEConfigUtil.writeAutoPull(tag, autoPull); if (!autoPull) { - CompoundTag tag = super.writeConfigToTag(); - tag.putBoolean("AutoPull", false); - return tag; + MEConfigUtil.writeConfigHandler(tag, configHandler); } - // if in auto-pull, no need to write actual configured slots, but still need to write the ghost circuit - CompoundTag tag = new CompoundTag(); - tag.putBoolean("AutoPull", true); - tag.putByte("GhostCircuit", - (byte) IntCircuitBehaviour.getCircuitConfiguration(circuitInventory.getStackInSlot(0))); - return tag; + MEConfigUtil.writeMinStackSize(tag, minStackSize); } @Override - protected void readConfigFromTag(CompoundTag tag) { - if (tag.getBoolean("AutoPull")) { - // if being set to auto-pull, no need to read the configured slots - this.setAutoPull(true); - circuitInventory.setStackInSlot(0, IntCircuitBehaviour.stack(tag.getByte("GhostCircuit"))); - return; + public void readConfig(CompoundTag tag) { + MEConfigUtil.readGhostCircuit(tag, circuitInventory); + MEConfigUtil.readAutoPull(tag, this::setAutoPull); + if (!autoPull) { + MEConfigUtil.readConfigHandler(tag, configHandler); + getInventory().onContentsChanged(); } - // set auto pull first to avoid issues with clearing the config after reading from the data stick - this.setAutoPull(false); - super.readConfigFromTag(tag); + MEConfigUtil.readMinStackSize(tag, this::setMinStackSize); } - private class ExportOnlyAEStockingItemList extends ExportOnlyAEItemList { + @Override + public ManagedFieldHolder getFieldHolder() { + return MANAGED_FIELD_HOLDER; + } - public ExportOnlyAEStockingItemList(MetaMachine holder, int slots) { - super(holder, slots, ExportOnlyAEStockingItemSlot::new); - } + final class MEStorageBackedItemHandler extends CustomItemStackHandler { - @Override - public boolean isAutoPull() { - return autoPull; + public MEStorageBackedItemHandler(int slots) { + super(slots); } @Override - public boolean isStocking() { - return true; + public boolean isItemValid(int slot, ItemStack stack) { + AEItemKey key = getItemKey(slot); + return key != null && key.matches(stack); } @Override - public boolean hasStackInConfig(GenericStack stack, boolean checkExternal) { - boolean inThisBus = super.hasStackInConfig(stack, false); - if (inThisBus) return true; - if (checkExternal) { - return testConfiguredInOtherPart(stack); - } - return false; - } - } + public ItemStack getStackInSlot(int slot) { + validateSlotIndex(slot); + + IManagedGridNode mainNode = nodeHost.getMainNode(); + if (!mainNode.isActive()) return ItemStack.EMPTY; + assert mainNode.getGrid() != null; + + AEItemKey key = getItemKey(slot); + if (key == null) return ItemStack.EMPTY; - private class ExportOnlyAEStockingItemSlot extends ExportOnlyAEItemSlot { + KeyCounter cachedInv = mainNode.getGrid().getStorageService().getCachedInventory(); + long existing = cachedInv.get(key); - public ExportOnlyAEStockingItemSlot() { - super(); + return key.toStack(GTMath.saturatedCast(existing)); } - public ExportOnlyAEStockingItemSlot(@Nullable GenericStack config, @Nullable GenericStack stock) { - super(config, stock); + @Override + public ItemStack insertItem(int slot, ItemStack stack, boolean simulate) { + return stack; } @Override public ItemStack extractItem(int slot, int amount, boolean simulate) { - if (slot == 0 && this.stock != null) { - if (this.config != null) { - // Extract the items from the real net to either validate (simulate) - // or extract (modulate) when this is called - if (!isOnline()) return ItemStack.EMPTY; - MEStorage aeNetwork = getMainNode().getGrid().getStorageService().getInventory(); - - Actionable action = simulate ? Actionable.SIMULATE : Actionable.MODULATE; - var key = config.what(); - long extracted = aeNetwork.extract(key, amount, action, actionSource); - - if (extracted > 0) { - ItemStack resultStack = key instanceof AEItemKey itemKey ? - itemKey.toStack((int) extracted) : ItemStack.EMPTY; - if (!simulate) { - // may as well update the display here - this.stock = ExportOnlyAESlot.copy(stock, stock.amount() - extracted); - if (this.stock.amount() == 0) { - this.stock = null; - } - if (this.onContentsChanged != null) { - this.onContentsChanged.run(); - } - } - return resultStack; - } - } - } - return ItemStack.EMPTY; + if (amount <= 0) return ItemStack.EMPTY; + + validateSlotIndex(slot); + + IManagedGridNode mainNode = nodeHost.getMainNode(); + if (!mainNode.isActive()) return ItemStack.EMPTY; + assert mainNode.getGrid() != null; + + AEItemKey key = getItemKey(slot); + if (key == null) return ItemStack.EMPTY; + + MEStorage networkInv = mainNode.getGrid().getStorageService().getInventory(); + long extracted = networkInv.extract( + key, + amount, + simulate ? Actionable.SIMULATE : Actionable.MODULATE, + actionSource + ); + + // do not call onContentsChanged() here, as it will be called by IStorageWatcherNode + return key.toStack(Math.toIntExact(extracted)); } - @Override - public ExportOnlyAEStockingItemSlot copy() { - return new ExportOnlyAEStockingItemSlot( - this.config == null ? null : copy(this.config), - this.stock == null ? null : copy(this.stock)); + private @Nullable AEItemKey getItemKey(int slot) { + return (AEItemKey) configHandler.getKeyInSlot(slot); } } } diff --git a/src/main/java/com/gregtechceu/gtceu/integration/ae2/machine/MEStockingHatchPartMachine.java b/src/main/java/com/gregtechceu/gtceu/integration/ae2/machine/MEStockingHatchPartMachine.java index 8b07ee7ad05..7a2bf72711c 100644 --- a/src/main/java/com/gregtechceu/gtceu/integration/ae2/machine/MEStockingHatchPartMachine.java +++ b/src/main/java/com/gregtechceu/gtceu/integration/ae2/machine/MEStockingHatchPartMachine.java @@ -1,28 +1,31 @@ package com.gregtechceu.gtceu.integration.ae2.machine; +import appeng.api.config.Actionable; +import appeng.api.networking.IGrid; +import appeng.api.networking.IGridNodeListener; +import appeng.api.networking.IManagedGridNode; +import appeng.api.networking.storage.IStorageWatcherNode; +import appeng.api.stacks.AEFluidKey; +import appeng.api.stacks.KeyCounter; +import appeng.api.storage.MEStorage; +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.gui.fancy.IFancyConfiguratorButton; import com.gregtechceu.gtceu.api.gui.fancy.TabsWidget; import com.gregtechceu.gtceu.api.machine.IMachineBlockEntity; -import com.gregtechceu.gtceu.api.machine.MetaMachine; -import com.gregtechceu.gtceu.api.machine.fancyconfigurator.AutoStockingFancyConfigurator; -import com.gregtechceu.gtceu.api.machine.feature.multiblock.IMultiController; -import com.gregtechceu.gtceu.api.machine.feature.multiblock.IMultiPart; +import com.gregtechceu.gtceu.api.machine.feature.IDataStickConfigurable; import com.gregtechceu.gtceu.api.machine.trait.NotifiableFluidTank; -import com.gregtechceu.gtceu.common.item.IntCircuitBehaviour; -import com.gregtechceu.gtceu.config.ConfigHolder; -import com.gregtechceu.gtceu.integration.ae2.machine.feature.multiblock.IMEStockingPart; -import com.gregtechceu.gtceu.integration.ae2.slot.ExportOnlyAEFluidList; -import com.gregtechceu.gtceu.integration.ae2.slot.ExportOnlyAEFluidSlot; -import com.gregtechceu.gtceu.integration.ae2.slot.ExportOnlyAESlot; -import com.gregtechceu.gtceu.integration.ae2.slot.IConfigurableSlotList; -import com.gregtechceu.gtceu.integration.ae2.utils.AEUtil; - +import com.gregtechceu.gtceu.api.transfer.fluid.CustomFluidTank; +import com.gregtechceu.gtceu.integration.ae2.gui.fancyconfigurator.StockingFancyConfigurator; +import com.gregtechceu.gtceu.integration.ae2.utils.MEConfigUtil; +import com.gregtechceu.gtceu.integration.ae2.utils.StockingConfigHandler; +import com.gregtechceu.gtceu.utils.GTMath; import com.lowdragmc.lowdraglib.syncdata.annotation.DescSynced; -import com.lowdragmc.lowdraglib.syncdata.annotation.DropSaved; import com.lowdragmc.lowdraglib.syncdata.annotation.Persisted; import com.lowdragmc.lowdraglib.syncdata.field.ManagedFieldHolder; - -import net.minecraft.MethodsReturnNonnullByDefault; +import lombok.Getter; +import lombok.Setter; import net.minecraft.core.Direction; import net.minecraft.nbt.CompoundTag; import net.minecraft.network.chat.Component; @@ -31,361 +34,239 @@ import net.minecraft.world.entity.player.Player; import net.minecraft.world.phys.BlockHitResult; import net.minecraftforge.fluids.FluidStack; - -import appeng.api.config.Actionable; -import appeng.api.networking.IGrid; -import appeng.api.stacks.AEFluidKey; -import appeng.api.stacks.AEKey; -import appeng.api.stacks.GenericStack; -import appeng.api.storage.MEStorage; -import it.unimi.dsi.fastutil.objects.Object2LongMap; -import lombok.Getter; -import lombok.Setter; import org.jetbrains.annotations.Nullable; -import java.util.Comparator; -import java.util.PriorityQueue; -import java.util.function.Predicate; - -import javax.annotation.ParametersAreNonnullByDefault; +import java.util.ArrayList; +import java.util.List; -@ParametersAreNonnullByDefault -@MethodsReturnNonnullByDefault -public class MEStockingHatchPartMachine extends MEInputHatchPartMachine implements IMEStockingPart { +public class MEStockingHatchPartMachine extends MEHatchPartMachine implements IDataStickConfigurable { protected static final ManagedFieldHolder MANAGED_FIELD_HOLDER = new ManagedFieldHolder( - MEStockingHatchPartMachine.class, MEInputHatchPartMachine.MANAGED_FIELD_HOLDER); - - private static final int CONFIG_SIZE = 16; + MEStockingHatchPartMachine.class, + MEHatchPartMachine.MANAGED_FIELD_HOLDER + ); + @Getter @DescSynced @Persisted - @Getter private boolean autoPull; @Getter @Setter @Persisted - @DropSaved private int minStackSize = 1; - @Getter - @Setter @Persisted - @DropSaved - private int ticksPerCycle = 40; - - @Setter - private Predicate autoPullTest; + protected final StockingConfigHandler configHandler; - public MEStockingHatchPartMachine(IMachineBlockEntity holder, Object... args) { - super(holder, args); - this.autoPullTest = $ -> false; + public MEStockingHatchPartMachine(IMachineBlockEntity holder, int tier, int slots, Object... args) { + super(holder, tier, IO.IN, -1, slots, args); + this.configHandler = new StockingConfigHandler(slots, tank::onContentsChanged); + nodeHost.getMainNode().addService(IStorageWatcherNode.class, configHandler); } - ///////////////////////////////// - // ***** Machine LifeCycle ****// - ///////////////////////////////// - @Override - public void addedToController(IMultiController controller) { - super.addedToController(controller); - IMEStockingPart.super.addedToController(controller); + protected NotifiableFluidTank createTank(int initialCapacity, int slots, Object... args) { + var storages = new ArrayList(slots); + for (int i = 0; i < slots; i++) { + storages.add(new MEStorageBackedFluidStorage(i)); + } + return new NotifiableFluidTank(this, storages, IO.IN, IO.NONE); } @Override - public void removedFromController(IMultiController controller) { - IMEStockingPart.super.removedFromController(controller); - super.removedFromController(controller); + protected boolean shouldUpdateSubscription(Direction newFacing) { + IManagedGridNode node = nodeHost.getMainNode(); + return isWorkingEnabled() && node.isActive() && isAutoPull(); } @Override - protected NotifiableFluidTank createTank(int initialCapacity, int slots, Object... args) { - this.aeFluidHandler = new ExportOnlyAEStockingFluidList(this, CONFIG_SIZE); - return this.aeFluidHandler; + protected void autoIO() { + if (!isMESyncTick()) return; + + IGrid grid = nodeHost.getMainNode().getGrid(); + if (grid == null) return; + + KeyCounter cachedInv = grid.getStorageService().getCachedInventory(); + configHandler.autoPull(cachedInv, (key, amount) -> amount >= minStackSize && key instanceof AEFluidKey); } @Override - public ManagedFieldHolder getFieldHolder() { - return MANAGED_FIELD_HOLDER; + public void onMainNodeStateChanged(IGridNodeListener.State reason) { + super.onMainNodeStateChanged(reason); + updateTankSubscription(); } - ///////////////////////////////// - // ********** Sync ME *********// - ///////////////////////////////// - - @Override - public void autoIO() { - super.autoIO(); - if (ticksPerCycle == 0) ticksPerCycle = ConfigHolder.INSTANCE.compat.ae2.updateIntervals; // Emergency Check to - // Avoid Crash loops. - if (getOffsetTimer() % ticksPerCycle == 0) { - if (autoPull) { - refreshList(); - } - syncME(); - } + public void setAutoPull(boolean autoPull) { + this.autoPull = autoPull; + updateTankSubscription(); } @Override - protected void syncME() { - MEStorage networkInv = this.getMainNode().getGrid().getStorageService().getInventory(); - for (ExportOnlyAEFluidSlot slot : aeFluidHandler.getInventory()) { - var config = slot.getConfig(); - if (config != null) { - // Try to fill the slot - var key = config.what(); - long extracted = networkInv.extract(key, Long.MAX_VALUE, Actionable.SIMULATE, actionSource); - if (extracted >= minStackSize) { - slot.setStock(new GenericStack(key, extracted)); - continue; - } - } - slot.setStock(null); + protected InteractionResult onScrewdriverClick(Player playerIn, InteractionHand hand, Direction gridSide, BlockHitResult hitResult) { + if (!isRemote()) { + setAutoPull(!autoPull); + playerIn.sendSystemMessage(autoPull + ? Component.translatable("gtceu.machine.me.stocking_auto_pull_enabled") + : Component.translatable("gtceu.machine.me.stocking_auto_pull_disabled") + ); } + return InteractionResult.sidedSuccess(isRemote()); } @Override public void attachSideTabs(TabsWidget sideTabs) { - sideTabs.setMainTab(this); // removes the cover configurator, it's pointless and clashes with layout. + sideTabs.setMainTab(this); } @Override - protected void flushInventory() { - // no-op, nothing to send back to the network + public void attachConfigurators(ConfiguratorPanel configuratorPanel) { + super.attachConfigurators(configuratorPanel); + configuratorPanel.attachConfigurators(new IFancyConfiguratorButton.Toggle( + GuiTextures.BUTTON_AUTO_PULL.getSubTexture(0, 0, 1, 0.5), + GuiTextures.BUTTON_AUTO_PULL.getSubTexture(0, 0.5, 1, 0.5), + this::isAutoPull, + (clickData, pressed) -> setAutoPull(pressed)) + .setTooltipsSupplier(pressed -> List.of(Component.translatable("gtceu.gui.me_bus.auto_pull_button")))); + configuratorPanel.attachConfigurators(new StockingFancyConfigurator( + "gtceu.gui.title.adv_stocking_config.min_fluid_count", + "gtceu.gui.adv_stocking_config.min_fluid_count", + this::getMinStackSize, + this::setMinStackSize + )); } @Override - public IConfigurableSlotList getSlotList() { - return aeFluidHandler; + public String getConfigKey() { + return MEInputHatchPartMachine.CONFIG_KEY; } @Override - public boolean testConfiguredInOtherPart(@Nullable GenericStack config) { - if (config == null) return false; - if (!isFormed()) return false; - - for (IMultiController controller : getControllers()) { - for (IMultiPart part : controller.getParts()) { - if (part instanceof MEStockingHatchPartMachine hatch) { - if (hatch == this) continue; - if (hatch.aeFluidHandler.hasStackInConfig(config, false)) { - return true; - } - } - } - } - return false; + public Component getConfigName() { + return MEInputHatchPartMachine.CONFIG_NAME; } @Override - public void setAutoPull(boolean autoPull) { - this.autoPull = autoPull; - if (!isRemote()) { - if (!this.autoPull) { - this.aeFluidHandler.clearInventory(0); - } else if (updateMEStatus()) { - this.refreshList(); - updateTankSubscription(); - } + public void writeConfig(CompoundTag tag) { + MEConfigUtil.writeGhostCircuit(tag, circuitInventory); + MEConfigUtil.writeAutoPull(tag, autoPull); + if (!autoPull) { + MEConfigUtil.writeConfigHandler(tag, configHandler); } + MEConfigUtil.writeMinStackSize(tag, minStackSize); } - private void refreshList() { - IGrid grid = this.getMainNode().getGrid(); - if (grid == null) { - aeFluidHandler.clearInventory(0); - return; - } - - MEStorage networkStorage = grid.getStorageService().getInventory(); - var counter = networkStorage.getAvailableStacks(); - - // Use a PriorityQueue to sort the stacks on size, take the first CONFIG_SIZE - // biggest stacks. - PriorityQueue> topFluids = new PriorityQueue<>( - Comparator.comparingLong(Object2LongMap.Entry::getLongValue)); - - for (Object2LongMap.Entry entry : counter) { - long amount = entry.getLongValue(); - AEKey what = entry.getKey(); - - if (amount <= 0) continue; - if (!(what instanceof AEFluidKey fluidKey)) continue; - - long request = networkStorage.extract(what, amount, Actionable.SIMULATE, actionSource); - if (request == 0) continue; - - // Ensure that it is valid to configure with this stack - if (autoPullTest != null && !autoPullTest.test(new GenericStack(fluidKey, amount))) continue; - if (amount >= minStackSize) { - if (topFluids.size() < CONFIG_SIZE) { - topFluids.offer(entry); - } else if (amount > topFluids.peek().getLongValue()) { - topFluids.poll(); - topFluids.offer(entry); - } - } - } - - // Now, topFluids is a PQ with CONFIG_SIZE highest amount fluids in the system. - int index; - int fluidAmount = topFluids.size(); - for (index = 0; index < CONFIG_SIZE; index++) { - if (topFluids.isEmpty()) break; - Object2LongMap.Entry entry = topFluids.poll(); - AEKey what = entry.getKey(); - long amount = entry.getLongValue(); - - // If we get here, the fluid has already been checked by the PQ. - long request = networkStorage.extract(what, amount, Actionable.SIMULATE, actionSource); - - // Since we want our fluids to be displayed from highest to lowest, but poll() returns - // the lowest first, we fill in the slots starting at fluidAmount-1 - var slot = this.aeFluidHandler.getInventory()[fluidAmount - index - 1]; - slot.setConfig(new GenericStack(what, 1)); - slot.setStock(new GenericStack(what, request)); + @Override + public void readConfig(CompoundTag tag) { + MEConfigUtil.readGhostCircuit(tag, circuitInventory); + MEConfigUtil.readAutoPull(tag, this::setAutoPull); + if (!autoPull) { + MEConfigUtil.readConfigHandler(tag, configHandler); + tank.onContentsChanged(); } - - aeFluidHandler.clearInventory(index); + MEConfigUtil.readMinStackSize(tag, this::setMinStackSize); } - /////////////////////////////// - // ********** GUI ***********// - /////////////////////////////// - @Override - public void attachConfigurators(ConfiguratorPanel configuratorPanel) { - IMEStockingPart.super.attachConfigurators(configuratorPanel); - super.attachConfigurators(configuratorPanel); - configuratorPanel.attachConfigurators(new AutoStockingFancyConfigurator(this)); + public ManagedFieldHolder getFieldHolder() { + return MANAGED_FIELD_HOLDER; } - //////////////////////////////// - // ******* Interaction *******// - //////////////////////////////// + private final class MEStorageBackedFluidStorage extends CustomFluidTank { - @Override - protected InteractionResult onScrewdriverClick(Player playerIn, InteractionHand hand, Direction gridSide, - BlockHitResult hitResult) { - if (!isRemote()) { - setAutoPull(!autoPull); - if (autoPull) { - playerIn.sendSystemMessage( - Component.translatable("gtceu.machine.me.stocking_auto_pull_enabled")); - } else { - playerIn.sendSystemMessage( - Component.translatable("gtceu.machine.me.stocking_auto_pull_disabled")); - } - } - return InteractionResult.sidedSuccess(isRemote()); - } + private final int slot; - //////////////////////////////// - // ****** Configuration ******// - //////////////////////////////// - - @Override - protected CompoundTag writeConfigToTag() { - if (!autoPull) { - CompoundTag tag = super.writeConfigToTag(); - tag.putBoolean("AutoPull", false); - return tag; + private MEStorageBackedFluidStorage(int slot) { + super(Integer.MAX_VALUE); + this.slot = slot; } - // if in auto-pull, no need to write actual configured slots, but still need to write the ghost circuit - CompoundTag tag = new CompoundTag(); - tag.putBoolean("AutoPull", true); - tag.putByte("GhostCircuit", - (byte) IntCircuitBehaviour.getCircuitConfiguration(circuitInventory.getStackInSlot(0))); - return tag; - } - @Override - protected void readConfigFromTag(CompoundTag tag) { - if (tag.getBoolean("AutoPull")) { - // if being set to auto-pull, no need to read the configured slots - this.setAutoPull(true); - circuitInventory.setStackInSlot(0, IntCircuitBehaviour.stack(tag.getByte("GhostCircuit"))); - return; + @Override + public void setFluid(FluidStack stack) { + // no-op } - // set auto pull first to avoid issues with clearing the config after reading from the data stick - this.setAutoPull(false); - super.readConfigFromTag(tag); - } - private class ExportOnlyAEStockingFluidList extends ExportOnlyAEFluidList { + @Override + public FluidStack getFluid() { + IManagedGridNode mainNode = nodeHost.getMainNode(); + if (!mainNode.isActive()) return FluidStack.EMPTY; + assert mainNode.getGrid() != null; - public ExportOnlyAEStockingFluidList(MetaMachine holder, int slots) { - super(holder, slots, ExportOnlyAEStockingFluidSlot::new); + AEFluidKey key = getFluidKey(slot); + if (key == null) return FluidStack.EMPTY; + + long existing = mainNode.getGrid().getStorageService().getCachedInventory().get(key); + if (existing <= 0) return FluidStack.EMPTY; + + return key.toStack(GTMath.saturatedCast(existing)); } @Override - public boolean isAutoPull() { - return autoPull; + public boolean isFluidValid(FluidStack stack) { + AEFluidKey key = getFluidKey(slot); + return key != null && key.matches(stack); } @Override - public boolean isStocking() { - return true; + public boolean supportsFill(int tank) { + return false; } @Override - public boolean hasStackInConfig(GenericStack stack, boolean checkExternal) { - boolean inThisHatch = super.hasStackInConfig(stack, false); - if (inThisHatch) return true; - if (checkExternal) { - return testConfiguredInOtherPart(stack); - } - return false; + public int fill(FluidStack resource, FluidAction action) { + return 0; } - } - private class ExportOnlyAEStockingFluidSlot extends ExportOnlyAEFluidSlot { + @Override + public FluidStack drain(FluidStack resource, FluidAction action) { + if (resource.isEmpty()) return FluidStack.EMPTY; + + AEFluidKey key = getFluidKey(slot); + if (key == null || !key.matches(resource)) return FluidStack.EMPTY; - public ExportOnlyAEStockingFluidSlot() { - super(); + return extract(key, resource.getAmount(), action); } - public ExportOnlyAEStockingFluidSlot(@Nullable GenericStack config, @Nullable GenericStack stock) { - super(config, stock); + @Override + public FluidStack drain(int maxDrain, FluidAction action) { + if (maxDrain <= 0) return FluidStack.EMPTY; + + AEFluidKey key = getFluidKey(slot); + if (key == null) return FluidStack.EMPTY; + + return extract(key, maxDrain, action); } @Override - public ExportOnlyAEFluidSlot copy() { - return new ExportOnlyAEStockingFluidSlot( - this.config == null ? null : copy(this.config), - this.stock == null ? null : copy(this.stock)); + public boolean isEmpty() { + return getFluid().isEmpty(); } @Override - public FluidStack drain(int maxDrain, FluidAction action) { - if (this.stock != null && this.config != null) { - // Extract the items from the real net to either validate (simulate) - // or extract (modulate) when this is called - if (!isOnline()) return FluidStack.EMPTY; - MEStorage aeNetwork = getMainNode().getGrid().getStorageService().getInventory(); - - Actionable actionable = action.simulate() ? Actionable.SIMULATE : Actionable.MODULATE; - var key = config.what(); - long extracted = aeNetwork.extract(key, maxDrain, actionable, actionSource); - - if (extracted > 0) { - FluidStack resultStack = key instanceof AEFluidKey fluidKey ? - AEUtil.toFluidStack(fluidKey, extracted) : FluidStack.EMPTY; - if (action.execute()) { - // may as well update the display here - this.stock = ExportOnlyAESlot.copy(stock, stock.amount() - extracted); - if (this.stock.amount() == 0) { - this.stock = null; - } - if (this.onContentsChanged != null) { - this.onContentsChanged.run(); - } - } - return resultStack; - } - } - return FluidStack.EMPTY; + public int getSpace() { + return Math.max(0, capacity - getFluid().getAmount()); + } + + private FluidStack extract(AEFluidKey key, int amount, FluidAction action) { + IManagedGridNode mainNode = nodeHost.getMainNode(); + if (!mainNode.isActive()) return FluidStack.EMPTY; + assert mainNode.getGrid() != null; + + MEStorage networkInv = mainNode.getGrid().getStorageService().getInventory(); + long extracted = networkInv.extract( + key, + amount, + action.simulate() ? Actionable.SIMULATE : Actionable.MODULATE, + actionSource + ); + if (extracted <= 0) return FluidStack.EMPTY; + + // do not call onContentsChanged() here, as it will be called by IStorageWatcherNode + return key.toStack(Math.toIntExact(extracted)); + } + + private @Nullable AEFluidKey getFluidKey(int slot) { + return (AEFluidKey) configHandler.getKeyInSlot(slot); } } } diff --git a/src/main/java/com/gregtechceu/gtceu/integration/ae2/machine/feature/IGridConnectedMachine.java b/src/main/java/com/gregtechceu/gtceu/integration/ae2/machine/feature/IGridConnectedMachine.java index 8dcbca56391..3e24289ed48 100644 --- a/src/main/java/com/gregtechceu/gtceu/integration/ae2/machine/feature/IGridConnectedMachine.java +++ b/src/main/java/com/gregtechceu/gtceu/integration/ae2/machine/feature/IGridConnectedMachine.java @@ -1,57 +1,17 @@ package com.gregtechceu.gtceu.integration.ae2.machine.feature; -import com.gregtechceu.gtceu.api.machine.feature.IMachineFeature; -import com.gregtechceu.gtceu.config.ConfigHolder; - -import net.minecraft.core.Direction; - import appeng.api.networking.IGridNodeListener; -import appeng.api.util.AECableType; -import appeng.me.helpers.IGridConnectedBlockEntity; +import com.gregtechceu.gtceu.api.machine.feature.IMachineFeature; /** * A machine that can connect to ME network. */ -public interface IGridConnectedMachine extends IMachineFeature, IGridConnectedBlockEntity { - - int ME_UPDATE_INTERVAL = ConfigHolder.INSTANCE.compat.ae2.updateIntervals; +public interface IGridConnectedMachine extends IMachineFeature { /** - * @return return {@code true} if current machine connected to a valid ME network, {@code false} otherwise. + * Called when the block entities main grid nodes power or channel assignment state changes. Primarily used to send + * rendering updates to the client. */ - boolean isOnline(); - - void setOnline(boolean online); - - /** - * @return {@code true} if current machine should interact with ME network, {@code false} otherwise. - */ - default boolean shouldSyncME() { - return self().getOffsetTimer() % ME_UPDATE_INTERVAL == 0; - } - - default AECableType getCableConnectionType(Direction dir) { - return AECableType.SMART; - } - - /** - * Update me network connection status. - * - * @return the updated status. - */ - default boolean updateMEStatus() { - var proxy = getMainNode(); - setOnline(proxy.isOnline() && proxy.isPowered()); - return isOnline(); - } - - @Override - default void saveChanges() { - self().onChanged(); - } - - @Override default void onMainNodeStateChanged(IGridNodeListener.State reason) { - this.updateMEStatus(); } } diff --git a/src/main/java/com/gregtechceu/gtceu/integration/ae2/machine/feature/multiblock/IAutoPullPart.java b/src/main/java/com/gregtechceu/gtceu/integration/ae2/machine/feature/multiblock/IAutoPullPart.java deleted file mode 100644 index cc6db1d8336..00000000000 --- a/src/main/java/com/gregtechceu/gtceu/integration/ae2/machine/feature/multiblock/IAutoPullPart.java +++ /dev/null @@ -1,32 +0,0 @@ -package com.gregtechceu.gtceu.integration.ae2.machine.feature.multiblock; - -import com.gregtechceu.gtceu.api.gui.GuiTextures; -import com.gregtechceu.gtceu.api.gui.fancy.ConfiguratorPanel; -import com.gregtechceu.gtceu.api.gui.fancy.IFancyConfiguratorButton; -import com.gregtechceu.gtceu.api.machine.feature.multiblock.IMultiPart; - -import net.minecraft.network.chat.Component; - -import appeng.api.stacks.GenericStack; - -import java.util.List; -import java.util.function.Predicate; - -public interface IAutoPullPart extends IMultiPart { - - boolean isAutoPull(); - - void setAutoPull(boolean autoPull); - - void setAutoPullTest(Predicate test); - - @Override - default void attachConfigurators(ConfiguratorPanel configuratorPanel) { - configuratorPanel.attachConfigurators(new IFancyConfiguratorButton.Toggle( - GuiTextures.BUTTON_AUTO_PULL.getSubTexture(0, 0, 1, 0.5), - GuiTextures.BUTTON_AUTO_PULL.getSubTexture(0, 0.5, 1, 0.5), - this::isAutoPull, - (clickData, pressed) -> setAutoPull(pressed)) - .setTooltipsSupplier(pressed -> List.of(Component.translatable("gtceu.gui.me_bus.auto_pull_button")))); - } -} diff --git a/src/main/java/com/gregtechceu/gtceu/integration/ae2/machine/feature/multiblock/IMEStockingPart.java b/src/main/java/com/gregtechceu/gtceu/integration/ae2/machine/feature/multiblock/IMEStockingPart.java deleted file mode 100644 index 75515fcaaab..00000000000 --- a/src/main/java/com/gregtechceu/gtceu/integration/ae2/machine/feature/multiblock/IMEStockingPart.java +++ /dev/null @@ -1,67 +0,0 @@ -package com.gregtechceu.gtceu.integration.ae2.machine.feature.multiblock; - -import com.gregtechceu.gtceu.api.machine.feature.multiblock.IMultiController; -import com.gregtechceu.gtceu.integration.ae2.slot.IConfigurableSlotList; - -import net.minecraft.server.TickTask; -import net.minecraft.server.level.ServerLevel; - -import appeng.api.stacks.GenericStack; -import org.jetbrains.annotations.Nullable; - -public interface IMEStockingPart extends IAutoPullPart { - - @Override - default void addedToController(IMultiController controller) { - // ensure that no other stocking bus on this multiblock is configured to hold the same item. - // that we have in our own bus. - setAutoPullTest(stack -> !this.testConfiguredInOtherPart(stack)); - // also ensure that our current config is valid given other inputs - if (self().getLevel() instanceof ServerLevel serverLevel) { - // wait for 1 tick - // we should not access the part list at this time - serverLevel.getServer().tell(new TickTask(0, this::validateConfig)); - } - } - - @Override - default void removedFromController(IMultiController controller) { - setAutoPullTest($ -> false); - if (isAutoPull()) { - getSlotList().clearInventory(0); - } - } - - IConfigurableSlotList getSlotList(); - - /** - * @return True if the passed stack is found as a configuration in any other stocking buses on the multiblock. - */ - boolean testConfiguredInOtherPart(@Nullable GenericStack config); - - /** - * Test for if any of our configured items are in another stocking bus on the multi - * we are attached to. Prevents dupes in certain situations. - */ - default void validateConfig() { - var slots = getSlotList(); - for (int i = 0; i < slots.getConfigurableSlots(); i++) { - var slot = slots.getConfigurableSlot(i); - if (slot.getConfig() != null) { - GenericStack configuredStack = slot.getConfig(); - if (testConfiguredInOtherPart(configuredStack)) { - slot.setConfig(null); - slot.setStock(null); - } - } - } - } - - int getMinStackSize(); - - void setMinStackSize(int newSize); - - int getTicksPerCycle(); - - void setTicksPerCycle(int newSize); -} diff --git a/src/main/java/com/gregtechceu/gtceu/integration/ae2/machine/package-info.java b/src/main/java/com/gregtechceu/gtceu/integration/ae2/machine/package-info.java new file mode 100644 index 00000000000..3842024cb17 --- /dev/null +++ b/src/main/java/com/gregtechceu/gtceu/integration/ae2/machine/package-info.java @@ -0,0 +1,7 @@ +@MethodsReturnNonnullByDefault +@ParametersAreNonnullByDefault +package com.gregtechceu.gtceu.integration.ae2.machine; + +import net.minecraft.MethodsReturnNonnullByDefault; + +import javax.annotation.ParametersAreNonnullByDefault; \ No newline at end of file diff --git a/src/main/java/com/gregtechceu/gtceu/integration/ae2/machine/trait/GridNodeHolder.java b/src/main/java/com/gregtechceu/gtceu/integration/ae2/machine/trait/GridNodeHolder.java deleted file mode 100644 index 50933b53c0f..00000000000 --- a/src/main/java/com/gregtechceu/gtceu/integration/ae2/machine/trait/GridNodeHolder.java +++ /dev/null @@ -1,96 +0,0 @@ -package com.gregtechceu.gtceu.integration.ae2.machine.trait; - -import com.gregtechceu.gtceu.api.machine.trait.MachineTrait; -import com.gregtechceu.gtceu.config.ConfigHolder; -import com.gregtechceu.gtceu.integration.ae2.machine.feature.IGridConnectedMachine; -import com.gregtechceu.gtceu.integration.ae2.utils.SerializableManagedGridNode; - -import com.lowdragmc.lowdraglib.syncdata.annotation.Persisted; -import com.lowdragmc.lowdraglib.syncdata.annotation.ReadOnlyManaged; -import com.lowdragmc.lowdraglib.syncdata.field.ManagedFieldHolder; - -import net.minecraft.core.Direction; -import net.minecraft.nbt.CompoundTag; -import net.minecraft.server.TickTask; -import net.minecraft.server.level.ServerLevel; - -import appeng.api.networking.GridFlags; -import appeng.me.helpers.BlockEntityNodeListener; -import appeng.me.helpers.IGridConnectedBlockEntity; -import lombok.Getter; - -import java.util.EnumSet; - -/** - * A MachineTrait that is only used for hosting grid node and does not provide grid node capability. - * Because IGridConnectedMachine has already extended IInWorldGridNodeHost. - */ -public class GridNodeHolder extends MachineTrait { - - protected final ManagedFieldHolder MANAGED_FIELD_HOLDER = new ManagedFieldHolder(GridNodeHolder.class); - - @Getter - @Persisted - @ReadOnlyManaged(onDirtyMethod = "onGridNodeDirty", - serializeMethod = "serializeGridNode", - deserializeMethod = "deserializeGridNode") - protected final SerializableManagedGridNode mainNode; - - public GridNodeHolder(IGridConnectedMachine machine) { - super(machine.self()); - this.mainNode = createManagedNode(); - } - - protected SerializableManagedGridNode createManagedNode() { - var node = (SerializableManagedGridNode) new SerializableManagedGridNode((IGridConnectedBlockEntity) machine, - BlockEntityNodeListener.INSTANCE) - .setFlags(GridFlags.REQUIRE_CHANNEL) - .setVisualRepresentation(machine.getDefinition().getItem()) - .setIdlePowerUsage(ConfigHolder.INSTANCE.compat.ae2.meHatchEnergyUsage) - .setInWorldNode(true) - .setExposedOnSides( - machine.hasFrontFacing() ? EnumSet.of(machine.getFrontFacing()) : - EnumSet.allOf(Direction.class)) - .setTagName("proxy"); - return node; - } - - protected void createMainNode() { - this.mainNode.create(machine.getLevel(), machine.getPos()); - } - - @Override - public void onMachineLoad() { - super.onMachineLoad(); - if (machine.getLevel() instanceof ServerLevel serverLevel) { - serverLevel.getServer().tell(new TickTask(0, this::createMainNode)); - } - } - - @Override - public void onMachineUnLoad() { - super.onMachineUnLoad(); - mainNode.destroy(); - } - - @Override - public ManagedFieldHolder getFieldHolder() { - return MANAGED_FIELD_HOLDER; - } - - @SuppressWarnings("unused") - public boolean onGridNodeDirty(SerializableManagedGridNode node) { - return node != null && node.isActive() && node.isOnline(); - } - - @SuppressWarnings("unused") - public CompoundTag serializeGridNode(SerializableManagedGridNode node) { - return node.serializeNBT(); - } - - @SuppressWarnings("unused") - public SerializableManagedGridNode deserializeGridNode(CompoundTag tag) { - this.mainNode.deserializeNBT(tag); - return this.mainNode; - } -} diff --git a/src/main/java/com/gregtechceu/gtceu/integration/ae2/machine/trait/GridNodeHost.java b/src/main/java/com/gregtechceu/gtceu/integration/ae2/machine/trait/GridNodeHost.java new file mode 100644 index 00000000000..e7b978150f3 --- /dev/null +++ b/src/main/java/com/gregtechceu/gtceu/integration/ae2/machine/trait/GridNodeHost.java @@ -0,0 +1,100 @@ +package com.gregtechceu.gtceu.integration.ae2.machine.trait; + +import appeng.api.networking.*; +import appeng.api.util.AECableType; +import appeng.me.InWorldGridNode; +import com.gregtechceu.gtceu.api.machine.MetaMachine; +import com.gregtechceu.gtceu.api.machine.trait.MachineTrait; +import com.gregtechceu.gtceu.integration.ae2.machine.feature.IGridConnectedMachine; +import com.lowdragmc.lowdraglib.syncdata.field.ManagedFieldHolder; +import lombok.Getter; +import lombok.Setter; +import net.minecraft.core.Direction; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.server.TickTask; +import net.minecraft.server.level.ServerLevel; +import org.jetbrains.annotations.Nullable; + +public class GridNodeHost extends MachineTrait implements IInWorldGridNodeHost { + + protected static final ManagedFieldHolder MANAGED_FIELD_HOLDER = new ManagedFieldHolder(GridNodeHost.class); + + protected static final IGridNodeListener NODE_LISTENER = new IGridNodeListener<>() { + @Override + public void onSaveChanges(MetaMachine nodeOwner, IGridNode node) { + nodeOwner.onChanged(); + } + + @Override + public void onStateChanged(MetaMachine nodeOwner, IGridNode node, IGridNodeListener.State state) { + if (nodeOwner instanceof IGridConnectedMachine machine) { + machine.onMainNodeStateChanged(state); + } + } + }; + + @Getter + private final IManagedGridNode mainNode; + + @Setter + private AECableType cableType = AECableType.SMART; + + public GridNodeHost(MetaMachine machine) { + super(machine); + this.mainNode = GridHelper.createManagedNode(machine, NODE_LISTENER) + .setInWorldNode(true) + .setVisualRepresentation(machine.getDefinition().getItem()); + } + + public @Nullable IGridNode getGridNode() { + return mainNode.getNode(); + } + + @Override + public @Nullable IGridNode getGridNode(Direction dir) { + var node = this.getMainNode().getNode(); + + // We use the node rather than getGridConnectableSides since the node is already using absolute sides + if (node instanceof InWorldGridNode inWorldGridNode && inWorldGridNode.isExposedOnSide(dir)) { + return node; + } + + return null; + } + + @Override + public AECableType getCableConnectionType(Direction dir) { + return cableType; + } + + @Override + public void onMachineLoad() { + // ensure the node is created after calling IManagedGridNode#loadFromNBT() + if (machine.getLevel() instanceof ServerLevel serverLevel) { + serverLevel.getServer().tell( + new TickTask(0, () -> mainNode.create(machine.getLevel(), machine.getPos())) + ); + } + } + + @Override + public void onMachineUnLoad() { + mainNode.destroy(); + } + + @Override + public void saveCustomPersistedData(CompoundTag tag, boolean forDrop) { + mainNode.saveToNBT(tag); + } + + @Override + public void loadCustomPersistedData(CompoundTag tag) { + mainNode.loadFromNBT(tag); + } + + @Override + public ManagedFieldHolder getFieldHolder() { + return MANAGED_FIELD_HOLDER; + } + +} diff --git a/src/main/java/com/gregtechceu/gtceu/integration/ae2/machine/trait/GridNodeHostTrait.java b/src/main/java/com/gregtechceu/gtceu/integration/ae2/machine/trait/GridNodeHostTrait.java deleted file mode 100644 index 41398dff529..00000000000 --- a/src/main/java/com/gregtechceu/gtceu/integration/ae2/machine/trait/GridNodeHostTrait.java +++ /dev/null @@ -1,51 +0,0 @@ -package com.gregtechceu.gtceu.integration.ae2.machine.trait; - -import com.gregtechceu.gtceu.api.machine.MetaMachine; -import com.gregtechceu.gtceu.api.machine.trait.MachineTrait; - -import com.lowdragmc.lowdraglib.syncdata.field.ManagedFieldHolder; - -import net.minecraft.core.Direction; - -import appeng.api.networking.GridHelper; -import appeng.api.networking.IManagedGridNode; -import appeng.api.util.AECableType; -import appeng.me.helpers.BlockEntityNodeListener; -import appeng.me.helpers.IGridConnectedBlockEntity; - -public class GridNodeHostTrait extends MachineTrait implements IGridConnectedBlockEntity { - - protected final ManagedFieldHolder MANAGED_FIELD_HOLDER = new ManagedFieldHolder(GridNodeHostTrait.class); - private final IManagedGridNode proxy; - - public GridNodeHostTrait(MetaMachine machine) { - super(machine); - this.proxy = GridHelper.createManagedNode(this, BlockEntityNodeListener.INSTANCE) - .setInWorldNode(true) - .setVisualRepresentation(machine.getDefinition().getItem()); - } - - public void init() { - this.proxy.create(machine.getLevel(), machine.getPos()); - } - - @Override - public IManagedGridNode getMainNode() { - return proxy; - } - - @Override - public void saveChanges() { - machine.onChanged(); - } - - @Override - public AECableType getCableConnectionType(Direction dir) { - return AECableType.SMART; - } - - @Override - public ManagedFieldHolder getFieldHolder() { - return MANAGED_FIELD_HOLDER; - } -} diff --git a/src/main/java/com/gregtechceu/gtceu/integration/ae2/machine/trait/KeyStorageBackedHandler.java b/src/main/java/com/gregtechceu/gtceu/integration/ae2/machine/trait/KeyStorageBackedHandler.java new file mode 100644 index 00000000000..4dfb47591b4 --- /dev/null +++ b/src/main/java/com/gregtechceu/gtceu/integration/ae2/machine/trait/KeyStorageBackedHandler.java @@ -0,0 +1,152 @@ +package com.gregtechceu.gtceu.integration.ae2.machine.trait; + +import appeng.api.stacks.AEItemKey; +import com.gregtechceu.gtceu.api.capability.recipe.IO; +import com.gregtechceu.gtceu.api.machine.MetaMachine; +import com.gregtechceu.gtceu.api.machine.trait.NotifiableItemStackHandler; +import com.gregtechceu.gtceu.api.recipe.GTRecipe; +import com.gregtechceu.gtceu.api.recipe.ingredient.IntProviderIngredient; +import com.gregtechceu.gtceu.api.recipe.ingredient.SizedIngredient; +import com.gregtechceu.gtceu.integration.ae2.utils.AEKeyStorage; +import com.gregtechceu.gtceu.utils.GTMath; +import com.lowdragmc.lowdraglib.syncdata.field.ManagedFieldHolder; +import it.unimi.dsi.fastutil.objects.Object2LongMap; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.crafting.Ingredient; +import org.apache.commons.lang3.mutable.MutableBoolean; +import org.jetbrains.annotations.Nullable; + +import java.util.ArrayList; +import java.util.List; +import java.util.ListIterator; + +public class KeyStorageBackedHandler extends NotifiableItemStackHandler { + + protected static final ManagedFieldHolder MANAGED_FIELD_HOLDER = new ManagedFieldHolder( + KeyStorageBackedHandler.class, + NotifiableItemStackHandler.MANAGED_FIELD_HOLDER + ); + + protected final AEKeyStorage keyStorage; + + public KeyStorageBackedHandler(MetaMachine machine, AEKeyStorage keyStorage) { + super(machine, 0, IO.OUT, IO.NONE); + this.keyStorage = keyStorage; + keyStorage.setOnContentsChanged(this::onContentsChanged); + } + + public static @Nullable List handleRecipe( + IO io, + GTRecipe recipe, + List left, + boolean simulate, + IO handlerIO, + AEKeyStorage storage + ) { + // Only handle the intended IO type + if (io != handlerIO || (io != IO.IN && io != IO.OUT)) { + return left.isEmpty() ? null : left; + } + + // Temporarily suppress keyStorage listener to batch notifications + Runnable originalListener = storage.getOnContentsChanged(); + MutableBoolean changed = new MutableBoolean(false); + storage.setOnContentsChanged(changed::setTrue); + + ListIterator it = left.listIterator(); + while (it.hasNext()) { + Ingredient ingredient = it.next(); + + // Remove empty ingredients + if (ingredient.isEmpty()) { + it.remove(); + continue; + } + + ItemStack output; + int amount; + // Handle IntProviderIngredient separately + if (ingredient instanceof IntProviderIngredient provider) { + provider.setItemStacks(null); + provider.setSampledCount(-1); + output = simulate ? provider.getMaxSizeStack() : getFirstStack(provider.getItems()); + amount = output.getCount(); + } else { + output = getFirstStack(ingredient.getItems()); + // Preserve the ingredient amount if it's sized + if (ingredient instanceof SizedIngredient si) { + amount = si.getAmount(); + } else { + amount = output.getCount(); + } + } + + // Insert into keyStorage and compute remaining amount + AEItemKey key = AEItemKey.of(output); + if (key == null) continue; + + int inserted = Math.toIntExact(storage.add(key, amount, simulate)); + int remaining = amount - inserted; + + if (remaining <= 0) { + it.remove(); + continue; + } + + // Update ingredient with remaining amount + if (ingredient instanceof SizedIngredient si) { + si.setAmount(remaining); + } else { + output.setCount(remaining); + } + } + + // Restore listener and trigger if changes occurred and not simulating + storage.setOnContentsChanged(originalListener); + if (changed.booleanValue() && !simulate) { + originalListener.run(); + } + + return left.isEmpty() ? null : left; + } + + private static ItemStack getFirstStack(ItemStack[] items) { + return (items.length == 0) ? ItemStack.EMPTY : items[0]; + } + + @Override + public @Nullable List handleRecipeInner(IO io, GTRecipe recipe, List left, boolean simulate) { + return handleRecipe(io, recipe, left, simulate, IO.OUT, keyStorage); + } + + @Override + public List getContents() { + List result = new ArrayList<>(keyStorage.size()); + for (var entry : keyStorage) { + AEItemKey key = (AEItemKey) entry.getKey(); + long amount = entry.getLongValue(); + result.addAll(GTMath.splitStacks(key.toStack(), amount)); + } + return result; + } + + @Override + public double getTotalContentAmount() { + return keyStorage.stream().mapToLong(Object2LongMap.Entry::getLongValue).sum(); + } + + @Override + public int getSize() { + return keyStorage.size(); + } + + @Override + public boolean isEmpty() { + return keyStorage.isEmpty(); + } + + @Override + public ManagedFieldHolder getFieldHolder() { + return MANAGED_FIELD_HOLDER; + } +} diff --git a/src/main/java/com/gregtechceu/gtceu/integration/ae2/machine/trait/KeyStorageBackedTank.java b/src/main/java/com/gregtechceu/gtceu/integration/ae2/machine/trait/KeyStorageBackedTank.java new file mode 100644 index 00000000000..88af217c6c9 --- /dev/null +++ b/src/main/java/com/gregtechceu/gtceu/integration/ae2/machine/trait/KeyStorageBackedTank.java @@ -0,0 +1,136 @@ +package com.gregtechceu.gtceu.integration.ae2.machine.trait; + +import appeng.api.stacks.AEFluidKey; +import com.gregtechceu.gtceu.api.capability.recipe.IO; +import com.gregtechceu.gtceu.api.machine.MetaMachine; +import com.gregtechceu.gtceu.api.machine.trait.NotifiableFluidTank; +import com.gregtechceu.gtceu.api.recipe.GTRecipe; +import com.gregtechceu.gtceu.api.recipe.ingredient.FluidIngredient; +import com.gregtechceu.gtceu.api.recipe.ingredient.IntProviderFluidIngredient; +import com.gregtechceu.gtceu.integration.ae2.utils.AEKeyStorage; +import com.gregtechceu.gtceu.utils.GTMath; +import com.lowdragmc.lowdraglib.syncdata.field.ManagedFieldHolder; +import it.unimi.dsi.fastutil.objects.Object2LongMap; +import net.minecraftforge.fluids.FluidStack; +import org.apache.commons.lang3.mutable.MutableBoolean; +import org.jetbrains.annotations.Nullable; + +import java.util.ArrayList; +import java.util.List; +import java.util.ListIterator; + +public class KeyStorageBackedTank extends NotifiableFluidTank { + + protected static final ManagedFieldHolder MANAGED_FIELD_HOLDER = new ManagedFieldHolder( + KeyStorageBackedTank.class, + NotifiableFluidTank.MANAGED_FIELD_HOLDER + ); + + protected final AEKeyStorage keyStorage; + + public KeyStorageBackedTank(MetaMachine machine, AEKeyStorage keyStorage) { + super(machine, 0, 0, IO.OUT, IO.NONE); + this.keyStorage = keyStorage; + keyStorage.setOnContentsChanged(this::onContentsChanged); + } + + public static @Nullable List handleRecipe( + IO io, + GTRecipe recipe, + List left, + boolean simulate, + IO handlerIO, + AEKeyStorage storage + ) { + if (io != handlerIO || (io != IO.IN && io != IO.OUT)) { + return left.isEmpty() ? null : left; + } + + Runnable originalListener = storage.getOnContentsChanged(); + MutableBoolean changed = new MutableBoolean(false); + storage.setOnContentsChanged(changed::setTrue); + + ListIterator it = left.listIterator(); + while (it.hasNext()) { + FluidIngredient ingredient = it.next(); + + if (ingredient.isEmpty()) { + it.remove(); + continue; + } + + FluidStack output; + int amount; + if (ingredient instanceof IntProviderFluidIngredient provider) { + provider.setFluidStacks(null); + provider.setSampledCount(-1); + output = simulate ? provider.getMaxSizeStack() : getFirstStack(provider.getStacks()); + } else { + output = getFirstStack(ingredient.getStacks()); + } + + // Insert into keyStorage and compute remaining amount + AEFluidKey key = AEFluidKey.of(output); + if (key == null) continue; + amount = output.getAmount(); + + int inserted = Math.toIntExact(storage.add(key, amount, simulate)); + int remaining = amount - inserted; + + if (remaining <= 0) { + it.remove(); + continue; + } + + ingredient.setAmount(remaining); + } + + storage.setOnContentsChanged(originalListener); + if (changed.booleanValue() && !simulate) { + originalListener.run(); + } + + return left.isEmpty() ? null : left; + } + + private static FluidStack getFirstStack(FluidStack[] stacks) { + return (stacks.length == 0) ? FluidStack.EMPTY : stacks[0]; + } + + @Override + public @Nullable List handleRecipeInner(IO io, GTRecipe recipe, List left, + boolean simulate) { + return handleRecipe(io, recipe, left, simulate, IO.OUT, keyStorage); + } + + @Override + public List getContents() { + List result = new ArrayList<>(keyStorage.size()); + for (var entry : keyStorage) { + AEFluidKey key = (AEFluidKey) entry.getKey(); + long amount = entry.getLongValue(); + result.addAll(GTMath.splitFluidStacks(key.toStack(1), amount)); + } + return result; + } + + @Override + public double getTotalContentAmount() { + return keyStorage.stream().mapToLong(Object2LongMap.Entry::getLongValue).sum(); + } + + @Override + public int getSize() { + return keyStorage.size(); + } + + @Override + public boolean isEmpty() { + return keyStorage.isEmpty(); + } + + @Override + public ManagedFieldHolder getFieldHolder() { + return MANAGED_FIELD_HOLDER; + } +} diff --git a/src/main/java/com/gregtechceu/gtceu/integration/ae2/machine/trait/package-info.java b/src/main/java/com/gregtechceu/gtceu/integration/ae2/machine/trait/package-info.java new file mode 100644 index 00000000000..6a9bf9491bd --- /dev/null +++ b/src/main/java/com/gregtechceu/gtceu/integration/ae2/machine/trait/package-info.java @@ -0,0 +1,7 @@ +@MethodsReturnNonnullByDefault +@ParametersAreNonnullByDefault +package com.gregtechceu.gtceu.integration.ae2.machine.trait; + +import net.minecraft.MethodsReturnNonnullByDefault; + +import javax.annotation.ParametersAreNonnullByDefault; \ No newline at end of file diff --git a/src/main/java/com/gregtechceu/gtceu/integration/ae2/slot/ExportOnlyAEFluidList.java b/src/main/java/com/gregtechceu/gtceu/integration/ae2/slot/ExportOnlyAEFluidList.java deleted file mode 100644 index a87d46b4269..00000000000 --- a/src/main/java/com/gregtechceu/gtceu/integration/ae2/slot/ExportOnlyAEFluidList.java +++ /dev/null @@ -1,144 +0,0 @@ -package com.gregtechceu.gtceu.integration.ae2.slot; - -import com.gregtechceu.gtceu.api.capability.recipe.IO; -import com.gregtechceu.gtceu.api.machine.MetaMachine; -import com.gregtechceu.gtceu.api.machine.trait.NotifiableFluidTank; -import com.gregtechceu.gtceu.api.transfer.fluid.CustomFluidTank; - -import com.lowdragmc.lowdraglib.syncdata.annotation.Persisted; -import com.lowdragmc.lowdraglib.syncdata.field.ManagedFieldHolder; - -import net.minecraftforge.fluids.FluidStack; - -import lombok.Getter; -import org.jetbrains.annotations.NotNull; - -import java.util.function.Supplier; - -public class ExportOnlyAEFluidList extends NotifiableFluidTank implements IConfigurableSlotList { - - public static final ManagedFieldHolder MANAGED_FIELD_HOLDER = new ManagedFieldHolder( - ExportOnlyAEFluidList.class, NotifiableFluidTank.MANAGED_FIELD_HOLDER); - - @Getter - @Persisted - protected ExportOnlyAEFluidSlot[] inventory; - - public ExportOnlyAEFluidList(MetaMachine machine, int slots) { - this(machine, slots, ExportOnlyAEFluidSlot::new); - } - - public ExportOnlyAEFluidList(MetaMachine machine, int slots, Supplier slotFactory) { - super(machine, slots, 0, IO.IN); - this.inventory = new ExportOnlyAEFluidSlot[slots]; - for (int i = 0; i < slots; i++) { - this.inventory[i] = slotFactory.get(); - this.inventory[i].setOnContentsChanged(this::onContentsChanged); - this.storages[i] = new FluidStorageDelegate(inventory[i]); - } - } - - @Override - public int fill(FluidStack resource, FluidAction action) { - return 0; - } - - @Override - public boolean supportsFill(int tank) { - return false; - } - - @Override - public FluidStack drainInternal(int maxDrain, FluidAction action) { - if (maxDrain == 0) { - return FluidStack.EMPTY; - } - FluidStack totalDrained = null; - for (var tank : inventory) { - if (totalDrained == null || totalDrained.isEmpty()) { - totalDrained = tank.drain(maxDrain, action); - if (totalDrained.isEmpty()) { - totalDrained = null; - } else { - maxDrain -= totalDrained.getAmount(); - } - } else { - FluidStack copy = totalDrained.copy(); - copy.setAmount(maxDrain); - FluidStack drain = tank.drain(copy, action); - totalDrained.grow(drain.getAmount()); - maxDrain -= drain.getAmount(); - } - if (maxDrain <= 0) break; - } - return totalDrained == null ? FluidStack.EMPTY : totalDrained; - } - - @Override - public IConfigurableSlot getConfigurableSlot(int index) { - return inventory[index]; - } - - @Override - public int getConfigurableSlots() { - return inventory.length; - } - - public boolean isAutoPull() { - return false; - } - - public boolean isStocking() { - return false; - } - - public boolean ownsSlot(ExportOnlyAEFluidSlot testSlot) { - for (var tank : inventory) { - if (tank == testSlot) { - return true; - } - } - return false; - } - - @Override - public ManagedFieldHolder getFieldHolder() { - return MANAGED_FIELD_HOLDER; - } - - private static class FluidStorageDelegate extends CustomFluidTank { - - private final ExportOnlyAEFluidSlot fluid; - - public FluidStorageDelegate(ExportOnlyAEFluidSlot fluid) { - super(0); - this.fluid = fluid; - } - - @Override - @NotNull - public FluidStack getFluid() { - return this.fluid.getFluid(); - } - - @Override - public @NotNull FluidStack drain(int maxDrain, FluidAction action) { - return fluid.drain(maxDrain, action); - } - - @Override - public @NotNull FluidStack drain(FluidStack resource, FluidAction action) { - return fluid.drain(resource, action); - } - - @Override - public int fill(FluidStack resource, FluidAction action) { - return 0; - } - - @Override - public boolean supportsFill(int tank) { - return false; - } - } -} diff --git a/src/main/java/com/gregtechceu/gtceu/integration/ae2/slot/ExportOnlyAEFluidSlot.java b/src/main/java/com/gregtechceu/gtceu/integration/ae2/slot/ExportOnlyAEFluidSlot.java deleted file mode 100644 index da1f5403259..00000000000 --- a/src/main/java/com/gregtechceu/gtceu/integration/ae2/slot/ExportOnlyAEFluidSlot.java +++ /dev/null @@ -1,151 +0,0 @@ -package com.gregtechceu.gtceu.integration.ae2.slot; - -import com.gregtechceu.gtceu.api.transfer.fluid.IFluidHandlerModifiable; -import com.gregtechceu.gtceu.utils.GTMath; - -import net.minecraft.MethodsReturnNonnullByDefault; -import net.minecraftforge.fluids.FluidStack; -import net.minecraftforge.fluids.IFluidTank; - -import appeng.api.stacks.AEFluidKey; -import appeng.api.stacks.GenericStack; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -import javax.annotation.ParametersAreNonnullByDefault; - -@MethodsReturnNonnullByDefault -@ParametersAreNonnullByDefault -public class ExportOnlyAEFluidSlot extends ExportOnlyAESlot implements IFluidHandlerModifiable, IFluidTank { - - public ExportOnlyAEFluidSlot() { - super(); - } - - public ExportOnlyAEFluidSlot(@Nullable GenericStack config, @Nullable GenericStack stock) { - super(config, stock); - } - - @Override - public void addStack(GenericStack stack) { - if (this.stock == null) { - this.stock = stack; - } else { - this.stock = GenericStack.sum(this.stock, stack); - } - onContentsChanged(); - } - - @Override - public void setStock(@Nullable GenericStack stack) { - if (this.stock == null && stack == null) { - return; - } else if (stack == null) { - this.stock = null; - } else { - if (stack.equals(stock)) return; - this.stock = stack; - } - onContentsChanged(); - } - - @Override - public FluidStack getFluid() { - if (this.stock != null && this.stock.what() instanceof AEFluidKey fluidKey) { - return fluidKey.toStack(GTMath.saturatedCast(this.stock.amount())); - } - return FluidStack.EMPTY; - } - - @Override - public boolean isFluidValid(FluidStack stack) { - return false; - } - - @Override - public int getFluidAmount() { - return this.stock != null ? GTMath.saturatedCast(this.stock.amount()) : 0; - } - - @Override - public int getCapacity() { - // Its capacity is always 0. - return 0; - } - - @Override - public int getTanks() { - return 0; - } - - @Override - public FluidStack getFluidInTank(int tank) { - return getFluid(); - } - - @Override - public void setFluidInTank(int tank, FluidStack stack) {} - - @Override - public int getTankCapacity(int tank) { - return 0; - } - - @Override - public boolean isFluidValid(int tank, @NotNull FluidStack stack) { - return false; - } - - @Override - public int fill(FluidStack resource, FluidAction action) { - return 0; - } - - @Override - public boolean supportsFill(int tank) { - return false; - } - - @Override - public FluidStack drain(FluidStack resource, FluidAction action) { - if (this.getFluid().isFluidEqual(resource)) { - return this.drain(resource.getAmount(), action); - } - return FluidStack.EMPTY; - } - - @Override - public FluidStack drain(int maxDrain, FluidAction action) { - if (this.stock == null || !(this.stock.what() instanceof AEFluidKey fluidKey)) { - return FluidStack.EMPTY; - } - int drained = (int) Math.min(this.stock.amount(), maxDrain); - FluidStack result = fluidKey.toStack(drained); - if (action.execute()) { - this.stock = new GenericStack(this.stock.what(), this.stock.amount() - drained); - if (this.stock.amount() == 0) { - this.stock = null; - } - onContentsChanged(); - } - return result; - } - - @Override - public boolean supportsDrain(int tank) { - return tank == 0; - } - - public void onContentsChanged() { - if (onContentsChanged != null) { - onContentsChanged.run(); - } - } - - @Override - public ExportOnlyAEFluidSlot copy() { - return new ExportOnlyAEFluidSlot( - this.config == null ? null : ExportOnlyAESlot.copy(this.config), - this.stock == null ? null : ExportOnlyAESlot.copy(this.stock)); - } -} diff --git a/src/main/java/com/gregtechceu/gtceu/integration/ae2/slot/ExportOnlyAEItemList.java b/src/main/java/com/gregtechceu/gtceu/integration/ae2/slot/ExportOnlyAEItemList.java deleted file mode 100644 index a757ca42bfa..00000000000 --- a/src/main/java/com/gregtechceu/gtceu/integration/ae2/slot/ExportOnlyAEItemList.java +++ /dev/null @@ -1,177 +0,0 @@ -package com.gregtechceu.gtceu.integration.ae2.slot; - -import com.gregtechceu.gtceu.api.capability.recipe.IO; -import com.gregtechceu.gtceu.api.machine.MetaMachine; -import com.gregtechceu.gtceu.api.machine.trait.NotifiableItemStackHandler; -import com.gregtechceu.gtceu.api.recipe.GTRecipe; -import com.gregtechceu.gtceu.api.transfer.item.CustomItemStackHandler; - -import com.lowdragmc.lowdraglib.syncdata.annotation.Persisted; -import com.lowdragmc.lowdraglib.syncdata.field.ManagedFieldHolder; - -import net.minecraft.world.item.ItemStack; -import net.minecraft.world.item.crafting.Ingredient; - -import lombok.Getter; -import org.jetbrains.annotations.NotNull; - -import java.util.List; -import java.util.function.Supplier; - -public class ExportOnlyAEItemList extends NotifiableItemStackHandler implements IConfigurableSlotList { - - public static final ManagedFieldHolder MANAGED_FIELD_HOLDER = new ManagedFieldHolder(ExportOnlyAEItemList.class, - NotifiableItemStackHandler.MANAGED_FIELD_HOLDER); - - @Persisted - @Getter - protected ExportOnlyAEItemSlot[] inventory; - - private CustomItemStackHandler itemHandler; - - public ExportOnlyAEItemList(MetaMachine holder, int slots) { - this(holder, slots, ExportOnlyAEItemSlot::new); - } - - public ExportOnlyAEItemList(MetaMachine holder, int slots, Supplier slotFactory) { - super(holder, 0, IO.IN, IO.NONE); - this.inventory = new ExportOnlyAEItemSlot[slots]; - for (int i = 0; i < slots; i++) { - this.inventory[i] = slotFactory.get(); - } - for (ExportOnlyAEItemSlot slot : this.inventory) { - slot.setOnContentsChanged(this::onContentsChanged); - } - } - - public CustomItemStackHandler getHandler() { - if (this.itemHandler == null) { - this.itemHandler = new ItemStackHandlerDelegate(inventory); - } - return itemHandler; - } - - @Override - public int getSlotLimit(int slot) { - return Integer.MAX_VALUE; - } - - @Override - public int getSlots() { - return inventory.length; - } - - @Override - public void setStackInSlot(int slot, @NotNull ItemStack stack) { - // NO-OP - } - - @NotNull - @Override - public ItemStack getStackInSlot(int slot) { - if (slot >= 0 && slot < inventory.length) { - return this.inventory[slot].getStackInSlot(0); - } - return ItemStack.EMPTY; - } - - @NotNull - @Override - public ItemStack insertItem(int slot, @NotNull ItemStack stack, boolean simulate) { - return stack; - } - - @NotNull - @Override - public ItemStack extractItemInternal(int slot, int amount, boolean simulate) { - if (slot >= 0 && slot < inventory.length) { - return this.inventory[slot].extractItem(0, amount, simulate); - } - return ItemStack.EMPTY; - } - - @Override - public List handleRecipeInner(IO io, GTRecipe recipe, List left, - boolean simulate) { - return NotifiableItemStackHandler.handleRecipe(io, recipe, left, simulate, this.handlerIO, getHandler()); - } - - @Override - public IConfigurableSlot getConfigurableSlot(int index) { - return inventory[index]; - } - - @Override - public int getConfigurableSlots() { - return inventory.length; - } - - public boolean isAutoPull() { - return false; - } - - public boolean isStocking() { - return false; - } - - @Override - public ManagedFieldHolder getFieldHolder() { - return MANAGED_FIELD_HOLDER; - } - - private static class ItemStackHandlerDelegate extends CustomItemStackHandler { - - private final ExportOnlyAEItemSlot[] inventory; - - public ItemStackHandlerDelegate(ExportOnlyAEItemSlot[] inventory) { - super(); - this.inventory = inventory; - } - - @Override - public int getSlots() { - return inventory.length; - } - - @Override - public ItemStack getStackInSlot(int slot) { - return inventory[slot].getStackInSlot(0); - } - - @Override - public void setStackInSlot(int slot, ItemStack stack) { - // NO-OP - } - - @Override - @NotNull - public ItemStack insertItem(int slot, ItemStack stack, boolean simulate) { - return stack; - } - - @Override - @NotNull - public ItemStack extractItem(int slot, int amount, boolean simulate) { - if (amount == 0) return ItemStack.EMPTY; - validateSlotIndex(slot); - return inventory[slot].extractItem(0, amount, simulate); - } - - @Override - protected void validateSlotIndex(int slot) { - if (slot < 0 || slot >= getSlots()) - throw new RuntimeException( - "Slot " + slot + " not in valid range - [0," + getSlots() + ")"); - } - - @Override - public int getSlotLimit(int slot) { - return Integer.MAX_VALUE; - } - - @Override - public boolean isItemValid(int slot, ItemStack stack) { - return false; - } - } -} diff --git a/src/main/java/com/gregtechceu/gtceu/integration/ae2/slot/ExportOnlyAEItemSlot.java b/src/main/java/com/gregtechceu/gtceu/integration/ae2/slot/ExportOnlyAEItemSlot.java deleted file mode 100644 index f0ce2d0bed5..00000000000 --- a/src/main/java/com/gregtechceu/gtceu/integration/ae2/slot/ExportOnlyAEItemSlot.java +++ /dev/null @@ -1,115 +0,0 @@ -package com.gregtechceu.gtceu.integration.ae2.slot; - -import com.gregtechceu.gtceu.utils.GTMath; - -import net.minecraft.MethodsReturnNonnullByDefault; -import net.minecraft.world.item.ItemStack; -import net.minecraftforge.items.IItemHandlerModifiable; - -import appeng.api.stacks.AEItemKey; -import appeng.api.stacks.GenericStack; -import org.jetbrains.annotations.Nullable; - -import javax.annotation.ParametersAreNonnullByDefault; - -@MethodsReturnNonnullByDefault -@ParametersAreNonnullByDefault -public class ExportOnlyAEItemSlot extends ExportOnlyAESlot implements IItemHandlerModifiable { - - public ExportOnlyAEItemSlot() { - super(); - } - - public ExportOnlyAEItemSlot(@Nullable GenericStack config, @Nullable GenericStack stock) { - super(config, stock); - } - - @Override - public void addStack(GenericStack stack) { - if (this.stock == null) { - this.stock = stack; - } else { - this.stock = GenericStack.sum(this.stock, stack); - } - onContentsChanged(); - } - - @Override - public void setStock(@Nullable GenericStack stack) { - if (this.stock == null && stack == null) { - return; - } else if (stack == null) { - this.stock = null; - } else { - if (stack.equals(stock)) return; - this.stock = stack; - } - onContentsChanged(); - } - - @Override - public int getSlots() { - return 1; - } - - @Override - public void setStackInSlot(int slot, ItemStack stack) { - // NO-OP - } - - @Override - public ItemStack getStackInSlot(int slot) { - if (slot == 0 && this.stock != null) { - return this.stock.what() instanceof AEItemKey itemKey ? - itemKey.toStack(GTMath.saturatedCast(this.stock.amount())) : - ItemStack.EMPTY; - } - return ItemStack.EMPTY; - } - - @Override - public int getSlotLimit(int slot) { - return Integer.MAX_VALUE; - } - - @Override - public boolean isItemValid(int slot, ItemStack stack) { - return false; - } - - @Override - public ItemStack insertItem(int slot, ItemStack stack, boolean simulate) { - return stack; - } - - @Override - public ItemStack extractItem(int slot, int amount, boolean simulate) { - if (slot == 0 && this.stock != null) { - int extracted = (int) Math.min(this.stock.amount(), amount); - if (!(this.stock.what() instanceof AEItemKey itemKey)) return ItemStack.EMPTY; - ItemStack result = itemKey.toStack(extracted); - if (!simulate) { - this.stock = ExportOnlyAESlot.copy(this.stock, this.stock.amount() - extracted); - if (this.stock.amount() == 0) { - this.stock = null; - } - } - onContentsChanged(); - return result; - } - return ItemStack.EMPTY; - } - - public void onContentsChanged() { - if (onContentsChanged != null) { - onContentsChanged.run(); - } - } - - @Override - public ExportOnlyAEItemSlot copy() { - return new ExportOnlyAEItemSlot( - this.config == null ? null : copy(this.config), - this.stock == null ? null : copy(this.stock)); - } -} diff --git a/src/main/java/com/gregtechceu/gtceu/integration/ae2/slot/ExportOnlyAESlot.java b/src/main/java/com/gregtechceu/gtceu/integration/ae2/slot/ExportOnlyAESlot.java deleted file mode 100644 index b98fe200f5a..00000000000 --- a/src/main/java/com/gregtechceu/gtceu/integration/ae2/slot/ExportOnlyAESlot.java +++ /dev/null @@ -1,113 +0,0 @@ -package com.gregtechceu.gtceu.integration.ae2.slot; - -import com.lowdragmc.lowdraglib.syncdata.IContentChangeAware; -import com.lowdragmc.lowdraglib.syncdata.ITagSerializable; - -import net.minecraft.nbt.CompoundTag; - -import appeng.api.stacks.GenericStack; -import lombok.Getter; -import lombok.Setter; -import org.jetbrains.annotations.Nullable; - -/** - * An export only slot to hold {@link appeng.api.stacks.GenericStack} - */ -public abstract class ExportOnlyAESlot implements IConfigurableSlot, ITagSerializable, - IContentChangeAware { - - protected final static String CONFIG_TAG = "config"; - protected final static String STOCK_TAG = "stock"; - - @Getter - @Setter - protected Runnable onContentsChanged = () -> {}; - - @Getter - @Setter - @Nullable - protected GenericStack config; - @Getter - @Setter - @Nullable - protected GenericStack stock; - - public ExportOnlyAESlot(@Nullable GenericStack config, @Nullable GenericStack stock) { - this.config = config; - this.stock = stock; - } - - public ExportOnlyAESlot() { - this(null, null); - } - - @Nullable - public GenericStack requestStack() { - if (this.stock != null && this.stock.amount() <= 0) { - this.stock = null; - } - if (this.config == null || (this.stock != null && !this.config.what().matches(this.stock))) { - return null; - } - if (this.stock == null) { - return copy(this.config); - } - if (this.stock.amount() <= this.config.amount()) { - return copy(this.config, this.config.amount() - this.stock.amount()); - } - return null; - } - - @Nullable - public GenericStack exceedStack() { - if (this.stock != null && this.stock.amount() <= 0) { - this.stock = null; - } - if (this.config == null && this.stock != null) { - return copy(this.stock); - } - if (this.config != null && this.stock != null) { - if (this.config.what().matches(this.stock) && this.config.amount() < this.stock.amount()) { - return copy(this.stock, this.stock.amount() - this.config.amount()); - } - if (!this.config.what().matches(this.stock)) { - return copy(this.stock); - } - } - return null; - } - - protected abstract void addStack(GenericStack stack); - - @Override - public CompoundTag serializeNBT() { - CompoundTag tag = new CompoundTag(); - if (this.config != null) { - CompoundTag configTag = GenericStack.writeTag(this.config); - tag.put(CONFIG_TAG, configTag); - } - if (this.stock != null) { - CompoundTag stockTag = GenericStack.writeTag(this.stock); - tag.put(STOCK_TAG, stockTag); - } - return tag; - } - - @Override - public void deserializeNBT(CompoundTag tag) { - if (tag.contains(CONFIG_TAG)) { - this.config = GenericStack.readTag(tag.getCompound(CONFIG_TAG)); - } - if (tag.contains(STOCK_TAG)) { - this.stock = GenericStack.readTag(tag.getCompound(STOCK_TAG)); - } - } - - public static GenericStack copy(GenericStack stack) { - return new GenericStack(stack.what(), stack.amount()); - } - - public static GenericStack copy(GenericStack stack, long amount) { - return new GenericStack(stack.what(), amount); - } -} diff --git a/src/main/java/com/gregtechceu/gtceu/integration/ae2/slot/IConfigurableSlot.java b/src/main/java/com/gregtechceu/gtceu/integration/ae2/slot/IConfigurableSlot.java deleted file mode 100644 index 98451f68a42..00000000000 --- a/src/main/java/com/gregtechceu/gtceu/integration/ae2/slot/IConfigurableSlot.java +++ /dev/null @@ -1,19 +0,0 @@ -package com.gregtechceu.gtceu.integration.ae2.slot; - -import appeng.api.stacks.GenericStack; - -/** - * A slot that can be set to keep requesting. - */ -public interface IConfigurableSlot { - - GenericStack getConfig(); - - GenericStack getStock(); - - void setConfig(GenericStack val); - - void setStock(GenericStack val); - - IConfigurableSlot copy(); -} diff --git a/src/main/java/com/gregtechceu/gtceu/integration/ae2/slot/IConfigurableSlotList.java b/src/main/java/com/gregtechceu/gtceu/integration/ae2/slot/IConfigurableSlotList.java deleted file mode 100644 index 7de0beafeba..00000000000 --- a/src/main/java/com/gregtechceu/gtceu/integration/ae2/slot/IConfigurableSlotList.java +++ /dev/null @@ -1,30 +0,0 @@ -package com.gregtechceu.gtceu.integration.ae2.slot; - -import appeng.api.stacks.GenericStack; - -public interface IConfigurableSlotList { - - IConfigurableSlot getConfigurableSlot(int index); - - int getConfigurableSlots(); - - default boolean hasStackInConfig(GenericStack stack, boolean checkExternal) { - if (stack == null || stack.amount() <= 0) return false; - for (int i = 0; i < getConfigurableSlots(); i++) { - var slot = getConfigurableSlot(i); - GenericStack config = slot.getConfig(); - if (config != null && config.what().equals(stack.what())) { - return true; - } - } - return false; - } - - default void clearInventory(int startIndex) { - for (int i = startIndex; i < getConfigurableSlots(); i++) { - var slot = getConfigurableSlot(i); - slot.setConfig(null); - slot.setStock(null); - } - } -} diff --git a/src/main/java/com/gregtechceu/gtceu/integration/ae2/utils/AEKeyStorage.java b/src/main/java/com/gregtechceu/gtceu/integration/ae2/utils/AEKeyStorage.java new file mode 100644 index 00000000000..09ed28eeea4 --- /dev/null +++ b/src/main/java/com/gregtechceu/gtceu/integration/ae2/utils/AEKeyStorage.java @@ -0,0 +1,110 @@ +package com.gregtechceu.gtceu.integration.ae2.utils; + +import appeng.api.stacks.AEKey; +import com.lowdragmc.lowdraglib.syncdata.IContentChangeAware; +import com.lowdragmc.lowdraglib.syncdata.ITagSerializable; +import it.unimi.dsi.fastutil.objects.Object2LongMap; +import it.unimi.dsi.fastutil.objects.Object2LongOpenHashMap; +import lombok.Getter; +import lombok.Setter; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.nbt.ListTag; + +import java.util.Iterator; +import java.util.stream.Stream; + +/** + * Storage for AE2 keys with associated amounts. + * Supports serialization, change tracking, and inventory operations. + */ +public class AEKeyStorage implements Iterable>, ITagSerializable, IContentChangeAware { + + private final Object2LongMap storage = new Object2LongOpenHashMap<>(); + + @Getter + @Setter + private Runnable onContentsChanged = () -> { + }; + + /** + * Adds a specified amount of an {@link AEKey} to the storage. + * The stored amount will not exceed {@link Long#MAX_VALUE}. + * + * @param key The key to add. + * @param amount The quantity to add (ignored if <= 0). + * @return The actual amount added to the storage. + */ + public long add(AEKey key, int amount, boolean simulate) { + if (amount <= 0) return 0; + + long existing = storage.getLong(key); + long inserted = Math.min(amount, Long.MAX_VALUE - existing); + if (inserted > 0 && !simulate) { + storage.put(key, existing + inserted); + // Notify that the storage contents have changed + onContentsChanged.run(); + } + return inserted; + } + + public long get(AEKey key) { + return storage.getLong(key); + } + + public long remove(AEKey key, boolean simulate) { + long amount = storage.getLong(key); + if (amount != 0 && !simulate) { + storage.removeLong(key); + onContentsChanged.run(); + } + return amount; + } + + public void clear() { + if (!storage.isEmpty()) { + storage.clear(); + onContentsChanged.run(); + } + } + + public boolean isEmpty() { + return storage.isEmpty(); + } + + public int size() { + return storage.size(); + } + + public Stream> stream() { + return storage.object2LongEntrySet().stream(); + } + + @Override + public Iterator> iterator() { + return storage.object2LongEntrySet().iterator(); + } + + @Override + public ListTag serializeNBT() { + var list = new ListTag(); + for (var entry : storage.object2LongEntrySet()) { + var tag = new CompoundTag(); + tag.put("key", entry.getKey().toTagGeneric()); + tag.putLong("amount", entry.getLongValue()); + list.add(tag); + } + return list; + } + + @Override + public void deserializeNBT(ListTag tags) { + storage.clear(); + for (int i = 0; i < tags.size(); i++) { + var tag = tags.getCompound(i); + var key = AEKey.fromTagGeneric(tag.getCompound("key")); + if (key != null) { + storage.put(key, tag.getInt("amount")); + } + } + } +} diff --git a/src/main/java/com/gregtechceu/gtceu/integration/ae2/utils/AEUtil.java b/src/main/java/com/gregtechceu/gtceu/integration/ae2/utils/AEUtil.java index 792b47dc52b..f215abfe3bb 100644 --- a/src/main/java/com/gregtechceu/gtceu/integration/ae2/utils/AEUtil.java +++ b/src/main/java/com/gregtechceu/gtceu/integration/ae2/utils/AEUtil.java @@ -1,58 +1,70 @@ package com.gregtechceu.gtceu.integration.ae2.utils; -import com.gregtechceu.gtceu.utils.GTMath; - -import net.minecraft.world.item.ItemStack; -import net.minecraftforge.fluids.FluidStack; - -import appeng.api.stacks.AEFluidKey; +import appeng.api.config.Actionable; +import appeng.api.networking.security.IActionSource; import appeng.api.stacks.AEItemKey; -import appeng.api.stacks.GenericStack; -import org.jetbrains.annotations.Nullable; +import appeng.api.stacks.AEKey; +import appeng.api.storage.MEStorage; +import com.gregtechceu.gtceu.utils.GTMath; +import lombok.experimental.UtilityClass; +import net.minecraft.core.BlockPos; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.Block; -import java.util.Objects; +@UtilityClass +public class AEUtil { -import static com.gregtechceu.gtceu.utils.GTMath.split; + /** + * Transfers AEKeyStorage entries to a MEStorage. + * + * @param from The {@link AEKeyStorage} to transfer from. + * @param to The {@link MEStorage} to transfer to. + * @param source The action source for the transfer. + * @param notify Whether to notify the {@link AEKeyStorage} of changes. + */ + public void transferTo(AEKeyStorage from, MEStorage to, IActionSource source, boolean notify) { + if (from.isEmpty()) return; -public class AEUtil { + boolean changed = false; - public static @Nullable GenericStack fromFluidStack(FluidStack stack) { - if (stack == null || stack.isEmpty()) return null; - var key = AEFluidKey.of(stack.getFluid(), stack.getTag()); - return new GenericStack(key, stack.getAmount()); - } + for (var it = from.iterator(); it.hasNext(); ) { + var entry = it.next(); + AEKey key = entry.getKey(); + long amount = entry.getLongValue(); + long inserted = to.insert(key, amount, Actionable.MODULATE, source); + if (inserted > 0) { + changed = true; + long remaining = amount - inserted; + if (remaining <= 0) { + it.remove(); + } else { + entry.setValue(remaining); + } + } + } - public static FluidStack toFluidStack(GenericStack stack) { - var key = stack.what(); - if (key instanceof AEFluidKey fluidKey) { - return toFluidStack(fluidKey, stack.amount()); + if (changed && notify) { + from.getOnContentsChanged().run(); } - return FluidStack.EMPTY; } - public static FluidStack toFluidStack(AEFluidKey key, long amount) { - return key.toStack(GTMath.saturatedCast(amount)); - } + public void dropAllItems(Level level, BlockPos pos, AEKeyStorage storage) { + for (var iterator = storage.iterator(); iterator.hasNext(); ) { + var entry = iterator.next(); + var key = entry.getKey(); - public static ItemStack[] toItemStacks(GenericStack stack) { - var key = stack.what(); - if (key instanceof AEItemKey itemKey) { - return toItemStacks(itemKey, stack.amount()); - } - return new ItemStack[0]; - } + if (!(key instanceof AEItemKey itemKey)) { + continue; + } - public static ItemStack[] toItemStacks(AEItemKey key, long amount) { - var ints = split(amount); - var itemStacks = new ItemStack[ints.length]; - for (int i = 0; i < ints.length; i++) { - itemStacks[i] = key.toStack(ints[i]); - } - return itemStacks; - } + long count = entry.getLongValue(); + var stacks = GTMath.splitStacks(itemKey.toStack(), count); + + for (var stack : stacks) { + Block.popResource(level, pos, stack); + } - public static boolean matches(AEFluidKey key, FluidStack stack) { - return !stack.isEmpty() && key.getFluid().isSame(stack.getFluid()) && - Objects.equals(key.getTag(), stack.getTag()); + iterator.remove(); + } } } diff --git a/src/main/java/com/gregtechceu/gtceu/integration/ae2/utils/DynamicItemStackHandler.java b/src/main/java/com/gregtechceu/gtceu/integration/ae2/utils/DynamicItemStackHandler.java new file mode 100644 index 00000000000..6c2fb40daf6 --- /dev/null +++ b/src/main/java/com/gregtechceu/gtceu/integration/ae2/utils/DynamicItemStackHandler.java @@ -0,0 +1,173 @@ +package com.gregtechceu.gtceu.integration.ae2.utils; + +import com.gregtechceu.gtceu.api.transfer.item.CustomItemStackHandler; +import it.unimi.dsi.fastutil.objects.Object2LongMap; +import net.minecraft.core.NonNullList; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.nbt.ListTag; +import net.minecraft.nbt.Tag; +import net.minecraft.world.item.ItemStack; +import net.minecraftforge.items.ItemHandlerHelper; + +import java.util.ArrayList; +import java.util.Objects; + +public class DynamicItemStackHandler extends CustomItemStackHandler { + + private static final NonNullList EMPTY_LIST = NonNullList.withSize(0, ItemStack.EMPTY); + + private final ArrayList stacks; + + public DynamicItemStackHandler() { + super(EMPTY_LIST); + this.stacks = new ArrayList<>(); + } + + @Override + public void setSize(int size) { + // no op + } + + @Override + public int getSlots() { + return stacks.size(); + } + + @Override + public ItemStack getStackInSlot(int slot) { + validateSlotIndex(slot); + return Objects.requireNonNullElse(stacks.get(slot), ItemStack.EMPTY); + } + + @Override + public void setStackInSlot(int slot, ItemStack stack) { + ensureCapacity(slot); + validateSlotIndex(slot); + stacks.set(slot, stack); + onContentsChanged(slot); + } + + @Override + public ItemStack insertItem(int slot, ItemStack stack, boolean simulate) { + if (stack.isEmpty()) return ItemStack.EMPTY; + if (!isItemValid(slot, stack)) return stack; + + ensureCapacity(slot); + validateSlotIndex(slot); + + ItemStack existing = stacks.get(slot); + int limit = getStackLimit(slot, stack); + + if (!existing.isEmpty()) { + if (!ItemHandlerHelper.canItemStacksStack(stack, existing)) return stack; + limit -= existing.getCount(); + } + + if (limit <= 0) return stack; + + boolean reachedLimit = stack.getCount() > limit; + + if (!simulate) { + if (existing.isEmpty()) { + stacks.set(slot, reachedLimit ? ItemHandlerHelper.copyStackWithSize(stack, limit) : stack); + } else { + existing.grow(reachedLimit ? limit : stack.getCount()); + } + onContentsChanged(slot); + } + + return reachedLimit ? ItemHandlerHelper.copyStackWithSize(stack, stack.getCount() - limit) : ItemStack.EMPTY; + } + + @Override + public ItemStack extractItem(int slot, int amount, boolean simulate) { + if (amount == 0) return ItemStack.EMPTY; + + validateSlotIndex(slot); + + ItemStack existing = stacks.get(slot); + if (existing.isEmpty()) return ItemStack.EMPTY; + + int toExtract = Math.min(amount, existing.getMaxStackSize()); + + if (existing.getCount() <= toExtract) { + if (!simulate) { + stacks.set(slot, ItemStack.EMPTY); + onContentsChanged(slot); + return existing; + } + return existing.copy(); + } + + if (!simulate) { + stacks.set(slot, ItemHandlerHelper.copyStackWithSize(existing, existing.getCount() - toExtract)); + onContentsChanged(slot); + } + + return ItemHandlerHelper.copyStackWithSize(existing, toExtract); + } + + @Override + public void clear() { + stacks.clear(); + onContentsChanged.run(); + } + + @Override + public int getSlotLimit(int slot) { + return Integer.MAX_VALUE; + } + + @Override + protected int getStackLimit(int slot, ItemStack stack) { + return Integer.MAX_VALUE; + } + + @Override + protected void validateSlotIndex(int slot) { + if (slot < 0 || slot >= stacks.size()) { + throw new RuntimeException("Slot " + slot + " not in valid range - [0," + stacks.size() + ")"); + } + } + + @Override + public CompoundTag serializeNBT() { + var nbt = new CompoundTag(); + var items = new ListTag(); + for (int i = 0; i < stacks.size(); i++) { + var stack = stacks.get(i); + if (!stack.isEmpty()) { + var itemTag = new CompoundTag(); + itemTag.putInt("Slot", i); + stack.save(itemTag); + items.add(itemTag); + } + } + nbt.put("Items", items); + nbt.putInt("Size", stacks.size()); + return nbt; + } + + @Override + public void deserializeNBT(CompoundTag nbt) { + int size = nbt.getInt("Size"); + stacks.clear(); + ensureCapacity(size); + + var items = nbt.getList("Items", Tag.TAG_COMPOUND); + for (int i = 0; i < items.size(); i++) { + var itemTag = items.getCompound(i); + int slot = itemTag.getInt("Slot"); + if (slot >= 0 && slot < size) { + stacks.set(slot, ItemStack.of(itemTag)); + } + } + onLoad(); + } + + protected void ensureCapacity(int slot) { + while (stacks.size() <= slot) { + stacks.add(ItemStack.EMPTY); + } + } +} diff --git a/src/main/java/com/gregtechceu/gtceu/integration/ae2/utils/GenericStackHandler.java b/src/main/java/com/gregtechceu/gtceu/integration/ae2/utils/GenericStackHandler.java new file mode 100644 index 00000000000..ac83dee1ad5 --- /dev/null +++ b/src/main/java/com/gregtechceu/gtceu/integration/ae2/utils/GenericStackHandler.java @@ -0,0 +1,94 @@ +package com.gregtechceu.gtceu.integration.ae2.utils; + +import appeng.api.stacks.AEKey; +import appeng.api.stacks.GenericStack; +import com.lowdragmc.lowdraglib.syncdata.IContentChangeAware; +import com.lowdragmc.lowdraglib.syncdata.ITagSerializable; +import lombok.Getter; +import lombok.Setter; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.nbt.ListTag; +import net.minecraft.nbt.Tag; +import org.jetbrains.annotations.Nullable; + +/** + * Multi-slot GenericStack storage handler, similar to ItemStackHandler. + */ +public class GenericStackHandler implements ITagSerializable, IContentChangeAware { + + protected GenericStack[] stacks; + + @Getter + @Setter + private Runnable onContentsChanged = () -> { + }; + + public GenericStackHandler(int size) { + this.stacks = new GenericStack[size]; + } + + public int getSlots() { + return stacks.length; + } + + public @Nullable GenericStack getStackInSlot(int slot) { + validateSlotIndex(slot); + return stacks[slot]; + } + + public @Nullable AEKey getKeyInSlot(int slot) { + GenericStack stack = getStackInSlot(slot); + return stack != null ? stack.what() : null; + } + + public void setStackInSlot(int slot, @Nullable GenericStack stack) { + validateSlotIndex(slot); + stacks[slot] = stack; + onContentsChanged(slot); + } + + public void setKeyInSlot(int slot, @Nullable AEKey key) { + setStackInSlot(slot, key != null ? new GenericStack(key, 1) : null); + } + + protected void validateSlotIndex(int slot) { + if (slot < 0 || slot >= stacks.length) + throw new RuntimeException("Slot " + slot + " not in valid range - [0," + stacks.length + ")"); + } + + protected void onContentsChanged(int slot) { + onContentsChanged.run(); + } + + @Override + public CompoundTag serializeNBT() { + var nbt = new CompoundTag(); + var stacksTag = new ListTag(); + for (int i = 0; i < stacks.length; i++) { + var stack = stacks[i]; + if (stack != null) { + var stackTag = GenericStack.writeTag(stack); + stackTag.putInt("Slot", i); + stacksTag.add(stackTag); + } + } + nbt.put("Stacks", stacksTag); + nbt.putInt("Size", stacks.length); + return nbt; + } + + @Override + public void deserializeNBT(CompoundTag nbt) { + int size = nbt.contains("Size", Tag.TAG_INT) ? nbt.getInt("Size") : stacks.length; + this.stacks = new GenericStack[size]; + + var stacksTag = nbt.getList("Stacks", Tag.TAG_COMPOUND); + for (int i = 0; i < stacksTag.size(); i++) { + var stackTag = stacksTag.getCompound(i); + int slot = stackTag.getInt("Slot"); + if (slot >= 0 && slot < stacks.length) { + stacks[slot] = GenericStack.readTag(stackTag); + } + } + } +} diff --git a/src/main/java/com/gregtechceu/gtceu/integration/ae2/machine/trait/InternalSlotRecipeHandler.java b/src/main/java/com/gregtechceu/gtceu/integration/ae2/utils/InternalSlotRecipeHandler.java similarity index 98% rename from src/main/java/com/gregtechceu/gtceu/integration/ae2/machine/trait/InternalSlotRecipeHandler.java rename to src/main/java/com/gregtechceu/gtceu/integration/ae2/utils/InternalSlotRecipeHandler.java index 4a2e4e49431..42bdb3ee1b4 100644 --- a/src/main/java/com/gregtechceu/gtceu/integration/ae2/machine/trait/InternalSlotRecipeHandler.java +++ b/src/main/java/com/gregtechceu/gtceu/integration/ae2/utils/InternalSlotRecipeHandler.java @@ -1,4 +1,4 @@ -package com.gregtechceu.gtceu.integration.ae2.machine.trait; +package com.gregtechceu.gtceu.integration.ae2.utils; import com.gregtechceu.gtceu.api.capability.recipe.*; import com.gregtechceu.gtceu.api.machine.trait.NotifiableRecipeHandlerTrait; diff --git a/src/main/java/com/gregtechceu/gtceu/integration/ae2/utils/KeyStorage.java b/src/main/java/com/gregtechceu/gtceu/integration/ae2/utils/KeyStorage.java deleted file mode 100644 index 81bb00f1216..00000000000 --- a/src/main/java/com/gregtechceu/gtceu/integration/ae2/utils/KeyStorage.java +++ /dev/null @@ -1,102 +0,0 @@ -package com.gregtechceu.gtceu.integration.ae2.utils; - -import com.lowdragmc.lowdraglib.syncdata.IContentChangeAware; -import com.lowdragmc.lowdraglib.syncdata.ITagSerializable; - -import net.minecraft.MethodsReturnNonnullByDefault; -import net.minecraft.nbt.CompoundTag; -import net.minecraft.nbt.ListTag; - -import appeng.api.config.Actionable; -import appeng.api.networking.security.IActionSource; -import appeng.api.stacks.AEKey; -import appeng.api.storage.MEStorage; -import it.unimi.dsi.fastutil.objects.Object2LongMap; -import it.unimi.dsi.fastutil.objects.Object2LongOpenHashMap; -import lombok.Getter; -import lombok.Setter; -import org.jetbrains.annotations.Nullable; - -import java.util.Iterator; - -/** - * Used to store {@link appeng.api.stacks.GenericStack } in a way that associates key and amount. - * Provides methods for serialization and deserialization. - */ -@MethodsReturnNonnullByDefault -public class KeyStorage implements ITagSerializable, IContentChangeAware, - Iterable> { - - public final Object2LongMap storage = new Object2LongOpenHashMap<>(); // TODO trim periodically or not - - @Nullable - @Getter - @Setter - private Runnable onContentsChanged; - - /** - * Insert the stacks into the inventory as much as possible - * - * @param inventory the inventory into which stacks will be inserted - * @param source the source of the action - */ - public void insertInventory(MEStorage inventory, IActionSource source) { - var it = iterator(); - boolean changed = false; - while (it.hasNext()) { - var entry = it.next(); - var key = entry.getKey(); - var amount = entry.getLongValue(); - long inserted = inventory.insert(key, amount, Actionable.MODULATE, - source); - if (inserted > 0) { - changed = true; - if (inserted >= amount) { - it.remove(); - } else { - entry.setValue(amount - inserted); - } - } - } - if (changed) { - onChanged(); - } - } - - public void onChanged() { - if (onContentsChanged != null) { - onContentsChanged.run(); - } - } - - @Override - public ListTag serializeNBT() { - var list = new ListTag(); - for (var entry : storage.object2LongEntrySet()) { - var tag = new CompoundTag(); - tag.put("key", entry.getKey().toTagGeneric()); - tag.putLong("value", entry.getLongValue()); - list.add(tag); - } - return list; - } - - @Override - public void deserializeNBT(ListTag tags) { - for (int i = 0; i < tags.size(); i++) { - var tag = tags.getCompound(i); - var key = AEKey.fromTagGeneric(tag.getCompound("key")); - long value = tag.getLong("value"); - storage.put(key, value); - } - } - - @Override - public Iterator> iterator() { - return storage.object2LongEntrySet().iterator(); - } - - public boolean isEmpty() { - return storage.isEmpty(); - } -} diff --git a/src/main/java/com/gregtechceu/gtceu/integration/ae2/utils/MEConfigUtil.java b/src/main/java/com/gregtechceu/gtceu/integration/ae2/utils/MEConfigUtil.java new file mode 100644 index 00000000000..68f3bf3b8de --- /dev/null +++ b/src/main/java/com/gregtechceu/gtceu/integration/ae2/utils/MEConfigUtil.java @@ -0,0 +1,71 @@ +package com.gregtechceu.gtceu.integration.ae2.utils; + +import com.gregtechceu.gtceu.common.item.IntCircuitBehaviour; +import lombok.experimental.UtilityClass; +import net.minecraft.nbt.CompoundTag; +import net.minecraftforge.items.IItemHandlerModifiable; + +import java.util.function.Consumer; + +@UtilityClass +public class MEConfigUtil { + + private final String TAG_GHOST_CIRCUIT = "GhostCircuit"; + private final String TAG_DISTINCT_BUSES = "DistinctBuses"; + private final String TAG_CONFIG_HANDLER = "ConfigHandler"; + private final String TAG_AUTO_PULL = "AutoPull"; + private final String TAG_MIN_STACK_SIZE = "MinStackSize"; + + public void writeGhostCircuit(CompoundTag tag, IItemHandlerModifiable circuitInventory) { + tag.putByte( + TAG_GHOST_CIRCUIT, + (byte) IntCircuitBehaviour.getCircuitConfiguration(circuitInventory.getStackInSlot(0)) + ); + } + + public void readGhostCircuit(CompoundTag tag, IItemHandlerModifiable circuitInventory) { + if (tag.contains(TAG_GHOST_CIRCUIT)) { + circuitInventory.setStackInSlot(0, IntCircuitBehaviour.stack(tag.getByte(TAG_GHOST_CIRCUIT))); + } + } + + public void writeDistinctBuses(CompoundTag tag, boolean distinctBuses) { + tag.putBoolean(TAG_DISTINCT_BUSES, distinctBuses); + } + + public void readDistinctBuses(CompoundTag tag, Consumer setter) { + if (tag.contains(TAG_DISTINCT_BUSES)) { + setter.accept(tag.getBoolean(TAG_DISTINCT_BUSES)); + } + } + + public void writeConfigHandler(CompoundTag tag, GenericStackHandler configHandler) { + tag.put(TAG_CONFIG_HANDLER, configHandler.serializeNBT()); + } + + public void readConfigHandler(CompoundTag tag, GenericStackHandler configHandler) { + if (tag.contains(TAG_CONFIG_HANDLER)) { + configHandler.deserializeNBT(tag.getCompound(TAG_CONFIG_HANDLER)); + } + } + + public void writeAutoPull(CompoundTag tag, boolean autoPull) { + tag.putBoolean(TAG_AUTO_PULL, autoPull); + } + + public void readAutoPull(CompoundTag tag, Consumer setter) { + if (tag.contains(TAG_AUTO_PULL)) { + setter.accept(false); + } + } + + public void writeMinStackSize(CompoundTag tag, int minStackSize) { + tag.putInt(TAG_MIN_STACK_SIZE, minStackSize); + } + + public void readMinStackSize(CompoundTag tag, Consumer setter) { + if (tag.contains(TAG_MIN_STACK_SIZE)) { + setter.accept(tag.getInt(TAG_MIN_STACK_SIZE)); + } + } +} diff --git a/src/main/java/com/gregtechceu/gtceu/integration/ae2/machine/trait/ProxySlotRecipeHandler.java b/src/main/java/com/gregtechceu/gtceu/integration/ae2/utils/ProxySlotRecipeHandler.java similarity index 94% rename from src/main/java/com/gregtechceu/gtceu/integration/ae2/machine/trait/ProxySlotRecipeHandler.java rename to src/main/java/com/gregtechceu/gtceu/integration/ae2/utils/ProxySlotRecipeHandler.java index 4d40ca03ebe..59195dab82c 100644 --- a/src/main/java/com/gregtechceu/gtceu/integration/ae2/machine/trait/ProxySlotRecipeHandler.java +++ b/src/main/java/com/gregtechceu/gtceu/integration/ae2/utils/ProxySlotRecipeHandler.java @@ -1,4 +1,4 @@ -package com.gregtechceu.gtceu.integration.ae2.machine.trait; +package com.gregtechceu.gtceu.integration.ae2.utils; import com.gregtechceu.gtceu.api.capability.recipe.*; import com.gregtechceu.gtceu.api.machine.MetaMachine; @@ -9,8 +9,8 @@ import com.gregtechceu.gtceu.api.recipe.GTRecipe; import com.gregtechceu.gtceu.api.recipe.ingredient.FluidIngredient; import com.gregtechceu.gtceu.integration.ae2.machine.MEPatternBufferPartMachine; -import com.gregtechceu.gtceu.integration.ae2.machine.MEPatternBufferProxyPartMachine; -import com.gregtechceu.gtceu.integration.ae2.machine.trait.InternalSlotRecipeHandler.SlotRHL; +import com.gregtechceu.gtceu.integration.ae2.machine.MEPatternProxyPartMachine; +import com.gregtechceu.gtceu.integration.ae2.utils.InternalSlotRecipeHandler.SlotRHL; import com.lowdragmc.lowdraglib.syncdata.ISubscription; @@ -28,7 +28,7 @@ public final class ProxySlotRecipeHandler { @Getter private final List proxySlotHandlers; - public ProxySlotRecipeHandler(MEPatternBufferProxyPartMachine machine, int slots) { + public ProxySlotRecipeHandler(MEPatternProxyPartMachine machine, int slots) { proxySlotHandlers = new ArrayList<>(slots); for (int i = 0; i < slots; ++i) { proxySlotHandlers.add(new ProxyRHL(machine)); @@ -58,7 +58,7 @@ private static class ProxyRHL extends RecipeHandlerList { private final ProxyFluidRecipeHandler sharedFluid; private final ProxyFluidRecipeHandler slotFluid; - public ProxyRHL(MEPatternBufferProxyPartMachine machine) { + public ProxyRHL(MEPatternProxyPartMachine machine) { super(IO.IN); circuit = new ProxyItemRecipeHandler(machine); sharedItem = new ProxyItemRecipeHandler(machine); diff --git a/src/main/java/com/gregtechceu/gtceu/integration/ae2/utils/SerializableManagedGridNode.java b/src/main/java/com/gregtechceu/gtceu/integration/ae2/utils/SerializableManagedGridNode.java deleted file mode 100644 index a4a062247a5..00000000000 --- a/src/main/java/com/gregtechceu/gtceu/integration/ae2/utils/SerializableManagedGridNode.java +++ /dev/null @@ -1,27 +0,0 @@ -package com.gregtechceu.gtceu.integration.ae2.utils; - -import com.lowdragmc.lowdraglib.syncdata.ITagSerializable; - -import net.minecraft.nbt.CompoundTag; - -import appeng.api.networking.IGridNodeListener; -import appeng.me.ManagedGridNode; - -public class SerializableManagedGridNode extends ManagedGridNode implements ITagSerializable { - - public SerializableManagedGridNode(T nodeOwner, IGridNodeListener listener) { - super(nodeOwner, listener); - } - - @Override - public CompoundTag serializeNBT() { - CompoundTag tag = new CompoundTag(); - super.saveToNBT(tag); - return tag; - } - - @Override - public void deserializeNBT(CompoundTag tag) { - super.loadFromNBT(tag); - } -} diff --git a/src/main/java/com/gregtechceu/gtceu/integration/ae2/utils/StockingConfigHandler.java b/src/main/java/com/gregtechceu/gtceu/integration/ae2/utils/StockingConfigHandler.java new file mode 100644 index 00000000000..3adefaa854d --- /dev/null +++ b/src/main/java/com/gregtechceu/gtceu/integration/ae2/utils/StockingConfigHandler.java @@ -0,0 +1,139 @@ +package com.gregtechceu.gtceu.integration.ae2.utils; + +import appeng.api.networking.IStackWatcher; +import appeng.api.networking.storage.IStorageWatcherNode; +import appeng.api.stacks.AEKey; +import appeng.api.stacks.GenericStack; +import appeng.api.stacks.KeyCounter; +import it.unimi.dsi.fastutil.objects.Object2LongMap; +import net.minecraft.nbt.CompoundTag; +import org.apache.commons.lang3.mutable.MutableBoolean; +import org.jetbrains.annotations.Nullable; +import org.jetbrains.annotations.UnknownNullability; + +import java.util.Comparator; +import java.util.Objects; +import java.util.PriorityQueue; + +public class StockingConfigHandler extends GenericStackHandler implements IStorageWatcherNode { + + private @UnknownNullability IStackWatcher storageWatcher; + private Runnable changeListener; + + public StockingConfigHandler(int size, Runnable changeListener) { + super(size); + this.changeListener = changeListener; + } + + @Override + public void updateWatcher(IStackWatcher newWatcher) { + storageWatcher = newWatcher; + syncWatcher(); + } + + @Override + public void onStackChange(AEKey what, long amount) { + changeListener.run(); + } + + @Override + public void setStackInSlot(int slot, @Nullable GenericStack newStack) { + AEKey oldKey = stacks[slot] == null ? null : stacks[slot].what(); + AEKey newKey = newStack == null ? null : newStack.what(); + + if (Objects.equals(oldKey, newKey)) return; + + super.setStackInSlot(slot, newStack); + + // Notify listener + changeListener.run(); + + // Update watcher + if (storageWatcher == null) { + return; + } + + if (oldKey != null) { + storageWatcher.remove(oldKey); + } + + if (newKey != null) { + storageWatcher.add(newKey); + } + } + + @Override + public void deserializeNBT(CompoundTag nbt) { + super.deserializeNBT(nbt); + syncWatcher(); + } + + /** + * Refresh configuration with Top-K keys (by amount) from the ME storage. + * Only keys matching the filter are considered. + * + * @param source ME storage source + * @param filter key filter + */ + public void autoPull(KeyCounter source, Filter filter) { + int slots = getSlots(); + if (slots == 0) return; + + // Top-K via PriorityQueue: keep the highest 'slotCount' entries by amount + var topEntries = new PriorityQueue<>(Comparator.comparingLong(Object2LongMap.Entry::getLongValue)); + + for (var entry : source) { + AEKey key = entry.getKey(); + long amount = entry.getLongValue(); + + if (!filter.test(key, amount)) { + continue; + } + + assert topEntries.peek() != null; + if (topEntries.size() < slots) { + // If the heap is not full, add the entry + topEntries.offer(entry); + } else if (topEntries.peek().getLongValue() < amount) { + // If the heap is full but the current entry has a higher amount, replace the smallest entry + topEntries.poll(); + topEntries.offer(entry); + } + } + + // Suppress listener; batch updates with a single notification + Runnable original = this.changeListener; + MutableBoolean changed = new MutableBoolean(false); + this.changeListener = changed::setTrue; + // Fill slots from highest to lowest + for (int i = slots - 1; i >= 0; i--) { + // Pad with null if no entry available + if (i >= topEntries.size()) { + setKeyInSlot(i, null); + continue; + } + var entry = topEntries.poll(); + setKeyInSlot(i, entry.getKey()); + } + // Restore listener and emit once if changed + this.changeListener = original; + if (changed.booleanValue()) { + changeListener.run(); + } + } + + private void syncWatcher() { + if (storageWatcher == null) return; + + storageWatcher.reset(); + for (GenericStack stack : stacks) { + if (stack != null) { + storageWatcher.add(stack.what()); + } + } + } + + public interface Filter { + boolean test(AEKey key, long amount); + } +} diff --git a/src/main/java/com/gregtechceu/gtceu/integration/ae2/utils/package-info.java b/src/main/java/com/gregtechceu/gtceu/integration/ae2/utils/package-info.java new file mode 100644 index 00000000000..027a5a91783 --- /dev/null +++ b/src/main/java/com/gregtechceu/gtceu/integration/ae2/utils/package-info.java @@ -0,0 +1,7 @@ +@MethodsReturnNonnullByDefault +@ParametersAreNonnullByDefault +package com.gregtechceu.gtceu.integration.ae2.utils; + +import net.minecraft.MethodsReturnNonnullByDefault; + +import javax.annotation.ParametersAreNonnullByDefault; \ No newline at end of file diff --git a/src/main/java/com/gregtechceu/gtceu/integration/jade/provider/GTFluidStorageProvider.java b/src/main/java/com/gregtechceu/gtceu/integration/jade/provider/GTFluidStorageProvider.java index 69b085bb8a5..af25e4aa08d 100644 --- a/src/main/java/com/gregtechceu/gtceu/integration/jade/provider/GTFluidStorageProvider.java +++ b/src/main/java/com/gregtechceu/gtceu/integration/jade/provider/GTFluidStorageProvider.java @@ -6,7 +6,7 @@ import com.gregtechceu.gtceu.common.machine.storage.CreativeTankMachine; import com.gregtechceu.gtceu.common.machine.storage.QuantumTankMachine; import com.gregtechceu.gtceu.integration.ae2.machine.MEPatternBufferPartMachine; -import com.gregtechceu.gtceu.integration.ae2.machine.MEPatternBufferProxyPartMachine; +import com.gregtechceu.gtceu.integration.ae2.machine.MEPatternProxyPartMachine; import net.minecraft.core.registries.BuiltInRegistries; import net.minecraft.nbt.CompoundTag; @@ -74,7 +74,7 @@ public List> getClientGroups(Accessor accessor, Li list.add(JadeForgeUtils.fromFluidStack(stack, capacity)); } return list.isEmpty() ? List.of() : List.of(new ViewGroup<>(list)); - } else if (GTCEu.Mods.isAE2Loaded() && machine instanceof MEPatternBufferProxyPartMachine proxy) { + } else if (GTCEu.Mods.isAE2Loaded() && machine instanceof MEPatternProxyPartMachine proxy) { var buffer = proxy.getBuffer(); if (buffer == null) return Collections.emptyList(); return FluidStorageProvider.INSTANCE.getGroups(serverPlayer, serverLevel, buffer.holder, b); diff --git a/src/main/java/com/gregtechceu/gtceu/integration/jade/provider/GTItemStorageProvider.java b/src/main/java/com/gregtechceu/gtceu/integration/jade/provider/GTItemStorageProvider.java index 6fbb859903f..68d5071f015 100644 --- a/src/main/java/com/gregtechceu/gtceu/integration/jade/provider/GTItemStorageProvider.java +++ b/src/main/java/com/gregtechceu/gtceu/integration/jade/provider/GTItemStorageProvider.java @@ -5,7 +5,7 @@ import com.gregtechceu.gtceu.api.machine.MetaMachine; import com.gregtechceu.gtceu.common.machine.storage.CreativeChestMachine; import com.gregtechceu.gtceu.common.machine.storage.QuantumChestMachine; -import com.gregtechceu.gtceu.integration.ae2.machine.MEPatternBufferProxyPartMachine; +import com.gregtechceu.gtceu.integration.ae2.machine.MEPatternProxyPartMachine; import com.gregtechceu.gtceu.utils.GTMath; import net.minecraft.resources.ResourceLocation; @@ -61,7 +61,7 @@ public List> getClientGroups(Accessor accessor, Lis list.add(stored.copyWithCount(stack)); } return list.isEmpty() ? Collections.emptyList() : List.of(new ViewGroup<>(list)); - } else if (machine instanceof MEPatternBufferProxyPartMachine proxy) { + } else if (machine instanceof MEPatternProxyPartMachine proxy) { var buffer = proxy.getBuffer(); if (buffer == null) return Collections.emptyList(); return ItemStorageProvider.INSTANCE.getGroups(serverPlayer, serverLevel, buffer.holder, b); diff --git a/src/main/java/com/gregtechceu/gtceu/integration/jade/provider/MEPatternBufferProxyProvider.java b/src/main/java/com/gregtechceu/gtceu/integration/jade/provider/MEPatternBufferProxyProvider.java index 562b3af3d11..4d2f7e1e50b 100644 --- a/src/main/java/com/gregtechceu/gtceu/integration/jade/provider/MEPatternBufferProxyProvider.java +++ b/src/main/java/com/gregtechceu/gtceu/integration/jade/provider/MEPatternBufferProxyProvider.java @@ -3,7 +3,7 @@ import com.gregtechceu.gtceu.GTCEu; import com.gregtechceu.gtceu.api.machine.IMachineBlockEntity; import com.gregtechceu.gtceu.client.util.TooltipHelper; -import com.gregtechceu.gtceu.integration.ae2.machine.MEPatternBufferProxyPartMachine; +import com.gregtechceu.gtceu.integration.ae2.machine.MEPatternProxyPartMachine; import net.minecraft.ChatFormatting; import net.minecraft.nbt.CompoundTag; @@ -21,7 +21,7 @@ public class MEPatternBufferProxyProvider implements IBlockComponentProvider, IS @Override public void appendTooltip(ITooltip iTooltip, BlockAccessor blockAccessor, IPluginConfig iPluginConfig) { if (blockAccessor.getBlockEntity() instanceof IMachineBlockEntity blockEntity) { - if (blockEntity.getMetaMachine() instanceof MEPatternBufferProxyPartMachine) { + if (blockEntity.getMetaMachine() instanceof MEPatternProxyPartMachine) { CompoundTag serverData = blockAccessor.getServerData(); if (!serverData.getBoolean("formed")) return; if (!serverData.getBoolean("bound")) { @@ -41,7 +41,7 @@ public void appendTooltip(ITooltip iTooltip, BlockAccessor blockAccessor, IPlugi @Override public void appendServerData(CompoundTag compoundTag, BlockAccessor blockAccessor) { if (blockAccessor.getBlockEntity() instanceof IMachineBlockEntity blockEntity) { - if (blockEntity.getMetaMachine() instanceof MEPatternBufferProxyPartMachine proxy) { + if (blockEntity.getMetaMachine() instanceof MEPatternProxyPartMachine proxy) { if (!proxy.isFormed()) { compoundTag.putBoolean("formed", false); return;