diff --git a/.github/ISSUE_TEMPLATE/bug_report.yml b/.github/ISSUE_TEMPLATE/bug_report.yml index 06ce14418..35f7d4221 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.yml +++ b/.github/ISSUE_TEMPLATE/bug_report.yml @@ -49,6 +49,7 @@ body: label: Mod Version description: The version of the mod you were using when the bug occured options: + - "0.5.1e" - "0.5.1d" - "0.5.1c" - "0.5.1b" diff --git a/build.gradle b/build.gradle index dd2b1d6c3..0c42b7c1f 100644 --- a/build.gradle +++ b/build.gradle @@ -202,6 +202,7 @@ dependencies { // runtimeOnly fg.deobf("slimeknights.tconstruct:TConstruct:1.16.5-3.1.1.252") // 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 } + // runtimeOnly fg.deobf("maven.modrinth:spark:1.10.38-forge") // https://discord.com/channels/313125603924639766/725850371834118214/910619168821354497 // Prevent Mixin annotation processor from getting into IntelliJ's annotation processor settings diff --git a/src/main/java/com/simibubi/create/content/kinetics/belt/BeltBlockEntity.java b/src/main/java/com/simibubi/create/content/kinetics/belt/BeltBlockEntity.java index 7f94a9a3c..e8e33eb82 100644 --- a/src/main/java/com/simibubi/create/content/kinetics/belt/BeltBlockEntity.java +++ b/src/main/java/com/simibubi/create/content/kinetics/belt/BeltBlockEntity.java @@ -95,7 +95,7 @@ public class BeltBlockEntity extends KineticBlockEntity { public void addBehaviours(List behaviours) { super.addBehaviours(behaviours); behaviours.add(new DirectBeltInputBehaviour(this).onlyInsertWhen(this::canInsertFrom) - .setInsertionHandler(this::tryInsertingFromSide)); + .setInsertionHandler(this::tryInsertingFromSide).considerOccupiedWhen(this::isOccupied)); behaviours.add(new TransportedItemStackHandlerBehaviour(this, this::applyToAllItems) .withStackPlacement(this::getWorldPositionOf)); } @@ -464,6 +464,22 @@ public class BeltBlockEntity extends KineticBlockEntity { return false; 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) { BeltBlockEntity nextBeltController = getControllerBE(); @@ -493,11 +509,7 @@ public class BeltBlockEntity extends KineticBlockEntity { } } - if (getSpeed() == 0) - return inserted; - if (getMovementFacing() == side.getOpposite()) - return inserted; - if (!nextInventory.canInsertAtFromSide(index, side)) + if (isOccupied(side)) return inserted; if (simulate) return empty; diff --git a/src/main/java/com/simibubi/create/content/kinetics/belt/behaviour/DirectBeltInputBehaviour.java b/src/main/java/com/simibubi/create/content/kinetics/belt/behaviour/DirectBeltInputBehaviour.java index f48f69cf0..8943ecb2f 100644 --- a/src/main/java/com/simibubi/create/content/kinetics/belt/behaviour/DirectBeltInputBehaviour.java +++ b/src/main/java/com/simibubi/create/content/kinetics/belt/behaviour/DirectBeltInputBehaviour.java @@ -33,6 +33,7 @@ public class DirectBeltInputBehaviour extends BlockEntityBehaviour { public static final BehaviourType TYPE = new BehaviourType<>(); private InsertionCallback tryInsert; + private OccupiedPredicate isOccupied; private AvailabilityPredicate canInsert; private Supplier supportsBeltFunnels; @@ -40,6 +41,7 @@ public class DirectBeltInputBehaviour extends BlockEntityBehaviour { super(be); tryInsert = this::defaultInsertionCallback; canInsert = d -> true; + isOccupied = d -> false; supportsBeltFunnels = () -> false; } @@ -57,6 +59,11 @@ public class DirectBeltInputBehaviour extends BlockEntityBehaviour { canInsert = pred; return this; } + + public DirectBeltInputBehaviour considerOccupiedWhen(OccupiedPredicate pred) { + isOccupied = pred; + return this; + } public DirectBeltInputBehaviour setInsertionHandler(InsertionCallback callback) { tryInsert = callback; @@ -75,6 +82,10 @@ public class DirectBeltInputBehaviour extends BlockEntityBehaviour { return canInsert.test(side); } + public boolean isOccupied(Direction side) { + return isOccupied.test(side); + } + public ItemStack handleInsertion(ItemStack stack, Direction side, boolean 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); } + @FunctionalInterface + public interface OccupiedPredicate { + public boolean test(Direction side); + } + @FunctionalInterface public interface AvailabilityPredicate { public boolean test(Direction side); diff --git a/src/main/java/com/simibubi/create/content/logistics/chute/ChuteBlockEntity.java b/src/main/java/com/simibubi/create/content/logistics/chute/ChuteBlockEntity.java index 0a1a4fd5f..673308384 100644 --- a/src/main/java/com/simibubi/create/content/logistics/chute/ChuteBlockEntity.java +++ b/src/main/java/com/simibubi/create/content/logistics/chute/ChuteBlockEntity.java @@ -20,6 +20,7 @@ import com.simibubi.create.content.logistics.funnel.FunnelBlock; import com.simibubi.create.foundation.advancement.AllAdvancements; import com.simibubi.create.foundation.blockEntity.SmartBlockEntity; 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.ExtractionCountMode; import com.simibubi.create.foundation.particle.AirParticleData; @@ -81,6 +82,8 @@ public class ChuteBlockEntity extends SmartBlockEntity implements IHaveGoggleInf int airCurrentUpdateCooldown; int entitySearchCooldown; + VersionedInventoryTrackerBehaviour invVersionTracker; + LazyOptional capAbove; LazyOptional capBelow; @@ -101,6 +104,7 @@ public class ChuteBlockEntity extends SmartBlockEntity implements IHaveGoggleInf @Override public void addBehaviours(List behaviours) { behaviours.add(new DirectBeltInputBehaviour(this).onlyInsertWhen((d) -> canDirectlyInsertCached())); + behaviours.add(invVersionTracker = new VersionedInventoryTrackerBehaviour(this)); registerAwardables(behaviours, AllAdvancements.CHUTE); } @@ -336,15 +340,20 @@ public class ChuteBlockEntity extends SmartBlockEntity implements IHaveGoggleInf private void handleInput(IItemHandler inv, float startLocation) { if (inv == null) return; + if (invVersionTracker.stillWaiting(inv)) + return; Predicate canAccept = this::canAcceptItem; int count = getExtractionAmount(); ExtractionCountMode mode = getExtractionMode(); if (mode == ExtractionCountMode.UPTO || !ItemHelper.extract(inv, canAccept, mode, count, true) .isEmpty()) { ItemStack extracted = ItemHelper.extract(inv, canAccept, mode, count, false); - if (!extracted.isEmpty()) + if (!extracted.isEmpty()) { setItem(extracted, startLocation); + return; + } } + invVersionTracker.awaitNewVersion(inv); } private boolean handleDownwardOutput(boolean simulate) { @@ -359,12 +368,16 @@ public class ChuteBlockEntity extends SmartBlockEntity implements IHaveGoggleInf if (capBelow.isPresent()) { if (level.isClientSide && !isVirtual()) 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(); if (!simulate) setItem(remainder, itemPosition.getValue(0)); if (remainder.getCount() != held.getCount()) return true; + invVersionTracker.awaitNewVersion(inv); if (direction == Direction.DOWN) return false; } @@ -414,10 +427,16 @@ public class ChuteBlockEntity extends SmartBlockEntity implements IHaveGoggleInf if (level.isClientSide && !isVirtual() && !ChuteBlock.isChute(stateAbove)) return false; 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) 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) { item = stack; itemPosition.startWithValue(insertionPos); + invVersionTracker.reset(); if (!level.isClientSide) { notifyUpdate(); award(AllAdvancements.CHUTE); diff --git a/src/main/java/com/simibubi/create/content/logistics/chute/SmartChuteBlockEntity.java b/src/main/java/com/simibubi/create/content/logistics/chute/SmartChuteBlockEntity.java index 0ac591938..14fbec7ad 100644 --- a/src/main/java/com/simibubi/create/content/logistics/chute/SmartChuteBlockEntity.java +++ b/src/main/java/com/simibubi/create/content/logistics/chute/SmartChuteBlockEntity.java @@ -51,7 +51,8 @@ public class SmartChuteBlockEntity extends ChuteBlockEntity { @Override public void addBehaviours(List behaviours) { 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); } diff --git a/src/main/java/com/simibubi/create/content/logistics/depot/DepotBehaviour.java b/src/main/java/com/simibubi/create/content/logistics/depot/DepotBehaviour.java index 97c9bd475..8d0dc3dd4 100644 --- a/src/main/java/com/simibubi/create/content/logistics/depot/DepotBehaviour.java +++ b/src/main/java/com/simibubi/create/content/logistics/depot/DepotBehaviour.java @@ -240,7 +240,7 @@ public class DepotBehaviour extends BlockEntityBehaviour { public void addSubBehaviours(List behaviours) { behaviours.add(new DirectBeltInputBehaviour(blockEntity).allowingBeltFunnels() - .setInsertionHandler(this::tryInsertingFromSide)); + .setInsertionHandler(this::tryInsertingFromSide).considerOccupiedWhen(this::isOccupied)); transportedHandler = new TransportedItemStackHandlerBehaviour(blockEntity, this::applyToAllItems) .withStackPlacement(this::getWorldPositionOf); behaviours.add(transportedHandler); @@ -339,14 +339,20 @@ public class DepotBehaviour extends BlockEntityBehaviour { 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) { ItemStack inserted = transportedStack.stack; - if (!getHeldItemStack().isEmpty() && !canMergeItems()) - return inserted; - if (!isOutputEmpty() && !canMergeItems()) - return inserted; - if (!canAcceptItems.get()) + if (isOccupied(side)) return inserted; int size = transportedStack.stack.getCount(); diff --git a/src/main/java/com/simibubi/create/content/logistics/funnel/FunnelBlockEntity.java b/src/main/java/com/simibubi/create/content/logistics/funnel/FunnelBlockEntity.java index 281168261..00474106b 100644 --- a/src/main/java/com/simibubi/create/content/logistics/funnel/FunnelBlockEntity.java +++ b/src/main/java/com/simibubi/create/content/logistics/funnel/FunnelBlockEntity.java @@ -3,6 +3,8 @@ package com.simibubi.create.content.logistics.funnel; import java.lang.ref.WeakReference; import java.util.List; +import org.apache.commons.lang3.mutable.MutableBoolean; + import com.jozufozu.flywheel.backend.instancing.InstancedRenderDispatcher; import com.simibubi.create.AllBlocks; 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.filtering.FilteringBehaviour; 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.utility.BlockFace; import com.simibubi.create.foundation.utility.VecHelper; @@ -42,6 +45,7 @@ public class FunnelBlockEntity extends SmartBlockEntity implements IHaveHovering private FilteringBehaviour filtering; private InvManipulationBehaviour invManipulation; + private VersionedInventoryTrackerBehaviour invVersionTracker; private int extractionCooldown; private WeakReference lastObserved; // In-world Extractors only @@ -111,6 +115,9 @@ public class FunnelBlockEntity extends SmartBlockEntity implements IHaveHovering } private void activateExtractor() { + if (invVersionTracker.stillWaiting(invManipulation)) + return; + BlockState blockState = getBlockState(); Direction facing = AbstractFunnelBlock.getFunnelFacing(blockState); @@ -140,8 +147,10 @@ public class FunnelBlockEntity extends SmartBlockEntity implements IHaveHovering ExtractionCountMode mode = getModeToExtract(); ItemStack stack = invManipulation.simulate() .extract(mode, amountToExtract); - if (stack.isEmpty()) + if (stack.isEmpty()) { + invVersionTracker.awaitNewVersion(invManipulation); return; + } for (ItemEntity itemEntity : level.getEntitiesOfClass(ItemEntity.class, area)) { lastObserved = new WeakReference<>(itemEntity); return; @@ -189,6 +198,9 @@ public class FunnelBlockEntity extends SmartBlockEntity implements IHaveHovering } private void activateExtractingBeltFunnel() { + if (invVersionTracker.stillWaiting(invManipulation)) + return; + BlockState blockState = getBlockState(); Direction facing = blockState.getValue(BeltFunnelBlock.HORIZONTAL_FACING); DirectBeltInputBehaviour inputBehaviour = @@ -198,14 +210,24 @@ public class FunnelBlockEntity extends SmartBlockEntity implements IHaveHovering return; if (!inputBehaviour.canInsertFromSide(facing)) return; + if (inputBehaviour.isOccupied(facing)) + return; int amountToExtract = getAmountToExtract(); ExtractionCountMode mode = getModeToExtract(); - ItemStack stack = - invManipulation.extract(mode, amountToExtract, s -> inputBehaviour.handleInsertion(s, facing, true) - .isEmpty()); - if (stack.isEmpty()) + MutableBoolean deniedByInsertion = new MutableBoolean(false); + ItemStack stack = invManipulation.extract(mode, amountToExtract, s -> { + ItemStack handleInsertion = inputBehaviour.handleInsertion(s, facing, true); + if (handleInsertion.isEmpty()) + return true; + deniedByInsertion.setTrue(); + return false; + }); + if (stack.isEmpty()) { + if (deniedByInsertion.isFalse()) + invVersionTracker.awaitNewVersion(invManipulation.getInventory()); return; + } flap(false); onTransfer(stack); inputBehaviour.handleInsertion(stack, facing, false); @@ -237,12 +259,15 @@ public class FunnelBlockEntity extends SmartBlockEntity implements IHaveHovering new InvManipulationBehaviour(this, (w, p, s) -> new BlockFace(p, AbstractFunnelBlock.getFunnelFacing(s) .getOpposite())); behaviours.add(invManipulation); + + behaviours.add(invVersionTracker = new VersionedInventoryTrackerBehaviour(this)); filtering = new FilteringBehaviour(this, new FunnelFilterSlotPositioning()); filtering.showCountWhen(this::supportsAmountOnFilter); filtering.onlyActiveWhen(this::supportsFiltering); + filtering.withCallback($ -> invVersionTracker.reset()); behaviours.add(filtering); - + behaviours.add(new DirectBeltInputBehaviour(this).onlyInsertWhen(this::supportsDirectBeltInput) .setInsertionHandler(this::handleDirectBeltInput)); registerAwardables(behaviours, AllAdvancements.FUNNEL); diff --git a/src/main/java/com/simibubi/create/content/logistics/vault/ItemVaultBlockEntity.java b/src/main/java/com/simibubi/create/content/logistics/vault/ItemVaultBlockEntity.java index 9127bc91d..d1d6f840d 100644 --- a/src/main/java/com/simibubi/create/content/logistics/vault/ItemVaultBlockEntity.java +++ b/src/main/java/com/simibubi/create/content/logistics/vault/ItemVaultBlockEntity.java @@ -7,6 +7,7 @@ import com.simibubi.create.api.connectivity.ConnectivityHandler; import com.simibubi.create.foundation.blockEntity.IMultiBlockEntityContainer; import com.simibubi.create.foundation.blockEntity.SmartBlockEntity; 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 net.minecraft.core.BlockPos; @@ -260,8 +261,8 @@ public class ItemVaultBlockEntity extends SmartBlockEntity implements IMultiBloc } } - CombinedInvWrapper combinedInvWrapper = new CombinedInvWrapper(invs); - itemCapability = LazyOptional.of(() -> combinedInvWrapper); + IItemHandler itemHandler = new VersionedInventoryWrapper(new CombinedInvWrapper(invs)); + itemCapability = LazyOptional.of(() -> itemHandler); } public static int getMaxLength(int radius) { diff --git a/src/main/java/com/simibubi/create/content/redstone/smartObserver/SmartObserverBlockEntity.java b/src/main/java/com/simibubi/create/content/redstone/smartObserver/SmartObserverBlockEntity.java index 484aeab56..e1c202639 100644 --- a/src/main/java/com/simibubi/create/content/redstone/smartObserver/SmartObserverBlockEntity.java +++ b/src/main/java/com/simibubi/create/content/redstone/smartObserver/SmartObserverBlockEntity.java @@ -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.InvManipulationBehaviour; 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.Iterate; @@ -31,6 +32,10 @@ public class SmartObserverBlockEntity extends SmartBlockEntity { private FilteringBehaviour filtering; private InvManipulationBehaviour observedInventory; private TankManipulationBehaviour observedTank; + + private VersionedInventoryTrackerBehaviour invVersionTracker; + private boolean sustainSignal; + public int turnOffTicks = 0; public SmartObserverBlockEntity(BlockEntityType type, BlockPos pos, BlockState state) { @@ -40,7 +45,9 @@ public class SmartObserverBlockEntity extends SmartBlockEntity { @Override public void addBehaviours(List 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 = (w, p, s) -> new BlockFace(p, DirectedDirectionalBlock.getTargetDirection(s)); @@ -105,11 +112,23 @@ public class SmartObserverBlockEntity extends SmartBlockEntity { return; } - if (!observedInventory.simulate() - .extract() - .isEmpty()) { - activate(); - 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() + .extract() + .isEmpty()) { + sustainSignal = true; + activate(); + return; + } + } } if (!observedTank.simulate() diff --git a/src/main/java/com/simibubi/create/content/redstone/thresholdSwitch/ThresholdSwitchBlockEntity.java b/src/main/java/com/simibubi/create/content/redstone/thresholdSwitch/ThresholdSwitchBlockEntity.java index 124e8fbfc..f623407a0 100644 --- a/src/main/java/com/simibubi/create/content/redstone/thresholdSwitch/ThresholdSwitchBlockEntity.java +++ b/src/main/java/com/simibubi/create/content/redstone/thresholdSwitch/ThresholdSwitchBlockEntity.java @@ -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.InvManipulationBehaviour; 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 net.minecraft.core.BlockPos; @@ -39,6 +40,7 @@ public class ThresholdSwitchBlockEntity extends SmartBlockEntity { private FilteringBehaviour filtering; private InvManipulationBehaviour observedInventory; private TankManipulationBehaviour observedTank; + private VersionedInventoryTrackerBehaviour invVersionTracker; public ThresholdSwitchBlockEntity(BlockEntityType type, BlockPos pos, BlockState state) { super(type, pos, state); @@ -107,18 +109,26 @@ public class ThresholdSwitchBlockEntity extends SmartBlockEntity { } else if (observedInventory.hasInventory() || observedTank.hasInventory()) { if (observedInventory.hasInventory()) { + // Item inventory IItemHandler inv = observedInventory.getInventory(); - for (int slot = 0; slot < inv.getSlots(); slot++) { - ItemStack stackInSlot = inv.getStackInSlot(slot); - int space = Math.min(stackInSlot.getMaxStackSize(), inv.getSlotLimit(slot)); - int count = stackInSlot.getCount(); - if (space == 0) - continue; - - totalSpace += 1; - if (filtering.test(stackInSlot)) - occupied += count * (1f / space); + if (invVersionTracker.stillWaiting(inv)) { + occupied = prevLevel; + totalSpace = 1f; + + } else { + invVersionTracker.awaitNewVersion(inv); + for (int slot = 0; slot < inv.getSlots(); slot++) { + ItemStack stackInSlot = inv.getStackInSlot(slot); + int space = Math.min(stackInSlot.getMaxStackSize(), inv.getSlotLimit(slot)); + int count = stackInSlot.getCount(); + if (space == 0) + continue; + + totalSpace += 1; + if (filtering.test(stackInSlot)) + occupied += count * (1f / space); + } } } @@ -195,7 +205,12 @@ public class ThresholdSwitchBlockEntity extends SmartBlockEntity { @Override public void addBehaviours(List behaviours) { 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 = (w, p, s) -> new BlockFace(p, DirectedDirectionalBlock.getTargetDirection(s)); diff --git a/src/main/java/com/simibubi/create/foundation/blockEntity/behaviour/inventory/VersionedInventoryTrackerBehaviour.java b/src/main/java/com/simibubi/create/foundation/blockEntity/behaviour/inventory/VersionedInventoryTrackerBehaviour.java new file mode 100644 index 000000000..9a40facd1 --- /dev/null +++ b/src/main/java/com/simibubi/create/foundation/blockEntity/behaviour/inventory/VersionedInventoryTrackerBehaviour.java @@ -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 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; + } + +} diff --git a/src/main/java/com/simibubi/create/foundation/blockEntity/behaviour/inventory/VersionedInventoryWrapper.java b/src/main/java/com/simibubi/create/foundation/blockEntity/behaviour/inventory/VersionedInventoryWrapper.java new file mode 100644 index 000000000..cfeae3519 --- /dev/null +++ b/src/main/java/com/simibubi/create/foundation/blockEntity/behaviour/inventory/VersionedInventoryWrapper.java @@ -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(); + } + +}