1.18.2 Changing ItemMeta Async

Discussion in 'Spigot Plugin Development' started by ChickenStyle, Dec 4, 2021.

  1. Hello, I am working on a plugin that will translate item's display name and lore depending on the language that the player chooses, the translation takes some time, so I need to change item's item meta in delay when its already in players inventory, sadly when I try to do it the regular way (setItemMeta) it doesn't change the display name or lore, and it doesn't send any error, so I need help, how to change item's itemmeta asynchronously? (For now I work only with EntityPickUpItemEvent)
     
  2. Code?
     
  3. When I do this:

    Code (Java):
        @EventHandler
        public void onPlayerPickUp(EntityPickupItemEvent e) {
            if (!(e.getEntity() instanceof Player)) return;
            Player player = (Player) e.getEntity();
            String lang = ItemTranslator.getPlayersLanguages().get(player.getUniqueId());

            ItemTranslateEvent event = new ItemTranslateEvent(e.getItem().getItemStack(),lang);
            Bukkit.getPluginManager().callEvent(event);

            if (!event.isCancelled()) {

                System.out.println("Works!");
                e.getItem().setItemStack(Utils.translateItemStack(event.getItemStack(),lang));
                player.updateInventory();


            }

        }
    The translation works, but there is a delay for picking up the item

    now If I want to run it async:

    Code (Java):
        @EventHandler
        public void onPlayerPickUp(EntityPickupItemEvent e) {
            if (!(e.getEntity() instanceof Player)) return;
            Player player = (Player) e.getEntity();
            String lang = ItemTranslator.getPlayersLanguages().get(player.getUniqueId());

            ItemTranslateEvent event = new ItemTranslateEvent(e.getItem().getItemStack(),lang);
            Bukkit.getPluginManager().callEvent(event);

            if (!event.isCancelled()) {

                new BukkitRunnable() {

                    @Override
                    public void run() {
                        System.out.println("Works!");
                        e.getItem().setItemStack(Utils.translateItemStack(event.getItemStack(),lang));
                        player.updateInventory();

                    }
                }.runTaskAsynchronously(ItemTranslator.getInstance());

            }

        }
    It just doesn't work, and yes I know that I cannot change the item in the event because its already finished, but it doesn't work when I am editing the itemstack itself
     
  4. Why dont you get the translation async using completableFutures or something, then set the ItemMeta sync?
     
  5. Hm, I will try to do this 0-0
     
  6. You can't do it like this, the item reference may not be the same at a given point in time. My personal suggestion here would be to delete the item when its picked up, and generate a translated copy of it asynchronously before adding the item to the player synchronously.
     
  7. This sounds like a good idea, but it means that it will delete the item, and give it to the player with some delay, which kinda sucks :(
     
    #8 ChickenStyle, Dec 5, 2021
    Last edited: Dec 5, 2021
  8. id probabbly avoid this, I always like to consider the worst case scenario when coding stuff. Like what if the server crashes before it gives the item back, then they have lost an item.
     
  9. I belive it only changes if they move it into another inventory or whatever, since the translation will probabbly take a second or two, it should be fine
     
  10. Tau

    Tau

    why not use packets?
    the easiest way to do this would be as follows:
    1. create a com.google.common.cache.Cache of string keys to translation values
    2. when a packet is sent, intercept it, check the cache for the required string, if not in the cache: translate it and cache it.
    3. profit

    the "translation values" could be an object such as another map like a Synchronized HashMap that have a language key and a string value.

    for the cache I'd probably use a max size of say 12000 strings and use softKeys
    Assuming each string key is an average of 20 chars, it'd use roughly 1mb of heap for the keys alone. not sure about the cache map itself, so let's say it uses ~3mb.
    For the values it would depend on how many languages you translate to.

    Overall let's say around ~50 or so mb of heap
     
    #11 Tau, Dec 5, 2021
    Last edited: Dec 6, 2021