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