Skip to content

Commit

Permalink
Dont provide ITEM_HANDLER for Inventory instances
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 committed Dec 28, 2023
1 parent 6c53905 commit aa38007
Showing 1 changed file with 38 additions and 17 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,19 @@

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.api.transfer.v1.storage.base.SidedStorageBlockEntity;
import net.fabricmc.fabric.impl.transfer.TransferApiImpl;
import net.minecraft.block.entity.BlockEntity;
import net.minecraft.item.ItemStack;
import net.minecraft.util.Identifier;
import net.minecraft.util.math.Direction;
import net.minecraftforge.common.MinecraftForge;
import net.minecraftforge.common.capabilities.Capability;
import net.minecraftforge.common.capabilities.ForgeCapabilities;
Expand All @@ -28,19 +38,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 @@ -51,6 +50,28 @@ public static void init() {
private static final Map<Storage<?>, LazyOptional<?>> CAPS = new HashMap<>();
public static final ThreadLocal<Boolean> COMPUTING_CAPABILITY_LOCK = ThreadLocal.withInitial(() -> false);

/**
* A variation of {@link ItemStorage#SIDED} that does not automatically convert everything that implements
* {@link net.minecraft.inventory.Inventory} into a {@code Storage}.
* <p>
* Used to ensure the capability system's semantics of "only expose explicitly registered stuff" are upheld.
* We assume that only blocks which provide an implementation of {@code Storage} or whose {@code BlockEntity}
* implements the Fabric specific interface {@link SidedStorageBlockEntity} count as explicit.
*/
private static final BlockApiLookup<Storage<ItemVariant>, @Nullable Direction> SIDED_WITHOUT_FALLBACK =
BlockApiLookup.get(new Identifier(TransferApiImpl.MODID, "sided_item_storage_without_fallback"), Storage.asClass(), Direction.class);

static {
// Support for SidedStorageBlockEntity.
SIDED_WITHOUT_FALLBACK.registerFallback((world, pos, state, blockEntity, direction) -> {
if (blockEntity instanceof SidedStorageBlockEntity sidedStorageBlockEntity) {
return sidedStorageBlockEntity.getItemStorage(direction);
}

return null;
});
}

private static void onAttachBlockEntityCapabilities(AttachCapabilitiesEvent<BlockEntity> event) {
BlockEntity be = event.getObject();
event.addCapability(new Identifier(TransferApiImpl.MODID, "forge_bridge"), new ICapabilityProvider() {
Expand All @@ -59,7 +80,7 @@ private static void onAttachBlockEntityCapabilities(AttachCapabilitiesEvent<Bloc
if (!COMPUTING_CAPABILITY_LOCK.get() && be.hasWorld()) {
if (cap == ForgeCapabilities.ITEM_HANDLER) {
COMPUTING_CAPABILITY_LOCK.set(true);
Storage<ItemVariant> storage = ItemStorage.SIDED.find(be.getWorld(), be.getPos(), be.getCachedState(), be, side);
Storage<ItemVariant> storage = SIDED_WITHOUT_FALLBACK.find(be.getWorld(), be.getPos(), be.getCachedState(), be, side);
COMPUTING_CAPABILITY_LOCK.set(false);
if (storage != null) {
return CAPS.computeIfAbsent(storage, s -> LazyOptional.of(() -> storage instanceof SlottedStorage<ItemVariant> slotted ? new SlottedItemStorageItemHandler(slotted) : new ItemStorageItemHandler(storage))).cast();
Expand Down

0 comments on commit aa38007

Please sign in to comment.