Get nbt tag from an itemstack in a player inventory

Discussion in 'Plugin Development' started by Marre_Parre_Ping_Pong, Apr 14, 2020.

  1. Hi!
    I am coding a plugin that is called Soul Trade. (it is being coded in spigot 1.13.2).

    The whole purpose of the plugin is that you can deposit player heads into a currency.

    And when I mean player heads I mean that I am using a mobhead plugin that drops player heads when killing mobs.

    The thing is that the player heads that I want to deposit is just not just basic ItemStack.player_heads, I want the plugin to be able to retrieve the player heads NBT tags from the players inventory and then set as some kind of variable to be able to remove the custom player head from the player inventory.

    Is this possible and how? Is there another or is my question way out of reach to understand?
    I hope if my question is understandable to help me because I am trying really hard to explain what I want my plugin to do.

    Please be kind with your explanation's if you want to help me because I am quite bad at spigot coding (I tried to learn it some years ago but to no avail, but now I have been giving it another chance).
     
  2. Offline

    KarimAKL

    @Marre_Parre_Ping_Pong You'll have to use NMS.

    First, get the NBTTagCompound from the item. Let me know if you don't know how.

    Second, loop the keys using the getKeys() method.

    Third, get the value as an NBTBase instance using the get(String) method.

    Fourth, check if the NBTBase is an instance of NBTTagString, if so use the asString() method on it, if it's not, check if it's an instance of NBTTagList, then use a standard for loop using the size() and get(int) methods, if it's not an instance of that either, check if it's an instance of NBTTagCompound and repeat if so.

    That's for getting strings, you can add integers, doubles, etc. using the NBTTagInt, NBTTagDouble, etc. instead of NBTTagString.
     
  3. I do not know how to get the NBTTagCompound from the item.
    How can I do that?
     
  4. Offline

    KarimAKL

    @Marre_Parre_Ping_Pong
    Code:Java
    1. // First we get your item
    2. org.bukkit.inventory.ItemStack item = new ItemStack(Material.YOUR_MATERIAL);
    3.  
    4. // Then we get a NMS copy of your item
    5. net.minecraft.server.<version>.ItemStack nmsItem = CraftItemStack.asNMSCopy(item);
    6.  
    7. // We then check if the item has a tag, if not, we return
    8. if (!nmsItem.hasTag()) return;
    9.  
    10. // If it does have a tag, we get it
    11. NBTTagCompound tag = nmsItem.getTag();

    I hope this helps.
     
  5. Ok, it helped, I tried to follow along your step to step after, but It seems I do not get how to get the size() and get(int) method in the loop for the NBTTagList instance.

    Although it is not complete since I do not know how to do the thing above, here is my code.
    Did do anything funky and wrong? Please let me know.

    Code:
    public void NBTGetTag() {
        org.bukkit.inventory.ItemStack head = new ItemStack(Material.PLAYER_HEAD);
       
        net.minecraft.server.v1_13_R2.ItemStack nmsHead = CraftItemStack.asNMSCopy(head);
       
        if (!nmsHead.hasTag()) return;
       
        NBTTagCompound tag = nmsHead.getTag();
       
       
            for (String key : tag.getKeys()) {
                NBTBase nbtbase = tag.get(key);
               
                if (nbtbase instanceof NBTTagString) {
                   
                    nbtbase.asString();
                   
                } else if (nbtbase instanceof NBTTagList) {
                   
                    for (((NBTTagList) nbtbase).size(); ((NBTTagList) nbtbase).get(i)) // I know this is wrong
                       
                       
                       
                }
               
            }
           
        }
     
  6. Offline

    KarimAKL

  7. I have read and done the exercises on the second url link.
    And I read from my pdf file (Java 8 the complete reference ninth edition) on loops

    Is it more like this?
    Code:
    for (String key : tag.getKeys()) {
                NBTBase nbtbase = tag.get(key);
              
                if (nbtbase instanceof NBTTagString) {
                  
                    nbtbase.asString();
                  
                } else if (nbtbase instanceof NBTTagList) {
                  
                    for (int i = 0; i < tag.getInt(key); i++) {
                      
                        ((NBTTagList) nbtbase).get(i);  
                    }   
                      
                } else if (nbtbase instanceof NBTTagCompound) {
                  
                    for (int i = 0; i < tag.getInt(key); i++) {
                      
                        ((NBTTagCompound) nbtbase).get(key);
                      
                    }
                  
                }
              
            }
    Am I missing the point on how to do loops?
    Should I go back read more on loops?
     
  8. Offline

    KarimAKL

    @Marre_Parre_Ping_Pong
    1. For the NBTTagList, you should loop "NBTTagList#size()" amount of times, not "tag.getInt(key)".
    2. For the NBTTagCompound, you should make the method recursive. Read this.
    3. You have to store the string somewhere, you're just calling "NBTTagString#asString()".
     
  9. okkk, I have tried to do that here is code:
    Code:
    public ArrayList<String> NBTGetTag(NBTTagCompound compound) {
          
        org.bukkit.inventory.ItemStack head = new ItemStack(Material.PLAYER_HEAD);
      
        net.minecraft.server.v1_13_R2.ItemStack nmsHead = CraftItemStack.asNMSCopy(head);
      
        if (!nmsHead.hasTag()) return null;
      
        NBTTagCompound tag = nmsHead.getTag();
        ArrayList<String> tagList = new ArrayList<String>();
      
            for (String key : tag.getKeys()) {
                NBTBase nbtbase = tag.get(key);
              
                if (nbtbase instanceof NBTTagString) {
                  
                    tagList.add(nbtbase.asString());
                  
                } else if (nbtbase instanceof NBTTagList) {
                  
                    for (int i = 0; i < ((NBTTagList) nbtbase).size() ; i++) {
                      
                        tagList.add(((NBTTagList) nbtbase).get(i).asString());
                      
                    }   
                      
                } else if (nbtbase instanceof NBTTagCompound) {
                  
                    tagList.addAll(NBTGetTag(((NBTTagCompound) nbtbase)));
                  
                }
            }
          
            return tagList;
          
        }
    Is this somewhere near the lines?
    What am I doing wrong?
    If this is the correct way to do it how am I soupossed to set it on a ItemStack in the code?
    Do I make a new ItemStack and somehow get the compound and set the tags?
    Will I able to remove the custom head with:
    Code:
    player.getInventory().removeItem(head);
    Or is it more complex?

    Thank you for helping me through this I am very grateful for your help, I would have not known how to do this without your help.
    I really want this to work since I am coding this plugin for my own server, I think it is a very nice feature.
     
  10. Offline

    KarimAKL

    @Marre_Parre_Ping_Pong Make the NBTTagList recursive as well, since you won't know if it's a string, you shouldn't be using "asString()" on it.

    I helped you with getting the NBT of the item, i'm not sure what you want to do with it.
     
  11. Hi!
    It was some time ago...

    I do not know how to make the NBTTagList recursive (I tried). What I want my plugin to do is simply that it makes it available to turn in player(or in my case custom mob heads) to a currency. My plugin does not recognize player heads with NBT tags in it, so I just want the plugin to return all NBT tags on it so I can somehow apply it on a itemstack in the plugin to make the plugin recognize the heads with NBT tags to turn it in into a currency.

    Is there a better way to do this? Can I somehow not do this and make that any player heads even with NBT tags can be turned in for a currency?
     
  12. Offline

    KarimAKL

    No problem, the thread wasn't closed. :p

    You'd have to modify the method a bit:
    1. Change the parameter type from NBTTagCompound to NBTBase.
    2. Add a check that handles NBTTagCompound and NBTTagList.
    3. Call the method with the NBTTagList's elements if the parameter type was NBTTagList, otherwise (if it's NBTTagCompound) call the method with the NBTTagList itself.

    Sounds like there might be a simpler way to do this.

    That depends on how you check it, paste the code that checks the item.
     

Share This Page