aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorquerns <33518699+querns@users.noreply.github.com>2024-07-29 19:46:55 -0500
committerGitHub <noreply@github.com>2024-07-30 07:46:55 +0700
commit450a7874b06ff508987a4b0f3c3621ab4d9d28b3 (patch)
tree264f273abb9f06530e088ca780fbaf2285f7633f /src
parent9cff1eb7d1621cb14ef433a75cda62592a31b2cf (diff)
downloadGT5-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')
-rw-r--r--src/main/java/gregtech/api/gui/modularui/GT_UITextures.java1
-rw-r--r--src/main/java/gregtech/api/gui/widgets/GT_PhantomItemButton.java92
-rw-r--r--src/main/java/gregtech/api/interfaces/metatileentity/IItemLockable.java41
-rw-r--r--src/main/java/gregtech/api/metatileentity/implementations/GT_MetaTileEntity_Hatch_OutputBus.java123
-rw-r--r--src/main/java/gregtech/api/metatileentity/implementations/GT_MetaTileEntity_MultiBlockBase.java41
-rw-r--r--src/main/java/gregtech/common/tileentities/machines/GT_MetaTileEntity_Hatch_OutputBus_ME.java4
-rw-r--r--src/main/java/gtPlusPlus/xmod/gregtech/api/metatileentity/implementations/GT_MetaTileEntity_SuperBus_Output.java8
-rw-r--r--src/main/resources/assets/gregtech/lang/en_US.lang6
-rw-r--r--src/main/resources/assets/gregtech/textures/gui/overlay_slot/filter.pngbin0 -> 4330 bytes
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
new file mode 100644
index 0000000000..1e15885ddb
--- /dev/null
+++ b/src/main/resources/assets/gregtech/textures/gui/overlay_slot/filter.png
Binary files differ