Filter code caused global warming

- Contents of a filter are no longer deserialised from item nbt each time a stack is tested
- FilteringBehaviour.getFilter() no longer creates a copy of the item
- MovementContext for contraption actors now have a shortcut to a cached filter from their corresponding BlockEntity
This commit is contained in:
simibubi 2023-11-02 00:08:34 +01:00
parent d6708cef3b
commit eea8bb2607
16 changed files with 338 additions and 240 deletions

View file

@ -117,7 +117,7 @@ public class RollerBlockEntity extends SmartBlockEntity {
protected void acceptSharedValues(int mode, ItemStack filter) { protected void acceptSharedValues(int mode, ItemStack filter) {
dontPropagate = true; dontPropagate = true;
this.filtering.setFilter(filter); this.filtering.setFilter(filter.copy());
this.mode.setValue(mode); this.mode.setValue(mode);
dontPropagate = false; dontPropagate = false;
notifyUpdate(); notifyUpdate();

View file

@ -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.ContraptionMatrices;
import com.simibubi.create.content.contraptions.render.ContraptionRenderDispatcher; import com.simibubi.create.content.contraptions.render.ContraptionRenderDispatcher;
import com.simibubi.create.content.kinetics.base.BlockBreakingMovementBehaviour; 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.bogey.StandardBogeyBlock;
import com.simibubi.create.content.trains.entity.Carriage; import com.simibubi.create.content.trains.entity.Carriage;
import com.simibubi.create.content.trains.entity.CarriageBogey; import com.simibubi.create.content.trains.entity.CarriageBogey;
@ -193,10 +193,10 @@ public class RollerMovementBehaviour extends BlockBreakingMovementBehaviour {
int startingY = 1; int startingY = 1;
if (!getStateToPaveWith(context).isAir()) { if (!getStateToPaveWith(context).isAir()) {
ItemStack filter = ItemStack.of(context.blockEntityData.getCompound("Filter")); FilterItemStack filter = context.getFilterFromBE();
if (!ItemHelper if (!ItemHelper
.extract(context.contraption.getSharedInventory(), .extract(context.contraption.getSharedInventory(),
stack -> FilterItem.test(context.world, stack, filter), 1, true) stack -> filter.test(context.world, stack), 1, true)
.isEmpty()) .isEmpty())
startingY = 0; startingY = 0;
} }
@ -473,9 +473,9 @@ public class RollerMovementBehaviour extends BlockBreakingMovementBehaviour {
.isEmpty()) .isEmpty())
return PaveResult.FAIL; return PaveResult.FAIL;
ItemStack filter = ItemStack.of(context.blockEntityData.getCompound("Filter")); FilterItemStack filter = context.getFilterFromBE();
ItemStack held = ItemHelper.extract(context.contraption.getSharedInventory(), 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()) if (held.isEmpty())
return PaveResult.FAIL; return PaveResult.FAIL;

View file

@ -3,6 +3,7 @@ package com.simibubi.create.content.contraptions.behaviour;
import java.util.function.UnaryOperator; import java.util.function.UnaryOperator;
import com.simibubi.create.content.contraptions.Contraption; import com.simibubi.create.content.contraptions.Contraption;
import com.simibubi.create.content.logistics.filter.FilterItemStack;
import com.simibubi.create.foundation.utility.VecHelper; import com.simibubi.create.foundation.utility.VecHelper;
import net.minecraft.core.BlockPos; import net.minecraft.core.BlockPos;
@ -31,6 +32,8 @@ public class MovementContext {
public CompoundTag data; public CompoundTag data;
public Contraption contraption; public Contraption contraption;
public Object temporaryData; public Object temporaryData;
private FilterItemStack filter;
public MovementContext(Level world, StructureBlockInfo info, Contraption contraption) { public MovementContext(Level world, StructureBlockInfo info, Contraption contraption) {
this.world = world; this.world = world;
@ -47,6 +50,7 @@ public class MovementContext {
position = null; position = null;
data = new CompoundTag(); data = new CompoundTag();
stall = false; stall = false;
filter = null;
} }
public float getAnimationSpeed() { public float getAnimationSpeed() {
@ -83,5 +87,11 @@ public class MovementContext {
nbt.put("Data", data.copy()); nbt.put("Data", data.copy());
return nbt; return nbt;
} }
public FilterItemStack getFilterFromBE() {
if (filter != null)
return filter;
return filter = FilterItemStack.of(blockEntityData.getCompound("Filter"));
}
} }

View file

@ -8,6 +8,7 @@ import com.simibubi.create.AllShapes;
import com.simibubi.create.AllSoundEvents; import com.simibubi.create.AllSoundEvents;
import com.simibubi.create.content.equipment.wrench.IWrenchable; import com.simibubi.create.content.equipment.wrench.IWrenchable;
import com.simibubi.create.content.logistics.filter.FilterItem; 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.ISpecialBlockItemRequirement;
import com.simibubi.create.content.schematics.requirement.ItemRequirement; import com.simibubi.create.content.schematics.requirement.ItemRequirement;
import com.simibubi.create.content.schematics.requirement.ItemRequirement.ItemUseType; import com.simibubi.create.content.schematics.requirement.ItemRequirement.ItemUseType;
@ -132,9 +133,9 @@ public class PlacardBlock extends FaceAttachedHorizontalDirectionalBlock
return InteractionResult.FAIL; return InteractionResult.FAIL;
if (pState.getValue(POWERED)) if (pState.getValue(POWERED))
return InteractionResult.FAIL; return InteractionResult.FAIL;
boolean test = inBlock.getItem() instanceof FilterItem ? FilterItem.test(pLevel, inHand, inBlock) boolean test = inBlock.getItem() instanceof FilterItem ? FilterItemStack.of(inBlock)
: ItemHandlerHelper.canItemStacksStack(inHand, inBlock); .test(pLevel, inHand) : ItemHandlerHelper.canItemStacksStack(inHand, inBlock);
if (!test) { if (!test) {
AllSoundEvents.DENY.play(pLevel, null, pPos, 1, 1); AllSoundEvents.DENY.play(pLevel, null, pPos, 1, 1);
return InteractionResult.SUCCESS; return InteractionResult.SUCCESS;

View file

@ -13,6 +13,7 @@ import com.simibubi.create.AllEntityTypes;
import com.simibubi.create.AllItems; import com.simibubi.create.AllItems;
import com.simibubi.create.Create; import com.simibubi.create.Create;
import com.simibubi.create.content.logistics.filter.FilterItem; 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.ISpecialEntityItemRequirement;
import com.simibubi.create.content.schematics.requirement.ItemRequirement; import com.simibubi.create.content.schematics.requirement.ItemRequirement;
import com.simibubi.create.content.schematics.requirement.ItemRequirement.ItemUseType; import com.simibubi.create.content.schematics.requirement.ItemRequirement.ItemUseType;
@ -365,14 +366,14 @@ public class BlueprintEntity extends HangingEntity
boolean success = true; boolean success = true;
Search: for (int i = 0; i < 9; i++) { Search: for (int i = 0; i < 9; i++) {
ItemStack requestedItem = items.getStackInSlot(i); FilterItemStack requestedItem = FilterItemStack.of(items.getStackInSlot(i));
if (requestedItem.isEmpty()) { if (requestedItem.isEmpty()) {
craftingGrid.put(i, ItemStack.EMPTY); craftingGrid.put(i, ItemStack.EMPTY);
continue; continue;
} }
for (int slot = 0; slot < playerInv.getSlots(); slot++) { for (int slot = 0; slot < playerInv.getSlots(); slot++) {
if (!FilterItem.test(level, playerInv.getStackInSlot(slot), requestedItem)) if (!requestedItem.test(level, playerInv.getStackInSlot(slot)))
continue; continue;
ItemStack currentItem = playerInv.extractItem(slot, 1, false); ItemStack currentItem = playerInv.extractItem(slot, 1, false);
if (stacksTaken.containsKey(slot)) if (stacksTaken.containsKey(slot))

View file

@ -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.equipment.blueprint.BlueprintEntity.BlueprintSection;
import com.simibubi.create.content.logistics.filter.AttributeFilterMenu.WhitelistMode; import com.simibubi.create.content.logistics.filter.AttributeFilterMenu.WhitelistMode;
import com.simibubi.create.content.logistics.filter.FilterItem; 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.logistics.filter.ItemAttribute;
import com.simibubi.create.content.trains.track.TrackPlacement.PlacementInfo; import com.simibubi.create.content.trains.track.TrackPlacement.PlacementInfo;
import com.simibubi.create.foundation.gui.AllGuiTextures; import com.simibubi.create.foundation.gui.AllGuiTextures;
@ -161,14 +162,14 @@ public class BlueprintOverlayRenderer {
newlyMissing.clear(); newlyMissing.clear();
Search: for (int i = 0; i < 9; i++) { Search: for (int i = 0; i < 9; i++) {
ItemStack requestedItem = items.getStackInSlot(i); FilterItemStack requestedItem = FilterItemStack.of(items.getStackInSlot(i));
if (requestedItem.isEmpty()) { if (requestedItem.isEmpty()) {
craftingGrid.put(i, ItemStack.EMPTY); craftingGrid.put(i, ItemStack.EMPTY);
continue; continue;
} }
for (int slot = 0; slot < playerInv.getSlots(); slot++) { 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; continue;
ItemStack currentItem = playerInv.extractItem(slot, 1, false); ItemStack currentItem = playerInv.extractItem(slot, 1, false);
craftingGrid.put(i, currentItem); craftingGrid.put(i, currentItem);
@ -177,7 +178,7 @@ public class BlueprintOverlayRenderer {
} }
success = false; success = false;
newlyMissing.add(requestedItem); newlyMissing.add(requestedItem.item());
} }
if (success) { if (success) {

View file

@ -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.ContraptionMatrices;
import com.simibubi.create.content.contraptions.render.ContraptionRenderDispatcher; import com.simibubi.create.content.contraptions.render.ContraptionRenderDispatcher;
import com.simibubi.create.content.kinetics.deployer.DeployerBlockEntity.Mode; 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.SchematicInstances;
import com.simibubi.create.content.schematics.SchematicWorld; import com.simibubi.create.content.schematics.SchematicWorld;
import com.simibubi.create.content.schematics.requirement.ItemRequirement; 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) { public void activate(MovementContext context, BlockPos pos, DeployerFakePlayer player, Mode mode) {
Level world = context.world; Level world = context.world;
ItemStack filter = getFilter(context); FilterItemStack filter = context.getFilterFromBE();
if (AllItems.SCHEMATIC.isIn(filter)) if (AllItems.SCHEMATIC.isIn(filter.item()))
activateAsSchematicPrinter(context, pos, player, world, filter); activateAsSchematicPrinter(context, pos, player, world, filter.item());
Vec3 facingVec = Vec3.atLowerCornerOf(context.state.getValue(DeployerBlock.FACING) Vec3 facingVec = Vec3.atLowerCornerOf(context.state.getValue(DeployerBlock.FACING)
.getNormal()); .getNormal());
@ -222,11 +222,11 @@ public class DeployerMovementBehaviour implements MovementBehaviour {
return; return;
if (player.getMainHandItem() if (player.getMainHandItem()
.isEmpty()) { .isEmpty()) {
ItemStack filter = getFilter(context); FilterItemStack filter = context.getFilterFromBE();
if (AllItems.SCHEMATIC.isIn(filter)) if (AllItems.SCHEMATIC.isIn(filter.item()))
return; return;
ItemStack held = ItemHelper.extract(context.contraption.getSharedInventory(), 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); player.setItemInHand(InteractionHand.MAIN_HAND, held);
} }
} }
@ -236,7 +236,7 @@ public class DeployerMovementBehaviour implements MovementBehaviour {
if (player == null) if (player == null)
return; return;
Inventory inv = player.getInventory(); Inventory inv = player.getInventory();
ItemStack filter = getFilter(context); FilterItemStack filter = context.getFilterFromBE();
for (List<ItemStack> list : Arrays.asList(inv.armor, inv.offhand, inv.items)) { for (List<ItemStack> list : Arrays.asList(inv.armor, inv.offhand, inv.items)) {
for (int i = 0; i < list.size(); ++i) { for (int i = 0; i < list.size(); ++i) {
@ -244,7 +244,7 @@ public class DeployerMovementBehaviour implements MovementBehaviour {
if (itemstack.isEmpty()) if (itemstack.isEmpty())
continue; 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; continue;
dropItem(context, itemstack); dropItem(context, itemstack);
@ -278,10 +278,6 @@ public class DeployerMovementBehaviour implements MovementBehaviour {
return (DeployerFakePlayer) context.temporaryData; return (DeployerFakePlayer) context.temporaryData;
} }
private ItemStack getFilter(MovementContext context) {
return ItemStack.of(context.blockEntityData.getCompound("Filter"));
}
private Mode getMode(MovementContext context) { private Mode getMode(MovementContext context) {
return NBTHelper.readEnum(context.blockEntityData, "Mode", Mode.class); return NBTHelper.readEnum(context.blockEntityData, "Mode", Mode.class);
} }

View file

@ -8,7 +8,6 @@ import javax.annotation.Nonnull;
import com.simibubi.create.AllItems; import com.simibubi.create.AllItems;
import com.simibubi.create.AllKeys; 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.content.logistics.filter.AttributeFilterMenu.WhitelistMode;
import com.simibubi.create.foundation.utility.Components; import com.simibubi.create.foundation.utility.Components;
import com.simibubi.create.foundation.utility.Lang; 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.minecraft.world.level.Level;
import net.minecraftforge.api.distmarker.Dist; import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.api.distmarker.OnlyIn; import net.minecraftforge.api.distmarker.OnlyIn;
import net.minecraftforge.fluids.FluidStack;
import net.minecraftforge.items.ItemHandlerHelper; import net.minecraftforge.items.ItemHandlerHelper;
import net.minecraftforge.items.ItemStackHandler; import net.minecraftforge.items.ItemStackHandler;
import net.minecraftforge.network.NetworkHooks; import net.minecraftforge.network.NetworkHooks;
@ -188,146 +186,7 @@ public class FilterItem extends Item implements MenuProvider {
return newInv; return newInv;
} }
public static boolean test(Level world, ItemStack stack, ItemStack filter) { public static boolean testDirect(ItemStack filter, ItemStack stack, boolean matchNBT) {
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) {
if (matchNBT) { if (matchNBT) {
return ItemHandlerHelper.canItemStacksStack(filter, stack); return ItemHandlerHelper.canItemStacksStack(filter, stack);
} else { } else {

View file

@ -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<FilterItemStack> 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<Pair<ItemAttribute, Boolean>> 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<ItemAttribute, Boolean> 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;
}
}
}

View file

@ -4,7 +4,7 @@ import java.util.List;
import com.simibubi.create.content.contraptions.behaviour.MovementBehaviour; import com.simibubi.create.content.contraptions.behaviour.MovementBehaviour;
import com.simibubi.create.content.contraptions.behaviour.MovementContext; 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 com.simibubi.create.foundation.item.ItemHelper;
import net.minecraft.core.BlockPos; import net.minecraft.core.BlockPos;
@ -71,14 +71,14 @@ public class FunnelMovementBehaviour implements MovementBehaviour {
.isEmpty()) .isEmpty())
return; return;
ItemStack filter = getFilter(context); FilterItemStack filter = context.getFilterFromBE();
int filterAmount = context.blockEntityData.getInt("FilterAmount"); int filterAmount = context.blockEntityData.getInt("FilterAmount");
boolean upTo = context.blockEntityData.getBoolean("UpTo"); boolean upTo = context.blockEntityData.getBoolean("UpTo");
if (filterAmount <= 0) if (filterAmount <= 0)
filterAmount = hasFilter ? 64 : 1; filterAmount = hasFilter ? 64 : 1;
ItemStack extract = ItemHelper.extract(context.contraption.getSharedInventory(), 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); upTo ? ItemHelper.ExtractionCountMode.UPTO : ItemHelper.ExtractionCountMode.EXACTLY, filterAmount, false);
if (extract.isEmpty()) if (extract.isEmpty())
@ -97,13 +97,13 @@ public class FunnelMovementBehaviour implements MovementBehaviour {
private void succ(MovementContext context, BlockPos pos) { private void succ(MovementContext context, BlockPos pos) {
Level world = context.world; Level world = context.world;
List<ItemEntity> items = world.getEntitiesOfClass(ItemEntity.class, new AABB(pos)); List<ItemEntity> items = world.getEntitiesOfClass(ItemEntity.class, new AABB(pos));
ItemStack filter = getFilter(context); FilterItemStack filter = context.getFilterFromBE();
for (ItemEntity item : items) { for (ItemEntity item : items) {
if (!item.isAlive()) if (!item.isAlive())
continue; continue;
ItemStack toInsert = item.getItem(); ItemStack toInsert = item.getItem();
if (!filter.isEmpty() && !FilterItem.test(context.world, toInsert, filter)) if (!filter.test(context.world, toInsert))
continue; continue;
ItemStack remainder = ItemStack remainder =
ItemHandlerHelper.insertItemStacked(context.contraption.getSharedInventory(), toInsert, false); ItemHandlerHelper.insertItemStacked(context.contraption.getSharedInventory(), toInsert, false);
@ -124,8 +124,4 @@ public class FunnelMovementBehaviour implements MovementBehaviour {
return true; return true;
} }
private ItemStack getFilter(MovementContext context) {
return hasFilter ? ItemStack.of(context.blockEntityData.getCompound("Filter")) : ItemStack.EMPTY;
}
} }

View file

@ -17,8 +17,6 @@ import java.util.function.Consumer;
import javax.annotation.Nullable; 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.MutableBoolean;
import org.apache.commons.lang3.mutable.MutableObject; 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.AllPackets;
import com.simibubi.create.Create; import com.simibubi.create.Create;
import com.simibubi.create.content.contraptions.behaviour.MovementBehaviour; 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.bogey.AbstractBogeyBlockEntity;
import com.simibubi.create.content.trains.entity.Carriage.DimensionalCarriageEntity; 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.IEdgePointListener;
import com.simibubi.create.content.trains.entity.TravellingPoint.SteerDirection; import com.simibubi.create.content.trains.entity.TravellingPoint.SteerDirection;
import com.simibubi.create.content.trains.graph.DimensionPalette; 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.EdgeData;
import com.simibubi.create.content.trains.graph.EdgePointType; import com.simibubi.create.content.trains.graph.EdgePointType;
import com.simibubi.create.content.trains.graph.TrackEdge; import com.simibubi.create.content.trains.graph.TrackEdge;
@ -197,7 +196,7 @@ public class Train {
if (observer == null) if (observer == null)
continue; continue;
ItemStack filter = observer.getFilter(); FilterItemStack filter = observer.getFilter();
if (filter.isEmpty()) { if (filter.isEmpty()) {
observer.keepAlive(this); observer.keepAlive(this);
continue; continue;
@ -225,7 +224,7 @@ public class Train {
ItemStack extractItem = inv.extractItem(slot, 1, true); ItemStack extractItem = inv.extractItem(slot, 1, true);
if (extractItem.isEmpty()) if (extractItem.isEmpty())
continue; 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); FluidStack drain = tank.drain(1, FluidAction.SIMULATE);
if (drain.isEmpty()) if (drain.isEmpty())
continue; continue;
shouldActivate |= FilterItem.test(level, drain, filter); shouldActivate |= filter.test(level, drain);
} }
} }
} }

View file

@ -3,6 +3,7 @@ package com.simibubi.create.content.trains.observer;
import java.util.UUID; import java.util.UUID;
import com.simibubi.create.Create; 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.entity.Train;
import com.simibubi.create.content.trains.graph.DimensionPalette; import com.simibubi.create.content.trains.graph.DimensionPalette;
import com.simibubi.create.content.trains.graph.TrackEdge; 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 { public class TrackObserver extends SingleBlockEntityEdgePoint {
private int activated; private int activated;
private ItemStack filter; private FilterItemStack filter;
private UUID currentTrain; private UUID currentTrain;
public TrackObserver() { public TrackObserver() {
activated = 0; activated = 0;
filter = ItemStack.EMPTY; filter = FilterItemStack.empty();
currentTrain = null; currentTrain = null;
} }
@ -48,7 +49,7 @@ public class TrackObserver extends SingleBlockEntityEdgePoint {
} }
public void setFilterAndNotify(Level level, ItemStack filter) { public void setFilterAndNotify(Level level, ItemStack filter) {
this.filter = filter; this.filter = FilterItemStack.of(filter.copy());
notifyTrains(level); notifyTrains(level);
} }
@ -63,7 +64,7 @@ public class TrackObserver extends SingleBlockEntityEdgePoint {
SignalPropagator.notifyTrains(graph, edge); SignalPropagator.notifyTrains(graph, edge);
} }
public ItemStack getFilter() { public FilterItemStack getFilter() {
return filter; return filter;
} }
@ -84,7 +85,7 @@ public class TrackObserver extends SingleBlockEntityEdgePoint {
public void read(CompoundTag nbt, boolean migration, DimensionPalette dimensions) { public void read(CompoundTag nbt, boolean migration, DimensionPalette dimensions) {
super.read(nbt, migration, dimensions); super.read(nbt, migration, dimensions);
activated = nbt.getInt("Activated"); activated = nbt.getInt("Activated");
filter = ItemStack.of(nbt.getCompound("Filter")); filter = FilterItemStack.of(nbt.getCompound("Filter"));
if (nbt.contains("TrainId")) if (nbt.contains("TrainId"))
currentTrain = nbt.getUUID("TrainId"); currentTrain = nbt.getUUID("TrainId");
} }

View file

@ -4,8 +4,7 @@ import java.util.List;
import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableList;
import com.simibubi.create.Create; import com.simibubi.create.Create;
import com.simibubi.create.content.fluids.transfer.GenericItemEmptying; import com.simibubi.create.content.logistics.filter.FilterItemStack;
import com.simibubi.create.content.logistics.filter.FilterItem;
import com.simibubi.create.content.trains.entity.Carriage; import com.simibubi.create.content.trains.entity.Carriage;
import com.simibubi.create.content.trains.entity.Train; import com.simibubi.create.content.trains.entity.Train;
import com.simibubi.create.foundation.gui.ModularGuiLineBuilder; import com.simibubi.create.foundation.gui.ModularGuiLineBuilder;
@ -26,8 +25,8 @@ import net.minecraftforge.fluids.FluidStack;
import net.minecraftforge.fluids.capability.IFluidHandler; import net.minecraftforge.fluids.capability.IFluidHandler;
public class FluidThresholdCondition extends CargoThresholdCondition { public class FluidThresholdCondition extends CargoThresholdCondition {
public ItemStack compareStack = ItemStack.EMPTY;
public FluidStack fluidStack = null; private FilterItemStack compareStack = FilterItemStack.empty();
@Override @Override
protected Component getUnit() { protected Component getUnit() {
@ -36,7 +35,7 @@ public class FluidThresholdCondition extends CargoThresholdCondition {
@Override @Override
protected ItemStack getIcon() { protected ItemStack getIcon() {
return compareStack; return compareStack.item();
} }
@Override @Override
@ -49,7 +48,7 @@ public class FluidThresholdCondition extends CargoThresholdCondition {
IFluidHandler fluids = carriage.storage.getFluids(); IFluidHandler fluids = carriage.storage.getFluids();
for (int i = 0; i < fluids.getTanks(); i++) { for (int i = 0; i < fluids.getTanks(); i++) {
FluidStack fluidInTank = fluids.getFluidInTank(i); FluidStack fluidInTank = fluids.getFluidInTank(i);
if (!FilterItem.test(level, fluidInTank, compareStack)) if (!compareStack.test(level, fluidInTank))
continue; continue;
foundFluid += fluidInTank.getAmount(); foundFluid += fluidInTank.getAmount();
} }
@ -69,7 +68,7 @@ public class FluidThresholdCondition extends CargoThresholdCondition {
protected void readAdditional(CompoundTag tag) { protected void readAdditional(CompoundTag tag) {
super.readAdditional(tag); super.readAdditional(tag);
if (tag.contains("Bucket")) if (tag.contains("Bucket"))
compareStack = ItemStack.of(tag.getCompound("Bucket")); compareStack = FilterItemStack.of(tag.getCompound("Bucket"));
} }
@Override @Override
@ -79,16 +78,7 @@ public class FluidThresholdCondition extends CargoThresholdCondition {
@OnlyIn(Dist.CLIENT) @OnlyIn(Dist.CLIENT)
private FluidStack loadFluid() { private FluidStack loadFluid() {
if (fluidStack != null) return compareStack.fluid(Minecraft.getInstance().level);
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;
} }
@Override @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.x_units_of_item", getThreshold(),
Lang.translateDirect("schedule.condition.threshold.buckets"), Lang.translateDirect("schedule.condition.threshold.buckets"),
compareStack.isEmpty() ? Lang.translateDirect("schedule.condition.threshold.anything") compareStack.isEmpty() ? Lang.translateDirect("schedule.condition.threshold.anything")
: compareStack.getItem() instanceof FilterItem : compareStack.isFilterItem()
? Lang.translateDirect("schedule.condition.threshold.matching_content") ? Lang.translateDirect("schedule.condition.threshold.matching_content")
: loadFluid().getDisplayName()) : loadFluid().getDisplayName())
.withStyle(ChatFormatting.DARK_AQUA)); .withStyle(ChatFormatting.DARK_AQUA));
@ -107,12 +97,12 @@ public class FluidThresholdCondition extends CargoThresholdCondition {
@Override @Override
public void setItem(int slot, ItemStack stack) { public void setItem(int slot, ItemStack stack) {
compareStack = stack; compareStack = FilterItemStack.of(stack);
} }
@Override @Override
public ItemStack getItem(int slot) { public ItemStack getItem(int slot) {
return compareStack; return compareStack.item();
} }
@Override @Override

View file

@ -4,7 +4,7 @@ import java.util.List;
import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableList;
import com.simibubi.create.Create; 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.Carriage;
import com.simibubi.create.content.trains.entity.Train; import com.simibubi.create.content.trains.entity.Train;
import com.simibubi.create.foundation.gui.ModularGuiLineBuilder; import com.simibubi.create.foundation.gui.ModularGuiLineBuilder;
@ -23,7 +23,8 @@ import net.minecraftforge.api.distmarker.OnlyIn;
import net.minecraftforge.items.IItemHandlerModifiable; import net.minecraftforge.items.IItemHandlerModifiable;
public class ItemThresholdCondition extends CargoThresholdCondition { public class ItemThresholdCondition extends CargoThresholdCondition {
public ItemStack stack = ItemStack.EMPTY;
private FilterItemStack stack = FilterItemStack.empty();
@Override @Override
protected Component getUnit() { protected Component getUnit() {
@ -32,7 +33,7 @@ public class ItemThresholdCondition extends CargoThresholdCondition {
@Override @Override
protected ItemStack getIcon() { protected ItemStack getIcon() {
return stack; return stack.item();
} }
@Override @Override
@ -46,7 +47,7 @@ public class ItemThresholdCondition extends CargoThresholdCondition {
IItemHandlerModifiable items = carriage.storage.getItems(); IItemHandlerModifiable items = carriage.storage.getItems();
for (int i = 0; i < items.getSlots(); i++) { for (int i = 0; i < items.getSlots(); i++) {
ItemStack stackInSlot = items.getStackInSlot(i); ItemStack stackInSlot = items.getStackInSlot(i);
if (!FilterItem.test(level, stackInSlot, stack)) if (!stack.test(level, stackInSlot))
continue; continue;
if (stacks) if (stacks)
@ -70,7 +71,7 @@ public class ItemThresholdCondition extends CargoThresholdCondition {
protected void readAdditional(CompoundTag tag) { protected void readAdditional(CompoundTag tag) {
super.readAdditional(tag); super.readAdditional(tag);
if (tag.contains("Item")) if (tag.contains("Item"))
stack = ItemStack.of(tag.getCompound("Item")); stack = FilterItemStack.of(tag.getCompound("Item"));
} }
@Override @Override
@ -80,12 +81,12 @@ public class ItemThresholdCondition extends CargoThresholdCondition {
@Override @Override
public void setItem(int slot, ItemStack stack) { public void setItem(int slot, ItemStack stack) {
this.stack = stack; this.stack = FilterItemStack.of(stack);
} }
@Override @Override
public ItemStack getItem(int slot) { public ItemStack getItem(int slot) {
return stack; return stack.item();
} }
@Override @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.x_units_of_item", getThreshold(),
Lang.translateDirect("schedule.condition.threshold." + (inStacks() ? "stacks" : "items")), Lang.translateDirect("schedule.condition.threshold." + (inStacks() ? "stacks" : "items")),
stack.isEmpty() ? Lang.translateDirect("schedule.condition.threshold.anything") stack.isEmpty() ? Lang.translateDirect("schedule.condition.threshold.anything")
: stack.getItem() instanceof FilterItem : stack.isFilterItem() ? Lang.translateDirect("schedule.condition.threshold.matching_content")
? Lang.translateDirect("schedule.condition.threshold.matching_content") : stack.item()
: stack.getHoverName()) .getHoverName())
.withStyle(ChatFormatting.DARK_AQUA)); .withStyle(ChatFormatting.DARK_AQUA));
} }

View file

@ -131,7 +131,7 @@ public class ValueBox extends ChasingAABBOutline {
return; return;
Font font = Minecraft.getInstance().font; 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 + ""); Component countString = Components.literal(wildcard ? "*" : count + "");
ms.translate(17.5f, -5f, 7f); ms.translate(17.5f, -5f, 7f);

View file

@ -8,6 +8,7 @@ import com.simibubi.create.AllBlocks;
import com.simibubi.create.AllItems; import com.simibubi.create.AllItems;
import com.simibubi.create.AllSoundEvents; import com.simibubi.create.AllSoundEvents;
import com.simibubi.create.content.logistics.filter.FilterItem; 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.content.schematics.requirement.ItemRequirement;
import com.simibubi.create.foundation.blockEntity.SmartBlockEntity; import com.simibubi.create.foundation.blockEntity.SmartBlockEntity;
import com.simibubi.create.foundation.blockEntity.behaviour.BehaviourType; 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.InteractionHand;
import net.minecraft.world.entity.item.ItemEntity; import net.minecraft.world.entity.item.ItemEntity;
import net.minecraft.world.entity.player.Player; import net.minecraft.world.entity.player.Player;
import net.minecraft.world.item.Item;
import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.ItemStack;
import net.minecraft.world.level.Level; import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.block.state.BlockState;
@ -51,7 +51,8 @@ public class FilteringBehaviour extends BlockEntityBehaviour implements ValueSet
ValueBoxTransform slotPositioning; ValueBoxTransform slotPositioning;
boolean showCount; boolean showCount;
private ItemStack filter; private FilterItemStack filter;
public int count; public int count;
public boolean upTo; public boolean upTo;
private Predicate<ItemStack> predicate; private Predicate<ItemStack> predicate;
@ -64,7 +65,7 @@ public class FilteringBehaviour extends BlockEntityBehaviour implements ValueSet
public FilteringBehaviour(SmartBlockEntity be, ValueBoxTransform slot) { public FilteringBehaviour(SmartBlockEntity be, ValueBoxTransform slot) {
super(be); super(be);
filter = ItemStack.EMPTY; filter = FilterItemStack.empty();
slotPositioning = slot; slotPositioning = slot;
showCount = false; showCount = false;
callback = stack -> { callback = stack -> {
@ -93,14 +94,15 @@ public class FilteringBehaviour extends BlockEntityBehaviour implements ValueSet
@Override @Override
public void read(CompoundTag nbt, boolean clientPacket) { public void read(CompoundTag nbt, boolean clientPacket) {
filter = ItemStack.of(nbt.getCompound("Filter")); filter = FilterItemStack.of(nbt.getCompound("Filter"));
count = nbt.getInt("FilterAmount"); count = nbt.getInt("FilterAmount");
upTo = nbt.getBoolean("UpTo"); upTo = nbt.getBoolean("UpTo");
// Migrate from previous behaviour // Migrate from previous behaviour
if (count == 0) { if (count == 0) {
upTo = true; upTo = true;
count = filter.getMaxStackSize(); count = filter.item()
.getMaxStackSize();
} }
super.read(nbt, clientPacket); super.read(nbt, clientPacket);
@ -153,7 +155,7 @@ public class FilteringBehaviour extends BlockEntityBehaviour implements ValueSet
ItemStack filter = stack.copy(); ItemStack filter = stack.copy();
if (!filter.isEmpty() && !predicate.test(filter)) if (!filter.isEmpty() && !predicate.test(filter))
return false; return false;
this.filter = filter; this.filter = FilterItemStack.of(filter);
if (!upTo) if (!upTo)
count = Math.min(count, stack.getMaxStackSize()); count = Math.min(count, stack.getMaxStackSize());
callback.accept(filter); callback.accept(filter);
@ -166,7 +168,8 @@ public class FilteringBehaviour extends BlockEntityBehaviour implements ValueSet
public void setValueSettings(Player player, ValueSettings settings, boolean ctrlDown) { public void setValueSettings(Player player, ValueSettings settings, boolean ctrlDown) {
if (getValueSettings().equals(settings)) if (getValueSettings().equals(settings))
return; return;
count = Mth.clamp(settings.value(), 1, filter.getMaxStackSize()); count = Mth.clamp(settings.value(), 1, filter.item()
.getMaxStackSize());
upTo = settings.row() == 0; upTo = settings.row() == 0;
blockEntity.setChanged(); blockEntity.setChanged();
blockEntity.sendData(); blockEntity.sendData();
@ -175,24 +178,25 @@ public class FilteringBehaviour extends BlockEntityBehaviour implements ValueSet
@Override @Override
public ValueSettings getValueSettings() { 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 @Override
public void destroy() { public void destroy() {
if (filter.getItem() instanceof FilterItem) { if (filter.isFilterItem()) {
Vec3 pos = VecHelper.getCenterOf(getPos()); Vec3 pos = VecHelper.getCenterOf(getPos());
Level world = getWorld(); 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(); super.destroy();
} }
@Override @Override
public ItemRequirement getRequiredItems() { public ItemRequirement getRequiredItems() {
Item filterItem = filter.getItem(); if (filter.isFilterItem())
if (filterItem instanceof FilterItem) return new ItemRequirement(ItemRequirement.ItemUseType.CONSUME, filter.item());
return new ItemRequirement(ItemRequirement.ItemUseType.CONSUME, filterItem);
return ItemRequirement.NONE; return ItemRequirement.NONE;
} }
@ -202,19 +206,20 @@ public class FilteringBehaviour extends BlockEntityBehaviour implements ValueSet
} }
public ItemStack getFilter() { public ItemStack getFilter() {
return filter.copy(); return filter.item();
} }
public boolean isCountVisible() { public boolean isCountVisible() {
return showCountPredicate.get() && filter.getMaxStackSize() > 1; return showCountPredicate.get() && filter.item()
.getMaxStackSize() > 1;
} }
public boolean test(ItemStack stack) { 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) { public boolean test(FluidStack stack) {
return !isActive() || filter.isEmpty() || FilterItem.test(blockEntity.getLevel(), stack, filter); return !isActive() || filter.test(blockEntity.getLevel(), stack);
} }
@Override @Override
@ -262,7 +267,8 @@ public class FilteringBehaviour extends BlockEntityBehaviour implements ValueSet
} }
public MutableComponent formatValue(ValueSettings value) { 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 Lang.translateDirect("logistics.filter.any_amount_short");
return Components.literal(((value.row() == 0) ? "\u2264" : "=") + Math.max(1, value.value())); 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) stack -> ItemHandlerHelper.canItemStacksStack(stack, getFilter(side)), true)
.isEmpty()) .isEmpty())
player.getInventory() player.getInventory()
.placeItemBackInInventory(getFilter(side)); .placeItemBackInInventory(getFilter(side).copy());
} }
if (toApply.getItem() instanceof FilterItem) if (toApply.getItem() instanceof FilterItem)