Solved PrepareAnvilEvent sending 3 messages :/

Discussion in 'Spigot Plugin Development' started by 6u5t4v, Jan 11, 2020.

  1. PrepareAnvilEvent sends a message foreach slot in the inventory and since there are 3 slots the player also gets the message 3 times. How do I send a message to the player, but have the message send once instead of the 3 times ?
     
    • Like Like x 1
  2. Do they all contain the exact same info? If that's not the case you could check if one of the events triggered contains a specific thing the others don't have, and then run your code.
     
  3. What if they do contain the exact same info, because in some cases they do.
     
    #3 6u5t4v, Jan 11, 2020
    Last edited: Jan 11, 2020
    • Like Like x 1
  4. Hm, well you could do a sorta scuffed solution of setting a boolean to true and starting a delayed task every time the event gets triggered, and only if the boolean is false you run the code. (And let the delayed task set the boolean to false after x amount of time).
    I currently can't come up with a better solution...
     
    • Funny Funny x 1
  5. I could do that, but as you say its pretty scuffed xD
     
    • Like Like x 1
  6. I still need help with fixing this problem :/
     
    • Like Like x 1
  7. I hope this is enough
    Code (Java):
    if (slot1.getEnchantments().containsKey(enchantment)) {
                            int slot1EnchantLevel = slot1.getEnchantmentLevel(enchantment);
                            int newEnchantLvl = slot2EnchantmentLvl > slot1EnchantLevel ? slot2EnchantmentLvl
                                    : slot2EnchantmentLvl == slot1EnchantLevel ? (slot2EnchantmentLvl + 1)
                                            : slot1EnchantLevel;
                            newEnchantLvl = newEnchantLvl > enchantLvlLimit ? slot2EnchantmentLvl : newEnchantLvl;

                            result.addUnsafeEnchantment(enchantment, newEnchantLvl);
                            e.setResult(result);

                            if (result.getEnchantmentLevel(enchantment) >= enchantLvlLimit) {
                           // Message player that he have reached limit of the specific enchantment "enchantment"
                                reachedLvlLimit(player, enchantment, enchantLvlLimit);
                            }
                        }
     
    • Like Like x 1
  8. If it always gets fired 3 times just build a Map with the player uuid and a StringBuilder, each time check if the number of args of the StringBuilder isn't 3, if yes append the message, if not print it and cancel the entry
     
  9. Can you give an example ? :)
     
    • Like Like x 1
  10. unless theres a bug with spigot, this shouldnt be happening. show all of your code. not just the class the issue is in, all of it. if you have 100 classes, then limit it to just the main class, where your event class gets instantiated, and the event class itself
     
  11. By the way, are you sure they all contain the exact same info? I've used the PreapreAnvilEvent before, and from my testing only one of the events contains the actual resulting item. So by checking this:
    Code (Java):
    ItemStack[] itemStacks = event.getInventory().getContents();
    if(itemStacks[0] == null || itemStacks[0].getType() == Material.AIR)
        return;
    I only have one resulting event. If that doesn't work, maybe there is something wrong with your code as Warren1001 said.
     
  12. Not happy with sharing my code, but I dont know what else todo
    Code (Java):

           if (e.getInventory().getItem(0) != null && e.getInventory().getItem(1) != null) {
                ItemStack slot1 = e.getInventory().getItem(0);
                ItemStack slot2 = e.getInventory().getItem(1);
                ItemStack result = e.getResult();

               if (slot1.getType().equals(slot2.getType())) {
                    Map<Enchantment, Integer> slot2Enchantments = slot2.getEnchantments();
                    for (Enchantment enchantment : slot2Enchantments.keySet()) {
                        int enchantLvlLimit = plugin.manager.getEnchantLimit(enchantment);
                        int slot2EnchantmentLvl = slot2Enchantments.get(enchantment);
                        if (slot1.getEnchantments().containsKey(enchantment)) {
                            int slot1EnchantLevel = slot1.getEnchantmentLevel(enchantment);
                            int newEnchantLvl = slot2EnchantmentLvl > slot1EnchantLevel ? slot2EnchantmentLvl
                                    : slot2EnchantmentLvl == slot1EnchantLevel ? (slot2EnchantmentLvl + 1)
                                            : slot1EnchantLevel;
                            newEnchantLvl = newEnchantLvl > enchantLvlLimit ? slot2EnchantmentLvl : newEnchantLvl;
                            result.addUnsafeEnchantment(enchantment, newEnchantLvl);
                            e.setResult(result);
                            if (result.getEnchantmentLevel(enchantment) >= enchantLvlLimit) {
                          [I]// I want to send the message here if: the enchantment on the weapon has reached it's limit[/I]
                                reachedLvlLimit(player, enchantment, enchantLvlLimit);
                            }
                        }
                    }
                }
            }
     
     
    • Like Like x 1
  13. https://hub.spigotmc.org/jira/browse/SPIGOT-2702
    did some testing, the bug indeed still exists.
    looked into ways to preventing it, this is how i did it:
    Code (Java):
    private final Map<Player, AnvilInventory> previousInventories = new HashMap<>();

    @EventHandler
    public void onPrepareAnvilFix(PrepareAnvilEvent event) {
       Player player = (Player)event.getView().getPlayer();
       AnvilInventory inventory = event.getInventory();
       if(previousInventories.put(player, inventory) == null) {
          onPrepareAnvil(event);
          getServer().getScheduler().runTask(this, () -> previousInventories.remove(player));
       }
    }

    public void onPrepareAnvil(PrepareAnvilEvent event) {
       System.out.println("1");
    }
    did some testing with this, no matter what i inputted where and spammed, the event only called once. the only possibility of issue is if two people are enchanting the exact same thing at the exact same time. one of them simply wont work, but picking up the item and dropping it again into the slot will correct it. difficult bug to produce.
    you can take what you want from this code segment, you can put your event logic in the onPrepareAnvil method (the one NOT tagged with eventhandler)

    /e actually, that bug could be avoided by changing the set into a map and keying players with the inventories. updated
     
    #14 Warren1001, Jan 12, 2020
    Last edited: Jan 12, 2020
    • Like Like x 1
    • Informative Informative x 1
  14. upload_2020-1-12_19-47-56.png
    Instead of checking this event check some inventory interaction event and see if it is an anvil!
     
  15. I'll try it out later today, thanks :)
     
    • Like Like x 1
  16. I'll try it out, thank you :D
     
  17. Hey, i've just tested it with my code and I have come to the conclusion that its not possible to only send the message once. The code you gave do send the message once, but the prepareanvilevent requires the three times, so I either have to find another way of achieving my goal or just dont have the message (which is important for the plugin :/).
     
  18. Can seem to get it to work using inventoryinteractevent :/
     
  19. mm i see what youre saying. because theyre all ignored except for 1, it wont have all the information. you can look and see if the events called follow a sequence and modify the code to always run the last one available, for instance.

    /e or make it work without my code to reduce to 1 call, and then add my code in after, and have the message be sent once there while using the original event functionality for everything not a message, if that works for your specific issue