Silent's Mechanisms

Silent's Mechanisms

7M Downloads

Lava Generator can be used to dupe empty buckets.

variousauthors opened this issue ยท 1 comments

commented

Versions

  • Silent's Mechanisms: 1.14.4-0.6.9+42
  • Silent Lib: 1.14.4-4.4.0+44
  • Forge: 28.1.80
  • Modpack: N/A

Expected Behavior

When I add something to the input slot of the lava generator
And there is already something in the output slow of the lava generator
Then I expect the lava generator not to consume the input
Unless the item in the output slot can stack with the input's container item

Actual Behavior

If you have an input that has a null containerItem
And you add it to the input slow of the lava generator
And there is already an empty bucket in the output slow
Then the input is consumed
And the output stack is incremented

Links/Images

Screen Shot 2019-12-11 at 12 00 42 AM

Screen Shot 2019-12-11 at 12 01 14 AM

Steps to Reproduce the Problem

This is a little tricky to reproduce because it is an edge case.

  1. construct a new BucketItem, like this:
new BucketItem(Fluids.LAVA, new Item.Properties());
  1. register the item in your mod
  2. start the client
  3. \give yourself: an empty bucket, a lava generator, and a stack of the new item
  4. first put the bucket in the output slot
  5. then put the items in the input slot

You should see the number of buckets in the stack increase, even though the item does not specify a containerItem property.

This exploit can be used to dupe any item that can go in the output slot of the lava generator.


So, this is an issue that I encountered while making a kind of melon that is full of lava (a lavamelon). The melon generates heat like a bucket of lava, but it has not "container" and no output. I installed your mod alongside mine to test, and I noticed this behaviour. I assumed it was a problem with the way I was doing things (because I am new to modding). However, upon investigating your code (to see how I should be doing things) I encountered this:

    private boolean canAcceptFluidContainer(ItemStack item, FluidStack fluid) {
        ItemStack output = getStackInSlot(1);
        return !fluid.isEmpty()
                && tank.isFluidValid(0, fluid)
                && tank.fill(fluid, IFluidHandler.FluidAction.SIMULATE) == fluid.getAmount()
                && (output.isEmpty() || InventoryUtils.canItemsStack(item.getContainerItem(), output))
                && (output.isEmpty() || output.getCount() < output.getMaxStackSize());
    }

The check against canItemsStack returns true if either of the items are empty. If the input's container item is "empty" but the output is not "empty" (ie it is a bucket), then this routine will return true (given all other conditions pass).

Then, in the calling code:

    protected void tryFillTank(ItemStack item) {
        FluidStack fluid = IFluidContainer.getBucketOrContainerFluid(item);
        if (canAcceptFluidContainer(item, fluid)) {
            tank.fill(fluid, IFluidHandler.FluidAction.EXECUTE);

            ItemStack output = getStackInSlot(1);
            if (output.isEmpty()) {
                setInventorySlotContents(1, item.getContainerItem());
            } else {
                // ASSUMPTION
                // if we canAcceptFluidContainer and the output is not empty
                // then the input and the output must be able to stack
                // which means they must be the same 
                output.grow(1);
            }

            item.shrink(1);
        }
    }

This is how my lavamelon is duping buckets in your lava generator.

Further, I thought I would point out: your implementation of canItemsStack is like this

    public static boolean canItemsStack(ItemStack a, ItemStack b) {
        // Determine if the item stacks can be merged
        if (a.isEmpty() || b.isEmpty()) return true;
        return ItemHandlerHelper.canItemStacksStack(a, b) && a.getCount() + b.getCount() <= a.getMaxStackSize();
    }

So first it handles the case where either stack is "empty", by saying "if either stack is empty, then they can stack". But in the canItemStacksStack helper from forge,

    public static boolean canItemStacksStack(@Nonnull ItemStack a, @Nonnull ItemStack b)
    {
        if (a.isEmpty() || !a.isItemEqual(b) || a.hasTag() != b.hasTag())
            return false;

        return (!a.hasTag() || a.getTag().equals(b.getTag())) && a.areCapsCompatible(b);
    }
  • if a is "empty" then they cannot stack
  • if a is non-empty and b is "empty", then they are not equal, so they cannot stack

I feeeeeel like empty cannot stack with non-empty. Like, my feeling is that the concept of "stacking" is something that only exists between two non-empty stacks. If you have a stack and an empty slot, or an empty slot and a stack, or two empty slots... then there is no "stacking" going on.


That all being said: I am a total noob at modding! And your mod has like 300k downloads on curseforge! So I may be totally crazy here. What do you think?

commented

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.