Skip to content

Commit

Permalink
Dont provide ITEM_HANDLER for Inventory instances (#88)
Browse files Browse the repository at this point in the history
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 <[email protected]>
  • Loading branch information
niklaswimmer authored Dec 29, 2023
1 parent 6c53905 commit b00938e
Show file tree
Hide file tree
Showing 2 changed files with 44 additions and 17 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,13 @@ private ItemStorage() {

static {
// Composter support.
ItemStorage.SIDED.registerForBlocks((world, pos, state, blockEntity, direction) -> ComposterWrapper.get(world, pos, direction), Blocks.COMPOSTER);
ItemStorage.SIDED.registerForBlocks((world, pos, state, blockEntity, direction) -> {
// FFAPI: do not provide composter compat if queried from our capability provider
if (TransferApiForgeCompat.COMPUTING_CAPABILITY_LOCK.get()) {
return null;
}
return ComposterWrapper.get(world, pos, direction);
}, Blocks.COMPOSTER);

// Support for SidedStorageBlockEntity.
ItemStorage.SIDED.registerFallback((world, pos, state, blockEntity, direction) -> {
Expand All @@ -109,6 +115,11 @@ private ItemStorage() {

// Register Inventory fallback.
ItemStorage.SIDED.registerFallback((world, pos, state, blockEntity, direction) -> {
// FFAPI: do not provide Inventory instace compat if queried from our capability provider
if (TransferApiForgeCompat.COMPUTING_CAPABILITY_LOCK.get()) {
return null;
}

Inventory inventoryToWrap = null;

if (state.getBlock() instanceof InventoryProvider provider) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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() {
Expand All @@ -49,6 +50,21 @@ public static void init() {
}

private static final Map<Storage<?>, 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}.
* <p>
* 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.
* <p>
* 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<Boolean> COMPUTING_CAPABILITY_LOCK = ThreadLocal.withInitial(() -> false);

private static void onAttachBlockEntityCapabilities(AttachCapabilitiesEvent<BlockEntity> event) {
Expand Down

0 comments on commit b00938e

Please sign in to comment.