From d456073807460b6e71d6121874be82d52cfd178b Mon Sep 17 00:00:00 2001 From: Niklas Wimmer Date: Thu, 28 Dec 2023 11:54:59 +0100 Subject: [PATCH] Dont provide ITEM_HANDLER for Inventory instances FFAPI's job is only to bridge implementation of the Fabric transfer API to the capability system, nothing more. Fabric's own lookup API considers Inventory instances to be a valid Storage because otherwise it would have no compat with Vanilla inventories. Forge however chose a different path by explicitly providing capability providers for selected Vanilla blocks. As such it is Forge's responsibility to bridge Vanilla blocks to the capability system and not ours by accidentally making everything that implements Inventory provide an ITEM_HANDLER capability. Fixes #87 Signed-off-by: Niklas Wimmer --- .../api/transfer/v1/item/ItemStorage.java | 4 ++ .../compat/TransferApiForgeCompat.java | 48 ++++++++++++------- 2 files changed, 36 insertions(+), 16 deletions(-) diff --git a/fabric-transfer-api-v1/src/main/java/net/fabricmc/fabric/api/transfer/v1/item/ItemStorage.java b/fabric-transfer-api-v1/src/main/java/net/fabricmc/fabric/api/transfer/v1/item/ItemStorage.java index 2f80ef77e..093faf89f 100644 --- a/fabric-transfer-api-v1/src/main/java/net/fabricmc/fabric/api/transfer/v1/item/ItemStorage.java +++ b/fabric-transfer-api-v1/src/main/java/net/fabricmc/fabric/api/transfer/v1/item/ItemStorage.java @@ -109,6 +109,10 @@ private ItemStorage() { // Register Inventory fallback. ItemStorage.SIDED.registerFallback((world, pos, state, blockEntity, direction) -> { + if (TransferApiForgeCompat.COMPUTING_CAPABILITY_LOCK.get()) { + return null; + } + Inventory inventoryToWrap = null; if (state.getBlock() instanceof InventoryProvider provider) { diff --git a/fabric-transfer-api-v1/src/main/java/net/fabricmc/fabric/impl/transfer/compat/TransferApiForgeCompat.java b/fabric-transfer-api-v1/src/main/java/net/fabricmc/fabric/impl/transfer/compat/TransferApiForgeCompat.java index 602ceb542..f84a5fb16 100644 --- a/fabric-transfer-api-v1/src/main/java/net/fabricmc/fabric/impl/transfer/compat/TransferApiForgeCompat.java +++ b/fabric-transfer-api-v1/src/main/java/net/fabricmc/fabric/impl/transfer/compat/TransferApiForgeCompat.java @@ -16,9 +16,21 @@ package net.fabricmc.fabric.impl.transfer.compat; -import java.util.HashMap; -import java.util.Map; - +import net.fabricmc.fabric.api.lookup.v1.block.BlockApiLookup; +import net.fabricmc.fabric.api.transfer.v1.fluid.FluidStorage; +import net.fabricmc.fabric.api.transfer.v1.fluid.FluidVariant; +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.SlottedStorage; +import net.fabricmc.fabric.api.transfer.v1.storage.Storage; +import net.fabricmc.fabric.impl.transfer.TransferApiImpl; +import net.minecraft.block.BlockState; +import net.minecraft.block.entity.BlockEntity; +import net.minecraft.item.ItemStack; +import net.minecraft.util.Identifier; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.Direction; +import net.minecraft.world.World; import net.minecraftforge.common.MinecraftForge; import net.minecraftforge.common.capabilities.Capability; import net.minecraftforge.common.capabilities.ForgeCapabilities; @@ -28,19 +40,8 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import net.minecraft.block.entity.BlockEntity; -import net.minecraft.item.ItemStack; -import net.minecraft.util.Identifier; -import net.minecraft.util.math.Direction; - -import net.fabricmc.fabric.api.transfer.v1.context.ContainerItemContext; -import net.fabricmc.fabric.api.transfer.v1.fluid.FluidStorage; -import net.fabricmc.fabric.api.transfer.v1.fluid.FluidVariant; -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.SlottedStorage; -import net.fabricmc.fabric.api.transfer.v1.storage.Storage; -import net.fabricmc.fabric.impl.transfer.TransferApiImpl; +import java.util.HashMap; +import java.util.Map; public class TransferApiForgeCompat { public static void init() { @@ -49,6 +50,21 @@ public static void init() { } private static final Map, LazyOptional> CAPS = new HashMap<>(); + + /** + * This lock has two purposes: avoiding recursive calls between {@link ICapabilityProvider#getCapability(Capability) getCapability} + * and {@link BlockApiLookup#find(World, BlockPos, BlockState, BlockEntity, Object) find} as well as influencing the + * behavior of {@code find} if it was called from {@code getCapability}. + *

+ * The recursive calls occur because our capabilities providers need to access the block lookup API to check if they + * should provide a capability (for Fabric from Forge compat), but the block lookup API needs to query the + * capabilities (for Forge from Fabric compat). This lock is set immediately before one API calls the other, which + * then disables the call from the other API to the first, breaking the recursion. + *

+ * Additionally, this lock is used to conditionally disable some of the block lookup API's fallback providers, if + * they got invoked by a capability provider. This is needed because Fabric has fallback providers for many Vanilla + * things, but Forge already implements their own compat for those. + */ public static final ThreadLocal COMPUTING_CAPABILITY_LOCK = ThreadLocal.withInitial(() -> false); private static void onAttachBlockEntityCapabilities(AttachCapabilitiesEvent event) {