Discussion in 'Plugin Development' started by Antybarrel, May 29, 2014.

Thread Status:
Not open for further replies.
  1. Offline


    Hi, Im trying to make a plugin where a cusom inventory opens when a block is right clicked, everything seems to be working however I wondered if there was a way to find the location of the block clicked through Inventory Click Event.

    Heres My event:
    1. @EventHandler
    2. public void onInventoryClick(InventoryClickEvent event) {
    3. Player player = (Player) event.getWhoClicked();
    4. ItemStack clicked = event.getCurrentItem();
    5. Inventory inventory = event.getInventory();
    6. if (inventory.getName().equals(Main.myInventory.getName())) {
    7. if (clicked.getType() == Material.IRON_BLOCK) {
    8. event.setCancelled(true);
    9. player.closeInventory();
    10. //InventoryHolder test = event.getInventory().getHolder();
    11. //Location loc = (Location) ((Block)test).getLocation(); <- Tryed this gives Null Pointer Exception
    12. }
    13. else if (clicked.getType() == Material.GOLD_BLOCK) {
    14. event.setCancelled(true);
    15. player.closeInventory();
    16. }
    17. }
    18. }

    Many thanks.
  2. Offline


  3. Offline


    There is no way to add secret data to an inventory... however you could do a workaround and set a decoy block in the corner of the inventory with data on it (via lore or NBT tags)...
  4. Offline


    Thanks, I would never of thought of this however is there away to add lore or NBT data that the player cant see? The player wouldn't be able to edit or change the inventory so thats fine.
  5. Offline


    Custom NBT can be added to a stack (the player won't see it), however this cannot be accomplished through the Bukkit API. To do it, you'd either have to use the NMS classes representing NBT, or you could use reflection. I know Comphenix has ProtocolLib, which contains NBT manipulation wrapper classes (as well as other MC reflection goodies), or you could just do it raw.

    Non-cached, slightly inefficient example of setting an NBT tag via reflection:
    2. ItemStack item = ...; // This is the ItemStack you want to hold NBT data
    4. try{
    5. String nmsPackage = "net.minecraft.server." + Bukkit.getServer().getClass().getPackage().getName()
    6. .split(Pattern.quote(ClassUtils.PACKAGE_SEPARATOR))[3]; // Get the NMS package
    7. // This example uses an integer array data tag to store the data - this is good for block locations
    8. Constructor<?> nbtIntegerArrayCtor = Class.forName(nmsPackage + ".NBTTagIntArray").getDeclaredConstructor(int[].class);
    9. Object dataTag = nbtIntegerArrayCtor.newInstance(new int[]{0,0,0}); // The int[] contains the data you want the NBT tag to store
    10. Object nmsItemStack = Class.forName(Bukkit.getServer().getClass().getPackage().getName() + ".inventory.CraftItemStack").getMethod("asNMSCopy", ItemStack.class).invoke(null, item);
    11. Object compound = nmsItemStack.getClass().getField("tag").get(nmsItemStack); // The actual NBT data tag instance
    12. if(compound == null){
    13. // Create it a datatag if it doesn't have one
    14. compound = Class.forName(nmsPackage + ".NBTTagCompound").getDeclaredConstructor().newInstance();
    15. }
    16. Class.forName(nmsPackage + ".NBTTagCompound").getDeclaredMethod("set", String.class, nbtIntegerArrayCtor.getDeclaringClass().getSuperclass() /* NBTBase */).invoke(compound, "WHATEVER_YOU_WANT_YOUR_NBT_TAG_TO_BE", dataTag);
    17. nmsItemStack.getClass().getField("tag").set(nmsItemStack, compound);
    19. // We've successfully set an NBT tag
    20. // Now, we must reassign the ItemStack to a CraftItemStack containing it
    21. // After this, it is no longer safe to use 'item' with ItemMeta, as it will OVERWRITE this NBT tag
    22. item = (ItemStack) Class.forName(Bukkit.getServer().getClass().getPackage().getName() + ".inventory.CraftItemStack").getDeclaredMethod("asCraftMirror",
    23. nmsItemStack.getClass()).invoke(null, nmsItemStack);
    24. }catch(Exception ex){
    25. // Error occurred during reflection, deal with it
    26. }

    As you can see, to actually set NBT data, you need to access NMS, which I do here using reflection. You can read this saved data from a CraftItemStack if you can get the NMS handle field, the tag instance, and so on.

    EDIT: I've been reading through the CraftBukkit source, and it looks like using any NBT tag that does not exist in ItemMeta will be overwritten by the clone/mirror methods in CraftItemStack. However, assuming it does not crash the client, I think you can add invalid data to valid NBT tags, assuming you use the same NBT type, which will not be overwritten as long as you don't use ItemMeta with the NMS modified stack.
Thread Status:
Not open for further replies.

Share This Page