diff --git a/src/main/java/com/simibubi/create/content/contraptions/actors/roller/RollerBlockEntity.java b/src/main/java/com/simibubi/create/content/contraptions/actors/roller/RollerBlockEntity.java index 17a3cb1b9..69fb55bc1 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/actors/roller/RollerBlockEntity.java +++ b/src/main/java/com/simibubi/create/content/contraptions/actors/roller/RollerBlockEntity.java @@ -117,7 +117,7 @@ public class RollerBlockEntity extends SmartBlockEntity { protected void acceptSharedValues(int mode, ItemStack filter) { dontPropagate = true; - this.filtering.setFilter(filter); + this.filtering.setFilter(filter.copy()); this.mode.setValue(mode); dontPropagate = false; notifyUpdate(); diff --git a/src/main/java/com/simibubi/create/content/contraptions/actors/roller/RollerMovementBehaviour.java b/src/main/java/com/simibubi/create/content/contraptions/actors/roller/RollerMovementBehaviour.java index d54a12bcf..8ce39cb40 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/actors/roller/RollerMovementBehaviour.java +++ b/src/main/java/com/simibubi/create/content/contraptions/actors/roller/RollerMovementBehaviour.java @@ -19,7 +19,7 @@ import com.simibubi.create.content.contraptions.render.ActorInstance; import com.simibubi.create.content.contraptions.render.ContraptionMatrices; import com.simibubi.create.content.contraptions.render.ContraptionRenderDispatcher; import com.simibubi.create.content.kinetics.base.BlockBreakingMovementBehaviour; -import com.simibubi.create.content.logistics.filter.FilterItem; +import com.simibubi.create.content.logistics.filter.FilterItemStack; import com.simibubi.create.content.trains.bogey.StandardBogeyBlock; import com.simibubi.create.content.trains.entity.Carriage; import com.simibubi.create.content.trains.entity.CarriageBogey; @@ -193,10 +193,10 @@ public class RollerMovementBehaviour extends BlockBreakingMovementBehaviour { int startingY = 1; if (!getStateToPaveWith(context).isAir()) { - ItemStack filter = ItemStack.of(context.blockEntityData.getCompound("Filter")); - if (!ItemHelper + FilterItemStack filter = context.getFilterFromBE(); + if (!ItemHelper .extract(context.contraption.getSharedInventory(), - stack -> FilterItem.test(context.world, stack, filter), 1, true) + stack -> filter.test(context.world, stack), 1, true) .isEmpty()) startingY = 0; } @@ -473,9 +473,9 @@ public class RollerMovementBehaviour extends BlockBreakingMovementBehaviour { .isEmpty()) return PaveResult.FAIL; - ItemStack filter = ItemStack.of(context.blockEntityData.getCompound("Filter")); + FilterItemStack filter = context.getFilterFromBE(); ItemStack held = ItemHelper.extract(context.contraption.getSharedInventory(), - stack -> FilterItem.test(context.world, stack, filter), 1, false); + stack -> filter.test(context.world, stack), 1, false); if (held.isEmpty()) return PaveResult.FAIL; diff --git a/src/main/java/com/simibubi/create/content/contraptions/behaviour/MovementContext.java b/src/main/java/com/simibubi/create/content/contraptions/behaviour/MovementContext.java index b5ff9ee76..faae63163 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/behaviour/MovementContext.java +++ b/src/main/java/com/simibubi/create/content/contraptions/behaviour/MovementContext.java @@ -3,6 +3,7 @@ package com.simibubi.create.content.contraptions.behaviour; import java.util.function.UnaryOperator; import com.simibubi.create.content.contraptions.Contraption; +import com.simibubi.create.content.logistics.filter.FilterItemStack; import com.simibubi.create.foundation.utility.VecHelper; import net.minecraft.core.BlockPos; @@ -31,6 +32,8 @@ public class MovementContext { public CompoundTag data; public Contraption contraption; public Object temporaryData; + + private FilterItemStack filter; public MovementContext(Level world, StructureBlockInfo info, Contraption contraption) { this.world = world; @@ -47,6 +50,7 @@ public class MovementContext { position = null; data = new CompoundTag(); stall = false; + filter = null; } public float getAnimationSpeed() { @@ -83,5 +87,11 @@ public class MovementContext { nbt.put("Data", data.copy()); return nbt; } + + public FilterItemStack getFilterFromBE() { + if (filter != null) + return filter; + return filter = FilterItemStack.of(blockEntityData.getCompound("Filter")); + } } \ No newline at end of file diff --git a/src/main/java/com/simibubi/create/content/decoration/placard/PlacardBlock.java b/src/main/java/com/simibubi/create/content/decoration/placard/PlacardBlock.java index 4b7012c4d..8a73cda1b 100644 --- a/src/main/java/com/simibubi/create/content/decoration/placard/PlacardBlock.java +++ b/src/main/java/com/simibubi/create/content/decoration/placard/PlacardBlock.java @@ -8,6 +8,7 @@ import com.simibubi.create.AllShapes; import com.simibubi.create.AllSoundEvents; import com.simibubi.create.content.equipment.wrench.IWrenchable; import com.simibubi.create.content.logistics.filter.FilterItem; +import com.simibubi.create.content.logistics.filter.FilterItemStack; import com.simibubi.create.content.schematics.requirement.ISpecialBlockItemRequirement; import com.simibubi.create.content.schematics.requirement.ItemRequirement; import com.simibubi.create.content.schematics.requirement.ItemRequirement.ItemUseType; @@ -132,9 +133,9 @@ public class PlacardBlock extends FaceAttachedHorizontalDirectionalBlock return InteractionResult.FAIL; if (pState.getValue(POWERED)) return InteractionResult.FAIL; - - boolean test = inBlock.getItem() instanceof FilterItem ? FilterItem.test(pLevel, inHand, inBlock) - : ItemHandlerHelper.canItemStacksStack(inHand, inBlock); + + boolean test = inBlock.getItem() instanceof FilterItem ? FilterItemStack.of(inBlock) + .test(pLevel, inHand) : ItemHandlerHelper.canItemStacksStack(inHand, inBlock); if (!test) { AllSoundEvents.DENY.play(pLevel, null, pPos, 1, 1); return InteractionResult.SUCCESS; diff --git a/src/main/java/com/simibubi/create/content/equipment/blueprint/BlueprintEntity.java b/src/main/java/com/simibubi/create/content/equipment/blueprint/BlueprintEntity.java index 6f2d65dc3..877a2ae16 100644 --- a/src/main/java/com/simibubi/create/content/equipment/blueprint/BlueprintEntity.java +++ b/src/main/java/com/simibubi/create/content/equipment/blueprint/BlueprintEntity.java @@ -13,6 +13,7 @@ import com.simibubi.create.AllEntityTypes; import com.simibubi.create.AllItems; import com.simibubi.create.Create; import com.simibubi.create.content.logistics.filter.FilterItem; +import com.simibubi.create.content.logistics.filter.FilterItemStack; import com.simibubi.create.content.schematics.requirement.ISpecialEntityItemRequirement; import com.simibubi.create.content.schematics.requirement.ItemRequirement; import com.simibubi.create.content.schematics.requirement.ItemRequirement.ItemUseType; @@ -365,14 +366,14 @@ public class BlueprintEntity extends HangingEntity boolean success = true; Search: for (int i = 0; i < 9; i++) { - ItemStack requestedItem = items.getStackInSlot(i); + FilterItemStack requestedItem = FilterItemStack.of(items.getStackInSlot(i)); if (requestedItem.isEmpty()) { craftingGrid.put(i, ItemStack.EMPTY); continue; } for (int slot = 0; slot < playerInv.getSlots(); slot++) { - if (!FilterItem.test(level, playerInv.getStackInSlot(slot), requestedItem)) + if (!requestedItem.test(level, playerInv.getStackInSlot(slot))) continue; ItemStack currentItem = playerInv.extractItem(slot, 1, false); if (stacksTaken.containsKey(slot)) diff --git a/src/main/java/com/simibubi/create/content/equipment/blueprint/BlueprintOverlayRenderer.java b/src/main/java/com/simibubi/create/content/equipment/blueprint/BlueprintOverlayRenderer.java index a02964bb2..e2939a767 100644 --- a/src/main/java/com/simibubi/create/content/equipment/blueprint/BlueprintOverlayRenderer.java +++ b/src/main/java/com/simibubi/create/content/equipment/blueprint/BlueprintOverlayRenderer.java @@ -14,6 +14,7 @@ import com.simibubi.create.content.equipment.blueprint.BlueprintEntity.Blueprint import com.simibubi.create.content.equipment.blueprint.BlueprintEntity.BlueprintSection; import com.simibubi.create.content.logistics.filter.AttributeFilterMenu.WhitelistMode; import com.simibubi.create.content.logistics.filter.FilterItem; +import com.simibubi.create.content.logistics.filter.FilterItemStack; import com.simibubi.create.content.logistics.filter.ItemAttribute; import com.simibubi.create.content.trains.track.TrackPlacement.PlacementInfo; import com.simibubi.create.foundation.gui.AllGuiTextures; @@ -161,14 +162,14 @@ public class BlueprintOverlayRenderer { newlyMissing.clear(); Search: for (int i = 0; i < 9; i++) { - ItemStack requestedItem = items.getStackInSlot(i); + FilterItemStack requestedItem = FilterItemStack.of(items.getStackInSlot(i)); if (requestedItem.isEmpty()) { craftingGrid.put(i, ItemStack.EMPTY); continue; } for (int slot = 0; slot < playerInv.getSlots(); slot++) { - if (!FilterItem.test(mc.level, playerInv.getStackInSlot(slot), requestedItem)) + if (!requestedItem.test(mc.level, playerInv.getStackInSlot(slot))) continue; ItemStack currentItem = playerInv.extractItem(slot, 1, false); craftingGrid.put(i, currentItem); @@ -177,7 +178,7 @@ public class BlueprintOverlayRenderer { } success = false; - newlyMissing.add(requestedItem); + newlyMissing.add(requestedItem.item()); } if (success) { diff --git a/src/main/java/com/simibubi/create/content/kinetics/deployer/DeployerMovementBehaviour.java b/src/main/java/com/simibubi/create/content/kinetics/deployer/DeployerMovementBehaviour.java index 305dbde12..8e5c17140 100644 --- a/src/main/java/com/simibubi/create/content/kinetics/deployer/DeployerMovementBehaviour.java +++ b/src/main/java/com/simibubi/create/content/kinetics/deployer/DeployerMovementBehaviour.java @@ -21,7 +21,7 @@ import com.simibubi.create.content.contraptions.render.ActorInstance; import com.simibubi.create.content.contraptions.render.ContraptionMatrices; import com.simibubi.create.content.contraptions.render.ContraptionRenderDispatcher; import com.simibubi.create.content.kinetics.deployer.DeployerBlockEntity.Mode; -import com.simibubi.create.content.logistics.filter.FilterItem; +import com.simibubi.create.content.logistics.filter.FilterItemStack; import com.simibubi.create.content.schematics.SchematicInstances; import com.simibubi.create.content.schematics.SchematicWorld; import com.simibubi.create.content.schematics.requirement.ItemRequirement; @@ -80,9 +80,9 @@ public class DeployerMovementBehaviour implements MovementBehaviour { public void activate(MovementContext context, BlockPos pos, DeployerFakePlayer player, Mode mode) { Level world = context.world; - ItemStack filter = getFilter(context); - if (AllItems.SCHEMATIC.isIn(filter)) - activateAsSchematicPrinter(context, pos, player, world, filter); + FilterItemStack filter = context.getFilterFromBE(); + if (AllItems.SCHEMATIC.isIn(filter.item())) + activateAsSchematicPrinter(context, pos, player, world, filter.item()); Vec3 facingVec = Vec3.atLowerCornerOf(context.state.getValue(DeployerBlock.FACING) .getNormal()); @@ -222,11 +222,11 @@ public class DeployerMovementBehaviour implements MovementBehaviour { return; if (player.getMainHandItem() .isEmpty()) { - ItemStack filter = getFilter(context); - if (AllItems.SCHEMATIC.isIn(filter)) + FilterItemStack filter = context.getFilterFromBE(); + if (AllItems.SCHEMATIC.isIn(filter.item())) return; ItemStack held = ItemHelper.extract(context.contraption.getSharedInventory(), - stack -> FilterItem.test(context.world, stack, filter), 1, false); + stack -> filter.test(context.world, stack), 1, false); player.setItemInHand(InteractionHand.MAIN_HAND, held); } } @@ -236,7 +236,7 @@ public class DeployerMovementBehaviour implements MovementBehaviour { if (player == null) return; Inventory inv = player.getInventory(); - ItemStack filter = getFilter(context); + FilterItemStack filter = context.getFilterFromBE(); for (List list : Arrays.asList(inv.armor, inv.offhand, inv.items)) { for (int i = 0; i < list.size(); ++i) { @@ -244,7 +244,7 @@ public class DeployerMovementBehaviour implements MovementBehaviour { if (itemstack.isEmpty()) continue; - if (list == inv.items && i == inv.selected && FilterItem.test(context.world, itemstack, filter)) + if (list == inv.items && i == inv.selected && filter.test(context.world, itemstack)) continue; dropItem(context, itemstack); @@ -278,10 +278,6 @@ public class DeployerMovementBehaviour implements MovementBehaviour { return (DeployerFakePlayer) context.temporaryData; } - private ItemStack getFilter(MovementContext context) { - return ItemStack.of(context.blockEntityData.getCompound("Filter")); - } - private Mode getMode(MovementContext context) { return NBTHelper.readEnum(context.blockEntityData, "Mode", Mode.class); } diff --git a/src/main/java/com/simibubi/create/content/logistics/filter/FilterItem.java b/src/main/java/com/simibubi/create/content/logistics/filter/FilterItem.java index 81111476c..b62a58907 100644 --- a/src/main/java/com/simibubi/create/content/logistics/filter/FilterItem.java +++ b/src/main/java/com/simibubi/create/content/logistics/filter/FilterItem.java @@ -8,7 +8,6 @@ import javax.annotation.Nonnull; import com.simibubi.create.AllItems; import com.simibubi.create.AllKeys; -import com.simibubi.create.content.fluids.transfer.GenericItemEmptying; import com.simibubi.create.content.logistics.filter.AttributeFilterMenu.WhitelistMode; import com.simibubi.create.foundation.utility.Components; import com.simibubi.create.foundation.utility.Lang; @@ -33,7 +32,6 @@ import net.minecraft.world.item.context.UseOnContext; import net.minecraft.world.level.Level; import net.minecraftforge.api.distmarker.Dist; import net.minecraftforge.api.distmarker.OnlyIn; -import net.minecraftforge.fluids.FluidStack; import net.minecraftforge.items.ItemHandlerHelper; import net.minecraftforge.items.ItemStackHandler; import net.minecraftforge.network.NetworkHooks; @@ -188,146 +186,7 @@ public class FilterItem extends Item implements MenuProvider { return newInv; } - public static boolean test(Level world, ItemStack stack, ItemStack filter) { - return test(world, stack, filter, false); - } - - public static boolean test(Level world, FluidStack stack, ItemStack filter) { - return test(world, stack, filter, true); - } - - public static boolean test(Level world, ItemStack stack, ItemStack filter, boolean matchNBT) { - if (filter.isEmpty()) - return true; - - if (!(filter.getItem() instanceof FilterItem)) - return testDirect(filter, stack, matchNBT); - - boolean defaults = !filter.hasTag(); - - if (defaults) { - return testDirect(filter, stack, matchNBT); - } - - if (AllItems.FILTER.get() == filter.getItem()) { - ItemStackHandler filterItems = getFilterItems(filter); - boolean respectNBT = defaults ? false - : filter.getTag() - .getBoolean("RespectNBT"); - boolean blacklist = defaults ? false - : filter.getTag() - .getBoolean("Blacklist"); - boolean isEmpty = true; - for (int slot = 0; slot < filterItems.getSlots(); slot++) { - ItemStack stackInSlot = filterItems.getStackInSlot(slot); - if (stackInSlot.isEmpty()) - continue; - isEmpty = false; - boolean matches = test(world, stack, stackInSlot, respectNBT); - if (matches) - return !blacklist; - } - if (isEmpty) { - return testDirect(filter, stack, matchNBT); - } - return blacklist; - } - - if (AllItems.ATTRIBUTE_FILTER.get() == filter.getItem()) { - ListTag attributes = defaults ? new ListTag() - : filter.getTag() - .getList("MatchedAttributes", Tag.TAG_COMPOUND); - if (attributes.isEmpty()) { - return testDirect(filter, stack, matchNBT); - } - WhitelistMode whitelistMode = WhitelistMode.values()[defaults ? 0 - : filter.getTag() - .getInt("WhitelistMode")]; - for (Tag inbt : attributes) { - CompoundTag compound = (CompoundTag) inbt; - ItemAttribute attribute = ItemAttribute.fromNBT(compound); - if (attribute == null) - continue; - boolean matches = attribute.appliesTo(stack, world) != compound.getBoolean("Inverted"); - - if (matches) { - switch (whitelistMode) { - case BLACKLIST: - return false; - case WHITELIST_CONJ: - continue; - case WHITELIST_DISJ: - return true; - } - } else { - switch (whitelistMode) { - case BLACKLIST: - continue; - case WHITELIST_CONJ: - return false; - case WHITELIST_DISJ: - continue; - } - } - } - - switch (whitelistMode) { - case BLACKLIST: - return true; - case WHITELIST_CONJ: - return true; - case WHITELIST_DISJ: - return false; - } - } - - return false; - } - - public static boolean test(Level world, FluidStack stack, ItemStack filter, boolean matchNBT) { - if (filter.isEmpty()) - return true; - if (stack.isEmpty()) - return false; - - if (!(filter.getItem() instanceof FilterItem)) { - if (!GenericItemEmptying.canItemBeEmptied(world, filter)) - return false; - FluidStack fluidInFilter = GenericItemEmptying.emptyItem(world, filter, true) - .getFirst(); - if (fluidInFilter == null) - return false; - if (!matchNBT) - return fluidInFilter.getFluid() - .isSame(stack.getFluid()); - boolean fluidEqual = fluidInFilter.isFluidEqual(stack); - return fluidEqual; - } - - boolean defaults = !filter.hasTag(); - - if (AllItems.FILTER.get() == filter.getItem()) { - ItemStackHandler filterItems = getFilterItems(filter); - boolean respectNBT = defaults ? false - : filter.getTag() - .getBoolean("RespectNBT"); - boolean blacklist = defaults ? false - : filter.getTag() - .getBoolean("Blacklist"); - for (int slot = 0; slot < filterItems.getSlots(); slot++) { - ItemStack stackInSlot = filterItems.getStackInSlot(slot); - if (stackInSlot.isEmpty()) - continue; - boolean matches = test(world, stack, stackInSlot, respectNBT); - if (matches) - return !blacklist; - } - return blacklist; - } - return false; - } - - private static boolean testDirect(ItemStack filter, ItemStack stack, boolean matchNBT) { + public static boolean testDirect(ItemStack filter, ItemStack stack, boolean matchNBT) { if (matchNBT) { return ItemHandlerHelper.canItemStacksStack(filter, stack); } else { diff --git a/src/main/java/com/simibubi/create/content/logistics/filter/FilterItemStack.java b/src/main/java/com/simibubi/create/content/logistics/filter/FilterItemStack.java new file mode 100644 index 000000000..78d5095eb --- /dev/null +++ b/src/main/java/com/simibubi/create/content/logistics/filter/FilterItemStack.java @@ -0,0 +1,237 @@ +package com.simibubi.create.content.logistics.filter; + +import java.util.ArrayList; +import java.util.List; + +import com.simibubi.create.AllItems; +import com.simibubi.create.content.fluids.transfer.GenericItemEmptying; +import com.simibubi.create.foundation.utility.Pair; + +import net.minecraft.nbt.CompoundTag; +import net.minecraft.nbt.ListTag; +import net.minecraft.nbt.Tag; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.level.Level; +import net.minecraftforge.fluids.FluidStack; +import net.minecraftforge.items.ItemStackHandler; + +public class FilterItemStack { + + private ItemStack filterItemStack; + private boolean fluidExtracted; + private FluidStack filterFluidStack; + + public static FilterItemStack of(ItemStack filter) { + if (filter.hasTag()) { + if (AllItems.FILTER.isIn(filter)) + return new ListFilterItemStack(filter); + if (AllItems.ATTRIBUTE_FILTER.isIn(filter)) + return new AttributeFilterItemStack(filter); + } + + return new FilterItemStack(filter); + } + + public static FilterItemStack of(CompoundTag tag) { + return of(ItemStack.of(tag)); + } + + public static FilterItemStack empty() { + return of(ItemStack.EMPTY); + } + + public boolean isEmpty() { + return filterItemStack.isEmpty(); + } + + public CompoundTag serializeNBT() { + return filterItemStack.serializeNBT(); + } + + public ItemStack item() { + return filterItemStack; + } + + public FluidStack fluid(Level level) { + resolveFluid(level); + return filterFluidStack; + } + + public boolean isFilterItem() { + return filterItemStack.getItem() instanceof FilterItem; + } + + // + + public boolean test(Level world, ItemStack stack) { + return test(world, stack, false); + } + + public boolean test(Level world, FluidStack stack) { + return test(world, stack, true); + } + + public boolean test(Level world, ItemStack stack, boolean matchNBT) { + if (isEmpty()) + return true; + return FilterItem.testDirect(filterItemStack, stack, matchNBT); + } + + public boolean test(Level world, FluidStack stack, boolean matchNBT) { + if (isEmpty()) + return true; + if (stack.isEmpty()) + return false; + + resolveFluid(world); + + if (filterFluidStack.isEmpty()) + return false; + if (!matchNBT) + return filterFluidStack.getFluid() + .isSame(stack.getFluid()); + return filterFluidStack.isFluidEqual(stack); + } + + // + + private void resolveFluid(Level world) { + if (!fluidExtracted) { + fluidExtracted = true; + if (GenericItemEmptying.canItemBeEmptied(world, filterItemStack)) + filterFluidStack = GenericItemEmptying.emptyItem(world, filterItemStack, true) + .getFirst(); + } + } + + protected FilterItemStack(ItemStack filter) { + filterItemStack = filter; + filterFluidStack = FluidStack.EMPTY; + fluidExtracted = false; + } + + public static class ListFilterItemStack extends FilterItemStack { + + public List containedItems; + public boolean shouldRespectNBT; + public boolean isBlacklist; + + protected ListFilterItemStack(ItemStack filter) { + super(filter); + boolean defaults = !filter.hasTag(); + + containedItems = new ArrayList<>(); + ItemStackHandler items = FilterItem.getFilterItems(filter); + for (int i = 0; i < items.getSlots(); i++) { + ItemStack stackInSlot = items.getStackInSlot(i); + if (!stackInSlot.isEmpty()) + containedItems.add(FilterItemStack.of(stackInSlot)); + } + + shouldRespectNBT = !defaults ? false + : filter.getTag() + .getBoolean("RespectNBT"); + isBlacklist = defaults ? false + : filter.getTag() + .getBoolean("Blacklist"); + } + + @Override + public boolean test(Level world, ItemStack stack, boolean matchNBT) { + if (containedItems.isEmpty()) + return super.test(world, stack, matchNBT); + for (FilterItemStack filterItemStack : containedItems) + if (filterItemStack.test(world, stack, shouldRespectNBT)) + return !isBlacklist; + return isBlacklist; + } + + @Override + public boolean test(Level world, FluidStack stack, boolean matchNBT) { + for (FilterItemStack filterItemStack : containedItems) + if (filterItemStack.test(world, stack, shouldRespectNBT)) + return !isBlacklist; + return isBlacklist; + } + + } + + public static class AttributeFilterItemStack extends FilterItemStack { + + public enum WhitelistMode { + WHITELIST_DISJ, WHITELIST_CONJ, BLACKLIST; + } + + public WhitelistMode whitelistMode; + public List> attributeTests; + + protected AttributeFilterItemStack(ItemStack filter) { + super(filter); + boolean defaults = !filter.hasTag(); + + attributeTests = new ArrayList<>(); + whitelistMode = WhitelistMode.values()[defaults ? 0 + : filter.getTag() + .getInt("WhitelistMode")]; + + ListTag attributes = defaults ? new ListTag() + : filter.getTag() + .getList("MatchedAttributes", Tag.TAG_COMPOUND); + for (Tag inbt : attributes) { + CompoundTag compound = (CompoundTag) inbt; + ItemAttribute attribute = ItemAttribute.fromNBT(compound); + if (attribute != null) + attributeTests.add(Pair.of(attribute, compound.getBoolean("Inverted"))); + } + } + + @Override + public boolean test(Level world, FluidStack stack, boolean matchNBT) { + return false; + } + + @Override + public boolean test(Level world, ItemStack stack, boolean matchNBT) { + if (attributeTests.isEmpty()) + return super.test(world, stack, matchNBT); + for (Pair test : attributeTests) { + ItemAttribute attribute = test.getFirst(); + boolean inverted = test.getSecond(); + boolean matches = attribute.appliesTo(stack, world) != inverted; + + if (matches) { + switch (whitelistMode) { + case BLACKLIST: + return false; + case WHITELIST_CONJ: + continue; + case WHITELIST_DISJ: + return true; + } + } else { + switch (whitelistMode) { + case BLACKLIST: + continue; + case WHITELIST_CONJ: + return false; + case WHITELIST_DISJ: + continue; + } + } + } + + switch (whitelistMode) { + case BLACKLIST: + return true; + case WHITELIST_CONJ: + return true; + case WHITELIST_DISJ: + return false; + } + + return false; + } + + } + +} diff --git a/src/main/java/com/simibubi/create/content/logistics/funnel/FunnelMovementBehaviour.java b/src/main/java/com/simibubi/create/content/logistics/funnel/FunnelMovementBehaviour.java index 9178f3684..9b461c5f9 100644 --- a/src/main/java/com/simibubi/create/content/logistics/funnel/FunnelMovementBehaviour.java +++ b/src/main/java/com/simibubi/create/content/logistics/funnel/FunnelMovementBehaviour.java @@ -4,7 +4,7 @@ import java.util.List; import com.simibubi.create.content.contraptions.behaviour.MovementBehaviour; import com.simibubi.create.content.contraptions.behaviour.MovementContext; -import com.simibubi.create.content.logistics.filter.FilterItem; +import com.simibubi.create.content.logistics.filter.FilterItemStack; import com.simibubi.create.foundation.item.ItemHelper; import net.minecraft.core.BlockPos; @@ -71,14 +71,14 @@ public class FunnelMovementBehaviour implements MovementBehaviour { .isEmpty()) return; - ItemStack filter = getFilter(context); + FilterItemStack filter = context.getFilterFromBE(); int filterAmount = context.blockEntityData.getInt("FilterAmount"); boolean upTo = context.blockEntityData.getBoolean("UpTo"); if (filterAmount <= 0) filterAmount = hasFilter ? 64 : 1; ItemStack extract = ItemHelper.extract(context.contraption.getSharedInventory(), - s -> FilterItem.test(world, s, filter), + s -> filter.test(world, s), upTo ? ItemHelper.ExtractionCountMode.UPTO : ItemHelper.ExtractionCountMode.EXACTLY, filterAmount, false); if (extract.isEmpty()) @@ -97,13 +97,13 @@ public class FunnelMovementBehaviour implements MovementBehaviour { private void succ(MovementContext context, BlockPos pos) { Level world = context.world; List items = world.getEntitiesOfClass(ItemEntity.class, new AABB(pos)); - ItemStack filter = getFilter(context); + FilterItemStack filter = context.getFilterFromBE(); for (ItemEntity item : items) { if (!item.isAlive()) continue; ItemStack toInsert = item.getItem(); - if (!filter.isEmpty() && !FilterItem.test(context.world, toInsert, filter)) + if (!filter.test(context.world, toInsert)) continue; ItemStack remainder = ItemHandlerHelper.insertItemStacked(context.contraption.getSharedInventory(), toInsert, false); @@ -124,8 +124,4 @@ public class FunnelMovementBehaviour implements MovementBehaviour { return true; } - private ItemStack getFilter(MovementContext context) { - return hasFilter ? ItemStack.of(context.blockEntityData.getCompound("Filter")) : ItemStack.EMPTY; - } - } diff --git a/src/main/java/com/simibubi/create/content/trains/entity/Train.java b/src/main/java/com/simibubi/create/content/trains/entity/Train.java index 3d539192a..c1c0b7c07 100644 --- a/src/main/java/com/simibubi/create/content/trains/entity/Train.java +++ b/src/main/java/com/simibubi/create/content/trains/entity/Train.java @@ -17,8 +17,6 @@ import java.util.function.Consumer; import javax.annotation.Nullable; -import com.simibubi.create.content.trains.graph.DiscoveredPath; - import org.apache.commons.lang3.mutable.MutableBoolean; import org.apache.commons.lang3.mutable.MutableObject; @@ -26,12 +24,13 @@ import com.simibubi.create.AllMovementBehaviours; import com.simibubi.create.AllPackets; import com.simibubi.create.Create; import com.simibubi.create.content.contraptions.behaviour.MovementBehaviour; -import com.simibubi.create.content.logistics.filter.FilterItem; +import com.simibubi.create.content.logistics.filter.FilterItemStack; import com.simibubi.create.content.trains.bogey.AbstractBogeyBlockEntity; import com.simibubi.create.content.trains.entity.Carriage.DimensionalCarriageEntity; import com.simibubi.create.content.trains.entity.TravellingPoint.IEdgePointListener; import com.simibubi.create.content.trains.entity.TravellingPoint.SteerDirection; import com.simibubi.create.content.trains.graph.DimensionPalette; +import com.simibubi.create.content.trains.graph.DiscoveredPath; import com.simibubi.create.content.trains.graph.EdgeData; import com.simibubi.create.content.trains.graph.EdgePointType; import com.simibubi.create.content.trains.graph.TrackEdge; @@ -197,7 +196,7 @@ public class Train { if (observer == null) continue; - ItemStack filter = observer.getFilter(); + FilterItemStack filter = observer.getFilter(); if (filter.isEmpty()) { observer.keepAlive(this); continue; @@ -225,7 +224,7 @@ public class Train { ItemStack extractItem = inv.extractItem(slot, 1, true); if (extractItem.isEmpty()) continue; - shouldActivate |= FilterItem.test(level, extractItem, filter); + shouldActivate |= filter.test(level, extractItem); } } @@ -237,7 +236,7 @@ public class Train { FluidStack drain = tank.drain(1, FluidAction.SIMULATE); if (drain.isEmpty()) continue; - shouldActivate |= FilterItem.test(level, drain, filter); + shouldActivate |= filter.test(level, drain); } } } diff --git a/src/main/java/com/simibubi/create/content/trains/observer/TrackObserver.java b/src/main/java/com/simibubi/create/content/trains/observer/TrackObserver.java index fb599f296..98ea21969 100644 --- a/src/main/java/com/simibubi/create/content/trains/observer/TrackObserver.java +++ b/src/main/java/com/simibubi/create/content/trains/observer/TrackObserver.java @@ -3,6 +3,7 @@ package com.simibubi.create.content.trains.observer; import java.util.UUID; import com.simibubi.create.Create; +import com.simibubi.create.content.logistics.filter.FilterItemStack; import com.simibubi.create.content.trains.entity.Train; import com.simibubi.create.content.trains.graph.DimensionPalette; import com.simibubi.create.content.trains.graph.TrackEdge; @@ -21,12 +22,12 @@ import net.minecraft.world.level.block.entity.BlockEntity; public class TrackObserver extends SingleBlockEntityEdgePoint { private int activated; - private ItemStack filter; + private FilterItemStack filter; private UUID currentTrain; public TrackObserver() { activated = 0; - filter = ItemStack.EMPTY; + filter = FilterItemStack.empty(); currentTrain = null; } @@ -48,7 +49,7 @@ public class TrackObserver extends SingleBlockEntityEdgePoint { } public void setFilterAndNotify(Level level, ItemStack filter) { - this.filter = filter; + this.filter = FilterItemStack.of(filter.copy()); notifyTrains(level); } @@ -63,7 +64,7 @@ public class TrackObserver extends SingleBlockEntityEdgePoint { SignalPropagator.notifyTrains(graph, edge); } - public ItemStack getFilter() { + public FilterItemStack getFilter() { return filter; } @@ -84,7 +85,7 @@ public class TrackObserver extends SingleBlockEntityEdgePoint { public void read(CompoundTag nbt, boolean migration, DimensionPalette dimensions) { super.read(nbt, migration, dimensions); activated = nbt.getInt("Activated"); - filter = ItemStack.of(nbt.getCompound("Filter")); + filter = FilterItemStack.of(nbt.getCompound("Filter")); if (nbt.contains("TrainId")) currentTrain = nbt.getUUID("TrainId"); } diff --git a/src/main/java/com/simibubi/create/content/trains/schedule/condition/FluidThresholdCondition.java b/src/main/java/com/simibubi/create/content/trains/schedule/condition/FluidThresholdCondition.java index 6fedc7789..4432a5c48 100644 --- a/src/main/java/com/simibubi/create/content/trains/schedule/condition/FluidThresholdCondition.java +++ b/src/main/java/com/simibubi/create/content/trains/schedule/condition/FluidThresholdCondition.java @@ -4,8 +4,7 @@ import java.util.List; import com.google.common.collect.ImmutableList; import com.simibubi.create.Create; -import com.simibubi.create.content.fluids.transfer.GenericItemEmptying; -import com.simibubi.create.content.logistics.filter.FilterItem; +import com.simibubi.create.content.logistics.filter.FilterItemStack; import com.simibubi.create.content.trains.entity.Carriage; import com.simibubi.create.content.trains.entity.Train; import com.simibubi.create.foundation.gui.ModularGuiLineBuilder; @@ -26,8 +25,8 @@ import net.minecraftforge.fluids.FluidStack; import net.minecraftforge.fluids.capability.IFluidHandler; public class FluidThresholdCondition extends CargoThresholdCondition { - public ItemStack compareStack = ItemStack.EMPTY; - public FluidStack fluidStack = null; + + private FilterItemStack compareStack = FilterItemStack.empty(); @Override protected Component getUnit() { @@ -36,7 +35,7 @@ public class FluidThresholdCondition extends CargoThresholdCondition { @Override protected ItemStack getIcon() { - return compareStack; + return compareStack.item(); } @Override @@ -49,7 +48,7 @@ public class FluidThresholdCondition extends CargoThresholdCondition { IFluidHandler fluids = carriage.storage.getFluids(); for (int i = 0; i < fluids.getTanks(); i++) { FluidStack fluidInTank = fluids.getFluidInTank(i); - if (!FilterItem.test(level, fluidInTank, compareStack)) + if (!compareStack.test(level, fluidInTank)) continue; foundFluid += fluidInTank.getAmount(); } @@ -69,7 +68,7 @@ public class FluidThresholdCondition extends CargoThresholdCondition { protected void readAdditional(CompoundTag tag) { super.readAdditional(tag); if (tag.contains("Bucket")) - compareStack = ItemStack.of(tag.getCompound("Bucket")); + compareStack = FilterItemStack.of(tag.getCompound("Bucket")); } @Override @@ -79,16 +78,7 @@ public class FluidThresholdCondition extends CargoThresholdCondition { @OnlyIn(Dist.CLIENT) private FluidStack loadFluid() { - if (fluidStack != null) - return fluidStack; - fluidStack = FluidStack.EMPTY; - if (!GenericItemEmptying.canItemBeEmptied(Minecraft.getInstance().level, compareStack)) - return fluidStack; - FluidStack fluidInFilter = GenericItemEmptying.emptyItem(Minecraft.getInstance().level, compareStack, true) - .getFirst(); - if (fluidInFilter == null) - return fluidStack; - return fluidStack = fluidInFilter; + return compareStack.fluid(Minecraft.getInstance().level); } @Override @@ -99,7 +89,7 @@ public class FluidThresholdCondition extends CargoThresholdCondition { Lang.translateDirect("schedule.condition.threshold.x_units_of_item", getThreshold(), Lang.translateDirect("schedule.condition.threshold.buckets"), compareStack.isEmpty() ? Lang.translateDirect("schedule.condition.threshold.anything") - : compareStack.getItem() instanceof FilterItem + : compareStack.isFilterItem() ? Lang.translateDirect("schedule.condition.threshold.matching_content") : loadFluid().getDisplayName()) .withStyle(ChatFormatting.DARK_AQUA)); @@ -107,12 +97,12 @@ public class FluidThresholdCondition extends CargoThresholdCondition { @Override public void setItem(int slot, ItemStack stack) { - compareStack = stack; + compareStack = FilterItemStack.of(stack); } @Override public ItemStack getItem(int slot) { - return compareStack; + return compareStack.item(); } @Override diff --git a/src/main/java/com/simibubi/create/content/trains/schedule/condition/ItemThresholdCondition.java b/src/main/java/com/simibubi/create/content/trains/schedule/condition/ItemThresholdCondition.java index 8b71e2344..c39d6316c 100644 --- a/src/main/java/com/simibubi/create/content/trains/schedule/condition/ItemThresholdCondition.java +++ b/src/main/java/com/simibubi/create/content/trains/schedule/condition/ItemThresholdCondition.java @@ -4,7 +4,7 @@ import java.util.List; import com.google.common.collect.ImmutableList; import com.simibubi.create.Create; -import com.simibubi.create.content.logistics.filter.FilterItem; +import com.simibubi.create.content.logistics.filter.FilterItemStack; import com.simibubi.create.content.trains.entity.Carriage; import com.simibubi.create.content.trains.entity.Train; import com.simibubi.create.foundation.gui.ModularGuiLineBuilder; @@ -23,7 +23,8 @@ import net.minecraftforge.api.distmarker.OnlyIn; import net.minecraftforge.items.IItemHandlerModifiable; public class ItemThresholdCondition extends CargoThresholdCondition { - public ItemStack stack = ItemStack.EMPTY; + + private FilterItemStack stack = FilterItemStack.empty(); @Override protected Component getUnit() { @@ -32,7 +33,7 @@ public class ItemThresholdCondition extends CargoThresholdCondition { @Override protected ItemStack getIcon() { - return stack; + return stack.item(); } @Override @@ -46,7 +47,7 @@ public class ItemThresholdCondition extends CargoThresholdCondition { IItemHandlerModifiable items = carriage.storage.getItems(); for (int i = 0; i < items.getSlots(); i++) { ItemStack stackInSlot = items.getStackInSlot(i); - if (!FilterItem.test(level, stackInSlot, stack)) + if (!stack.test(level, stackInSlot)) continue; if (stacks) @@ -70,7 +71,7 @@ public class ItemThresholdCondition extends CargoThresholdCondition { protected void readAdditional(CompoundTag tag) { super.readAdditional(tag); if (tag.contains("Item")) - stack = ItemStack.of(tag.getCompound("Item")); + stack = FilterItemStack.of(tag.getCompound("Item")); } @Override @@ -80,12 +81,12 @@ public class ItemThresholdCondition extends CargoThresholdCondition { @Override public void setItem(int slot, ItemStack stack) { - this.stack = stack; + this.stack = FilterItemStack.of(stack); } @Override public ItemStack getItem(int slot) { - return stack; + return stack.item(); } @Override @@ -96,9 +97,9 @@ public class ItemThresholdCondition extends CargoThresholdCondition { Lang.translateDirect("schedule.condition.threshold.x_units_of_item", getThreshold(), Lang.translateDirect("schedule.condition.threshold." + (inStacks() ? "stacks" : "items")), stack.isEmpty() ? Lang.translateDirect("schedule.condition.threshold.anything") - : stack.getItem() instanceof FilterItem - ? Lang.translateDirect("schedule.condition.threshold.matching_content") - : stack.getHoverName()) + : stack.isFilterItem() ? Lang.translateDirect("schedule.condition.threshold.matching_content") + : stack.item() + .getHoverName()) .withStyle(ChatFormatting.DARK_AQUA)); } diff --git a/src/main/java/com/simibubi/create/foundation/blockEntity/behaviour/ValueBox.java b/src/main/java/com/simibubi/create/foundation/blockEntity/behaviour/ValueBox.java index d19feaa2c..4689d3361 100644 --- a/src/main/java/com/simibubi/create/foundation/blockEntity/behaviour/ValueBox.java +++ b/src/main/java/com/simibubi/create/foundation/blockEntity/behaviour/ValueBox.java @@ -131,7 +131,7 @@ public class ValueBox extends ChasingAABBOutline { return; Font font = Minecraft.getInstance().font; - boolean wildcard = count == 0 || upTo && count == stack.getMaxStackSize(); + boolean wildcard = count == 0 || upTo && count >= stack.getMaxStackSize(); Component countString = Components.literal(wildcard ? "*" : count + ""); ms.translate(17.5f, -5f, 7f); diff --git a/src/main/java/com/simibubi/create/foundation/blockEntity/behaviour/filtering/FilteringBehaviour.java b/src/main/java/com/simibubi/create/foundation/blockEntity/behaviour/filtering/FilteringBehaviour.java index 25b2a8918..3d800183a 100644 --- a/src/main/java/com/simibubi/create/foundation/blockEntity/behaviour/filtering/FilteringBehaviour.java +++ b/src/main/java/com/simibubi/create/foundation/blockEntity/behaviour/filtering/FilteringBehaviour.java @@ -8,6 +8,7 @@ import com.simibubi.create.AllBlocks; import com.simibubi.create.AllItems; import com.simibubi.create.AllSoundEvents; import com.simibubi.create.content.logistics.filter.FilterItem; +import com.simibubi.create.content.logistics.filter.FilterItemStack; import com.simibubi.create.content.schematics.requirement.ItemRequirement; import com.simibubi.create.foundation.blockEntity.SmartBlockEntity; import com.simibubi.create.foundation.blockEntity.behaviour.BehaviourType; @@ -33,7 +34,6 @@ import net.minecraft.util.Mth; import net.minecraft.world.InteractionHand; import net.minecraft.world.entity.item.ItemEntity; import net.minecraft.world.entity.player.Player; -import net.minecraft.world.item.Item; import net.minecraft.world.item.ItemStack; import net.minecraft.world.level.Level; import net.minecraft.world.level.block.state.BlockState; @@ -51,7 +51,8 @@ public class FilteringBehaviour extends BlockEntityBehaviour implements ValueSet ValueBoxTransform slotPositioning; boolean showCount; - private ItemStack filter; + private FilterItemStack filter; + public int count; public boolean upTo; private Predicate predicate; @@ -64,7 +65,7 @@ public class FilteringBehaviour extends BlockEntityBehaviour implements ValueSet public FilteringBehaviour(SmartBlockEntity be, ValueBoxTransform slot) { super(be); - filter = ItemStack.EMPTY; + filter = FilterItemStack.empty(); slotPositioning = slot; showCount = false; callback = stack -> { @@ -93,14 +94,15 @@ public class FilteringBehaviour extends BlockEntityBehaviour implements ValueSet @Override public void read(CompoundTag nbt, boolean clientPacket) { - filter = ItemStack.of(nbt.getCompound("Filter")); + filter = FilterItemStack.of(nbt.getCompound("Filter")); count = nbt.getInt("FilterAmount"); upTo = nbt.getBoolean("UpTo"); // Migrate from previous behaviour if (count == 0) { upTo = true; - count = filter.getMaxStackSize(); + count = filter.item() + .getMaxStackSize(); } super.read(nbt, clientPacket); @@ -153,7 +155,7 @@ public class FilteringBehaviour extends BlockEntityBehaviour implements ValueSet ItemStack filter = stack.copy(); if (!filter.isEmpty() && !predicate.test(filter)) return false; - this.filter = filter; + this.filter = FilterItemStack.of(filter); if (!upTo) count = Math.min(count, stack.getMaxStackSize()); callback.accept(filter); @@ -166,7 +168,8 @@ public class FilteringBehaviour extends BlockEntityBehaviour implements ValueSet public void setValueSettings(Player player, ValueSettings settings, boolean ctrlDown) { if (getValueSettings().equals(settings)) return; - count = Mth.clamp(settings.value(), 1, filter.getMaxStackSize()); + count = Mth.clamp(settings.value(), 1, filter.item() + .getMaxStackSize()); upTo = settings.row() == 0; blockEntity.setChanged(); blockEntity.sendData(); @@ -175,24 +178,25 @@ public class FilteringBehaviour extends BlockEntityBehaviour implements ValueSet @Override public ValueSettings getValueSettings() { - return new ValueSettings(upTo ? 0 : 1, count == 0 ? filter.getMaxStackSize() : count); + return new ValueSettings(upTo ? 0 : 1, count == 0 ? filter.item() + .getMaxStackSize() : count); } @Override public void destroy() { - if (filter.getItem() instanceof FilterItem) { + if (filter.isFilterItem()) { Vec3 pos = VecHelper.getCenterOf(getPos()); Level world = getWorld(); - world.addFreshEntity(new ItemEntity(world, pos.x, pos.y, pos.z, filter.copy())); + world.addFreshEntity(new ItemEntity(world, pos.x, pos.y, pos.z, filter.item() + .copy())); } super.destroy(); } @Override public ItemRequirement getRequiredItems() { - Item filterItem = filter.getItem(); - if (filterItem instanceof FilterItem) - return new ItemRequirement(ItemRequirement.ItemUseType.CONSUME, filterItem); + if (filter.isFilterItem()) + return new ItemRequirement(ItemRequirement.ItemUseType.CONSUME, filter.item()); return ItemRequirement.NONE; } @@ -202,19 +206,20 @@ public class FilteringBehaviour extends BlockEntityBehaviour implements ValueSet } public ItemStack getFilter() { - return filter.copy(); + return filter.item(); } public boolean isCountVisible() { - return showCountPredicate.get() && filter.getMaxStackSize() > 1; + return showCountPredicate.get() && filter.item() + .getMaxStackSize() > 1; } public boolean test(ItemStack stack) { - return !isActive() || filter.isEmpty() || FilterItem.test(blockEntity.getLevel(), stack, filter); + return !isActive() || filter.test(blockEntity.getLevel(), stack); } public boolean test(FluidStack stack) { - return !isActive() || filter.isEmpty() || FilterItem.test(blockEntity.getLevel(), stack, filter); + return !isActive() || filter.test(blockEntity.getLevel(), stack); } @Override @@ -262,7 +267,8 @@ public class FilteringBehaviour extends BlockEntityBehaviour implements ValueSet } public MutableComponent formatValue(ValueSettings value) { - if (value.row() == 0 && value.value() == filter.getMaxStackSize()) + if (value.row() == 0 && value.value() == filter.item() + .getMaxStackSize()) return Lang.translateDirect("logistics.filter.any_amount_short"); return Components.literal(((value.row() == 0) ? "\u2264" : "=") + Math.max(1, value.value())); } @@ -287,7 +293,7 @@ public class FilteringBehaviour extends BlockEntityBehaviour implements ValueSet stack -> ItemHandlerHelper.canItemStacksStack(stack, getFilter(side)), true) .isEmpty()) player.getInventory() - .placeItemBackInInventory(getFilter(side)); + .placeItemBackInInventory(getFilter(side).copy()); } if (toApply.getItem() instanceof FilterItem)