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) {
dontPropagate = true;
this.filtering.setFilter(filter);
this.filtering.setFilter(filter.copy());
this.mode.setValue(mode);
dontPropagate = false;
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.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;

View file

@ -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"));
}
}

View file

@ -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;

View file

@ -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))

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.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) {

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.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<ItemStack> 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);
}

View file

@ -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 {

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.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<ItemEntity> 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;
}
}

View file

@ -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);
}
}
}

View file

@ -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");
}

View file

@ -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

View file

@ -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));
}

View file

@ -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);

View file

@ -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<ItemStack> 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)