PocketDimensionItemHandler
public class PocketDimensionItemHandler implements IItemHandler, INBTSerializable<CompoundTag> {
private static final String SLOT_COUNT = "slotCount";
private static final String STACK_SIZE = "stackSize";
private static final String POCKET_INVENTORY = "pocketInventory";
protected NonNullList<DimensionalStack> pocketInventory;
private int slotCount;
private long stackCapacity;
private final ItemStack itemStack;
public PocketDimensionItemHandler(ItemStack itemStack, int slotCount, long stackSize) {
this.itemStack = itemStack;
if (itemStack.hasTag()) {
deserializeNBT(itemStack.getOrCreateTag());
} else {
this.slotCount = slotCount;
this.stackCapacity = stackSize;
pocketInventory = NonNullList.create();
for (int i = 0; i < slotCount; i++) {
pocketInventory.add(i, new DimensionalStack(ItemStack.EMPTY));
}
}
}
@Override
public int getSlots() {
return 0;
}
@Override
public @NotNull ItemStack getStackInSlot(int slot) {
return null;
}
@Override
public @NotNull ItemStack insertItem(int slot, @NotNull ItemStack addedStack, boolean simulate) {
if (addedStack.isEmpty()) return ItemStack.EMPTY;
if (slot < 0 || slot > slotCount) throw new IndexOutOfBoundsException("Slot is not available");
DimensionalStack dimensionalStack = pocketInventory.get(slot);
ItemStack topStack = dimensionalStack.getTopStack();
if (topStack.isEmpty()) {
dimensionalStack.setTopStack(addedStack);
return ItemStack.EMPTY;
}
boolean isEligibleForNewStack = topStack.getCount() + addedStack.getCount() > topStack.getMaxStackSize();
long dimensionalStackSize = ((long) topStack.getMaxStackSize() * dimensionalStack.getFullStackCount()) + topStack.getCount();
long remainingCapacity = stackCapacity - dimensionalStackSize;
if (isEligibleForNewStack) {
if (remainingCapacity < topStack.getMaxStackSize()) {
addedStack.shrink((int) remainingCapacity);
topStack.setCount(topStack.getMaxStackSize());
dimensionalStack.setTopStack(topStack);
return addedStack;
} else {
int spaceLeft = calculateAvailableSpace(topStack);
addedStack.shrink(spaceLeft); // shrink added stack by amount left in topStack
topStack = addedStack.copy(); // make what's left in addedStack to topStack
dimensionalStack.setTopStack(topStack);
dimensionalStack.setFullStackCount(dimensionalStack.getFullStackCount() + 1); // increment by 1 fullStackCount
return ItemStack.EMPTY;
}
} else {
topStack.setCount(topStack.getCount() + addedStack.getCount());
dimensionalStack.setTopStack(topStack);
return ItemStack.EMPTY;
}
}
@Override
public @NotNull ItemStack extractItem(int slot, int amount, boolean simulate) {
return null;
}
@Override
public int getSlotLimit(int slot) {
return 0;
}
@Override
public boolean isItemValid(int slot, @NotNull ItemStack stack) {
return false;
}
@Override
public CompoundTag serializeNBT() {
CompoundTag nbt = new CompoundTag();
CompoundTag inventoryNbt = new CompoundTag();
for (int i = 1; i <= slotCount; i++) {
inventoryNbt.put(String.valueOf(i), pocketInventory.get(i - 1).saveNBTData());
}
nbt.putInt(SLOT_COUNT, slotCount);
nbt.putLong(STACK_SIZE, stackCapacity);
nbt.put(POCKET_INVENTORY, inventoryNbt);
return nbt;
}
@Override
public void deserializeNBT(CompoundTag nbt) {
this.slotCount = nbt.getInt(SLOT_COUNT);
this.stackCapacity = nbt.getLong(STACK_SIZE);
CompoundTag inventoryNbt;
pocketInventory = NonNullList.create();
for (int i = 1; i <= slotCount; i++) {
inventoryNbt = nbt.getCompound(String.valueOf(i));
pocketInventory.add(i - 1, new DimensionalStack());
pocketInventory.get(i - 1).loadNBTData(inventoryNbt);
}
}
public static int calculateAvailableSpace(ItemStack stack) {
return stack.getMaxStackSize() - stack.getCount();
}
}
PocketDimensionProvider
public class PocketDimensionProvider implements ICapabilityProvider, INBTSerializable<CompoundTag> {
private final ItemStack itemStack;
public static final Capability<PocketDimensionItemHandler> POCKET_DIMENSION = CapabilityManager.get(new CapabilityToken<>() {
});
private PocketDimensionItemHandler pocketDimension = null;
private final LazyOptional<IItemHandler> optionalData = LazyOptional.of(this::createPocketDimension);
public PocketDimensionProvider(ItemStack itemStack) {
this.itemStack = itemStack;
}
private PocketDimensionItemHandler createPocketDimension() {
if (pocketDimension == null) {
pocketDimension = new PocketDimensionItemHandler(itemStack, 9, 2048);
}
return pocketDimension;
}
@Nonnull
@Override
public <T> LazyOptional<T> getCapability(@Nonnull Capability<T> cap) {
if (cap == POCKET_DIMENSION) {
return optionalData.cast();
}
return LazyOptional.empty();
}
@Nonnull
@Override
public <T> LazyOptional<T> getCapability(@Nonnull Capability<T> cap, @Nullable Direction side) {
return getCapability(cap);
}
void invalidate() {
this.optionalData.invalidate();
}
@Override
public CompoundTag serializeNBT() {
return createPocketDimension().serializeNBT();
}
@Override
public void deserializeNBT(CompoundTag nbt) {
createPocketDimension().deserializeNBT(nbt);
}
}
PocketItem
public class PocketItem extends Item implements MenuProvider {
public PocketItem(Properties pProperties) {
super(pProperties);
}
@Override
public InteractionResult useOn(UseOnContext pContext) {
Level pLevel = pContext.getLevel();
if (!pLevel.isClientSide) {
Player pPlayer = pContext.getPlayer();
InteractionHand pUsedHand = pContext.getHand();
BlockPos pos = pContext.getClickedPos();
BlockState clickedBlock = pLevel.getBlockState(pos);
ItemStack itemStack = new ItemStack(clickedBlock.getBlock(), 10);
ItemStack heldItem = pPlayer.getItemInHand(pUsedHand);
@NotNull LazyOptional<PocketDimensionItemHandler> pocketCap = heldItem.getCapability(PocketDimensionProvider.POCKET_DIMENSION);
Random rand = new Random();
pocketCap.ifPresent((pocketDimension) -> {
pocketDimension.insertItem(rand.nextInt(9), itemStack, false);
});
}
return InteractionResult.sidedSuccess(pLevel.isClientSide());
}
@Override
public Component getDisplayName() {
return null;
}
@Nullable
@Override
public AbstractContainerMenu createMenu(int pContainerId, Inventory pPlayerInventory, Player pPlayer) {
return null;
}
@Nullable
@Override
public ICapabilityProvider initCapabilities(ItemStack stack, @Nullable CompoundTag nbt) {
return new PocketDimensionProvider(stack);
}
}
DimensionalStack
public class DimensionalStack {
private ItemStack topStack;
private int fullStackCount;
public DimensionalStack() {
topStack = ItemStack.EMPTY;
}
public DimensionalStack(ItemStack topStack) {
this.topStack = topStack;
fullStackCount = 0;
}
public DimensionalStack(ItemStack topStack, int fullStackCount) {
this.topStack = topStack;
this.fullStackCount = fullStackCount;
}
public ItemStack getTopStack() {
return topStack;
}
public void setTopStack(ItemStack topStack) {
this.topStack = topStack;
}
public int getFullStackCount() {
return fullStackCount;
}
public void setFullStackCount(int fullStackCount) {
this.fullStackCount = fullStackCount;
}
public CompoundTag saveNBTData() {
CompoundTag nbt = new CompoundTag();
nbt.put("topStack", topStack.serializeNBT());
nbt.putInt("fullStackCount", fullStackCount);
return nbt;
}
public void loadNBTData(CompoundTag nbt) {
ItemStack deserializedItemStack = ItemStack.of(nbt.getCompound("topStack"));
this.fullStackCount = nbt.getInt("fullStackCount");
}
}
Hello, I have a problem understanding why the item doesn't retain it's NBT data when dropped on the ground and picked back up, to my understanding I'm calling the method to insert items in server enviroment, but should I create and send sync packet server -> client? Please ignore quality of the code and it's nonsense I'm trying to understand things.