diff --git a/fabric-transfer-api-v1/src/main/java/net/fabricmc/fabric/impl/transfer/TransferApiImpl.java b/fabric-transfer-api-v1/src/main/java/net/fabricmc/fabric/impl/transfer/TransferApiImpl.java index 538caddde..f1d227425 100644 --- a/fabric-transfer-api-v1/src/main/java/net/fabricmc/fabric/impl/transfer/TransferApiImpl.java +++ b/fabric-transfer-api-v1/src/main/java/net/fabricmc/fabric/impl/transfer/TransferApiImpl.java @@ -20,11 +20,15 @@ import java.util.Collections; import java.util.Iterator; import java.util.concurrent.atomic.AtomicLong; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; + import net.fabricmc.fabric.api.transfer.v1.storage.Storage; import net.fabricmc.fabric.api.transfer.v1.storage.StorageView; import net.fabricmc.fabric.api.transfer.v1.transaction.TransactionContext; public class TransferApiImpl { + public static final Logger LOGGER = LogManager.getLogger("fabric-transfer-api-v1"); public static final AtomicLong version = new AtomicLong(); @SuppressWarnings("rawtypes") public static final Storage EMPTY_STORAGE = new Storage() { 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 cacd3d4c5..27890d0e7 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 @@ -20,13 +20,11 @@ import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.injection.At; 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.server.world.ServerWorld; -import net.minecraft.util.math.BlockPointerImpl; import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.Direction; @@ -35,37 +33,47 @@ import net.fabricmc.fabric.api.transfer.v1.item.ItemStorage; import net.fabricmc.fabric.api.transfer.v1.item.ItemVariant; import net.fabricmc.fabric.api.transfer.v1.storage.Storage; import net.fabricmc.fabric.api.transfer.v1.storage.StorageUtil; +import net.fabricmc.fabric.impl.transfer.TransferApiImpl; /** * 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/block/entity/DispenserBlockEntity;getStack(I)Lnet/minecraft/item/ItemStack;" + target = "Lnet/minecraft/block/dispenser/DispenserBehavior;dispense(Lnet/minecraft/util/math/BlockPointer;Lnet/minecraft/item/ItemStack;)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) { - if (dispenser.getStack(slot).isEmpty()) return; + public void hookDispense(ServerWorld world, BlockPos pos, CallbackInfo ci) { + DispenserBlockEntity dispenser = (DispenserBlockEntity) world.getBlockEntity(pos); + Direction direction = dispenser.getCachedState().get(DispenserBlock.FACING); - Direction direction = world.getBlockState(pos).get(DispenserBlock.FACING); Storage<ItemVariant> target = ItemStorage.SIDED.find(world, pos.offset(direction), direction.getOpposite()); if (target != null) { - Storage<ItemVariant> source = InventoryStorage.of(dispenser, null).getSlots().get(slot); + // Always cancel if a storage is available. + ci.cancel(); - if (StorageUtil.move(source, target, k -> true, 1, null) == 1) { - ci.cancel(); + // We pick a non empty slot. It's not necessarily the same as the one vanilla picked, but that doesn't matter. + int slot = dispenser.chooseNonEmptySlot(); + + if (slot == -1) { + TransferApiImpl.LOGGER.warn("Skipping dropper transfer because the empty slot is unexpectedly -1."); + return; } + + StorageUtil.move( + InventoryStorage.of(dispenser, null).getSlots().get(slot), + target, + k -> true, + 1, + null + ); } } } diff --git a/fabric-transfer-api-v1/src/main/java/net/fabricmc/fabric/mixin/transfer/HopperBlockEntityMixin.java b/fabric-transfer-api-v1/src/main/java/net/fabricmc/fabric/mixin/transfer/HopperBlockEntityMixin.java index c48a3cc75..cc0d2cb88 100644 --- a/fabric-transfer-api-v1/src/main/java/net/fabricmc/fabric/mixin/transfer/HopperBlockEntityMixin.java +++ b/fabric-transfer-api-v1/src/main/java/net/fabricmc/fabric/mixin/transfer/HopperBlockEntityMixin.java @@ -16,15 +16,14 @@ package net.fabricmc.fabric.mixin.transfer; -import org.jetbrains.annotations.Nullable; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; +import org.spongepowered.asm.mixin.injection.callback.LocalCapture; import net.minecraft.block.BlockState; import net.minecraft.block.HopperBlock; -import net.minecraft.block.entity.BlockEntity; import net.minecraft.block.entity.Hopper; import net.minecraft.block.entity.HopperBlockEntity; import net.minecraft.inventory.Inventory; @@ -44,49 +43,61 @@ import net.fabricmc.fabric.api.transfer.v1.storage.StorageUtil; @Mixin(HopperBlockEntity.class) public class HopperBlockEntityMixin { @Inject( - at = @At("HEAD"), + at = @At( + value = "INVOKE_ASSIGN", + target = "Lnet/minecraft/block/entity/HopperBlockEntity;getOutputInventory(Lnet/minecraft/world/World;Lnet/minecraft/util/math/BlockPos;Lnet/minecraft/block/BlockState;)Lnet/minecraft/inventory/Inventory;" + ), method = "insert(Lnet/minecraft/world/World;Lnet/minecraft/util/math/BlockPos;Lnet/minecraft/block/BlockState;Lnet/minecraft/inventory/Inventory;)Z", + locals = LocalCapture.CAPTURE_FAILHARD, cancellable = true ) - private static void hookInsert(World world, BlockPos pos, BlockState state, Inventory inventory, CallbackInfoReturnable<Boolean> cir) { + private static void hookInsert(World world, BlockPos pos, BlockState state, Inventory inventory, CallbackInfoReturnable<Boolean> cir, Inventory targetInventory) { + // Let vanilla handle the transfer if it found an inventory. + if (targetInventory != null) return; + + // Otherwise inject our transfer logic. Direction direction = state.get(HopperBlock.FACING); BlockPos targetPos = pos.offset(direction); - BlockEntity targetBe = world.getBlockEntity(targetPos); - Storage<ItemVariant> target = ItemStorage.SIDED.find(world, targetPos, null, targetBe, direction.getOpposite()); + Storage<ItemVariant> target = ItemStorage.SIDED.find(world, targetPos, direction.getOpposite()); if (target != null) { - cir.setReturnValue(doTransfer(InventoryStorage.of(inventory, direction), target, inventory, targetBe)); + long moved = StorageUtil.move( + InventoryStorage.of(inventory, direction), + target, + iv -> true, + 1, + null + ); + cir.setReturnValue(moved == 1); } } @Inject( - at = @At("HEAD"), + at = @At( + value = "INVOKE_ASSIGN", + target = "Lnet/minecraft/block/entity/HopperBlockEntity;getInputInventory(Lnet/minecraft/world/World;Lnet/minecraft/block/entity/Hopper;)Lnet/minecraft/inventory/Inventory;" + ), method = "extract(Lnet/minecraft/world/World;Lnet/minecraft/block/entity/Hopper;)Z", + locals = LocalCapture.CAPTURE_FAILHARD, cancellable = true ) - private static void hookExtract(World world, Hopper hopper, CallbackInfoReturnable<Boolean> cir) { + private static void hookExtract(World world, Hopper hopper, CallbackInfoReturnable<Boolean> cir, Inventory inputInventory) { + // Let vanilla handle the transfer if it found an inventory. + if (inputInventory != null) return; + + // Otherwise inject our transfer logic. BlockPos sourcePos = new BlockPos(hopper.getHopperX(), hopper.getHopperY() + 1.0D, hopper.getHopperZ()); - BlockEntity sourceBe = world.getBlockEntity(sourcePos); - Storage<ItemVariant> source = ItemStorage.SIDED.find(world, sourcePos, null, sourceBe, Direction.DOWN); + Storage<ItemVariant> source = ItemStorage.SIDED.find(world, sourcePos, Direction.DOWN); if (source != null) { - cir.setReturnValue(doTransfer(source, InventoryStorage.of(hopper, Direction.UP), sourceBe, hopper)); - } - } - - private static boolean doTransfer(Storage<ItemVariant> from, Storage<ItemVariant> to, @Nullable Object invFrom, @Nullable Object invTo) { - if (invFrom instanceof HopperBlockEntityAccessor hopperFrom && invTo instanceof HopperBlockEntityAccessor hopperTo) { - // Hoppers have some special interactions (see HopperBlockEntity#transfer) - boolean wasEmpty = hopperTo.isEmpty(); - boolean moved = StorageUtil.move(from, to, k -> true, 1, null) == 1; - - if (moved && wasEmpty && hopperTo.fabric_getLastTickTime() >= hopperFrom.fabric_getLastTickTime()) { - hopperTo.fabric_callSetCooldown(7); - } - - return moved; - } else { - return StorageUtil.move(from, to, k -> true, 1, null) == 1; + long moved = StorageUtil.move( + source, + InventoryStorage.of(hopper, Direction.UP), + iv -> true, + 1, + null + ); + cir.setReturnValue(moved == 1); } } } diff --git a/fabric-transfer-api-v1/src/main/resources/fabric-transfer-api-v1.mixins.json b/fabric-transfer-api-v1/src/main/resources/fabric-transfer-api-v1.mixins.json index becd80534..f084d4d06 100644 --- a/fabric-transfer-api-v1/src/main/resources/fabric-transfer-api-v1.mixins.json +++ b/fabric-transfer-api-v1/src/main/resources/fabric-transfer-api-v1.mixins.json @@ -7,7 +7,6 @@ "DoubleInventoryAccessor", "DropperBlockMixin", "FluidMixin", - "HopperBlockEntityAccessor", "HopperBlockEntityMixin", "ItemMixin" ] diff --git a/fabric-transfer-api-v1/src/testmod/java/net/fabricmc/fabric/test/transfer/fluid/CreativeFluidStorage.java b/fabric-transfer-api-v1/src/testmod/java/net/fabricmc/fabric/test/transfer/ingame/CreativeStorage.java similarity index 55% rename from fabric-transfer-api-v1/src/testmod/java/net/fabricmc/fabric/test/transfer/fluid/CreativeFluidStorage.java rename to fabric-transfer-api-v1/src/testmod/java/net/fabricmc/fabric/test/transfer/ingame/CreativeStorage.java index 35bacc7ec..f2121ae72 100644 --- a/fabric-transfer-api-v1/src/testmod/java/net/fabricmc/fabric/test/transfer/fluid/CreativeFluidStorage.java +++ b/fabric-transfer-api-v1/src/testmod/java/net/fabricmc/fabric/test/transfer/ingame/CreativeStorage.java @@ -14,37 +14,38 @@ * limitations under the License. */ -package net.fabricmc.fabric.test.transfer.fluid; - -import java.util.Iterator; +package net.fabricmc.fabric.test.transfer.ingame; import net.minecraft.fluid.Fluids; +import net.minecraft.item.Items; import net.fabricmc.fabric.api.transfer.v1.fluid.FluidVariant; +import net.fabricmc.fabric.api.transfer.v1.item.ItemVariant; +import net.fabricmc.fabric.api.transfer.v1.storage.TransferVariant; 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.base.ExtractionOnlyStorage; -import net.fabricmc.fabric.api.transfer.v1.storage.base.SingleViewIterator; +import net.fabricmc.fabric.api.transfer.v1.storage.base.SingleSlotStorage; import net.fabricmc.fabric.api.transfer.v1.transaction.TransactionContext; -public class CreativeFluidStorage implements ExtractionOnlyStorage<FluidVariant>, StorageView<FluidVariant> { - public static final CreativeFluidStorage WATER = new CreativeFluidStorage(FluidVariant.of(Fluids.WATER)); - public static final CreativeFluidStorage LAVA = new CreativeFluidStorage(FluidVariant.of(Fluids.LAVA)); +public class CreativeStorage<T extends TransferVariant<?>> implements ExtractionOnlyStorage<T>, SingleSlotStorage<T> { + public static final CreativeStorage<FluidVariant> WATER = new CreativeStorage<>(FluidVariant.of(Fluids.WATER)); + public static final CreativeStorage<FluidVariant> LAVA = new CreativeStorage<>(FluidVariant.of(Fluids.LAVA)); + public static final CreativeStorage<ItemVariant> DIAMONDS = new CreativeStorage<>(ItemVariant.of(Items.DIAMOND)); - private final FluidVariant infiniteFluid; + private final T infiniteResource; - private CreativeFluidStorage(FluidVariant infiniteFluid) { - this.infiniteFluid = infiniteFluid; + private CreativeStorage(T infiniteResource) { + this.infiniteResource = infiniteResource; } @Override public boolean isResourceBlank() { - return infiniteFluid.isBlank(); + return infiniteResource.isBlank(); } @Override - public FluidVariant getResource() { - return infiniteFluid; + public T getResource() { + return infiniteResource; } @Override @@ -58,21 +59,16 @@ public class CreativeFluidStorage implements ExtractionOnlyStorage<FluidVariant> } @Override - public long extract(FluidVariant resource, long maxAmount, TransactionContext transaction) { + public long extract(T resource, long maxAmount, TransactionContext transaction) { StoragePreconditions.notBlankNotNegative(resource, maxAmount); - if (resource.equals(infiniteFluid)) { + if (resource.equals(infiniteResource)) { return maxAmount; } else { return 0; } } - @Override - public Iterator<StorageView<FluidVariant>> iterator(TransactionContext transaction) { - return SingleViewIterator.create(this, transaction); - } - @Override public long getVersion() { return 0; diff --git a/fabric-transfer-api-v1/src/testmod/java/net/fabricmc/fabric/test/transfer/fluid/ExtractStickItem.java b/fabric-transfer-api-v1/src/testmod/java/net/fabricmc/fabric/test/transfer/ingame/ExtractStickItem.java similarity index 97% rename from fabric-transfer-api-v1/src/testmod/java/net/fabricmc/fabric/test/transfer/fluid/ExtractStickItem.java rename to fabric-transfer-api-v1/src/testmod/java/net/fabricmc/fabric/test/transfer/ingame/ExtractStickItem.java index d284890f5..140d7baef 100644 --- a/fabric-transfer-api-v1/src/testmod/java/net/fabricmc/fabric/test/transfer/fluid/ExtractStickItem.java +++ b/fabric-transfer-api-v1/src/testmod/java/net/fabricmc/fabric/test/transfer/ingame/ExtractStickItem.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package net.fabricmc.fabric.test.transfer.fluid; +package net.fabricmc.fabric.test.transfer.ingame; import net.minecraft.item.Item; import net.minecraft.item.ItemGroup; diff --git a/fabric-transfer-api-v1/src/testmod/java/net/fabricmc/fabric/test/transfer/fluid/FluidChuteBlock.java b/fabric-transfer-api-v1/src/testmod/java/net/fabricmc/fabric/test/transfer/ingame/FluidChuteBlock.java similarity index 97% rename from fabric-transfer-api-v1/src/testmod/java/net/fabricmc/fabric/test/transfer/fluid/FluidChuteBlock.java rename to fabric-transfer-api-v1/src/testmod/java/net/fabricmc/fabric/test/transfer/ingame/FluidChuteBlock.java index 4bfc0389c..ed3f186c8 100644 --- a/fabric-transfer-api-v1/src/testmod/java/net/fabricmc/fabric/test/transfer/fluid/FluidChuteBlock.java +++ b/fabric-transfer-api-v1/src/testmod/java/net/fabricmc/fabric/test/transfer/ingame/FluidChuteBlock.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package net.fabricmc.fabric.test.transfer.fluid; +package net.fabricmc.fabric.test.transfer.ingame; import org.jetbrains.annotations.Nullable; diff --git a/fabric-transfer-api-v1/src/testmod/java/net/fabricmc/fabric/test/transfer/fluid/FluidChuteBlockEntity.java b/fabric-transfer-api-v1/src/testmod/java/net/fabricmc/fabric/test/transfer/ingame/FluidChuteBlockEntity.java similarity index 93% rename from fabric-transfer-api-v1/src/testmod/java/net/fabricmc/fabric/test/transfer/fluid/FluidChuteBlockEntity.java rename to fabric-transfer-api-v1/src/testmod/java/net/fabricmc/fabric/test/transfer/ingame/FluidChuteBlockEntity.java index 5bc537bb6..2cc6411b4 100644 --- a/fabric-transfer-api-v1/src/testmod/java/net/fabricmc/fabric/test/transfer/fluid/FluidChuteBlockEntity.java +++ b/fabric-transfer-api-v1/src/testmod/java/net/fabricmc/fabric/test/transfer/ingame/FluidChuteBlockEntity.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package net.fabricmc.fabric.test.transfer.fluid; +package net.fabricmc.fabric.test.transfer.ingame; import net.minecraft.block.BlockState; import net.minecraft.block.entity.BlockEntity; @@ -31,7 +31,7 @@ public class FluidChuteBlockEntity extends BlockEntity { private int tickCounter = 0; public FluidChuteBlockEntity(BlockPos pos, BlockState state) { - super(FluidTransferTest.FLUID_CHUTE_TYPE, pos, state); + super(TransferTestInitializer.FLUID_CHUTE_TYPE, pos, state); } @SuppressWarnings("ConstantConditions") diff --git a/fabric-transfer-api-v1/src/testmod/java/net/fabricmc/fabric/test/transfer/ingame/TransferTestInitializer.java b/fabric-transfer-api-v1/src/testmod/java/net/fabricmc/fabric/test/transfer/ingame/TransferTestInitializer.java new file mode 100644 index 000000000..f608e11ab --- /dev/null +++ b/fabric-transfer-api-v1/src/testmod/java/net/fabricmc/fabric/test/transfer/ingame/TransferTestInitializer.java @@ -0,0 +1,68 @@ +/* + * 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.ingame; + +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.item.BlockItem; +import net.minecraft.item.Item; +import net.minecraft.item.ItemGroup; +import net.minecraft.util.Identifier; +import net.minecraft.util.registry.Registry; + +import net.fabricmc.api.ModInitializer; +import net.fabricmc.fabric.api.object.builder.v1.block.entity.FabricBlockEntityTypeBuilder; +import net.fabricmc.fabric.api.transfer.v1.fluid.FluidStorage; +import net.fabricmc.fabric.api.transfer.v1.item.ItemStorage; + +public class TransferTestInitializer implements ModInitializer { + public static final String MOD_ID = "fabric-transfer-api-v1-testmod"; + + private static final Block INFINITE_WATER_SOURCE = new Block(AbstractBlock.Settings.of(Material.METAL)); + private static final Block INFINITE_LAVA_SOURCE = new Block(AbstractBlock.Settings.of(Material.METAL)); + private static final Block FLUID_CHUTE = new FluidChuteBlock(); + private static final Item EXTRACT_STICK = new ExtractStickItem(); + public static BlockEntityType<FluidChuteBlockEntity> FLUID_CHUTE_TYPE; + + @Override + public void onInitialize() { + registerBlock(INFINITE_WATER_SOURCE, "infinite_water_source"); + registerBlock(INFINITE_LAVA_SOURCE, "infinite_lava_source"); + registerBlock(FLUID_CHUTE, "fluid_chute"); + Registry.register(Registry.ITEM, new Identifier(MOD_ID, "extract_stick"), EXTRACT_STICK); + + FLUID_CHUTE_TYPE = FabricBlockEntityTypeBuilder.create(FluidChuteBlockEntity::new, FLUID_CHUTE).build(); + Registry.register(Registry.BLOCK_ENTITY_TYPE, new Identifier(MOD_ID, "fluid_chute"), FLUID_CHUTE_TYPE); + + FluidStorage.SIDED.registerForBlocks((world, pos, state, be, direction) -> CreativeStorage.WATER, INFINITE_WATER_SOURCE); + FluidStorage.SIDED.registerForBlocks((world, pos, state, be, direction) -> CreativeStorage.LAVA, INFINITE_LAVA_SOURCE); + + // Obsidian is now a trash can :-P + ItemStorage.SIDED.registerForBlocks((world, pos, state, be, direction) -> TrashingStorage.ITEM, Blocks.OBSIDIAN); + // And diamond ore blocks are an infinite source of diamonds! Yay! + ItemStorage.SIDED.registerForBlocks((world, pos, state, be, direction) -> CreativeStorage.DIAMONDS, Blocks.DIAMOND_ORE); + } + + private static void registerBlock(Block block, String name) { + Identifier id = new Identifier(MOD_ID, name); + Registry.register(Registry.BLOCK, id, block); + Registry.register(Registry.ITEM, id, new BlockItem(block, new Item.Settings().group(ItemGroup.MISC))); + } +} 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/ingame/TrashingStorage.java similarity index 97% rename from fabric-transfer-api-v1/src/testmod/java/net/fabricmc/fabric/test/transfer/fluid/TrashingStorage.java rename to fabric-transfer-api-v1/src/testmod/java/net/fabricmc/fabric/test/transfer/ingame/TrashingStorage.java index 24387fa48..30716eecc 100644 --- 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/ingame/TrashingStorage.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package net.fabricmc.fabric.test.transfer.fluid; +package net.fabricmc.fabric.test.transfer.ingame; import java.util.Collections; import java.util.Iterator; diff --git a/fabric-transfer-api-v1/src/testmod/java/net/fabricmc/fabric/test/transfer/fluid/FluidItemTests.java b/fabric-transfer-api-v1/src/testmod/java/net/fabricmc/fabric/test/transfer/unittests/FluidItemTests.java similarity index 99% rename from fabric-transfer-api-v1/src/testmod/java/net/fabricmc/fabric/test/transfer/fluid/FluidItemTests.java rename to fabric-transfer-api-v1/src/testmod/java/net/fabricmc/fabric/test/transfer/unittests/FluidItemTests.java index 55687ea3b..50380f3a9 100644 --- a/fabric-transfer-api-v1/src/testmod/java/net/fabricmc/fabric/test/transfer/fluid/FluidItemTests.java +++ b/fabric-transfer-api-v1/src/testmod/java/net/fabricmc/fabric/test/transfer/unittests/FluidItemTests.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package net.fabricmc.fabric.test.transfer.fluid; +package net.fabricmc.fabric.test.transfer.unittests; import static net.fabricmc.fabric.api.transfer.v1.fluid.FluidConstants.BOTTLE; import static net.fabricmc.fabric.api.transfer.v1.fluid.FluidConstants.BUCKET; @@ -43,7 +43,7 @@ import net.fabricmc.fabric.api.transfer.v1.storage.base.SingleSlotStorage; import net.fabricmc.fabric.api.transfer.v1.transaction.Transaction; import net.fabricmc.fabric.api.transfer.v1.transaction.TransactionContext; -public class FluidItemTests { +class FluidItemTests { public static void run() { testFluidItemApi(); testWaterPotion(); 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/unittests/FluidTests.java similarity index 59% rename from fabric-transfer-api-v1/src/testmod/java/net/fabricmc/fabric/test/transfer/fluid/FluidTransferTest.java rename to fabric-transfer-api-v1/src/testmod/java/net/fabricmc/fabric/test/transfer/unittests/FluidTests.java index d7c67def8..a25b7e396 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/unittests/FluidTests.java @@ -14,67 +14,21 @@ * limitations under the License. */ -package net.fabricmc.fabric.test.transfer.fluid; +package net.fabricmc.fabric.test.transfer.unittests; 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; -import net.minecraft.item.BlockItem; -import net.minecraft.item.Item; -import net.minecraft.item.ItemGroup; import net.minecraft.nbt.NbtCompound; -import net.minecraft.util.Identifier; -import net.minecraft.util.registry.Registry; -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; -public class FluidTransferTest implements ModInitializer { - public static final String MOD_ID = "fabric-transfer-api-v1-testmod"; - - private static final Block INFINITE_WATER_SOURCE = new Block(AbstractBlock.Settings.of(Material.METAL)); - private static final Block INFINITE_LAVA_SOURCE = new Block(AbstractBlock.Settings.of(Material.METAL)); - private static final Block FLUID_CHUTE = new FluidChuteBlock(); - private static final Item EXTRACT_STICK = new ExtractStickItem(); - public static BlockEntityType<FluidChuteBlockEntity> FLUID_CHUTE_TYPE; - - @Override - public void onInitialize() { - registerBlock(INFINITE_WATER_SOURCE, "infinite_water_source"); - registerBlock(INFINITE_LAVA_SOURCE, "infinite_lava_source"); - registerBlock(FLUID_CHUTE, "fluid_chute"); - Registry.register(Registry.ITEM, new Identifier(MOD_ID, "extract_stick"), EXTRACT_STICK); - - FLUID_CHUTE_TYPE = FabricBlockEntityTypeBuilder.create(FluidChuteBlockEntity::new, FLUID_CHUTE).build(); - Registry.register(Registry.BLOCK_ENTITY_TYPE, new Identifier(MOD_ID, "fluid_chute"), FLUID_CHUTE_TYPE); - - 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); - +class FluidTests { + public static void run() { testFluidStorage(); - testTransactionExceptions(); - ItemTests.run(); - FluidItemTests.run(); - } - - private static void registerBlock(Block block, String name) { - Identifier id = new Identifier(MOD_ID, name); - Registry.register(Registry.BLOCK, id, block); - Registry.register(Registry.ITEM, id, new BlockItem(block, new Item.Settings().group(ItemGroup.MISC))); } private static final FluidVariant TAGGED_WATER, TAGGED_WATER_2, WATER, LAVA; @@ -195,61 +149,4 @@ public class FluidTransferTest implements ModInitializer { } } } - - private static int callbacksInvoked = 0; - - /** - * Make sure that transaction global state stays valid in case of exceptions. - */ - private static void testTransactionExceptions() { - // Test exception inside the try. - ensureException(() -> { - try (Transaction tx = Transaction.openOuter()) { - tx.addCloseCallback((t, result) -> { - callbacksInvoked++; throw new RuntimeException("Close."); - }); - throw new RuntimeException("Inside try."); - } - }, "Exception should have propagated through the transaction."); - if (callbacksInvoked != 1) throw new AssertionError("Callback should have been invoked."); - - // Test exception inside the close. - callbacksInvoked = 0; - ensureException(() -> { - try (Transaction tx = Transaction.openOuter()) { - tx.addCloseCallback((t, result) -> { - callbacksInvoked++; throw new RuntimeException("Close 1."); - }); - tx.addCloseCallback((t, result) -> { - callbacksInvoked++; throw new RuntimeException("Close 2."); - }); - tx.addOuterCloseCallback(result -> { - callbacksInvoked++; throw new RuntimeException("Outer close 1."); - }); - tx.addOuterCloseCallback(result -> { - callbacksInvoked++; throw new RuntimeException("Outer close 2."); - }); - } - }, "Exceptions in close callbacks should be propagated through the transaction."); - if (callbacksInvoked != 4) throw new AssertionError("All 4 callbacks should have been invoked, only so many were: " + callbacksInvoked); - - // Test that transaction state is still OK after these exceptions. - try (Transaction tx = Transaction.openOuter()) { - tx.commit(); - } - } - - private static void ensureException(Runnable runnable, String message) { - boolean failed = false; - - try { - runnable.run(); - } catch (Throwable t) { - failed = true; - } - - if (!failed) { - throw new AssertionError(message); - } - } } diff --git a/fabric-transfer-api-v1/src/testmod/java/net/fabricmc/fabric/test/transfer/fluid/ItemTests.java b/fabric-transfer-api-v1/src/testmod/java/net/fabricmc/fabric/test/transfer/unittests/ItemTests.java similarity index 98% rename from fabric-transfer-api-v1/src/testmod/java/net/fabricmc/fabric/test/transfer/fluid/ItemTests.java rename to fabric-transfer-api-v1/src/testmod/java/net/fabricmc/fabric/test/transfer/unittests/ItemTests.java index b5d817acc..191ccea66 100644 --- a/fabric-transfer-api-v1/src/testmod/java/net/fabricmc/fabric/test/transfer/fluid/ItemTests.java +++ b/fabric-transfer-api-v1/src/testmod/java/net/fabricmc/fabric/test/transfer/unittests/ItemTests.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package net.fabricmc.fabric.test.transfer.fluid; +package net.fabricmc.fabric.test.transfer.unittests; import java.util.stream.IntStream; @@ -38,7 +38,7 @@ import net.fabricmc.fabric.api.transfer.v1.transaction.Transaction; /** * Tests for the item transfer APIs. */ -public class ItemTests { +class ItemTests { public static void run() { testInventoryWrappers(); testLimitedStackCountInventory(); diff --git a/fabric-transfer-api-v1/src/testmod/java/net/fabricmc/fabric/test/transfer/unittests/TransactionExceptionsTests.java b/fabric-transfer-api-v1/src/testmod/java/net/fabricmc/fabric/test/transfer/unittests/TransactionExceptionsTests.java new file mode 100644 index 000000000..3a7ebc801 --- /dev/null +++ b/fabric-transfer-api-v1/src/testmod/java/net/fabricmc/fabric/test/transfer/unittests/TransactionExceptionsTests.java @@ -0,0 +1,82 @@ +/* + * 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.unittests; + +import net.fabricmc.fabric.api.transfer.v1.transaction.Transaction; + +class TransactionExceptionsTests { + public static void run() { + testTransactionExceptions(); + } + + private static int callbacksInvoked = 0; + + /** + * Make sure that transaction global state stays valid in case of exceptions. + */ + private static void testTransactionExceptions() { + // Test exception inside the try. + ensureException(() -> { + try (Transaction tx = Transaction.openOuter()) { + tx.addCloseCallback((t, result) -> { + callbacksInvoked++; throw new RuntimeException("Close."); + }); + throw new RuntimeException("Inside try."); + } + }, "Exception should have propagated through the transaction."); + if (callbacksInvoked != 1) throw new AssertionError("Callback should have been invoked."); + + // Test exception inside the close. + callbacksInvoked = 0; + ensureException(() -> { + try (Transaction tx = Transaction.openOuter()) { + tx.addCloseCallback((t, result) -> { + callbacksInvoked++; throw new RuntimeException("Close 1."); + }); + tx.addCloseCallback((t, result) -> { + callbacksInvoked++; throw new RuntimeException("Close 2."); + }); + tx.addOuterCloseCallback(result -> { + callbacksInvoked++; throw new RuntimeException("Outer close 1."); + }); + tx.addOuterCloseCallback(result -> { + callbacksInvoked++; throw new RuntimeException("Outer close 2."); + }); + } + }, "Exceptions in close callbacks should be propagated through the transaction."); + if (callbacksInvoked != 4) throw new AssertionError("All 4 callbacks should have been invoked, only so many were: " + callbacksInvoked); + + // Test that transaction state is still OK after these exceptions. + try (Transaction tx = Transaction.openOuter()) { + tx.commit(); + } + } + + private static void ensureException(Runnable runnable, String message) { + boolean failed = false; + + try { + runnable.run(); + } catch (Throwable t) { + failed = true; + } + + if (!failed) { + throw new AssertionError(message); + } + } +} diff --git a/fabric-transfer-api-v1/src/main/java/net/fabricmc/fabric/mixin/transfer/HopperBlockEntityAccessor.java b/fabric-transfer-api-v1/src/testmod/java/net/fabricmc/fabric/test/transfer/unittests/UnitTestsInitializer.java similarity index 51% rename from fabric-transfer-api-v1/src/main/java/net/fabricmc/fabric/mixin/transfer/HopperBlockEntityAccessor.java rename to fabric-transfer-api-v1/src/testmod/java/net/fabricmc/fabric/test/transfer/unittests/UnitTestsInitializer.java index a4784fbb8..7b7b51e3b 100644 --- a/fabric-transfer-api-v1/src/main/java/net/fabricmc/fabric/mixin/transfer/HopperBlockEntityAccessor.java +++ b/fabric-transfer-api-v1/src/testmod/java/net/fabricmc/fabric/test/transfer/unittests/UnitTestsInitializer.java @@ -14,23 +14,19 @@ * limitations under the License. */ -package net.fabricmc.fabric.mixin.transfer; +package net.fabricmc.fabric.test.transfer.unittests; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.gen.Accessor; -import org.spongepowered.asm.mixin.gen.Invoker; +import org.apache.logging.log4j.LogManager; -import net.minecraft.block.entity.HopperBlockEntity; -import net.minecraft.inventory.Inventory; +import net.fabricmc.api.ModInitializer; -/** - * Hopper accessors, for use in {@link HopperBlockEntityMixin}. - */ -@Mixin(HopperBlockEntity.class) -public interface HopperBlockEntityAccessor extends Inventory { - @Invoker("setCooldown") - void fabric_callSetCooldown(int cooldown); - - @Accessor("lastTickTime") - long fabric_getLastTickTime(); +public class UnitTestsInitializer implements ModInitializer { + @Override + public void onInitialize() { + TransactionExceptionsTests.run(); + FluidTests.run(); + ItemTests.run(); + FluidItemTests.run(); + LogManager.getLogger("fabric-transfer-api-v1 testmod").info("Transfer API unit tests successful."); + } } diff --git a/fabric-transfer-api-v1/src/testmod/resources/fabric.mod.json b/fabric-transfer-api-v1/src/testmod/resources/fabric.mod.json index a2441ca41..aa6036370 100644 --- a/fabric-transfer-api-v1/src/testmod/resources/fabric.mod.json +++ b/fabric-transfer-api-v1/src/testmod/resources/fabric.mod.json @@ -10,7 +10,8 @@ }, "entrypoints": { "main": [ - "net.fabricmc.fabric.test.transfer.fluid.FluidTransferTest" + "net.fabricmc.fabric.test.transfer.ingame.TransferTestInitializer", + "net.fabricmc.fabric.test.transfer.unittests.UnitTestsInitializer" ] } }