diff options
author | querns <33518699+querns@users.noreply.github.com> | 2024-07-29 19:46:55 -0500 |
---|---|---|
committer | GitHub <noreply@github.com> | 2024-07-30 07:46:55 +0700 |
commit | 450a7874b06ff508987a4b0f3c3621ab4d9d28b3 (patch) | |
tree | 264f273abb9f06530e088ca780fbaf2285f7633f /src | |
parent | 9cff1eb7d1621cb14ef433a75cda62592a31b2cf (diff) | |
download | GT5-Unofficial-450a7874b06ff508987a4b0f3c3621ab4d9d28b3.tar.gz GT5-Unofficial-450a7874b06ff508987a4b0f3c3621ab4d9d28b3.tar.bz2 GT5-Unofficial-450a7874b06ff508987a4b0f3c3621ab4d9d28b3.zip |
Adds lockable output buses (#2787)
* Adds output locking for non-ME output buses
* Add data stick support for output bus filters
* Small optimization to output bus iteration
* spotless, my one true enemy
Diffstat (limited to 'src')
9 files changed, 308 insertions, 8 deletions
diff --git a/src/main/java/gregtech/api/gui/modularui/GT_UITextures.java b/src/main/java/gregtech/api/gui/modularui/GT_UITextures.java index c39b47e903..100c39ea1a 100644 --- a/src/main/java/gregtech/api/gui/modularui/GT_UITextures.java +++ b/src/main/java/gregtech/api/gui/modularui/GT_UITextures.java @@ -88,6 +88,7 @@ public class GT_UITextures { .fullImage(GregTech.ID, "gui/overlay_slot/explosive"); public static final UITexture OVERLAY_SLOT_EXTRUDER_SHAPE = UITexture .fullImage(GregTech.ID, "gui/overlay_slot/extruder_shape"); + public static final UITexture OVERLAY_SLOT_FILTER = UITexture.fullImage(GregTech.ID, "gui/overlay_slot/filter"); public static final UITexture OVERLAY_SLOT_FURNACE = UITexture.fullImage(GregTech.ID, "gui/overlay_slot/furnace"); public static final SteamTexture OVERLAY_SLOT_FURNACE_STEAM = SteamTexture .fullImage(GregTech.ID, "gui/overlay_slot/furnace_%s"); diff --git a/src/main/java/gregtech/api/gui/widgets/GT_PhantomItemButton.java b/src/main/java/gregtech/api/gui/widgets/GT_PhantomItemButton.java new file mode 100644 index 0000000000..4e2d144aa7 --- /dev/null +++ b/src/main/java/gregtech/api/gui/widgets/GT_PhantomItemButton.java @@ -0,0 +1,92 @@ +package gregtech.api.gui.widgets; + +import java.util.List; + +import net.minecraft.item.ItemStack; +import net.minecraft.util.StatCollector; + +import org.apache.commons.lang3.NotImplementedException; +import org.jetbrains.annotations.Nullable; + +import com.google.common.collect.ImmutableList; +import com.gtnewhorizons.modularui.api.ModularUITextures; +import com.gtnewhorizons.modularui.api.drawable.IDrawable; +import com.gtnewhorizons.modularui.api.drawable.Text; +import com.gtnewhorizons.modularui.api.forge.IItemHandlerModifiable; +import com.gtnewhorizons.modularui.common.internal.wrapper.BaseSlot; +import com.gtnewhorizons.modularui.common.widget.SlotWidget; + +import gregtech.api.gui.modularui.GT_UITextures; +import gregtech.api.interfaces.metatileentity.IItemLockable; + +/** + * Creates a phantom item in a GUI. Useful for filtering. + */ +public class GT_PhantomItemButton extends SlotWidget { + + public static final IDrawable[] FILTER_BACKGROUND = { ModularUITextures.ITEM_SLOT, + GT_UITextures.OVERLAY_SLOT_FILTER }; + + public GT_PhantomItemButton(final IItemLockable delegate) { + super(BaseSlot.phantom(new PhantomItemDelegate(delegate), 0)); + controlsAmount = false; + } + + @Override + public List<Text> getTooltip() { + return ImmutableList.of(new Text(StatCollector.translateToLocal("GT5U.bus.filterTooltip.empty"))); + } + + @Override + public List<String> getExtraTooltip() { + return ImmutableList.of(StatCollector.translateToLocal("GT5U.bus.filterTooltip.full")); + } + + @Override + public boolean onMouseScroll(int direction) { + return false; + } + + @SuppressWarnings("ClassCanBeRecord") + private static class PhantomItemDelegate implements IItemHandlerModifiable { + + private final IItemLockable delegate; + + public PhantomItemDelegate(final IItemLockable delegate) { + this.delegate = delegate; + } + + @Override + public void setStackInSlot(int slot, ItemStack itemStack) { + delegate.setLockedItem(itemStack); + } + + @Override + public int getSlots() { + return 1; + } + + @Override + public ItemStack getStackInSlot(int slot) { + return delegate.getLockedItem(); + } + + @Nullable + @Override + public ItemStack insertItem(int slot, ItemStack itemStack, boolean simulate) { + delegate.setLockedItem(itemStack); + return null; + } + + @Nullable + @Override + public ItemStack extractItem(int var1, int var2, boolean var3) { + throw new NotImplementedException("Extract item is disabled for GhostItemButtons."); + } + + @Override + public int getSlotLimit(int slot) { + return 1; + } + } +} diff --git a/src/main/java/gregtech/api/interfaces/metatileentity/IItemLockable.java b/src/main/java/gregtech/api/interfaces/metatileentity/IItemLockable.java new file mode 100644 index 0000000000..65bfb416e2 --- /dev/null +++ b/src/main/java/gregtech/api/interfaces/metatileentity/IItemLockable.java @@ -0,0 +1,41 @@ +package gregtech.api.interfaces.metatileentity; + +import javax.annotation.Nullable; + +import net.minecraft.item.ItemStack; + +/** + * Implement this interface if your MetaTileEntity supports item locking. + */ +public interface IItemLockable { + + /** + * Set the locked item. + * <p> + * Implementers should make a copy of this item, as it can be either a physical item or a ghost item dragged from + * NEI. + * + * @param itemStack An item stack to lock + * @see com.gtnewhorizons.modularui.api.forge.ItemHandlerHelper#copyStackWithSize(ItemStack, int) + */ + void setLockedItem(@Nullable ItemStack itemStack); + + /** + * Get the locked item. + * + * @return an ItemStack of the locked item. Returns null if there is no locked item. + */ + @Nullable + ItemStack getLockedItem(); + + /** + * Clears the lock on the machine. + */ + void clearLock(); + + boolean isLocked(); + + default boolean acceptsItemLock() { + return false; + } +} diff --git a/src/main/java/gregtech/api/metatileentity/implementations/GT_MetaTileEntity_Hatch_OutputBus.java b/src/main/java/gregtech/api/metatileentity/implementations/GT_MetaTileEntity_Hatch_OutputBus.java index 3bd92c6871..4bb85cbd09 100644 --- a/src/main/java/gregtech/api/metatileentity/implementations/GT_MetaTileEntity_Hatch_OutputBus.java +++ b/src/main/java/gregtech/api/metatileentity/implementations/GT_MetaTileEntity_Hatch_OutputBus.java @@ -5,16 +5,25 @@ import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_PIPE_OUT; import static gregtech.api.util.GT_Utility.moveMultipleItemStacks; import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.entity.player.EntityPlayerMP; import net.minecraft.inventory.IInventory; import net.minecraft.item.ItemStack; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.util.ChatComponentTranslation; import net.minecraftforge.common.util.ForgeDirection; +import org.jetbrains.annotations.Nullable; + +import com.gtnewhorizons.modularui.api.forge.ItemHandlerHelper; import com.gtnewhorizons.modularui.api.screen.ModularWindow; import com.gtnewhorizons.modularui.api.screen.UIBuildContext; import gregtech.GT_Mod; +import gregtech.api.enums.ItemList; import gregtech.api.gui.modularui.GT_UIInfos; +import gregtech.api.gui.widgets.GT_PhantomItemButton; import gregtech.api.interfaces.ITexture; +import gregtech.api.interfaces.metatileentity.IItemLockable; import gregtech.api.interfaces.modularui.IAddUIWidgets; import gregtech.api.interfaces.tileentity.IGregTechTileEntity; import gregtech.api.metatileentity.MetaTileEntity; @@ -22,7 +31,12 @@ import gregtech.api.render.TextureFactory; import gregtech.api.util.GT_Utility; import gregtech.api.util.extensions.ArrayExt; -public class GT_MetaTileEntity_Hatch_OutputBus extends GT_MetaTileEntity_Hatch implements IAddUIWidgets { +public class GT_MetaTileEntity_Hatch_OutputBus extends GT_MetaTileEntity_Hatch implements IAddUIWidgets, IItemLockable { + + private static final String DATA_STICK_DATA_TYPE = "outputBusFilter"; + private static final String LOCKED_ITEM_NBT_KEY = "lockedItem"; + + protected ItemStack lockedItem = null; public GT_MetaTileEntity_Hatch_OutputBus(int aID, String aName, String aNameRegional, int aTier) { this(aID, aName, aNameRegional, aTier, getSlots(aTier)); @@ -37,7 +51,9 @@ public class GT_MetaTileEntity_Hatch_OutputBus extends GT_MetaTileEntity_Hatch i slots, ArrayExt.of( "Item Output for Multiblocks", - "Capacity: " + getSlots(tier) + " stack" + (getSlots(tier) >= 2 ? "s" : ""))); + "Capacity: " + getSlots(tier) + " stack" + (getSlots(tier) >= 2 ? "s" : ""), + "Left click with data stick to save filter config", + "Right click with data stick to load filter config")); } public GT_MetaTileEntity_Hatch_OutputBus(int aID, String aName, String aNameRegional, int aTier, @@ -107,8 +123,52 @@ public class GT_MetaTileEntity_Hatch_OutputBus extends GT_MetaTileEntity_Hatch i @Override public boolean onRightclick(IGregTechTileEntity aBaseMetaTileEntity, EntityPlayer aPlayer) { - GT_UIInfos.openGTTileEntityUI(aBaseMetaTileEntity, aPlayer); + if (!acceptsItemLock() || !(aPlayer instanceof EntityPlayerMP)) { + GT_UIInfos.openGTTileEntityUI(aBaseMetaTileEntity, aPlayer); + return super.onRightclick(aBaseMetaTileEntity, aPlayer); + } + + final ItemStack dataStick = aPlayer.inventory.getCurrentItem(); + if (!ItemList.Tool_DataStick.isStackEqual(dataStick, false, true)) { + GT_UIInfos.openGTTileEntityUI(aBaseMetaTileEntity, aPlayer); + return super.onRightclick(aBaseMetaTileEntity, aPlayer); + } + + if (!dataStick.hasTagCompound() || !DATA_STICK_DATA_TYPE.equals(dataStick.stackTagCompound.getString("type"))) { + aPlayer.addChatMessage(new ChatComponentTranslation("GT5U.machines.output_bus.invalid")); + return false; + } + + final NBTTagCompound nbt = dataStick.stackTagCompound; + if (nbt.hasKey(LOCKED_ITEM_NBT_KEY)) { + lockedItem = ItemStack.loadItemStackFromNBT(nbt.getCompoundTag(LOCKED_ITEM_NBT_KEY)); + } else { + lockedItem = null; + } + aPlayer.addChatMessage(new ChatComponentTranslation("GT5U.machines.output_bus.loaded")); return true; + + } + + @Override + public void onLeftclick(IGregTechTileEntity aBaseMetaTileEntity, EntityPlayer aPlayer) { + if (!acceptsItemLock() || !(aPlayer instanceof EntityPlayerMP)) { + return; + } + final ItemStack dataStick = aPlayer.inventory.getCurrentItem(); + if (!ItemList.Tool_DataStick.isStackEqual(dataStick, false, true)) { + return; + } + + final NBTTagCompound nbt = new NBTTagCompound(); + nbt.setString("type", DATA_STICK_DATA_TYPE); + if (lockedItem != null) { + nbt.setTag(LOCKED_ITEM_NBT_KEY, lockedItem.writeToNBT(new NBTTagCompound())); + } + + dataStick.stackTagCompound = nbt; + dataStick.setStackDisplayName("Output Bus Configuration"); + aPlayer.addChatMessage(new ChatComponentTranslation("GT5U.machines.output_bus.saved")); } /** @@ -121,6 +181,11 @@ public class GT_MetaTileEntity_Hatch_OutputBus extends GT_MetaTileEntity_Hatch i */ public boolean storeAll(ItemStack aStack) { markDirty(); + + if (lockedItem != null && !lockedItem.isItemEqual(aStack)) { + return false; + } + for (int i = 0, mInventoryLength = mInventory.length; i < mInventoryLength && aStack.stackSize > 0; i++) { ItemStack tSlot = mInventory[i]; if (GT_Utility.isStackInvalid(tSlot)) { @@ -186,6 +251,22 @@ public class GT_MetaTileEntity_Hatch_OutputBus extends GT_MetaTileEntity_Hatch i } @Override + public void saveNBTData(NBTTagCompound aNBT) { + super.saveNBTData(aNBT); + if (lockedItem != null) { + aNBT.setTag(LOCKED_ITEM_NBT_KEY, lockedItem.writeToNBT(new NBTTagCompound())); + } + } + + @Override + public void loadNBTData(NBTTagCompound aNBT) { + super.loadNBTData(aNBT); + if (aNBT.hasKey(LOCKED_ITEM_NBT_KEY)) { + lockedItem = ItemStack.loadItemStackFromNBT(aNBT.getCompoundTag(LOCKED_ITEM_NBT_KEY)); + } + } + + @Override public boolean useModularUI() { return true; } @@ -198,5 +279,41 @@ public class GT_MetaTileEntity_Hatch_OutputBus extends GT_MetaTileEntity_Hatch i case 2 -> getBaseMetaTileEntity().add3by3Slots(builder); default -> getBaseMetaTileEntity().add4by4Slots(builder); } + + if (acceptsItemLock()) { + builder.widget( + new GT_PhantomItemButton(this).setPos(getGUIWidth() - 25, 40) + .setBackground(GT_PhantomItemButton.FILTER_BACKGROUND)); + } + } + + @Override + public void setLockedItem(@Nullable ItemStack itemStack) { + if (itemStack == null) { + clearLock(); + } else { + lockedItem = ItemHandlerHelper.copyStackWithSize(itemStack, 1); + } + } + + @Nullable + @Override + public ItemStack getLockedItem() { + return lockedItem; + } + + @Override + public void clearLock() { + lockedItem = null; + } + + @Override + public boolean isLocked() { + return lockedItem != null; + } + + @Override + public boolean acceptsItemLock() { + return true; } } diff --git a/src/main/java/gregtech/api/metatileentity/implementations/GT_MetaTileEntity_MultiBlockBase.java b/src/main/java/gregtech/api/metatileentity/implementations/GT_MetaTileEntity_MultiBlockBase.java index 31052f8b8e..ca3e73dfbf 100644 --- a/src/main/java/gregtech/api/metatileentity/implementations/GT_MetaTileEntity_MultiBlockBase.java +++ b/src/main/java/gregtech/api/metatileentity/implementations/GT_MetaTileEntity_MultiBlockBase.java @@ -66,6 +66,7 @@ import gregtech.api.enums.VoidingMode; import gregtech.api.gui.modularui.GT_UIInfos; import gregtech.api.gui.modularui.GT_UITextures; import gregtech.api.interfaces.fluid.IFluidStore; +import gregtech.api.interfaces.metatileentity.IItemLockable; import gregtech.api.interfaces.metatileentity.IMetaTileEntity; import gregtech.api.interfaces.modularui.ControllerWithOptionalFeatures; import gregtech.api.interfaces.modularui.IAddGregtechLogo; @@ -1285,12 +1286,14 @@ public abstract class GT_MetaTileEntity_MultiBlockBase extends MetaTileEntity public boolean addOutput(ItemStack aStack) { if (GT_Utility.isStackInvalid(aStack)) return false; aStack = GT_Utility.copyOrNull(aStack); - for (GT_MetaTileEntity_Hatch_OutputBus tHatch : filterValidMTEs(mOutputBusses)) { - if (tHatch.storeAll(aStack)) { - return true; - } + + final List<GT_MetaTileEntity_Hatch_OutputBus> filteredBuses = filterValidMTEs(mOutputBusses); + if (dumpItem(filteredBuses, aStack, true) || dumpItem(filteredBuses, aStack, false)) { + return true; } + boolean outputSuccess = true; + // noinspection DataFlowIssue while (outputSuccess && aStack.stackSize > 0) { outputSuccess = false; ItemStack single = aStack.splitStack(1); @@ -1304,6 +1307,21 @@ public abstract class GT_MetaTileEntity_MultiBlockBase extends MetaTileEntity return outputSuccess; } + private boolean dumpItem(List<GT_MetaTileEntity_Hatch_OutputBus> outputBuses, ItemStack itemStack, + boolean restrictiveBusesOnly) { + for (GT_MetaTileEntity_Hatch_OutputBus outputBus : outputBuses) { + if (restrictiveBusesOnly && !outputBus.isLocked()) { + continue; + } + + if (outputBus.storeAll(itemStack)) { + return true; + } + } + + return false; + } + public boolean depleteInput(ItemStack aStack) { if (GT_Utility.isStackInvalid(aStack)) return false; FluidStack aLiquid = GT_Utility.getFluidForFilledItem(aStack, true); @@ -2163,7 +2181,20 @@ public abstract class GT_MetaTileEntity_MultiBlockBase extends MetaTileEntity if (!(tBus instanceof GT_MetaTileEntity_Hatch_OutputBus_ME)) { final IInventory tBusInv = tBus.getBaseMetaTileEntity(); for (int i = 0; i < tBusInv.getSizeInventory(); i++) { - ret.add(tBus.getStackInSlot(i)); + final ItemStack stackInSlot = tBus.getStackInSlot(i); + + if (stackInSlot == null && tBus instanceof IItemLockable lockable && lockable.isLocked()) { + // getItemOutputSlots is only used to calculate free room for the purposes of parallels and + // void protection. We can use a fake item stack here without creating weirdness in the output + // bus' actual inventory. + assert lockable.getLockedItem() != null; + ItemStack fakeItemStack = lockable.getLockedItem() + .copy(); + fakeItemStack.stackSize = 0; + ret.add(fakeItemStack); + } else { + ret.add(stackInSlot); + } } } } diff --git a/src/main/java/gregtech/common/tileentities/machines/GT_MetaTileEntity_Hatch_OutputBus_ME.java b/src/main/java/gregtech/common/tileentities/machines/GT_MetaTileEntity_Hatch_OutputBus_ME.java index 8f255b19f6..b32a7be172 100644 --- a/src/main/java/gregtech/common/tileentities/machines/GT_MetaTileEntity_Hatch_OutputBus_ME.java +++ b/src/main/java/gregtech/common/tileentities/machines/GT_MetaTileEntity_Hatch_OutputBus_ME.java @@ -378,4 +378,8 @@ public class GT_MetaTileEntity_Hatch_OutputBus_ME extends GT_MetaTileEntity_Hatc getBaseMetaTileEntity().add1by1Slot(builder); } + @Override + public boolean acceptsItemLock() { + return false; + } } diff --git a/src/main/java/gtPlusPlus/xmod/gregtech/api/metatileentity/implementations/GT_MetaTileEntity_SuperBus_Output.java b/src/main/java/gtPlusPlus/xmod/gregtech/api/metatileentity/implementations/GT_MetaTileEntity_SuperBus_Output.java index aee6235ab9..f5f80bed11 100644 --- a/src/main/java/gtPlusPlus/xmod/gregtech/api/metatileentity/implementations/GT_MetaTileEntity_SuperBus_Output.java +++ b/src/main/java/gtPlusPlus/xmod/gregtech/api/metatileentity/implementations/GT_MetaTileEntity_SuperBus_Output.java @@ -7,6 +7,7 @@ import com.gtnewhorizons.modularui.api.screen.UIBuildContext; import com.gtnewhorizons.modularui.common.widget.Scrollable; import com.gtnewhorizons.modularui.common.widget.SlotWidget; +import gregtech.api.gui.widgets.GT_PhantomItemButton; import gregtech.api.interfaces.ITexture; import gregtech.api.interfaces.tileentity.IGregTechTileEntity; import gregtech.api.metatileentity.MetaTileEntity; @@ -83,6 +84,7 @@ public class GT_MetaTileEntity_SuperBus_Output extends GT_MetaTileEntity_Hatch_O @Override public String[] getDescription() { String[] aDesc = new String[] { "Item Output for Multiblocks", "" + getSlots(this.mTier) + " Slots", + "Left click with data stick to save filter config", "Right click with data stick to load filter config", CORE.GT_Tooltip.get() }; return aDesc; } @@ -101,5 +103,11 @@ public class GT_MetaTileEntity_SuperBus_Output extends GT_MetaTileEntity_Hatch_O builder.widget( scrollable.setSize(18 * 4 + 4, 18 * 4) .setPos(52, 7)); + + if (acceptsItemLock()) { + builder.widget( + new GT_PhantomItemButton(this).setPos(getGUIWidth() - 25, 40) + .setBackground(GT_PhantomItemButton.FILTER_BACKGROUND)); + } } } diff --git a/src/main/resources/assets/gregtech/lang/en_US.lang b/src/main/resources/assets/gregtech/lang/en_US.lang index 1607a2cfb1..c6c55cb9a4 100644 --- a/src/main/resources/assets/gregtech/lang/en_US.lang +++ b/src/main/resources/assets/gregtech/lang/en_US.lang @@ -428,6 +428,9 @@ GT5U.machines.stocking_hatch.auto_pull_toggle.enabled=Automatic Fluid Pull Enabl GT5U.machines.stocking_hatch.auto_pull_toggle.disabled=Automatic Fluid Pull Disabled GT5U.machines.stocking_bus.saved=Saved Config to Data Stick GT5U.machines.stocking_bus.loaded=Loaded Config From Data Stick +GT5U.machines.output_bus.saved=Saved Config to Data Stick +GT5U.machines.output_bus.loaded=Loaded Config From Data Stick +GT5U.machines.output_bus.invalid=Invalid Data Stick config GT5U.machines.dronecentre.shutdown=You cannot control machine when drone centre shut down! GT5U.machines.dronecentre.turnon=Successfully turn on all machines! GT5U.machines.dronecentre.turnoff=Successfully turn off all machines! @@ -573,6 +576,9 @@ GT5U.hatch.infiniteCacheFluid.false=ME Output hatch will stop accepting fluid wh GT5U.hatch.additionalConnection.true=ME channels connect to any side GT5U.hatch.additionalConnection.false=ME channels connect to front side only +GT5U.bus.filterTooltip.empty=§aDrag item from NEI to set output filter +GT5U.bus.filterTooltip.full=§aClick to clear output filter + GT5U.multiblock.pollution=Pollution reduced to GT5U.multiblock.energy=Stored Energy GT5U.multiblock.Progress=Progress diff --git a/src/main/resources/assets/gregtech/textures/gui/overlay_slot/filter.png b/src/main/resources/assets/gregtech/textures/gui/overlay_slot/filter.png Binary files differnew file mode 100644 index 0000000000..1e15885ddb --- /dev/null +++ b/src/main/resources/assets/gregtech/textures/gui/overlay_slot/filter.png |