diff --git a/src/main/java/mekanism/client/gui/element/window/GuiTransporterConfig.java b/src/main/java/mekanism/client/gui/element/window/GuiTransporterConfig.java index d0f6df8d411..12bea87cad4 100644 --- a/src/main/java/mekanism/client/gui/element/window/GuiTransporterConfig.java +++ b/src/main/java/mekanism/client/gui/element/window/GuiTransporterConfig.java @@ -47,6 +47,9 @@ public GuiTransporterConfig(IGuiWrapper gui, int x, int y, TILE tile, SelectedWi addChild(new ColorButton(gui, relativeX + 112, relativeY + 49, 16, 16, () -> this.tile.getEjector().getOutputColor(), (element, mouseX, mouseY) -> PacketUtils.sendToServer(new PacketEjectColor(this.tile.getBlockPos(), MekClickType.left(Screen.hasShiftDown()))), (element, mouseX, mouseY) -> PacketUtils.sendToServer(new PacketEjectColor(this.tile.getBlockPos(), MekClickType.RIGHT)))); + addChild(new MekanismImageButton(gui, relativeX + 136, relativeY + 20, 14, getButtonLocation("round_robin"), + (element, mouseX, mouseY) -> PacketUtils.sendToServer(new PacketGuiInteract(GuiInteraction.ROUND_ROBIN_BUTTON, this.tile)))) + .setTooltip(MekanismLang.SORTER_ROUND_ROBIN_DESCRIPTION); addSideDataButton(RelativeSide.BOTTOM, 41, 64 + 16); addSideDataButton(RelativeSide.TOP, 41, 34); addSideDataButton(RelativeSide.FRONT, 41, 57); diff --git a/src/main/java/mekanism/common/content/network/transmitter/LogisticalTransporterBase.java b/src/main/java/mekanism/common/content/network/transmitter/LogisticalTransporterBase.java index d3507d64f97..987067cb6b0 100644 --- a/src/main/java/mekanism/common/content/network/transmitter/LogisticalTransporterBase.java +++ b/src/main/java/mekanism/common/content/network/transmitter/LogisticalTransporterBase.java @@ -26,6 +26,8 @@ import mekanism.common.network.to_client.transmitter.PacketTransporterBatch; import mekanism.common.network.to_client.transmitter.PacketTransporterSync; import mekanism.common.tier.TransporterTier; +import mekanism.common.tile.component.TileComponentEjector; +import mekanism.common.tile.prefab.TileEntityConfigurableMachine; import mekanism.common.tile.transmitter.TileEntityTransmitter; import mekanism.common.util.MekanismUtils; import mekanism.common.util.TransporterUtils; @@ -403,6 +405,14 @@ public TransitResponse inse return insert(outputter, outputterPos, request, color, doEmit, min); } + public TransitResponse insertMaybeRR(@NotNull TileEntityConfigurableMachine outputter, BlockPos outputterPos, TransitRequest request, @Nullable EnumColor color, boolean doEmit, int min) { + TileComponentEjector ejector = outputter.getEjector(); + if (ejector != null && ejector.getRoundRobin()) { + return insert(outputter, outputterPos, request, color, min, doEmit, TransporterStack::recalculateRRPath); + } + return insert(outputter, outputterPos, request, color, doEmit, min); + } + public TransitResponse insert(@Nullable BlockEntity outputter, BlockPos outputterPos, TransitRequest request, @Nullable EnumColor color, boolean doEmit, int min) { return insert(outputter, outputterPos, request, color, min, doEmit, TransporterStack::recalculatePath); } diff --git a/src/main/java/mekanism/common/content/transporter/TransporterStack.java b/src/main/java/mekanism/common/content/transporter/TransporterStack.java index b87c8823f89..975dc510baf 100644 --- a/src/main/java/mekanism/common/content/transporter/TransporterStack.java +++ b/src/main/java/mekanism/common/content/transporter/TransporterStack.java @@ -17,6 +17,7 @@ import mekanism.common.lib.inventory.IAdvancedTransportEjector; import mekanism.common.lib.inventory.TransitRequest; import mekanism.common.lib.inventory.TransitRequest.TransitResponse; +import mekanism.common.tile.prefab.TileEntityConfigurableMachine; import mekanism.common.util.NBTUtils; import mekanism.common.util.WorldUtils; import net.minecraft.core.BlockPos; @@ -228,7 +229,15 @@ public TransitResponse reca return recalculateRRPath(request, outputter, transporter, min, true); } + public TransitResponse recalculateRRPath(TransitRequest request, BE outputter, LogisticalTransporterBase transporter, int min, boolean updateFlowing) { + return getTransitResponseInner(request, outputter.getEjector(), transporter, min, updateFlowing); + } + public TransitResponse recalculateRRPath(TransitRequest request, BE outputter, LogisticalTransporterBase transporter, int min, boolean updateFlowing) { + return getTransitResponseInner(request, outputter, transporter, min, updateFlowing); + } + + public TransitResponse getTransitResponseInner(TransitRequest request, IAdvancedTransportEjector outputter, LogisticalTransporterBase transporter, int min, boolean updateFlowing) { Destination newPath = TransporterPathfinder.getNewRRPath(transporter, this, request, outputter, min); if (newPath == null) { return request.getEmptyResponse(); diff --git a/src/main/java/mekanism/common/lib/inventory/TransitRequest.java b/src/main/java/mekanism/common/lib/inventory/TransitRequest.java index 4ddbcaae95c..619dc8fafab 100644 --- a/src/main/java/mekanism/common/lib/inventory/TransitRequest.java +++ b/src/main/java/mekanism/common/lib/inventory/TransitRequest.java @@ -11,6 +11,7 @@ import mekanism.common.content.network.transmitter.LogisticalTransporterBase; import mekanism.common.content.transporter.TransporterManager; import mekanism.common.lib.inventory.TransitRequest.ItemData; +import mekanism.common.tile.prefab.TileEntityConfigurableMachine; import mekanism.common.util.StackUtils; import mekanism.common.util.WorldUtils; import net.minecraft.core.BlockPos; @@ -81,6 +82,22 @@ public TransitResponse eject(BlockEntity outputter, BlockPos outputterPos, @Null return addToInventoryUnchecked(target, min); } + public TransitResponse ejectMaybeRR(TileEntityConfigurableMachine outputter, @Nullable IItemHandler target, int min, Function outputColor) { + return ejectMaybeRR(outputter, outputter.getBlockPos(), target, min, outputColor); + } + + @NotNull + public TransitResponse ejectMaybeRR(TileEntityConfigurableMachine outputter, BlockPos outputterPos, @Nullable IItemHandler target, int min, + Function outputColor) { + if (isEmpty()) {//Short circuit if our request is empty + return getEmptyResponse(); + } else if (target instanceof CursedTransporterItemHandler cursed) { + LogisticalTransporterBase transporter = cursed.getTransporter(); + return transporter.insertMaybeRR(outputter, outputterPos, this, outputColor.apply(transporter), true, min); + } + return addToInventoryUnchecked(target, min); + } + @NotNull public TransitResponse addToInventory(Level level, BlockPos pos, @Nullable IItemHandler inventory, int min, boolean force) { if (isEmpty()) {//Short circuit if our request is empty diff --git a/src/main/java/mekanism/common/network/to_server/PacketGuiInteract.java b/src/main/java/mekanism/common/network/to_server/PacketGuiInteract.java index 21c16c54537..3e9e80754b1 100644 --- a/src/main/java/mekanism/common/network/to_server/PacketGuiInteract.java +++ b/src/main/java/mekanism/common/network/to_server/PacketGuiInteract.java @@ -30,6 +30,7 @@ import mekanism.common.tile.machine.TileEntityDigitalMiner; import mekanism.common.tile.machine.TileEntityDimensionalStabilizer; import mekanism.common.tile.machine.TileEntityFormulaicAssemblicator; +import mekanism.common.tile.prefab.TileEntityConfigurableMachine; import mekanism.common.tile.qio.TileEntityQIODashboard; import mekanism.common.tile.qio.TileEntityQIOExporter; import mekanism.common.tile.qio.TileEntityQIOImporter; @@ -415,6 +416,8 @@ public enum GuiInteraction {//TODO: Cleanup this enum/the elements in it as it i ROUND_ROBIN_BUTTON((tile, player, extra) -> { if (tile instanceof IAdvancedTransportEjector sorter) { sorter.toggleRoundRobin(); + } else if (tile instanceof TileEntityConfigurableMachine machine) { + machine.getEjector().toggleRoundRobin(); } }), SINGLE_ITEM_BUTTON((tile, player, extra) -> { diff --git a/src/main/java/mekanism/common/tile/component/TileComponentConfig.java b/src/main/java/mekanism/common/tile/component/TileComponentConfig.java index bc35231db3c..3efe72233e4 100644 --- a/src/main/java/mekanism/common/tile/component/TileComponentConfig.java +++ b/src/main/java/mekanism/common/tile/component/TileComponentConfig.java @@ -9,8 +9,8 @@ import java.util.Set; import java.util.function.BiConsumer; import java.util.function.Consumer; -import mekanism.api.SerializationConstants; import mekanism.api.RelativeSide; +import mekanism.api.SerializationConstants; import mekanism.api.chemical.IChemicalTank; import mekanism.api.energy.IEnergyContainer; import mekanism.api.fluid.IExtendedFluidTank; @@ -30,7 +30,6 @@ import mekanism.common.tile.base.TileEntityMekanism; import mekanism.common.tile.component.config.ConfigInfo; import mekanism.common.tile.component.config.DataType; -import mekanism.common.tile.component.config.IPersistentConfigInfo; import mekanism.common.tile.component.config.slot.BaseSlotInfo; import mekanism.common.tile.component.config.slot.ChemicalSlotInfo; import mekanism.common.tile.component.config.slot.EnergySlotInfo; @@ -306,6 +305,7 @@ public static void read(CompoundTag configNBT, Map ConfigInfo info = entry.getValue(); int ordinalToUse = isLegacyData ? type.getLegacyOrdinal() : type.ordinal(); NBTUtils.setBooleanIfPresent(configNBT, SerializationConstants.EJECT + ordinalToUse, info::setEjecting); + NBTUtils.setBooleanIfPresent(configNBT, SerializationConstants.ROUND_ROBIN + ordinalToUse, info::setRoundRobin); String configKey = SerializationConstants.CONFIG + ordinalToUse; if (configNBT.contains(configKey, Tag.TAG_INT_ARRAY)) { readConfigSides(configNBT, onChange, configKey, info, type); @@ -337,13 +337,16 @@ public CompoundTag serialize(HolderLookup.Provider provider) { return write(configInfo, true); } - public static CompoundTag write(Map configInfo, boolean full) { + public static CompoundTag write(Map configInfo, boolean full) { CompoundTag configNBT = new CompoundTag(); - for (Entry entry : configInfo.entrySet()) { + for (Entry entry : configInfo.entrySet()) { TransmissionType type = entry.getKey(); - IPersistentConfigInfo info = entry.getValue(); + ConfigInfo info = entry.getValue(); if (full) { configNBT.putBoolean(SerializationConstants.EJECT + type.ordinal(), info.isEjecting()); + if (type == TransmissionType.ITEM) { + configNBT.putBoolean(SerializationConstants.ROUND_ROBIN + type.ordinal(), info.isRoundRobin()); + } } int[] sideData = new int[EnumUtils.SIDES.length]; for (int i = 0; i < EnumUtils.SIDES.length; i++) { diff --git a/src/main/java/mekanism/common/tile/component/TileComponentEjector.java b/src/main/java/mekanism/common/tile/component/TileComponentEjector.java index 257218187a0..325d4967d13 100644 --- a/src/main/java/mekanism/common/tile/component/TileComponentEjector.java +++ b/src/main/java/mekanism/common/tile/component/TileComponentEjector.java @@ -32,12 +32,14 @@ import mekanism.common.inventory.container.sync.ISyncableData; import mekanism.common.inventory.container.sync.SyncableBoolean; import mekanism.common.inventory.container.sync.SyncableInt; +import mekanism.common.lib.SidedBlockPos; import mekanism.common.lib.inventory.HandlerTransitRequest; +import mekanism.common.lib.inventory.IAdvancedTransportEjector; +import mekanism.common.lib.inventory.TransitRequest; import mekanism.common.lib.inventory.TransitRequest.TransitResponse; import mekanism.common.lib.transmitter.TransmissionType; import mekanism.common.registries.MekanismDataComponents; import mekanism.common.tile.base.CapabilityTileEntity; -import mekanism.common.tile.base.TileEntityMekanism; import mekanism.common.tile.component.config.ConfigInfo; import mekanism.common.tile.component.config.DataType; import mekanism.common.tile.component.config.slot.ChemicalSlotInfo; @@ -45,6 +47,7 @@ import mekanism.common.tile.component.config.slot.FluidSlotInfo; import mekanism.common.tile.component.config.slot.ISlotInfo; import mekanism.common.tile.component.config.slot.InventorySlotInfo; +import mekanism.common.tile.prefab.TileEntityConfigurableMachine; import mekanism.common.util.CableUtils; import mekanism.common.util.ChemicalUtil; import mekanism.common.util.EnumUtils; @@ -60,6 +63,7 @@ import net.minecraft.nbt.CompoundTag; import net.minecraft.nbt.Tag; import net.minecraft.server.level.ServerLevel; +import net.minecraft.world.item.ItemStack; import net.minecraft.world.level.block.entity.BlockEntity; import net.neoforged.neoforge.capabilities.BlockCapabilityCache; import net.neoforged.neoforge.fluids.capability.IFluidHandler; @@ -67,9 +71,9 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -public class TileComponentEjector implements ITileComponent, ISpecificContainerTracker { +public class TileComponentEjector implements ITileComponent, ISpecificContainerTracker, IAdvancedTransportEjector { - private final TileEntityMekanism tile; + private final TileEntityConfigurableMachine tile; private final Map configInfo = new EnumMap<>(TransmissionType.class); private final Map>> capabilityCaches = new EnumMap<>(TransmissionType.class); @@ -88,24 +92,26 @@ public class TileComponentEjector implements ITileComponent, ISpecificContainerT private boolean strictInput; private EnumColor outputColor; private int tickDelay = 0; + @Nullable + private SidedBlockPos rrTarget; - public TileComponentEjector(TileEntityMekanism tile) { + public TileComponentEjector(TileEntityConfigurableMachine tile) { this(tile, MekanismConfig.general.chemicalAutoEjectRate); } - public TileComponentEjector(TileEntityMekanism tile, LongSupplier chemicalEjectRate) { + public TileComponentEjector(TileEntityConfigurableMachine tile, LongSupplier chemicalEjectRate) { this(tile, chemicalEjectRate, MekanismConfig.general.fluidAutoEjectRate); } - public TileComponentEjector(TileEntityMekanism tile, LongSupplier chemicalEjectRate, IntSupplier fluidEjectRate) { + public TileComponentEjector(TileEntityConfigurableMachine tile, LongSupplier chemicalEjectRate, IntSupplier fluidEjectRate) { this(tile, chemicalEjectRate, fluidEjectRate, null); } - public TileComponentEjector(TileEntityMekanism tile, LongSupplier energyEjectRate, boolean energyMarker) { + public TileComponentEjector(TileEntityConfigurableMachine tile, LongSupplier energyEjectRate, boolean energyMarker) { this(tile, MekanismConfig.general.chemicalAutoEjectRate, MekanismConfig.general.fluidAutoEjectRate, energyEjectRate); } - public TileComponentEjector(TileEntityMekanism tile, LongSupplier chemicalEjectRate, IntSupplier fluidEjectRate, @Nullable LongSupplier energyEjectRate) { + public TileComponentEjector(TileEntityConfigurableMachine tile, LongSupplier chemicalEjectRate, IntSupplier fluidEjectRate, @Nullable LongSupplier energyEjectRate) { this.tile = tile; this.chemicalEjectRate = chemicalEjectRate; this.fluidEjectRate = fluidEjectRate; @@ -309,7 +315,7 @@ private void outputItems(Direction facing, ConfigInfo info) { ejectMap.handler = handler; } //If the spot is not loaded just skip trying to eject to it - TransitResponse response = ejectMap.eject(tile, capability, 0, this.outputColorFunction); + TransitResponse response = ejectMap.ejectMaybeRR(tile, capability, 0, this.outputColorFunction); if (!response.isEmpty()) { // use the items returned by the TransitResponse; will be visible next loop response.useAll(); @@ -535,8 +541,48 @@ void computerSetOutputColor(EnumColor color) throws ComputerException { tile.validateSecurityIsPublic(); setOutputColor(color); } + + @Override + public @Nullable SidedBlockPos getRoundRobinTarget() { + return rrTarget; + } + + @Override + public void setRoundRobinTarget(@Nullable SidedBlockPos target) { + rrTarget = target; + } + + @Override + public boolean getRoundRobin() { + ConfigInfo itemConfig = configInfo.get(TransmissionType.ITEM); + return itemConfig != null && itemConfig.isRoundRobin(); + } + + @Override + public void toggleRoundRobin() { + ConfigInfo itemConfig = configInfo.get(TransmissionType.ITEM); + if (itemConfig != null) { + itemConfig.setRoundRobin(!itemConfig.isRoundRobin()); + setRoundRobinTarget((SidedBlockPos) null); + tile.markForSave(); + } + } + + @Override + public boolean canSendHome(@NotNull ItemStack stack) { + //not really likely to be used, as not implemented on Tile + return false; + } + + @Override + @NotNull + public TransitResponse sendHome(TransitRequest request) { + //not really likely to be used, as not implemented on Tile + return request.getEmptyResponse(); + } //End computer related methods + //todo this seems redundant? private static class EjectTransitRequest extends HandlerTransitRequest { public IItemHandler handler; diff --git a/src/main/java/mekanism/common/tile/component/config/ConfigInfo.java b/src/main/java/mekanism/common/tile/component/config/ConfigInfo.java index 0901a597b96..a97a68b0486 100644 --- a/src/main/java/mekanism/common/tile/component/config/ConfigInfo.java +++ b/src/main/java/mekanism/common/tile/component/config/ConfigInfo.java @@ -24,6 +24,7 @@ public class ConfigInfo implements IPersistentConfigInfo { //TODO: Ejecting/can eject, how do we want to use these private boolean canEject; private boolean ejecting; + private boolean roundRobin;//items only private final Map sideConfig; private final Map slotInfo; // used so slot & tank GUIs can quickly reference which color overlay to render @@ -37,6 +38,7 @@ public class ConfigInfo implements IPersistentConfigInfo { public ConfigInfo() { canEject = true; ejecting = false; + roundRobin = false; sideConfig = new EnumMap<>(RelativeSide.class); for (RelativeSide side : EnumUtils.SIDES) { sideConfig.put(side, DataType.NONE); @@ -62,6 +64,14 @@ public void setEjecting(boolean ejecting) { this.ejecting = ejecting; } + public boolean isRoundRobin() { + return roundRobin; + } + + public void setRoundRobin(boolean newRR) { + this.roundRobin = newRR; + } + public void addDisabledSides(@NotNull RelativeSide... sides) { if (disabledSides == null) { disabledSides = EnumSet.noneOf(RelativeSide.class);