Jump to content

Item doesn't retain NBT data when dropped on the ground


xand3s

Recommended Posts

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.

Edited by xand3s
indistinguishable code blocks
Link to comment
Share on other sites

- Removed for bad formatting -

Edited by warjort

Boilerplate:

If you don't post your logs/debug.log we can't help you. For curseforge you need to enable the forge debug.log in its minecraft settings. You should also post your crash report if you have one.

If there is no error in the log file and you don't have a crash report then post the launcher_log.txt from the minecraft folder. Again for curseforge this will be in your curseforge/minecraft/Install

Large files should be posted to a file sharing site like https://gist.github.com  You should also read the support forum sticky post.

Link to comment
Share on other sites

 @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);
                                      
        // HERE you put your inventory in a subtag                              
        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++) {

            // HERE you are trying to read the inventory from the top level tag?
            inventoryNbt = nbt.getCompound(String.valueOf(i));
            pocketInventory.add(i - 1, new DimensionalStack());
            pocketInventory.get(i - 1).loadNBTData(inventoryNbt);
        }
    }

 

Boilerplate:

If you don't post your logs/debug.log we can't help you. For curseforge you need to enable the forge debug.log in its minecraft settings. You should also post your crash report if you have one.

If there is no error in the log file and you don't have a crash report then post the launcher_log.txt from the minecraft folder. Again for curseforge this will be in your curseforge/minecraft/Install

Large files should be posted to a file sharing site like https://gist.github.com  You should also read the support forum sticky post.

Link to comment
Share on other sites

You can use the EntityJoinLevelEvent and check if it is an ItemEntity to see what NBT its ItemStack has.

You can also see if your NBT survives saving and reloading the game. If it does not, you are not modifying the correct ItemStack on the server.

Edited by warjort

Boilerplate:

If you don't post your logs/debug.log we can't help you. For curseforge you need to enable the forge debug.log in its minecraft settings. You should also post your crash report if you have one.

If there is no error in the log file and you don't have a crash report then post the launcher_log.txt from the minecraft folder. Again for curseforge this will be in your curseforge/minecraft/Install

Large files should be posted to a file sharing site like https://gist.github.com  You should also read the support forum sticky post.

Link to comment
Share on other sites

So, for future somebody who stumbles upon this, besides the error pointed out I've also didn't assign a value to class field in 

public void loadNBTData(CompoundTag nbt) {
        ItemStack deserializedItemStack = ItemStack.of(nbt.getCompound("topStack"));
        this.fullStackCount = nbt.getInt("fullStackCount");
    }

 

Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Unfortunately, your content contains terms that we do not allow. Please edit your content to remove the highlighted words below.
Reply to this topic...

×   Pasted as rich text.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.



×
×
  • Create New...

Important Information

By using this site, you agree to our Terms of Use.