mirror of
https://github.com/MinecraftForge/MinecraftForge.git
synced 2026-11-11 15:57:32 +00:00
Default IItemHandler capability for shulker box itemstacks (#8827)
Co-authored-by: LexManos <LexManos@gmail.com>
This commit is contained in:
1 parent
aab0e4c82e
commit
a2b35cae92
2 files changed
+241
-1
No files matched your search
@@ -41,6 +41,7 @@ import net.minecraft.network.chat.Component;
|
||||
import net.minecraft.world.level.Level;
|
||||
import net.minecraftforge.common.ToolAction;
|
||||
import net.minecraftforge.common.ToolActions;
|
||||
import net.minecraftforge.items.wrapper.ShulkerItemStackInvWrapper;
|
||||
import net.minecraftforge.registries.IForgeRegistry;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
@@ -655,7 +656,8 @@ public interface IForgeItem
|
||||
@Nullable
|
||||
default net.minecraftforge.common.capabilities.ICapabilityProvider initCapabilities(ItemStack stack, @Nullable CompoundTag nbt)
|
||||
{
|
||||
return null;
|
||||
var ret = ShulkerItemStackInvWrapper.createDefaultProvider(stack);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -0,0 +1,238 @@
|
||||
/*
|
||||
* Copyright (c) Forge Development LLC and contributors
|
||||
* SPDX-License-Identifier: LGPL-2.1-only
|
||||
*/
|
||||
|
||||
package net.minecraftforge.items.wrapper;
|
||||
|
||||
import net.minecraft.core.Direction;
|
||||
import net.minecraft.core.NonNullList;
|
||||
import net.minecraft.nbt.CompoundTag;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.world.ContainerHelper;
|
||||
import net.minecraft.world.item.BlockItem;
|
||||
import net.minecraft.world.item.Item;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import net.minecraft.world.item.Items;
|
||||
import net.minecraft.world.level.block.entity.BlockEntityType;
|
||||
import net.minecraftforge.common.capabilities.Capability;
|
||||
import net.minecraftforge.common.capabilities.ICapabilityProvider;
|
||||
import net.minecraftforge.common.util.LazyOptional;
|
||||
import net.minecraftforge.items.CapabilityItemHandler;
|
||||
import net.minecraftforge.items.IItemHandler;
|
||||
import net.minecraftforge.items.IItemHandlerModifiable;
|
||||
import net.minecraftforge.items.ItemHandlerHelper;
|
||||
import net.minecraftforge.registries.ForgeRegistries;
|
||||
import org.jetbrains.annotations.ApiStatus;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
|
||||
@ApiStatus.Internal
|
||||
public class ShulkerItemStackInvWrapper implements IItemHandlerModifiable, ICapabilityProvider
|
||||
{
|
||||
@ApiStatus.Internal
|
||||
@Nullable
|
||||
public static ICapabilityProvider createDefaultProvider(ItemStack itemStack)
|
||||
{
|
||||
var item = itemStack.getItem();
|
||||
if (item == Items.SHULKER_BOX ||
|
||||
item == Items.BLACK_SHULKER_BOX ||
|
||||
item == Items.BLUE_SHULKER_BOX ||
|
||||
item == Items.BROWN_SHULKER_BOX ||
|
||||
item == Items.CYAN_SHULKER_BOX ||
|
||||
item == Items.GRAY_SHULKER_BOX ||
|
||||
item == Items.GREEN_SHULKER_BOX ||
|
||||
item == Items.LIGHT_BLUE_SHULKER_BOX ||
|
||||
item == Items.LIGHT_GRAY_SHULKER_BOX ||
|
||||
item == Items.LIME_SHULKER_BOX ||
|
||||
item == Items.MAGENTA_SHULKER_BOX ||
|
||||
item == Items.ORANGE_SHULKER_BOX ||
|
||||
item == Items.PINK_SHULKER_BOX ||
|
||||
item == Items.PURPLE_SHULKER_BOX ||
|
||||
item == Items.RED_SHULKER_BOX ||
|
||||
item == Items.WHITE_SHULKER_BOX ||
|
||||
item == Items.YELLOW_SHULKER_BOX
|
||||
)
|
||||
return new ShulkerItemStackInvWrapper(itemStack);
|
||||
return null;
|
||||
}
|
||||
|
||||
private final ItemStack stack;
|
||||
private final LazyOptional<IItemHandler> holder = LazyOptional.of(() -> this);
|
||||
|
||||
private CompoundTag cachedTag;
|
||||
private NonNullList<ItemStack> itemStacksCache;
|
||||
|
||||
private ShulkerItemStackInvWrapper(ItemStack stack)
|
||||
{
|
||||
this.stack = stack;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getSlots()
|
||||
{
|
||||
return 27;
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public ItemStack getStackInSlot(int slot)
|
||||
{
|
||||
validateSlotIndex(slot);
|
||||
return getItemList().get(slot);
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public ItemStack insertItem(int slot, @NotNull ItemStack stack, boolean simulate)
|
||||
{
|
||||
if (stack.isEmpty())
|
||||
return ItemStack.EMPTY;
|
||||
|
||||
if (!isItemValid(slot, stack))
|
||||
return stack;
|
||||
|
||||
validateSlotIndex(slot);
|
||||
|
||||
NonNullList<ItemStack> itemStacks = getItemList();
|
||||
|
||||
ItemStack existing = itemStacks.get(slot);
|
||||
|
||||
int limit = Math.min(getSlotLimit(slot), stack.getMaxStackSize());
|
||||
|
||||
if (!existing.isEmpty())
|
||||
{
|
||||
if (!ItemHandlerHelper.canItemStacksStack(stack, existing))
|
||||
return stack;
|
||||
|
||||
limit -= existing.getCount();
|
||||
}
|
||||
|
||||
if (limit <= 0)
|
||||
return stack;
|
||||
|
||||
boolean reachedLimit = stack.getCount() > limit;
|
||||
|
||||
if (!simulate)
|
||||
{
|
||||
if (existing.isEmpty())
|
||||
{
|
||||
itemStacks.set(slot, reachedLimit ? ItemHandlerHelper.copyStackWithSize(stack, limit) : stack);
|
||||
}
|
||||
else
|
||||
{
|
||||
existing.grow(reachedLimit ? limit : stack.getCount());
|
||||
}
|
||||
setItemList(itemStacks);
|
||||
}
|
||||
|
||||
return reachedLimit ? ItemHandlerHelper.copyStackWithSize(stack, stack.getCount()- limit) : ItemStack.EMPTY;
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public ItemStack extractItem(int slot, int amount, boolean simulate)
|
||||
{
|
||||
NonNullList<ItemStack> itemStacks = getItemList();
|
||||
if (amount == 0)
|
||||
return ItemStack.EMPTY;
|
||||
|
||||
validateSlotIndex(slot);
|
||||
|
||||
ItemStack existing = itemStacks.get(slot);
|
||||
|
||||
if (existing.isEmpty())
|
||||
return ItemStack.EMPTY;
|
||||
|
||||
int toExtract = Math.min(amount, existing.getMaxStackSize());
|
||||
|
||||
if (existing.getCount() <= toExtract)
|
||||
{
|
||||
if (!simulate)
|
||||
{
|
||||
itemStacks.set(slot, ItemStack.EMPTY);
|
||||
setItemList(itemStacks);
|
||||
return existing;
|
||||
}
|
||||
else
|
||||
{
|
||||
return existing.copy();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!simulate)
|
||||
{
|
||||
itemStacks.set(slot, ItemHandlerHelper.copyStackWithSize(existing, existing.getCount() - toExtract));
|
||||
setItemList(itemStacks);
|
||||
}
|
||||
|
||||
return ItemHandlerHelper.copyStackWithSize(existing, toExtract);
|
||||
}
|
||||
}
|
||||
|
||||
private void validateSlotIndex(int slot)
|
||||
{
|
||||
if (slot < 0 || slot >= getSlots())
|
||||
throw new RuntimeException("Slot " + slot + " not in valid range - [0," + getSlots() + ")");
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getSlotLimit(int slot)
|
||||
{
|
||||
return 64;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isItemValid(int slot, @NotNull ItemStack stack)
|
||||
{
|
||||
return stack.getItem().canFitInsideContainerItems();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setStackInSlot(int slot, @NotNull ItemStack stack)
|
||||
{
|
||||
validateSlotIndex(slot);
|
||||
if (!isItemValid(slot, stack)) throw new RuntimeException("Invalid stack " + stack + " for slot " + slot + ")");
|
||||
NonNullList<ItemStack> itemStacks = getItemList();
|
||||
itemStacks.set(slot, stack);
|
||||
setItemList(itemStacks);
|
||||
}
|
||||
|
||||
private NonNullList<ItemStack> getItemList()
|
||||
{
|
||||
CompoundTag rootTag = BlockItem.getBlockEntityData(this.stack);
|
||||
if (cachedTag == null || !cachedTag.equals(rootTag))
|
||||
itemStacksCache = refreshItemList(rootTag);
|
||||
return itemStacksCache;
|
||||
}
|
||||
|
||||
private NonNullList<ItemStack> refreshItemList(CompoundTag rootTag)
|
||||
{
|
||||
NonNullList<ItemStack> itemStacks = NonNullList.withSize(getSlots(), ItemStack.EMPTY);
|
||||
if (rootTag != null && rootTag.contains("Items", CompoundTag.TAG_LIST))
|
||||
{
|
||||
ContainerHelper.loadAllItems(rootTag, itemStacks);
|
||||
}
|
||||
cachedTag = rootTag;
|
||||
return itemStacks;
|
||||
}
|
||||
|
||||
private void setItemList(NonNullList<ItemStack> itemStacks)
|
||||
{
|
||||
CompoundTag existing = BlockItem.getBlockEntityData(this.stack);
|
||||
CompoundTag rootTag = ContainerHelper.saveAllItems(existing == null ? new CompoundTag() : existing, itemStacks);
|
||||
BlockItem.setBlockEntityData(this.stack, BlockEntityType.SHULKER_BOX, rootTag);
|
||||
cachedTag = rootTag;
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public <T> LazyOptional<T> getCapability(@NotNull Capability<T> cap, @Nullable Direction side)
|
||||
{
|
||||
return CapabilityItemHandler.ITEM_HANDLER_CAPABILITY.orEmpty(cap, this.holder);
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user