satisfyu / Let-s-Do-Hub

A collection of all things Let's Do: Share bugs, suggest improvements, or find links to perhaps yet unknown Let's Do Mods.
3 stars 0 forks source link

Ticking player with Spice of Fabric lunch box #272

Open valiray opened 2 weeks ago

valiray commented 2 weeks ago

Minecraft Version

1.20.1

Mod

Candlelight

Mod Version

1.2.13

Latest Version

Issue Description

when eating items from Candlelight inside the Spice of Fabric lunch box the game will crash with a Ticking player error if eat from it

Steps to Reproduce

put an food item with nbt data in the lunch box try to eat and crash/dc

Logs

https://mclo.gs/Xjt9XWM

Minimal Instance Test

Check for Similar Issues

Pandaismyname1 commented 1 week ago

Can confirm this issue. From my testing, it also has trouble with Sophisticated Backpacks.

From my research, it happens because the mod expects the item slot from which the item is consumed to be the in the player's inventory. After reading the code from EffectFoodBlockItem

@Override
    public @NotNull ItemStack finishUsingItem(ItemStack stack, Level world, LivingEntity user) {
        if (!world.isClientSide) {
            List<Pair<MobEffectInstance, Float>> effects = EffectFoodHelper.getEffects(stack);
            for (Pair<MobEffectInstance, Float> effect : effects) {
                if (effect.getFirst() != null && world.random.nextFloat() < effect.getSecond()) {
                    user.addEffect(new MobEffectInstance(effect.getFirst()));
                }
            }
        }

        int slot = -1;
        Inventory playerInventory = null;
        if (user instanceof Player player && !player.isCreative()) {
            playerInventory = player.getInventory();
            slot = playerInventory.findSlotMatchingUnusedItem(stack);
        }
        ItemStack returnStack =  super.finishUsingItem(stack, world, user);
        int stage = EffectFoodHelper.getStage(stack);
        if (playerInventory != null && stage < this.foodStages) {
            ItemStack itemStack = EffectFoodHelper.setStage(new ItemStack(this), stage + 1);
            if (playerInventory.getItem(slot).isEmpty()) {
                playerInventory.add(slot, itemStack);
            }
            else {
                slot = playerInventory.getSlotWithRemainingSpace(itemStack);
                playerInventory.add(slot, itemStack);
            }
        }
        return returnStack;
    }

It starts with slot -1, and tries to find the slot in the player inventory, but it fails to do so, because the item was not consumed from the inventory, so it tries to call playerInventory.getItem(-1).isEmpty() which is undefined behaviour.

A fix would be to gracefully fail by checking if the slotIndex is -1. This is a quick and dirty fix. Another idea would be to get the correct inventory from which the food item has been consumed, but that might prove a bit more challenging.