ItemStack enchantment not being removed when player inventory is open

Hey!

I return once again (I know, I know, still getting to grips with the API :wink: )

My issue this time is that when a player right-clicks with a pickaxe, axe or shovel, I apply a +efficiency 5 enchantment for a few seconds and then remove it. This works almost perfectly. Where it fails, is that the enchantment is not removed at the end of the period if the player has their inventory open.

I doubt it is really necessary here but I will add some code nonetheless.

Here is where I add the enchantment and schedule its removal.

@Listener
public void onPlayerSecondaryInteracted(InteractBlockEvent.Secondary.MainHand event, @First Player p){
    // @TODO:
    // Make this actually work. Differentiate between pickaxe, shovel and hatchet right-clicks.
    // Can multiple speed skills be going at the same time?

    final Optional<ItemStack> itemMainHand = p.getItemInHand(HandTypes.MAIN_HAND);

    if(!itemMainHand.isPresent())
        return;

    final String itemName = itemMainHand.get().getType().getId().toLowerCase();

    // @TODO:
    // Differentiate between when using a pickaxe, hatchet and shovel
    if(StringExtensions.containsAny(itemName,
        "pickaxe",
        "axe",
        "shovel")){

        Skills currentSkill = Skills.NONE;

        if(itemName.contains("pickaxe"))
            currentSkill = Skills.MINING;
        else if(itemName.contains("axe"))
            currentSkill = Skills.WOODCUTTING;
        else if(itemName.contains("shovel"))
            currentSkill = Skills.EXCAVATION;
        else
            logger.info("MineRPG -- No matching skill!");

        SkillsRightClicks currentRightClick = SkillsRightClicks.valueOf(currentSkill.toString());

        // @TODO:
        // Add to configuration file
        final int ENCHANTMENT_LEVELS_BONUS = 5;

        final int skillLevel = Database.DbSkills.getSkillLevel(p.getUniqueId().toString(), currentSkill);

        // @TODO:
        // This should be getRightClickDuration.
        final int abilityDuration = Database.DbSkills.getSkillLevel(p.getUniqueId().toString(), currentSkill);

        final LocalDateTime nextUseTime = Database.DbSkills.getSkillRightClickNextUse(p.getUniqueId().toString(), currentRightClick);

        if(!LocalDateTime.now().isAfter(nextUseTime)){
            p.sendMessage(Text.of("You attempt to use your SPEED " + currentSkill.toString() + " skill however you are too tired! (" + LocalDateTime.now().until(nextUseTime, ChronoUnit.SECONDS) + "s)"));
            return;
        }

        final int itemStartEnchantmentLevel = ItemStackExtensions.getEnchantmentLevel(
            itemMainHand.get(),
            EnchantmentTypes.EFFICIENCY
        );

        ItemStack currentItem = itemMainHand.get();
        ItemStackExtensions.addEnchantment(currentItem, EnchantmentTypes.EFFICIENCY, itemStartEnchantmentLevel + ENCHANTMENT_LEVELS_BONUS);

        Database.DbSkills.setSkillRightClickAsUsed(p.getUniqueId().toString(), currentRightClick);

        final Skills finalCurrentSkill = currentSkill;

        p.sendMessage(Text.of("Your SPEED " + finalCurrentSkill.toString() + " has started! (" + abilityDuration + "s)"));

        Task.builder().execute(() -> {
            p.sendMessage(Text.of("Your SPEED " + finalCurrentSkill.toString() + " has ended!"));

            // I specifically check for not 0 here as opposed to less than 0 so that if there are any
            // plugins that add a negative efficiency enchantment (if that even works) we do not conflict
            // with them
            if(itemStartEnchantmentLevel != 0)
                ItemStackExtensions.addEnchantment(currentItem, EnchantmentTypes.EFFICIENCY, itemStartEnchantmentLevel);
            else
                ItemStackExtensions.removeEnchantment(currentItem, EnchantmentTypes.EFFICIENCY);
        })
        .delay(abilityDuration, TimeUnit.SECONDS)
        .submit(pluginContainer);
    }

Here is my ItemStackExtensions.java script:

package io.github.carlhalstead.minerpg.helpers;

import org.spongepowered.api.data.key.Keys;
import org.spongepowered.api.data.manipulator.mutable.item.EnchantmentData;
import org.spongepowered.api.item.enchantment.Enchantment;
import org.spongepowered.api.item.enchantment.EnchantmentType;
import org.spongepowered.api.item.inventory.ItemStack;

import java.util.List;
import java.util.Optional;

public abstract class ItemStackExtensions {

    /**
     * @param item - Item to check enchantments of
     * @param enchantmentType - Specific enchantment to get the level of
     * @return Enchantment level, 0 if it does not exist on the item
     */
    public static int getEnchantmentLevel(ItemStack item, EnchantmentType enchantmentType){
        Optional<List<Enchantment>> opEnchantments = item.get(Keys.ITEM_ENCHANTMENTS);

        if(!opEnchantments.isPresent())
            return 0;

        List<Enchantment> currentEnchantments = opEnchantments.get();

        for (Enchantment enchantment : currentEnchantments) {
            if (enchantment.getType() == enchantmentType) {
                return enchantment.getLevel();
            }
        }

        return 0;
    }

    public static void addEnchantment(ItemStack item, Enchantment enchantment){
        EnchantmentData itemEnchantments = item.getOrCreate(EnchantmentData.class).get();
        itemEnchantments.set(itemEnchantments.enchantments().add(enchantment));

        item.offer(itemEnchantments);
    }

    public static void addEnchantment(ItemStack item, EnchantmentType enchantmentType, int enchantmentLevel){
        final Enchantment newEnchantment = Enchantment.of(
                enchantmentType,
                enchantmentLevel
        );

        addEnchantment(item, newEnchantment);
    }

    public static void removeEnchantment(ItemStack item, EnchantmentType enchantmentType){
        EnchantmentData itemEnchantments = item.getOrCreate(EnchantmentData.class).get();

        for (Enchantment enchantment : itemEnchantments.getListValue()) {
            if(enchantment.getType() == enchantmentType){
                itemEnchantments.remove(enchantment);
                break;
            }
        }

        item.offer(itemEnchantments);
    }
}

If there is any other code you require, let me know!

Thanks!

Still looking for a way to fix this! I have no ideas.

Not sure if this would work but have you attempted to create a snapshot of the itemstack, do the modifications to the snapshot and then replace the old itemstack with the new one in the inventory … Or in your case the inventory slot in the main hand

I will give that a go soon and report back! Thanks for the suggestion!