diff --git a/fabric-transfer-api-v1/src/main/java/net/fabricmc/fabric/mixin/transfer/DropperBlockMixin.java b/fabric-transfer-api-v1/src/main/java/net/fabricmc/fabric/mixin/transfer/DropperBlockMixin.java index a5c94c200..cacd3d4c5 100644 --- a/fabric-transfer-api-v1/src/main/java/net/fabricmc/fabric/mixin/transfer/DropperBlockMixin.java +++ b/fabric-transfer-api-v1/src/main/java/net/fabricmc/fabric/mixin/transfer/DropperBlockMixin.java @@ -22,9 +22,9 @@ import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; import org.spongepowered.asm.mixin.injection.callback.LocalCapture; +import net.minecraft.block.DispenserBlock; import net.minecraft.block.DropperBlock; import net.minecraft.block.entity.DispenserBlockEntity; -import net.minecraft.item.ItemStack; import net.minecraft.server.world.ServerWorld; import net.minecraft.util.math.BlockPointerImpl; import net.minecraft.util.math.BlockPos; @@ -38,20 +38,26 @@ import net.fabricmc.fabric.api.transfer.v1.storage.StorageUtil; /** * Allows droppers to insert into ItemVariant storages. + * + * <p>Maintainer note: it's important that we inject BEFORE the getStack() call, + * as the returned stack can be mutated by the StorageUtil.move() call in the injected callback. */ @Mixin(DropperBlock.class) public class DropperBlockMixin { @Inject( at = @At( value = "INVOKE", - target = "Lnet/minecraft/util/math/BlockPos;offset(Lnet/minecraft/util/math/Direction;)Lnet/minecraft/util/math/BlockPos;" + target = "Lnet/minecraft/block/entity/DispenserBlockEntity;getStack(I)Lnet/minecraft/item/ItemStack;" ), method = "dispense", locals = LocalCapture.CAPTURE_FAILHARD, cancellable = true, allow = 1 ) - public void hookDispense(ServerWorld world, BlockPos pos, CallbackInfo ci, BlockPointerImpl blockPointerImpl, DispenserBlockEntity dispenser, int slot, ItemStack stack, Direction direction) { + public void hookDispense(ServerWorld world, BlockPos pos, CallbackInfo ci, BlockPointerImpl blockPointerImpl, DispenserBlockEntity dispenser, int slot) { + if (dispenser.getStack(slot).isEmpty()) return; + + Direction direction = world.getBlockState(pos).get(DispenserBlock.FACING); Storage<ItemVariant> target = ItemStorage.SIDED.find(world, pos.offset(direction), direction.getOpposite()); if (target != null) { diff --git a/fabric-transfer-api-v1/src/testmod/java/net/fabricmc/fabric/test/transfer/fluid/FluidTransferTest.java b/fabric-transfer-api-v1/src/testmod/java/net/fabricmc/fabric/test/transfer/fluid/FluidTransferTest.java index 8675d8cf8..d7c67def8 100644 --- a/fabric-transfer-api-v1/src/testmod/java/net/fabricmc/fabric/test/transfer/fluid/FluidTransferTest.java +++ b/fabric-transfer-api-v1/src/testmod/java/net/fabricmc/fabric/test/transfer/fluid/FluidTransferTest.java @@ -20,6 +20,7 @@ import static net.fabricmc.fabric.api.transfer.v1.fluid.FluidConstants.BUCKET; import net.minecraft.block.AbstractBlock; import net.minecraft.block.Block; +import net.minecraft.block.Blocks; import net.minecraft.block.Material; import net.minecraft.block.entity.BlockEntityType; import net.minecraft.fluid.Fluids; @@ -34,6 +35,7 @@ import net.fabricmc.api.ModInitializer; import net.fabricmc.fabric.api.object.builder.v1.block.entity.FabricBlockEntityTypeBuilder; import net.fabricmc.fabric.api.transfer.v1.fluid.FluidVariant; import net.fabricmc.fabric.api.transfer.v1.fluid.FluidStorage; +import net.fabricmc.fabric.api.transfer.v1.item.ItemStorage; import net.fabricmc.fabric.api.transfer.v1.storage.base.SingleSlotStorage; import net.fabricmc.fabric.api.transfer.v1.storage.base.SingleVariantStorage; import net.fabricmc.fabric.api.transfer.v1.transaction.Transaction; @@ -60,6 +62,9 @@ public class FluidTransferTest implements ModInitializer { FluidStorage.SIDED.registerForBlocks((world, pos, state, be, direction) -> CreativeFluidStorage.WATER, INFINITE_WATER_SOURCE); FluidStorage.SIDED.registerForBlocks((world, pos, state, be, direction) -> CreativeFluidStorage.LAVA, INFINITE_LAVA_SOURCE); + // Obsidian is now a trash can :-P + ItemStorage.SIDED.registerForBlocks((world, pos, state, be, direction) -> TrashingStorage.ITEM, Blocks.OBSIDIAN); + testFluidStorage(); testTransactionExceptions(); ItemTests.run(); diff --git a/fabric-transfer-api-v1/src/testmod/java/net/fabricmc/fabric/test/transfer/fluid/TrashingStorage.java b/fabric-transfer-api-v1/src/testmod/java/net/fabricmc/fabric/test/transfer/fluid/TrashingStorage.java new file mode 100644 index 000000000..24387fa48 --- /dev/null +++ b/fabric-transfer-api-v1/src/testmod/java/net/fabricmc/fabric/test/transfer/fluid/TrashingStorage.java @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2016, 2017, 2018, 2019 FabricMC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package net.fabricmc.fabric.test.transfer.fluid; + +import java.util.Collections; +import java.util.Iterator; + +import net.fabricmc.fabric.api.transfer.v1.item.ItemVariant; +import net.fabricmc.fabric.api.transfer.v1.storage.StoragePreconditions; +import net.fabricmc.fabric.api.transfer.v1.storage.StorageView; +import net.fabricmc.fabric.api.transfer.v1.storage.TransferVariant; +import net.fabricmc.fabric.api.transfer.v1.storage.base.InsertionOnlyStorage; +import net.fabricmc.fabric.api.transfer.v1.transaction.TransactionContext; + +public class TrashingStorage<T extends TransferVariant<?>> implements InsertionOnlyStorage<T> { + public static final TrashingStorage<ItemVariant> ITEM = new TrashingStorage<>(); + + @Override + public long insert(T resource, long maxAmount, TransactionContext transaction) { + StoragePreconditions.notBlankNotNegative(resource, maxAmount); + + // Insertion always succeeds. + return maxAmount; + } + + @Override + public Iterator<StorageView<T>> iterator(TransactionContext transaction) { + return Collections.emptyIterator(); + } +}