[Util] Edit ItemStack attributes, adding speed, damage or health bonuses.

Discussion in 'Resources' started by Comphenix, Jul 7, 2013.

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


    The new attribute system in 1.6.1 allows map makers and plugin authors (yes, you) to set arbitrary bonuses on armor and weaponry, much like any old RPG. This include things like extra health, displayed as additional hearts in the UI and faster movement speed and "follow range" on mobs - things that would have been difficult to impossible to do in 1.5.2.

    Unfortunately, this system isn't exposed as an API in CraftBukkit yet, nor is it entirely supported. ItemStacks may lose their attributes when they're cloned, or when plugins edit their ItemMeta. But you can still play with this system - it's just a bit buggy.

    You can get my utility for editing attributes here:

    However, is it dependent on 1.6.1, and since 1.6.2 is soon out, it might be a good idea to use a version-independent edition. It's dependent on ProtocolLib instead:

    NEW! If you add this class to your project (thread), you'll avoid referencing CB/NMS without also having to depend on ProtocolLib:

    In either case, it's very easy to use:
    1. @Override
    2. public boolean onCommand(CommandSender sender, Command command, String label, String[] args) {
    3. if (sender instanceof Player) {
    4. ItemStack helmet = new ItemStack(Material.GOLD_HELMET);
    5. Attributes attributes = new Attributes(helmet);
    7. attributes.add(Attribute.newBuilder().name("Health")
    8. .type(AttributeType.GENERIC_MAX_HEALTH).amount(20).build());
    10. attributes.add(Attribute.newBuilder().name("Speed")
    11. .type(AttributeType.GENERIC_MOVEMENT_SPEED).amount(2).build());
    13. ((Player) sender).getInventory().addItem(attributes.getStack());
    14. }
    15. return true;
    16. }

    Just remember to always call attributes.getStack(), as the item stack may get recreated as a CraftItemStack underneath.
  2. Offline


    Very nice! May use this.
    You mentioned you knew how to remove them with metadata? How?
  3. Offline


    Currently, they're always removed when a plugin is using ItemMeta:
    1. ItemStack result = attributes.getStack();
    2. result.setItemMeta(result.getItemMeta());
    4. ((Player) sender).getInventory().addItem(result);

    The reason for this, is that ItemMeta will only extract information it is familiar with from the native NBTTagCompound field, expose it for modification, and then restore it using a new NBTTagCompound. Any data ItemMeta isn't aware of will be deleted. This is presumably intentional, and serves as a way to discourage saving data as custom NBT tags. So, plugins typically store metadata using lore lines instead.

    Of course, this will be fixed when the Bukkit team adds support for attributes for item stacks and entities, which should be fairly easy to do with the current system.
    hawkfalcon likes this.
  4. Offline


    For me it gets cleared after opening inventory :/
  5. Offline


    Strange. It worked fine for me as long as I didn't change game mode.

    Though now that you mention it, it's possible this doesn't work at all in creative mode, only survival mode. Unfortunately, there's very few ways aroundt this - either simulate it by setting the attributes on the entity yourself, or patch the server so that it at least keeps this information around.

    It is possible to patch the server in memory, but it's exceedingly difficult as all the possible "entry points" are final. You can do this with PowerMock, but it's ment for testing and not production. I doubt a plugin could use it. So - you have to fork CraftBukkit, modify it and distribute it.
  6. Offline


    I had ready lib for attributes 5 days ago and worked on it for about 3-4 hours, but i thought it's not working. I tested it on creative...
    Comphenix likes this.
  7. Offline


    stirante and hawkfalcon like this.
  8. Offline


    I have a question, does this have to have ProtocolLib or is it independent?
  9. Offline


    he has 2 versions.
    Comphenix likes this.
  10. Offline


    Does this work on Bukkit 1.6.2? I've tested the independent version - changed imports for new NMS and nothing. No effect, did something changed?
  11. Offline


    KodekPL Może testujesz na trybie kreatywnym? W trybie kreatywnym bukkit czyści od razu wszystkie nieznane tagi NBT.
    //Maybe you test it on creative? In Creative mode bukkit automaticlly cleares all unknown tags.
  12. Offline


    Okay, that was not fault of gamemode. Itemstack in hand of player didn't want to update. Sorry.
    It's really helpful utility, thanks!
  13. Offline


    I've found a different workaround for the creative problem (download):
    1. public class ExampleMod extends JavaPlugin implements Listener {
    2. private ItemStack expectedCursor;
    3. private long expectedTime;
    5. @Override
    6. public void onEnable() {
    7. getServer().getPluginManager().registerEvents(this, this);
    9. ProtocolLibrary.getProtocolManager().addPacketListener(
    10. new PacketAdapter(
    11. this, ConnectionSide.CLIENT_SIDE, new ListenerOptions[] { ListenerOptions.INTERCEPT_INPUT_BUFFER }, Packets.Client.SET_CREATIVE_SLOT) {
    12. @Override
    13. public void onPacketReceiving(PacketEvent event) {
    14. DataInputStream input = event.getNetworkMarker().getInputStream();
    15. try {
    16. // Read slot
    17. input.readShort();
    18. ItemStack stack = readItemStack(input, new StreamSerializer());
    20. // Undo the stupid "item meta" cleanup
    21. event.getPacket().getItemModifier().write(0, stack);
    23. // Update the next event handler
    24. expectedTime = System.currentTimeMillis();
    25. expectedCursor = stack;
    27. } catch (IOException e) {
    28. e.printStackTrace();
    29. }
    30. }
    31. });
    32. }
    34. @EventHandler(priority = EventPriority.LOWEST)
    35. public void onCreativeInventory(InventoryCreativeEvent e) {
    36. if ((System.currentTimeMillis() - expectedTime) < 50) {
    37. e.setCursor(expectedCursor);
    38. }
    39. }
    41. private ItemStack readItemStack(DataInputStream input, StreamSerializer serializer) throws IOException {
    42. ItemStack result = null;
    43. short type = input.readShort();
    45. if (type >= 0) {
    46. byte amount = input.readByte();
    47. short damage = input.readShort();
    49. result = new ItemStack(type, amount, damage);
    50. NbtCompound tag = serializer.deserializeCompound(input);
    52. if (tag != null) {
    53. result = MinecraftReflection.getBukkitItemStack(result);
    54. NbtFactory.setItemTag(result, tag);
    55. }
    56. }
    57. return result;
    58. }
    60. @Override
    61. public boolean onCommand(CommandSender sender, Command command, String label, String[] args) {
    62. if (sender instanceof Player) {
    63. ItemStack helmet = new ItemStack(Material.GOLD_HELMET);
    64. Attributes attributes = new Attributes(helmet);
    66. attributes.add(Attribute.newBuilder().name("Health")
    67. .type(AttributeType.GENERIC_MAX_HEALTH).amount(20).build());
    69. attributes.add(Attribute.newBuilder().name("Speed")
    70. .type(AttributeType.GENERIC_MOVEMENT_SPEED).amount(2).build());
    72. ((Player) sender).getInventory().addItem(attributes.getStack());
    73. }
    74. return true;
    75. }
    76. }

    This particular solution requires ProtocolLib 2.5.0 or newer, though I'm sure there's a way that doesn't require it. The key here is to reapply the Attributes in InventoryCreativeEvent.
    Cybermaxke likes this.
  14. Offline


    I should probably mention that the latest CraftBukkit build (#2822++) support attributes out of the box - though without an attribute API.

    So, the ProtocolLib method in post #13 is no longer necessary.
  15. Offline


    This looks amazing. :O Thanks!
  16. Offline


    Been trying to do this on offline players for a couple hours now...any tips?
  17. Offline



    (Trodde aldri du var Norsk? :p) <- Translate: Never thought you were Norwegian? :p
  18. Offline


    How are you modifying a offline player's inventory? Keep in mind that Bukkit doesn't support serializing and de-serializing attributes, though it should work fine if Minecraft itself is doing that job.

    Maybe I just chose a random name and country to obfuscate my identity? A pseudonym to protect my privacy.

    Neida, er ikke så paranoid. Har jo til og med et bilde av fjeset mitt på GitHub. :p
  19. Offline


    Comphenix, I'm trying to change the generic.maxHealth attribute of player's dat files.
  20. Offline


    By modifying the NBT data manually?

    Perhaps you could post a code snippet?
  21. Offline


    I tried doing it with your library, but nothing worked.
  22. Offline


    My library DOES NOT support offline players, so I don't know what you did.

    You can edit the dat-files, but you need to rewrite the attribute classes extensively to use the slightly different NBT format.
  23. Offline


    Alright thank you very much, I had also tried another public library for offline players that didn't support Attributes that I tried to implement, but the key "generic.maxHealth" wasn't found in the dat files for some reason. Either that or the string I entered was wrong.
  24. Offline


    =( Why?! This is exactly what I want to do. Just an arbitrary NBTCompound tag titled "BukkitPluginCustom" *sigh*

    Anyway great job on this, its really cool and helpful!
  25. So what version should we use right now?​
  26. Offline


    Both works, you just have to decide whether or not to depend on ProtocolLib or CraftBukkit 1.6.2.

    It's probably best to just go for CB, unless you already are using ProtocolLib.
  27. Offline


    I've now added a new version that is version-independent, without relying on ProtocolLib. Take a look at the main post for more information.
  28. Offline


    Ok, i'm trying to get the damage of the players' item in hand, and damage the nearby entities with this damage. All is ready except the part from getting the damage. How do i can do that?
  29. Offline


  30. Offline


    Yeah i know, but how i can convert o an int?
    int damage = ?
    Current code:
    1. ItemStack hand = yaw.getItemInHand();
    2. Attributes attributesa = new Attributes(hand);
    3. attributesa.add(Attribute.newBuilder().name("Damage")
    4. .type(AttributeType.GENERIC_ATTACK_DAMAGE).amount(2).build());
Thread Status:
Not open for further replies.

Share This Page