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

View file

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

View file

@ -95,7 +95,7 @@ public class BeltBlockEntity extends KineticBlockEntity {
public void addBehaviours(List<BlockEntityBehaviour> 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;

View file

@ -33,6 +33,7 @@ public class DirectBeltInputBehaviour extends BlockEntityBehaviour {
public static final BehaviourType<DirectBeltInputBehaviour> TYPE = new BehaviourType<>();
private InsertionCallback tryInsert;
private OccupiedPredicate isOccupied;
private AvailabilityPredicate canInsert;
private Supplier<Boolean> 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);

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.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<IItemHandler> capAbove;
LazyOptional<IItemHandler> capBelow;
@ -101,6 +104,7 @@ public class ChuteBlockEntity extends SmartBlockEntity implements IHaveGoggleInf
@Override
public void addBehaviours(List<BlockEntityBehaviour> 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<ItemStack> 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);

View file

@ -51,7 +51,8 @@ public class SmartChuteBlockEntity extends ChuteBlockEntity {
@Override
public void addBehaviours(List<BlockEntityBehaviour> 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);
}

View file

@ -240,7 +240,7 @@ public class DepotBehaviour extends BlockEntityBehaviour {
public void addSubBehaviours(List<BlockEntityBehaviour> 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();

View file

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

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

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.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<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 =
(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()

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.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<BlockEntityBehaviour> 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));

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