From 346b0b54f7a8746279c26714ef18b2b078ab65d7 Mon Sep 17 00:00:00 2001 From: Ellpeck Date: Thu, 17 Nov 2016 14:56:26 +0100 Subject: [PATCH] Added filter mod mode --- .../mod/inventory/ContainerBag.java | 6 +- .../mod/inventory/gui/FilterSettingsGui.java | 33 +++-- .../mod/inventory/gui/GuiInputter.java | 10 +- .../actuallyadditions/mod/items/ItemBag.java | 2 +- .../mod/tile/FilterSettings.java | 132 +++++++++++------- .../mod/tile/TileEntityInputter.java | 4 +- .../TileEntityLaserRelayItemWhitelist.java | 6 +- .../mod/tile/TileEntityRangedCollector.java | 2 +- .../textures/gui/guiinputter.png | Bin 3842 -> 4090 bytes 9 files changed, 123 insertions(+), 72 deletions(-) diff --git a/src/main/java/de/ellpeck/actuallyadditions/mod/inventory/ContainerBag.java b/src/main/java/de/ellpeck/actuallyadditions/mod/inventory/ContainerBag.java index 250251169..d8755c2c8 100644 --- a/src/main/java/de/ellpeck/actuallyadditions/mod/inventory/ContainerBag.java +++ b/src/main/java/de/ellpeck/actuallyadditions/mod/inventory/ContainerBag.java @@ -33,7 +33,7 @@ import java.util.Arrays; public class ContainerBag extends Container implements IButtonReactor{ - public final FilterSettings filter = new FilterSettings(0, 4, false, true, false, 0, -1000); + public final FilterSettings filter = new FilterSettings(0, 4, false, true, false, false, 0, -1000); private final InventoryBag bagInventory; private final InventoryPlayer inventory; private final boolean isVoid; @@ -110,6 +110,7 @@ public class ContainerBag extends Container implements IButtonReactor{ listener.sendProgressBarUpdate(this, 2, this.filter.respectNBT ? 1 : 0); listener.sendProgressBarUpdate(this, 3, this.filter.respectOredict); listener.sendProgressBarUpdate(this, 4, this.autoInsert ? 1 : 0); + listener.sendProgressBarUpdate(this, 5, this.filter.respectMod ? 1 : 0); } this.filter.updateLasts(); this.oldAutoInsert = this.autoInsert; @@ -134,6 +135,9 @@ public class ContainerBag extends Container implements IButtonReactor{ else if(id == 4){ this.autoInsert = data == 1; } + else if(id == 5){ + this.filter.respectMod = data == 1; + } } @Override diff --git a/src/main/java/de/ellpeck/actuallyadditions/mod/inventory/gui/FilterSettingsGui.java b/src/main/java/de/ellpeck/actuallyadditions/mod/inventory/gui/FilterSettingsGui.java index 2e6f3dbf3..f628f2275 100644 --- a/src/main/java/de/ellpeck/actuallyadditions/mod/inventory/gui/FilterSettingsGui.java +++ b/src/main/java/de/ellpeck/actuallyadditions/mod/inventory/gui/FilterSettingsGui.java @@ -34,31 +34,36 @@ public class FilterSettingsGui extends Gui{ public SmallerButton whitelistButton; public SmallerButton metaButton; public SmallerButton nbtButton; + public SmallerButton modButton; public SmallerButton oredictButton; public FilterSettingsGui(FilterSettings settings, int x, int y, List buttonList){ this.theSettings = settings; - this.whitelistButton = new SmallerButton(this.theSettings.whitelistButtonId, x, y, ""); + this.whitelistButton = new SmallerButton(this.theSettings.whitelistButtonId, x, y, "", true); buttonList.add(this.whitelistButton); - - this.metaButton = new SmallerButton(this.theSettings.metaButtonId, x, y+18, ""); + y+=14; + this.metaButton = new SmallerButton(this.theSettings.metaButtonId, x, y, "", true); buttonList.add(this.metaButton); - - this.nbtButton = new SmallerButton(this.theSettings.nbtButtonId, x, y+36, ""); + y+=14; + this.nbtButton = new SmallerButton(this.theSettings.nbtButtonId, x, y, "", true); buttonList.add(this.nbtButton); - - this.oredictButton = new SmallerButton(this.theSettings.oredictButtonId, x, y+54, ""); + y+=14; + this.oredictButton = new SmallerButton(this.theSettings.oredictButtonId, x, y, "", true); buttonList.add(this.oredictButton); + y+=15; + this.modButton = new SmallerButton(this.theSettings.modButtonId, x, y, "", true); + buttonList.add(this.modButton); this.update(); } public void update(){ - this.whitelistButton.displayString = (this.theSettings.isWhitelist ? TextFormatting.DARK_GREEN : TextFormatting.RED)+"W"; - this.metaButton.displayString = (this.theSettings.respectMeta ? TextFormatting.DARK_GREEN : TextFormatting.RED)+"M"; - this.nbtButton.displayString = (this.theSettings.respectNBT ? TextFormatting.DARK_GREEN : TextFormatting.RED)+"N"; - this.oredictButton.displayString = (this.theSettings.respectOredict == 0 ? TextFormatting.RED : (this.theSettings.respectOredict == 1 ? TextFormatting.GREEN : TextFormatting.DARK_GREEN))+"O"; + this.whitelistButton.displayString = (this.theSettings.isWhitelist ? TextFormatting.DARK_GREEN : TextFormatting.RED)+"WH"; + this.metaButton.displayString = (this.theSettings.respectMeta ? TextFormatting.DARK_GREEN : TextFormatting.RED)+"ME"; + this.nbtButton.displayString = (this.theSettings.respectNBT ? TextFormatting.DARK_GREEN : TextFormatting.RED)+"NB"; + this.modButton.displayString = (this.theSettings.respectMod ? TextFormatting.DARK_GREEN : TextFormatting.RED)+"MO"; + this.oredictButton.displayString = (this.theSettings.respectOredict == 0 ? TextFormatting.RED : (this.theSettings.respectOredict == 1 ? TextFormatting.GREEN : TextFormatting.DARK_GREEN))+"OR"; } public void drawHover(int mouseX, int mouseY){ @@ -76,6 +81,12 @@ public class FilterSettingsGui extends Gui{ else if(this.nbtButton.isMouseOver()){ GuiUtils.drawHoveringText(Collections.singletonList(TextFormatting.BOLD+(this.theSettings.respectNBT ? "Respecting" : "Ignoring")+" NBT"), mouseX, mouseY, mc.displayWidth, mc.displayHeight, -1, mc.fontRendererObj); } + else if(this.modButton.isMouseOver()){ + List list = new ArrayList(); + list.add(TextFormatting.BOLD+"Mod Mode "+(this.theSettings.respectMod ? "On" : "Off")); + list.addAll(mc.fontRendererObj.listFormattedStringToWidth("If this is enabled, the filter will compare the mods items come from "+TextFormatting.RED+"instead of comparing the items themselves"+TextFormatting.RESET+". This can be useful for storage systems with mod-based chests. \nCan also be combined with the other options, but that normally isn't very useful.", 200)); + GuiUtils.drawHoveringText(list, mouseX, mouseY, mc.displayWidth, mc.displayHeight, -1, mc.fontRendererObj); + } else if(this.oredictButton.isMouseOver()){ List list = new ArrayList(); list.add(TextFormatting.BOLD+(this.theSettings.respectOredict == 0 ? "Ignoring" : (this.theSettings.respectOredict == 1 ? "Soft Respecting" : "Hard Respecting"))+" OreDictionary"); diff --git a/src/main/java/de/ellpeck/actuallyadditions/mod/inventory/gui/GuiInputter.java b/src/main/java/de/ellpeck/actuallyadditions/mod/inventory/gui/GuiInputter.java index b1625d522..040784dc1 100644 --- a/src/main/java/de/ellpeck/actuallyadditions/mod/inventory/gui/GuiInputter.java +++ b/src/main/java/de/ellpeck/actuallyadditions/mod/inventory/gui/GuiInputter.java @@ -265,9 +265,15 @@ public class GuiInputter extends GuiContainer{ public static class SmallerButton extends GuiButton{ public final ResourceLocation resLoc = AssetUtil.getGuiLocation("guiInputter"); + private final boolean smaller; public SmallerButton(int id, int x, int y, String display){ - super(id, x, y, 16, 16, display); + this(id, x, y, display, false); + } + + public SmallerButton(int id, int x, int y, String display, boolean smaller){ + super(id, x, y, 16, smaller ? 12 : 16, display); + this.smaller = smaller; } @Override @@ -280,7 +286,7 @@ public class GuiInputter extends GuiContainer{ GlStateManager.enableBlend(); GlStateManager.tryBlendFuncSeparate(770, 771, 1, 0); GlStateManager.blendFunc(770, 771); - this.drawTexturedModalRect(this.xPosition, this.yPosition, 176, k*16, 16, 16); + this.drawTexturedModalRect(this.xPosition, this.yPosition, this.smaller ? 200 : 176, k*this.height, this.width, this.height); this.mouseDragged(mc, x, y); int color = 14737632; diff --git a/src/main/java/de/ellpeck/actuallyadditions/mod/items/ItemBag.java b/src/main/java/de/ellpeck/actuallyadditions/mod/items/ItemBag.java index 32610782c..44e442c9d 100644 --- a/src/main/java/de/ellpeck/actuallyadditions/mod/items/ItemBag.java +++ b/src/main/java/de/ellpeck/actuallyadditions/mod/items/ItemBag.java @@ -78,7 +78,7 @@ public class ItemBag extends ItemBase{ ItemStack[] inventory = new ItemStack[ContainerBag.getSlotAmount(isVoid)]; ItemDrill.loadSlotsFromNBT(inventory, invStack); - FilterSettings filter = new FilterSettings(0, 4, false, false, false, 0, 0); + FilterSettings filter = new FilterSettings(0, 4, false, false, false, false, 0, 0); filter.readFromNBT(invStack.getTagCompound(), "Filter"); if(filter.check(stack, inventory)){ if(isVoid){ diff --git a/src/main/java/de/ellpeck/actuallyadditions/mod/tile/FilterSettings.java b/src/main/java/de/ellpeck/actuallyadditions/mod/tile/FilterSettings.java index aba51bd12..b0d5bc4f0 100644 --- a/src/main/java/de/ellpeck/actuallyadditions/mod/tile/FilterSettings.java +++ b/src/main/java/de/ellpeck/actuallyadditions/mod/tile/FilterSettings.java @@ -14,48 +14,58 @@ import de.ellpeck.actuallyadditions.mod.inventory.ContainerFilter; import de.ellpeck.actuallyadditions.mod.items.ItemDrill; import de.ellpeck.actuallyadditions.mod.items.ItemFilter; import de.ellpeck.actuallyadditions.mod.util.StackUtil; +import net.minecraft.item.Item; import net.minecraft.item.ItemStack; import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.util.ResourceLocation; import net.minecraftforge.oredict.OreDictionary; import org.apache.commons.lang3.ArrayUtils; public class FilterSettings{ - public final int startSlot; - public final int endSlot; public final int whitelistButtonId; public final int metaButtonId; public final int nbtButtonId; public final int oredictButtonId; + public final int modButtonId; + + public final int startSlot; + public final int endSlot; + public boolean isWhitelist; public boolean respectMeta; public boolean respectNBT; + public boolean respectMod; public int respectOredict; + private boolean lastWhitelist; private boolean lastRespectMeta; private boolean lastRespectNBT; + private boolean lastRespectMod; private int lastRecpectOredict; - public FilterSettings(int startSlot, int endSlot, boolean defaultWhitelist, boolean defaultRespectMeta, boolean defaultRespectNBT, int defaultRespectOredict, int buttonIdStart){ + public FilterSettings(int startSlot, int endSlot, boolean defaultWhitelist, boolean defaultRespectMeta, boolean defaultRespectNBT, boolean defaultRespectMod, int defaultRespectOredict, int buttonIdStart){ this.startSlot = startSlot; this.endSlot = endSlot; this.isWhitelist = defaultWhitelist; this.respectMeta = defaultRespectMeta; this.respectNBT = defaultRespectNBT; + this.respectMod = defaultRespectMod; this.respectOredict = defaultRespectOredict; this.whitelistButtonId = buttonIdStart; this.metaButtonId = buttonIdStart+1; this.nbtButtonId = buttonIdStart+2; this.oredictButtonId = buttonIdStart+3; + this.modButtonId = buttonIdStart+4; } - public static boolean check(ItemStack stack, ItemStack[] slots, int startSlot, int endSlot, boolean whitelist, boolean meta, boolean nbt, int oredict){ + public static boolean check(ItemStack stack, ItemStack[] slots, int startSlot, int endSlot, boolean whitelist, boolean meta, boolean nbt, boolean mod, int oredict){ if(StackUtil.isValid(stack)){ for(int i = startSlot; i < endSlot; i++){ if(StackUtil.isValid(slots[i])){ - if(areEqualEnough(slots[i], stack, meta, nbt, oredict)){ + if(areEqualEnough(slots[i], stack, meta, nbt, mod, oredict)){ return whitelist; } else if(slots[i].getItem() instanceof ItemFilter){ @@ -63,7 +73,7 @@ public class FilterSettings{ ItemDrill.loadSlotsFromNBT(filterSlots, slots[i]); if(filterSlots != null && filterSlots.length > 0){ for(ItemStack filterSlot : filterSlots){ - if(StackUtil.isValid(filterSlot) && areEqualEnough(filterSlot, stack, meta, nbt, oredict)){ + if(StackUtil.isValid(filterSlot) && areEqualEnough(filterSlot, stack, meta, nbt, mod, oredict)){ return whitelist; } } @@ -75,54 +85,68 @@ public class FilterSettings{ return !whitelist; } - private static boolean areEqualEnough(ItemStack first, ItemStack second, boolean meta, boolean nbt, int oredict){ - if(first.getItem() != second.getItem()){ - return false; - } - else{ - boolean metaFine = !meta || first.getItemDamage() == second.getItemDamage(); - boolean nbtFine = !nbt || ItemStack.areItemStackTagsEqual(first, second); - if(metaFine && nbtFine){ - if(oredict == 0){ - return true; - } - else{ - int[] firstIds = OreDictionary.getOreIDs(first); - int[] secondIds = OreDictionary.getOreIDs(second); - boolean firstEmpty = ArrayUtils.isEmpty(firstIds); - boolean secondEmpty = ArrayUtils.isEmpty(secondIds); - - //Both empty, meaning none has OreDict entries, so they are equal - if(firstEmpty && secondEmpty){ - return true; - } - //Only one empty, meaning they are not equal - else if(firstEmpty || secondEmpty){ + private static boolean areEqualEnough(ItemStack first, ItemStack second, boolean meta, boolean nbt, boolean mod, int oredict){ + Item firstItem = first.getItem(); + Item secondItem = second.getItem(); + if(mod){ + ResourceLocation firstReg = firstItem.getRegistryName(); + ResourceLocation secondReg = secondItem.getRegistryName(); + if(firstReg != null && secondReg != null){ + String firstDomain = firstReg.getResourceDomain(); + String secondDomain = secondReg.getResourceDomain(); + if(firstDomain != null && secondDomain != null){ + if(!firstDomain.equals(secondDomain)){ return false; } - else{ - for(int id : firstIds){ - if(ArrayUtils.contains(secondIds, id)){ - //Needs to match only one id, so return true on first match - if(oredict == 1){ - return true; - } - } - //Needs to match every id, so just return false when no match - else if(oredict == 2){ - return false; - } - - } - //If oredict mode 1, this will fail because nothing matched - //If oredict mode 2, this will mean nothing hasn't matched - return oredict == 2; - } } } - else{ - return false; + } + else if(firstItem != secondItem){ + return false; + } + + boolean metaFine = !meta || first.getItemDamage() == second.getItemDamage(); + boolean nbtFine = !nbt || ItemStack.areItemStackTagsEqual(first, second); + if(metaFine && nbtFine){ + if(oredict == 0){ + return true; } + else{ + int[] firstIds = OreDictionary.getOreIDs(first); + int[] secondIds = OreDictionary.getOreIDs(second); + boolean firstEmpty = ArrayUtils.isEmpty(firstIds); + boolean secondEmpty = ArrayUtils.isEmpty(secondIds); + + //Both empty, meaning none has OreDict entries, so they are equal + if(firstEmpty && secondEmpty){ + return true; + } + //Only one empty, meaning they are not equal + else if(firstEmpty || secondEmpty){ + return false; + } + else{ + for(int id : firstIds){ + if(ArrayUtils.contains(secondIds, id)){ + //Needs to match only one id, so return true on first match + if(oredict == 1){ + return true; + } + } + //Needs to match every id, so just return false when no match + else if(oredict == 2){ + return false; + } + + } + //If oredict mode 1, this will fail because nothing matched + //If oredict mode 2, this will mean nothing hasn't matched + return oredict == 2; + } + } + } + else{ + return false; } } @@ -131,6 +155,7 @@ public class FilterSettings{ compound.setBoolean("Whitelist", this.isWhitelist); compound.setBoolean("Meta", this.respectMeta); compound.setBoolean("NBT", this.respectNBT); + compound.setBoolean("Mod", this.respectMod); compound.setInteger("Oredict", this.respectOredict); tag.setTag(name, compound); } @@ -140,17 +165,19 @@ public class FilterSettings{ this.isWhitelist = compound.getBoolean("Whitelist"); this.respectMeta = compound.getBoolean("Meta"); this.respectNBT = compound.getBoolean("NBT"); + this.respectMod = compound.getBoolean("Mod"); this.respectOredict = compound.getInteger("Oredict"); } public boolean needsUpdateSend(){ - return this.lastWhitelist != this.isWhitelist || this.lastRespectMeta != this.respectMeta || this.lastRespectNBT != this.respectNBT || this.lastRecpectOredict != this.respectOredict; + return this.lastWhitelist != this.isWhitelist || this.lastRespectMeta != this.respectMeta || this.lastRespectNBT != this.respectNBT || this.lastRespectMod != this.respectMod || this.lastRecpectOredict != this.respectOredict; } public void updateLasts(){ this.lastWhitelist = this.isWhitelist; this.lastRespectMeta = this.respectMeta; this.lastRespectNBT = this.respectNBT; + this.lastRespectMod = this.respectMod; this.lastRecpectOredict = this.respectOredict; } @@ -164,6 +191,9 @@ public class FilterSettings{ else if(id == this.nbtButtonId){ this.respectNBT = !this.respectNBT; } + else if(id == this.modButtonId){ + this.respectMod = !this.respectMod; + } else if(id == this.oredictButtonId){ if(this.respectOredict+1 > 2){ this.respectOredict = 0; @@ -175,6 +205,6 @@ public class FilterSettings{ } public boolean check(ItemStack stack, ItemStack[] slots){ - return check(stack, slots, this.startSlot, this.endSlot, this.isWhitelist, this.respectMeta, this.respectNBT, this.respectOredict); + return check(stack, slots, this.startSlot, this.endSlot, this.isWhitelist, this.respectMeta, this.respectNBT, this.respectMod, this.respectOredict); } } diff --git a/src/main/java/de/ellpeck/actuallyadditions/mod/tile/TileEntityInputter.java b/src/main/java/de/ellpeck/actuallyadditions/mod/tile/TileEntityInputter.java index 821577bdc..ad073858f 100644 --- a/src/main/java/de/ellpeck/actuallyadditions/mod/tile/TileEntityInputter.java +++ b/src/main/java/de/ellpeck/actuallyadditions/mod/tile/TileEntityInputter.java @@ -38,8 +38,8 @@ public class TileEntityInputter extends TileEntityInventoryBase implements IButt public int slotToPullEnd; public TileEntity placeToPull; public boolean isAdvanced; - public FilterSettings leftFilter = new FilterSettings(PULL_FILTER_START, PULL_FILTER_START+12, true, true, false, 0, -1000); - public FilterSettings rightFilter = new FilterSettings(PUT_FILTER_START, PUT_FILTER_START+12, true, true, false, 0, -2000); + public FilterSettings leftFilter = new FilterSettings(PULL_FILTER_START, PULL_FILTER_START+12, true, true, false, false, 0, -1000); + public FilterSettings rightFilter = new FilterSettings(PUT_FILTER_START, PUT_FILTER_START+12, true, true, false, false, 0, -2000); private int lastPutSide; private int lastPutStart; private int lastPutEnd; diff --git a/src/main/java/de/ellpeck/actuallyadditions/mod/tile/TileEntityLaserRelayItemWhitelist.java b/src/main/java/de/ellpeck/actuallyadditions/mod/tile/TileEntityLaserRelayItemWhitelist.java index 16ad52c74..e0d0a7853 100644 --- a/src/main/java/de/ellpeck/actuallyadditions/mod/tile/TileEntityLaserRelayItemWhitelist.java +++ b/src/main/java/de/ellpeck/actuallyadditions/mod/tile/TileEntityLaserRelayItemWhitelist.java @@ -28,8 +28,8 @@ import java.util.Arrays; public class TileEntityLaserRelayItemWhitelist extends TileEntityLaserRelayItem implements IButtonReactor{ public final IInventory filterInventory; - public FilterSettings leftFilter = new FilterSettings(0, 12, true, true, false, 0, -1000); - public FilterSettings rightFilter = new FilterSettings(12, 24, true, true, false, 0, -2000); + public FilterSettings leftFilter = new FilterSettings(0, 12, true, true, false, false, 0, -1000); + public FilterSettings rightFilter = new FilterSettings(12, 24, true, true, false, false, 0, -2000); private ItemStack[] slots = new ItemStack[24]; public TileEntityLaserRelayItemWhitelist(){ @@ -219,7 +219,7 @@ public class TileEntityLaserRelayItemWhitelist extends TileEntityLaserRelayItem ItemStack copy = stack.copy(); copy = StackUtil.setStackSize(copy, 1); - if(!FilterSettings.check(copy, this.slots, usedSettings.startSlot, usedSettings.endSlot, true, usedSettings.respectMeta, usedSettings.respectNBT, usedSettings.respectOredict)){ + if(!FilterSettings.check(copy, this.slots, usedSettings.startSlot, usedSettings.endSlot, true, usedSettings.respectMeta, usedSettings.respectNBT, usedSettings.respectMod, usedSettings.respectOredict)){ for(int k = usedSettings.startSlot; k < usedSettings.endSlot; k++){ if(StackUtil.isValid(this.slots[k])){ if(this.slots[k].getItem() instanceof ItemFilter){ diff --git a/src/main/java/de/ellpeck/actuallyadditions/mod/tile/TileEntityRangedCollector.java b/src/main/java/de/ellpeck/actuallyadditions/mod/tile/TileEntityRangedCollector.java index 7c3f345bc..659ad2fd7 100644 --- a/src/main/java/de/ellpeck/actuallyadditions/mod/tile/TileEntityRangedCollector.java +++ b/src/main/java/de/ellpeck/actuallyadditions/mod/tile/TileEntityRangedCollector.java @@ -28,7 +28,7 @@ public class TileEntityRangedCollector extends TileEntityInventoryBase implement public static final int WHITELIST_START = 6; public static final int RANGE = 6; - public FilterSettings filter = new FilterSettings(WHITELIST_START, WHITELIST_START+12, true, true, false, 0, -1000); + public FilterSettings filter = new FilterSettings(WHITELIST_START, WHITELIST_START+12, true, true, false, false, 0, -1000); public TileEntityRangedCollector(){ super(18, "rangedCollector"); diff --git a/src/main/resources/assets/actuallyadditions/textures/gui/guiinputter.png b/src/main/resources/assets/actuallyadditions/textures/gui/guiinputter.png index a5aadf9a0e5cb9ea7d369c7c11439b8d257b0e53..ac09b3ad95efa734a7022d9c03b4d3e1f0759567 100644 GIT binary patch literal 4090 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 R%U7Dx`Nv}i${c;K{|jR)o|^yw literal 3842 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