Perform over Function

- Chutes, (Extracting) Funnels, Smart Observers and Threshold Switches no longer search vault contents unless the vault contents have changed
- Extracting Funnels no longer search their inventories' contents if their target depot or belt is occupied
This commit is contained in:
simibubi 2023-09-21 13:09:03 +02:00
parent 8b5c3a90fb
commit 0510ea3e20
13 changed files with 304 additions and 42 deletions

View File

@ -49,6 +49,7 @@ body:
label: Mod Version label: Mod Version
description: The version of the mod you were using when the bug occured description: The version of the mod you were using when the bug occured
options: options:
- "0.5.1e"
- "0.5.1d" - "0.5.1d"
- "0.5.1c" - "0.5.1c"
- "0.5.1b" - "0.5.1b"

View File

@ -202,6 +202,7 @@ dependencies {
// runtimeOnly fg.deobf("slimeknights.tconstruct:TConstruct:1.16.5-3.1.1.252") // runtimeOnly fg.deobf("slimeknights.tconstruct:TConstruct:1.16.5-3.1.1.252")
// runtimeOnly fg.deobf("maven.modrinth:rubidium:0.5.3") // runtimeOnly fg.deobf("maven.modrinth:rubidium:0.5.3")
// implementation fg.deobf("com.railwayteam.railways:railways-1.18.2-1.1.1:all") { transitive = false } // implementation fg.deobf("com.railwayteam.railways:railways-1.18.2-1.1.1:all") { transitive = false }
// runtimeOnly fg.deobf("maven.modrinth:spark:1.10.38-forge")
// https://discord.com/channels/313125603924639766/725850371834118214/910619168821354497 // https://discord.com/channels/313125603924639766/725850371834118214/910619168821354497
// Prevent Mixin annotation processor from getting into IntelliJ's annotation processor settings // Prevent Mixin annotation processor from getting into IntelliJ's annotation processor settings

View File

@ -95,7 +95,7 @@ public class BeltBlockEntity extends KineticBlockEntity {
public void addBehaviours(List<BlockEntityBehaviour> behaviours) { public void addBehaviours(List<BlockEntityBehaviour> behaviours) {
super.addBehaviours(behaviours); super.addBehaviours(behaviours);
behaviours.add(new DirectBeltInputBehaviour(this).onlyInsertWhen(this::canInsertFrom) behaviours.add(new DirectBeltInputBehaviour(this).onlyInsertWhen(this::canInsertFrom)
.setInsertionHandler(this::tryInsertingFromSide)); .setInsertionHandler(this::tryInsertingFromSide).considerOccupiedWhen(this::isOccupied));
behaviours.add(new TransportedItemStackHandlerBehaviour(this, this::applyToAllItems) behaviours.add(new TransportedItemStackHandlerBehaviour(this, this::applyToAllItems)
.withStackPlacement(this::getWorldPositionOf)); .withStackPlacement(this::getWorldPositionOf));
} }
@ -465,6 +465,22 @@ public class BeltBlockEntity extends KineticBlockEntity {
return getMovementFacing() != side.getOpposite(); return getMovementFacing() != side.getOpposite();
} }
private boolean isOccupied(Direction side) {
BeltBlockEntity nextBeltController = getControllerBE();
if (nextBeltController == null)
return true;
BeltInventory nextInventory = nextBeltController.getInventory();
if (nextInventory == null)
return true;
if (getSpeed() == 0)
return true;
if (getMovementFacing() == side.getOpposite())
return true;
if (!nextInventory.canInsertAtFromSide(index, side))
return true;
return false;
}
private ItemStack tryInsertingFromSide(TransportedItemStack transportedStack, Direction side, boolean simulate) { private ItemStack tryInsertingFromSide(TransportedItemStack transportedStack, Direction side, boolean simulate) {
BeltBlockEntity nextBeltController = getControllerBE(); BeltBlockEntity nextBeltController = getControllerBE();
ItemStack inserted = transportedStack.stack; ItemStack inserted = transportedStack.stack;
@ -493,11 +509,7 @@ public class BeltBlockEntity extends KineticBlockEntity {
} }
} }
if (getSpeed() == 0) if (isOccupied(side))
return inserted;
if (getMovementFacing() == side.getOpposite())
return inserted;
if (!nextInventory.canInsertAtFromSide(index, side))
return inserted; return inserted;
if (simulate) if (simulate)
return empty; return empty;

View File

@ -33,6 +33,7 @@ public class DirectBeltInputBehaviour extends BlockEntityBehaviour {
public static final BehaviourType<DirectBeltInputBehaviour> TYPE = new BehaviourType<>(); public static final BehaviourType<DirectBeltInputBehaviour> TYPE = new BehaviourType<>();
private InsertionCallback tryInsert; private InsertionCallback tryInsert;
private OccupiedPredicate isOccupied;
private AvailabilityPredicate canInsert; private AvailabilityPredicate canInsert;
private Supplier<Boolean> supportsBeltFunnels; private Supplier<Boolean> supportsBeltFunnels;
@ -40,6 +41,7 @@ public class DirectBeltInputBehaviour extends BlockEntityBehaviour {
super(be); super(be);
tryInsert = this::defaultInsertionCallback; tryInsert = this::defaultInsertionCallback;
canInsert = d -> true; canInsert = d -> true;
isOccupied = d -> false;
supportsBeltFunnels = () -> false; supportsBeltFunnels = () -> false;
} }
@ -58,6 +60,11 @@ public class DirectBeltInputBehaviour extends BlockEntityBehaviour {
return this; return this;
} }
public DirectBeltInputBehaviour considerOccupiedWhen(OccupiedPredicate pred) {
isOccupied = pred;
return this;
}
public DirectBeltInputBehaviour setInsertionHandler(InsertionCallback callback) { public DirectBeltInputBehaviour setInsertionHandler(InsertionCallback callback) {
tryInsert = callback; tryInsert = callback;
return this; return this;
@ -75,6 +82,10 @@ public class DirectBeltInputBehaviour extends BlockEntityBehaviour {
return canInsert.test(side); return canInsert.test(side);
} }
public boolean isOccupied(Direction side) {
return isOccupied.test(side);
}
public ItemStack handleInsertion(ItemStack stack, Direction side, boolean simulate) { public ItemStack handleInsertion(ItemStack stack, Direction side, boolean simulate) {
return handleInsertion(new TransportedItemStack(stack), side, simulate); return handleInsertion(new TransportedItemStack(stack), side, simulate);
} }
@ -93,6 +104,11 @@ public class DirectBeltInputBehaviour extends BlockEntityBehaviour {
public ItemStack apply(TransportedItemStack stack, Direction side, boolean simulate); public ItemStack apply(TransportedItemStack stack, Direction side, boolean simulate);
} }
@FunctionalInterface
public interface OccupiedPredicate {
public boolean test(Direction side);
}
@FunctionalInterface @FunctionalInterface
public interface AvailabilityPredicate { public interface AvailabilityPredicate {
public boolean test(Direction side); public boolean test(Direction side);

View File

@ -20,6 +20,7 @@ import com.simibubi.create.content.logistics.funnel.FunnelBlock;
import com.simibubi.create.foundation.advancement.AllAdvancements; import com.simibubi.create.foundation.advancement.AllAdvancements;
import com.simibubi.create.foundation.blockEntity.SmartBlockEntity; import com.simibubi.create.foundation.blockEntity.SmartBlockEntity;
import com.simibubi.create.foundation.blockEntity.behaviour.BlockEntityBehaviour; import com.simibubi.create.foundation.blockEntity.behaviour.BlockEntityBehaviour;
import com.simibubi.create.foundation.blockEntity.behaviour.inventory.VersionedInventoryTrackerBehaviour;
import com.simibubi.create.foundation.item.ItemHelper; import com.simibubi.create.foundation.item.ItemHelper;
import com.simibubi.create.foundation.item.ItemHelper.ExtractionCountMode; import com.simibubi.create.foundation.item.ItemHelper.ExtractionCountMode;
import com.simibubi.create.foundation.particle.AirParticleData; import com.simibubi.create.foundation.particle.AirParticleData;
@ -81,6 +82,8 @@ public class ChuteBlockEntity extends SmartBlockEntity implements IHaveGoggleInf
int airCurrentUpdateCooldown; int airCurrentUpdateCooldown;
int entitySearchCooldown; int entitySearchCooldown;
VersionedInventoryTrackerBehaviour invVersionTracker;
LazyOptional<IItemHandler> capAbove; LazyOptional<IItemHandler> capAbove;
LazyOptional<IItemHandler> capBelow; LazyOptional<IItemHandler> capBelow;
@ -101,6 +104,7 @@ public class ChuteBlockEntity extends SmartBlockEntity implements IHaveGoggleInf
@Override @Override
public void addBehaviours(List<BlockEntityBehaviour> behaviours) { public void addBehaviours(List<BlockEntityBehaviour> behaviours) {
behaviours.add(new DirectBeltInputBehaviour(this).onlyInsertWhen((d) -> canDirectlyInsertCached())); behaviours.add(new DirectBeltInputBehaviour(this).onlyInsertWhen((d) -> canDirectlyInsertCached()));
behaviours.add(invVersionTracker = new VersionedInventoryTrackerBehaviour(this));
registerAwardables(behaviours, AllAdvancements.CHUTE); registerAwardables(behaviours, AllAdvancements.CHUTE);
} }
@ -336,16 +340,21 @@ public class ChuteBlockEntity extends SmartBlockEntity implements IHaveGoggleInf
private void handleInput(IItemHandler inv, float startLocation) { private void handleInput(IItemHandler inv, float startLocation) {
if (inv == null) if (inv == null)
return; return;
if (invVersionTracker.stillWaiting(inv))
return;
Predicate<ItemStack> canAccept = this::canAcceptItem; Predicate<ItemStack> canAccept = this::canAcceptItem;
int count = getExtractionAmount(); int count = getExtractionAmount();
ExtractionCountMode mode = getExtractionMode(); ExtractionCountMode mode = getExtractionMode();
if (mode == ExtractionCountMode.UPTO || !ItemHelper.extract(inv, canAccept, mode, count, true) if (mode == ExtractionCountMode.UPTO || !ItemHelper.extract(inv, canAccept, mode, count, true)
.isEmpty()) { .isEmpty()) {
ItemStack extracted = ItemHelper.extract(inv, canAccept, mode, count, false); ItemStack extracted = ItemHelper.extract(inv, canAccept, mode, count, false);
if (!extracted.isEmpty()) if (!extracted.isEmpty()) {
setItem(extracted, startLocation); setItem(extracted, startLocation);
return;
} }
} }
invVersionTracker.awaitNewVersion(inv);
}
private boolean handleDownwardOutput(boolean simulate) { private boolean handleDownwardOutput(boolean simulate) {
BlockState blockState = getBlockState(); BlockState blockState = getBlockState();
@ -359,12 +368,16 @@ public class ChuteBlockEntity extends SmartBlockEntity implements IHaveGoggleInf
if (capBelow.isPresent()) { if (capBelow.isPresent()) {
if (level.isClientSide && !isVirtual()) if (level.isClientSide && !isVirtual())
return false; return false;
ItemStack remainder = ItemHandlerHelper.insertItemStacked(capBelow.orElse(null), item, simulate); IItemHandler inv = capBelow.orElse(null);
if (invVersionTracker.stillWaiting(inv))
return false;
ItemStack remainder = ItemHandlerHelper.insertItemStacked(inv, item, simulate);
ItemStack held = getItem(); ItemStack held = getItem();
if (!simulate) if (!simulate)
setItem(remainder, itemPosition.getValue(0)); setItem(remainder, itemPosition.getValue(0));
if (remainder.getCount() != held.getCount()) if (remainder.getCount() != held.getCount())
return true; return true;
invVersionTracker.awaitNewVersion(inv);
if (direction == Direction.DOWN) if (direction == Direction.DOWN)
return false; return false;
} }
@ -414,10 +427,16 @@ public class ChuteBlockEntity extends SmartBlockEntity implements IHaveGoggleInf
if (level.isClientSide && !isVirtual() && !ChuteBlock.isChute(stateAbove)) if (level.isClientSide && !isVirtual() && !ChuteBlock.isChute(stateAbove))
return false; return false;
int countBefore = item.getCount(); int countBefore = item.getCount();
ItemStack remainder = ItemHandlerHelper.insertItemStacked(capAbove.orElse(null), item, simulate); IItemHandler inv = capAbove.orElse(null);
if (invVersionTracker.stillWaiting(inv))
return false;
ItemStack remainder = ItemHandlerHelper.insertItemStacked(inv, item, simulate);
if (!simulate) if (!simulate)
item = remainder; item = remainder;
return countBefore != remainder.getCount(); if (countBefore != remainder.getCount())
return true;
invVersionTracker.awaitNewVersion(inv);
return false;
} }
} }
@ -502,6 +521,7 @@ public class ChuteBlockEntity extends SmartBlockEntity implements IHaveGoggleInf
public void setItem(ItemStack stack, float insertionPos) { public void setItem(ItemStack stack, float insertionPos) {
item = stack; item = stack;
itemPosition.startWithValue(insertionPos); itemPosition.startWithValue(insertionPos);
invVersionTracker.reset();
if (!level.isClientSide) { if (!level.isClientSide) {
notifyUpdate(); notifyUpdate();
award(AllAdvancements.CHUTE); award(AllAdvancements.CHUTE);

View File

@ -51,7 +51,8 @@ public class SmartChuteBlockEntity extends ChuteBlockEntity {
@Override @Override
public void addBehaviours(List<BlockEntityBehaviour> behaviours) { public void addBehaviours(List<BlockEntityBehaviour> behaviours) {
behaviours.add(filtering = behaviours.add(filtering =
new FilteringBehaviour(this, new SmartChuteFilterSlotPositioning()).showCountWhen(this::isExtracting)); new FilteringBehaviour(this, new SmartChuteFilterSlotPositioning()).showCountWhen(this::isExtracting)
.withCallback($ -> invVersionTracker.reset()));
super.addBehaviours(behaviours); super.addBehaviours(behaviours);
} }

View File

@ -240,7 +240,7 @@ public class DepotBehaviour extends BlockEntityBehaviour {
public void addSubBehaviours(List<BlockEntityBehaviour> behaviours) { public void addSubBehaviours(List<BlockEntityBehaviour> behaviours) {
behaviours.add(new DirectBeltInputBehaviour(blockEntity).allowingBeltFunnels() behaviours.add(new DirectBeltInputBehaviour(blockEntity).allowingBeltFunnels()
.setInsertionHandler(this::tryInsertingFromSide)); .setInsertionHandler(this::tryInsertingFromSide).considerOccupiedWhen(this::isOccupied));
transportedHandler = new TransportedItemStackHandlerBehaviour(blockEntity, this::applyToAllItems) transportedHandler = new TransportedItemStackHandlerBehaviour(blockEntity, this::applyToAllItems)
.withStackPlacement(this::getWorldPositionOf); .withStackPlacement(this::getWorldPositionOf);
behaviours.add(transportedHandler); behaviours.add(transportedHandler);
@ -339,14 +339,20 @@ public class DepotBehaviour extends BlockEntityBehaviour {
return lazyItemHandler.cast(); return lazyItemHandler.cast();
} }
private boolean isOccupied(Direction side) {
if (!getHeldItemStack().isEmpty() && !canMergeItems())
return true;
if (!isOutputEmpty() && !canMergeItems())
return true;
if (!canAcceptItems.get())
return true;
return false;
}
private ItemStack tryInsertingFromSide(TransportedItemStack transportedStack, Direction side, boolean simulate) { private ItemStack tryInsertingFromSide(TransportedItemStack transportedStack, Direction side, boolean simulate) {
ItemStack inserted = transportedStack.stack; ItemStack inserted = transportedStack.stack;
if (!getHeldItemStack().isEmpty() && !canMergeItems()) if (isOccupied(side))
return inserted;
if (!isOutputEmpty() && !canMergeItems())
return inserted;
if (!canAcceptItems.get())
return inserted; return inserted;
int size = transportedStack.stack.getCount(); int size = transportedStack.stack.getCount();

View File

@ -3,6 +3,8 @@ package com.simibubi.create.content.logistics.funnel;
import java.lang.ref.WeakReference; import java.lang.ref.WeakReference;
import java.util.List; import java.util.List;
import org.apache.commons.lang3.mutable.MutableBoolean;
import com.jozufozu.flywheel.backend.instancing.InstancedRenderDispatcher; import com.jozufozu.flywheel.backend.instancing.InstancedRenderDispatcher;
import com.simibubi.create.AllBlocks; import com.simibubi.create.AllBlocks;
import com.simibubi.create.AllPackets; import com.simibubi.create.AllPackets;
@ -18,6 +20,7 @@ import com.simibubi.create.foundation.blockEntity.SmartBlockEntity;
import com.simibubi.create.foundation.blockEntity.behaviour.BlockEntityBehaviour; import com.simibubi.create.foundation.blockEntity.behaviour.BlockEntityBehaviour;
import com.simibubi.create.foundation.blockEntity.behaviour.filtering.FilteringBehaviour; import com.simibubi.create.foundation.blockEntity.behaviour.filtering.FilteringBehaviour;
import com.simibubi.create.foundation.blockEntity.behaviour.inventory.InvManipulationBehaviour; import com.simibubi.create.foundation.blockEntity.behaviour.inventory.InvManipulationBehaviour;
import com.simibubi.create.foundation.blockEntity.behaviour.inventory.VersionedInventoryTrackerBehaviour;
import com.simibubi.create.foundation.item.ItemHelper.ExtractionCountMode; import com.simibubi.create.foundation.item.ItemHelper.ExtractionCountMode;
import com.simibubi.create.foundation.utility.BlockFace; import com.simibubi.create.foundation.utility.BlockFace;
import com.simibubi.create.foundation.utility.VecHelper; import com.simibubi.create.foundation.utility.VecHelper;
@ -42,6 +45,7 @@ public class FunnelBlockEntity extends SmartBlockEntity implements IHaveHovering
private FilteringBehaviour filtering; private FilteringBehaviour filtering;
private InvManipulationBehaviour invManipulation; private InvManipulationBehaviour invManipulation;
private VersionedInventoryTrackerBehaviour invVersionTracker;
private int extractionCooldown; private int extractionCooldown;
private WeakReference<ItemEntity> lastObserved; // In-world Extractors only private WeakReference<ItemEntity> lastObserved; // In-world Extractors only
@ -111,6 +115,9 @@ public class FunnelBlockEntity extends SmartBlockEntity implements IHaveHovering
} }
private void activateExtractor() { private void activateExtractor() {
if (invVersionTracker.stillWaiting(invManipulation))
return;
BlockState blockState = getBlockState(); BlockState blockState = getBlockState();
Direction facing = AbstractFunnelBlock.getFunnelFacing(blockState); Direction facing = AbstractFunnelBlock.getFunnelFacing(blockState);
@ -140,8 +147,10 @@ public class FunnelBlockEntity extends SmartBlockEntity implements IHaveHovering
ExtractionCountMode mode = getModeToExtract(); ExtractionCountMode mode = getModeToExtract();
ItemStack stack = invManipulation.simulate() ItemStack stack = invManipulation.simulate()
.extract(mode, amountToExtract); .extract(mode, amountToExtract);
if (stack.isEmpty()) if (stack.isEmpty()) {
invVersionTracker.awaitNewVersion(invManipulation);
return; return;
}
for (ItemEntity itemEntity : level.getEntitiesOfClass(ItemEntity.class, area)) { for (ItemEntity itemEntity : level.getEntitiesOfClass(ItemEntity.class, area)) {
lastObserved = new WeakReference<>(itemEntity); lastObserved = new WeakReference<>(itemEntity);
return; return;
@ -189,6 +198,9 @@ public class FunnelBlockEntity extends SmartBlockEntity implements IHaveHovering
} }
private void activateExtractingBeltFunnel() { private void activateExtractingBeltFunnel() {
if (invVersionTracker.stillWaiting(invManipulation))
return;
BlockState blockState = getBlockState(); BlockState blockState = getBlockState();
Direction facing = blockState.getValue(BeltFunnelBlock.HORIZONTAL_FACING); Direction facing = blockState.getValue(BeltFunnelBlock.HORIZONTAL_FACING);
DirectBeltInputBehaviour inputBehaviour = DirectBeltInputBehaviour inputBehaviour =
@ -198,14 +210,24 @@ public class FunnelBlockEntity extends SmartBlockEntity implements IHaveHovering
return; return;
if (!inputBehaviour.canInsertFromSide(facing)) if (!inputBehaviour.canInsertFromSide(facing))
return; return;
if (inputBehaviour.isOccupied(facing))
return;
int amountToExtract = getAmountToExtract(); int amountToExtract = getAmountToExtract();
ExtractionCountMode mode = getModeToExtract(); ExtractionCountMode mode = getModeToExtract();
ItemStack stack = MutableBoolean deniedByInsertion = new MutableBoolean(false);
invManipulation.extract(mode, amountToExtract, s -> inputBehaviour.handleInsertion(s, facing, true) ItemStack stack = invManipulation.extract(mode, amountToExtract, s -> {
.isEmpty()); ItemStack handleInsertion = inputBehaviour.handleInsertion(s, facing, true);
if (stack.isEmpty()) if (handleInsertion.isEmpty())
return true;
deniedByInsertion.setTrue();
return false;
});
if (stack.isEmpty()) {
if (deniedByInsertion.isFalse())
invVersionTracker.awaitNewVersion(invManipulation.getInventory());
return; return;
}
flap(false); flap(false);
onTransfer(stack); onTransfer(stack);
inputBehaviour.handleInsertion(stack, facing, false); inputBehaviour.handleInsertion(stack, facing, false);
@ -238,9 +260,12 @@ public class FunnelBlockEntity extends SmartBlockEntity implements IHaveHovering
.getOpposite())); .getOpposite()));
behaviours.add(invManipulation); behaviours.add(invManipulation);
behaviours.add(invVersionTracker = new VersionedInventoryTrackerBehaviour(this));
filtering = new FilteringBehaviour(this, new FunnelFilterSlotPositioning()); filtering = new FilteringBehaviour(this, new FunnelFilterSlotPositioning());
filtering.showCountWhen(this::supportsAmountOnFilter); filtering.showCountWhen(this::supportsAmountOnFilter);
filtering.onlyActiveWhen(this::supportsFiltering); filtering.onlyActiveWhen(this::supportsFiltering);
filtering.withCallback($ -> invVersionTracker.reset());
behaviours.add(filtering); behaviours.add(filtering);
behaviours.add(new DirectBeltInputBehaviour(this).onlyInsertWhen(this::supportsDirectBeltInput) behaviours.add(new DirectBeltInputBehaviour(this).onlyInsertWhen(this::supportsDirectBeltInput)

View File

@ -7,6 +7,7 @@ import com.simibubi.create.api.connectivity.ConnectivityHandler;
import com.simibubi.create.foundation.blockEntity.IMultiBlockEntityContainer; import com.simibubi.create.foundation.blockEntity.IMultiBlockEntityContainer;
import com.simibubi.create.foundation.blockEntity.SmartBlockEntity; import com.simibubi.create.foundation.blockEntity.SmartBlockEntity;
import com.simibubi.create.foundation.blockEntity.behaviour.BlockEntityBehaviour; import com.simibubi.create.foundation.blockEntity.behaviour.BlockEntityBehaviour;
import com.simibubi.create.foundation.blockEntity.behaviour.inventory.VersionedInventoryWrapper;
import com.simibubi.create.infrastructure.config.AllConfigs; import com.simibubi.create.infrastructure.config.AllConfigs;
import net.minecraft.core.BlockPos; import net.minecraft.core.BlockPos;
@ -260,8 +261,8 @@ public class ItemVaultBlockEntity extends SmartBlockEntity implements IMultiBloc
} }
} }
CombinedInvWrapper combinedInvWrapper = new CombinedInvWrapper(invs); IItemHandler itemHandler = new VersionedInventoryWrapper(new CombinedInvWrapper(invs));
itemCapability = LazyOptional.of(() -> combinedInvWrapper); itemCapability = LazyOptional.of(() -> itemHandler);
} }
public static int getMaxLength(int radius) { public static int getMaxLength(int radius) {

View File

@ -14,6 +14,7 @@ import com.simibubi.create.foundation.blockEntity.behaviour.filtering.FilteringB
import com.simibubi.create.foundation.blockEntity.behaviour.inventory.CapManipulationBehaviourBase.InterfaceProvider; import com.simibubi.create.foundation.blockEntity.behaviour.inventory.CapManipulationBehaviourBase.InterfaceProvider;
import com.simibubi.create.foundation.blockEntity.behaviour.inventory.InvManipulationBehaviour; import com.simibubi.create.foundation.blockEntity.behaviour.inventory.InvManipulationBehaviour;
import com.simibubi.create.foundation.blockEntity.behaviour.inventory.TankManipulationBehaviour; import com.simibubi.create.foundation.blockEntity.behaviour.inventory.TankManipulationBehaviour;
import com.simibubi.create.foundation.blockEntity.behaviour.inventory.VersionedInventoryTrackerBehaviour;
import com.simibubi.create.foundation.utility.BlockFace; import com.simibubi.create.foundation.utility.BlockFace;
import com.simibubi.create.foundation.utility.Iterate; import com.simibubi.create.foundation.utility.Iterate;
@ -31,6 +32,10 @@ public class SmartObserverBlockEntity extends SmartBlockEntity {
private FilteringBehaviour filtering; private FilteringBehaviour filtering;
private InvManipulationBehaviour observedInventory; private InvManipulationBehaviour observedInventory;
private TankManipulationBehaviour observedTank; private TankManipulationBehaviour observedTank;
private VersionedInventoryTrackerBehaviour invVersionTracker;
private boolean sustainSignal;
public int turnOffTicks = 0; public int turnOffTicks = 0;
public SmartObserverBlockEntity(BlockEntityType<?> type, BlockPos pos, BlockState state) { public SmartObserverBlockEntity(BlockEntityType<?> type, BlockPos pos, BlockState state) {
@ -40,7 +45,9 @@ public class SmartObserverBlockEntity extends SmartBlockEntity {
@Override @Override
public void addBehaviours(List<BlockEntityBehaviour> behaviours) { public void addBehaviours(List<BlockEntityBehaviour> behaviours) {
behaviours.add(filtering = new FilteringBehaviour(this, new FilteredDetectorFilterSlot(false))); behaviours.add(filtering = new FilteringBehaviour(this, new FilteredDetectorFilterSlot(false))
.withCallback($ -> invVersionTracker.reset()));
behaviours.add(invVersionTracker = new VersionedInventoryTrackerBehaviour(this));
InterfaceProvider towardBlockFacing = InterfaceProvider towardBlockFacing =
(w, p, s) -> new BlockFace(p, DirectedDirectionalBlock.getTargetDirection(s)); (w, p, s) -> new BlockFace(p, DirectedDirectionalBlock.getTargetDirection(s));
@ -105,12 +112,24 @@ public class SmartObserverBlockEntity extends SmartBlockEntity {
return; return;
} }
if (observedInventory.hasInventory()) {
boolean skipInv = invVersionTracker.stillWaiting(observedInventory);
invVersionTracker.awaitNewVersion(observedInventory);
if (skipInv && sustainSignal)
turnOffTicks = DEFAULT_DELAY;
if (!skipInv) {
sustainSignal = false;
if (!observedInventory.simulate() if (!observedInventory.simulate()
.extract() .extract()
.isEmpty()) { .isEmpty()) {
sustainSignal = true;
activate(); activate();
return; return;
} }
}
}
if (!observedTank.simulate() if (!observedTank.simulate()
.extractAny() .extractAny()

View File

@ -12,6 +12,7 @@ import com.simibubi.create.foundation.blockEntity.behaviour.filtering.FilteringB
import com.simibubi.create.foundation.blockEntity.behaviour.inventory.CapManipulationBehaviourBase.InterfaceProvider; import com.simibubi.create.foundation.blockEntity.behaviour.inventory.CapManipulationBehaviourBase.InterfaceProvider;
import com.simibubi.create.foundation.blockEntity.behaviour.inventory.InvManipulationBehaviour; import com.simibubi.create.foundation.blockEntity.behaviour.inventory.InvManipulationBehaviour;
import com.simibubi.create.foundation.blockEntity.behaviour.inventory.TankManipulationBehaviour; import com.simibubi.create.foundation.blockEntity.behaviour.inventory.TankManipulationBehaviour;
import com.simibubi.create.foundation.blockEntity.behaviour.inventory.VersionedInventoryTrackerBehaviour;
import com.simibubi.create.foundation.utility.BlockFace; import com.simibubi.create.foundation.utility.BlockFace;
import net.minecraft.core.BlockPos; import net.minecraft.core.BlockPos;
@ -39,6 +40,7 @@ public class ThresholdSwitchBlockEntity extends SmartBlockEntity {
private FilteringBehaviour filtering; private FilteringBehaviour filtering;
private InvManipulationBehaviour observedInventory; private InvManipulationBehaviour observedInventory;
private TankManipulationBehaviour observedTank; private TankManipulationBehaviour observedTank;
private VersionedInventoryTrackerBehaviour invVersionTracker;
public ThresholdSwitchBlockEntity(BlockEntityType<?> type, BlockPos pos, BlockState state) { public ThresholdSwitchBlockEntity(BlockEntityType<?> type, BlockPos pos, BlockState state) {
super(type, pos, state); super(type, pos, state);
@ -107,8 +109,15 @@ public class ThresholdSwitchBlockEntity extends SmartBlockEntity {
} else if (observedInventory.hasInventory() || observedTank.hasInventory()) { } else if (observedInventory.hasInventory() || observedTank.hasInventory()) {
if (observedInventory.hasInventory()) { if (observedInventory.hasInventory()) {
// Item inventory // Item inventory
IItemHandler inv = observedInventory.getInventory(); IItemHandler inv = observedInventory.getInventory();
if (invVersionTracker.stillWaiting(inv)) {
occupied = prevLevel;
totalSpace = 1f;
} else {
invVersionTracker.awaitNewVersion(inv);
for (int slot = 0; slot < inv.getSlots(); slot++) { for (int slot = 0; slot < inv.getSlots(); slot++) {
ItemStack stackInSlot = inv.getStackInSlot(slot); ItemStack stackInSlot = inv.getStackInSlot(slot);
int space = Math.min(stackInSlot.getMaxStackSize(), inv.getSlotLimit(slot)); int space = Math.min(stackInSlot.getMaxStackSize(), inv.getSlotLimit(slot));
@ -121,6 +130,7 @@ public class ThresholdSwitchBlockEntity extends SmartBlockEntity {
occupied += count * (1f / space); occupied += count * (1f / space);
} }
} }
}
if (observedTank.hasInventory()) { if (observedTank.hasInventory()) {
// Fluid inventory // Fluid inventory
@ -195,7 +205,12 @@ public class ThresholdSwitchBlockEntity extends SmartBlockEntity {
@Override @Override
public void addBehaviours(List<BlockEntityBehaviour> behaviours) { public void addBehaviours(List<BlockEntityBehaviour> behaviours) {
behaviours.add(filtering = new FilteringBehaviour(this, new FilteredDetectorFilterSlot(true)) behaviours.add(filtering = new FilteringBehaviour(this, new FilteredDetectorFilterSlot(true))
.withCallback($ -> this.updateCurrentLevel())); .withCallback($ -> {
this.updateCurrentLevel();
invVersionTracker.reset();
}));
behaviours.add(invVersionTracker = new VersionedInventoryTrackerBehaviour(this));
InterfaceProvider towardBlockFacing = InterfaceProvider towardBlockFacing =
(w, p, s) -> new BlockFace(p, DirectedDirectionalBlock.getTargetDirection(s)); (w, p, s) -> new BlockFace(p, DirectedDirectionalBlock.getTargetDirection(s));

View File

@ -0,0 +1,53 @@
package com.simibubi.create.foundation.blockEntity.behaviour.inventory;
import com.simibubi.create.foundation.blockEntity.SmartBlockEntity;
import com.simibubi.create.foundation.blockEntity.behaviour.BehaviourType;
import com.simibubi.create.foundation.blockEntity.behaviour.BlockEntityBehaviour;
import net.minecraftforge.items.IItemHandler;
public class VersionedInventoryTrackerBehaviour extends BlockEntityBehaviour {
public static final BehaviourType<VersionedInventoryTrackerBehaviour> TYPE = new BehaviourType<>();
private int ignoredId;
private int ignoredVersion;
public VersionedInventoryTrackerBehaviour(SmartBlockEntity be) {
super(be);
reset();
}
public boolean stillWaiting(InvManipulationBehaviour behaviour) {
return behaviour.hasInventory() && stillWaiting(behaviour.getInventory());
}
public boolean stillWaiting(IItemHandler handler) {
if (handler instanceof VersionedInventoryWrapper viw)
return viw.getId() == ignoredId && viw.getVersion() == ignoredVersion;
return false;
}
public void awaitNewVersion(InvManipulationBehaviour behaviour) {
if (behaviour.hasInventory())
awaitNewVersion(behaviour.getInventory());
}
public void awaitNewVersion(IItemHandler handler) {
if (handler instanceof VersionedInventoryWrapper viw) {
ignoredId = viw.getId();
ignoredVersion = viw.getVersion();
}
}
public void reset() {
ignoredVersion = -1;
ignoredId = -1;
}
@Override
public BehaviourType<?> getType() {
return TYPE;
}
}

View File

@ -0,0 +1,92 @@
package com.simibubi.create.foundation.blockEntity.behaviour.inventory;
import java.util.concurrent.atomic.AtomicInteger;
import net.minecraft.world.item.ItemStack;
import net.minecraftforge.items.IItemHandlerModifiable;
import net.minecraftforge.items.ItemHandlerHelper;
public class VersionedInventoryWrapper implements IItemHandlerModifiable {
public static final AtomicInteger idGenerator = new AtomicInteger();
private IItemHandlerModifiable inventory;
private int version;
private int id;
public VersionedInventoryWrapper(IItemHandlerModifiable inventory) {
this.id = idGenerator.getAndIncrement();
this.inventory = inventory;
this.version = 0;
}
public void incrementVersion() {
version++;
}
public int getVersion() {
return version;
}
public int getId() {
return id;
}
//
@Override
public int getSlots() {
return inventory.getSlots();
}
@Override
public int getSlotLimit(int slot) {
return inventory.getSlotLimit(slot);
}
@Override
public boolean isItemValid(int slot, ItemStack stack) {
return inventory.isItemValid(slot, stack);
}
@Override
public ItemStack getStackInSlot(int slot) {
return inventory.getStackInSlot(slot);
}
//
@Override
public ItemStack insertItem(int slot, ItemStack stack, boolean simulate) {
int count = stack.getCount();
ItemStack result = inventory.insertItem(slot, stack, simulate);
if (!simulate && count != result.getCount())
incrementVersion();
return result;
}
@Override
public ItemStack extractItem(int slot, int amount, boolean simulate) {
ItemStack result = inventory.extractItem(slot, amount, simulate);
if (!simulate && !result.isEmpty())
incrementVersion();
return result;
}
@Override
public void setStackInSlot(int slot, ItemStack stack) {
ItemStack previousItem = inventory.getStackInSlot(slot);
inventory.setStackInSlot(slot, stack);
if (stack.isEmpty() == previousItem.isEmpty()) {
if (stack.isEmpty())
return;
if (ItemHandlerHelper.canItemStacksStack(stack, previousItem)
&& stack.getCount() == previousItem.getCount())
return;
}
incrementVersion();
}
}