[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

    Comphenix

    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:
    https://gist.github.com/aadnk/5943946

    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:
    https://gist.github.com/aadnk/5943952

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

    In either case, it's very easy to use:
    Code:java
    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);
    6.  
    7. attributes.add(Attribute.newBuilder().name("Health")
    8. .type(AttributeType.GENERIC_MAX_HEALTH).amount(20).build());
    9.  
    10. attributes.add(Attribute.newBuilder().name("Speed")
    11. .type(AttributeType.GENERIC_MOVEMENT_SPEED).amount(2).build());
    12.  
    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

    hawkfalcon

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

    Comphenix

    Currently, they're always removed when a plugin is using ItemMeta:
    Code:java
    1. ItemStack result = attributes.getStack();
    2. result.setItemMeta(result.getItemMeta());
    3.  
    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

    stirante

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

    Comphenix

    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

    stirante

    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

    Comphenix

    stirante and hawkfalcon like this.
  8. Offline

    kreashenz

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

    hawkfalcon

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

    KodekPL

    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

    stirante

    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

    KodekPL

    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

    Comphenix

    I've found a different workaround for the creative problem (download):
    Code:java
    1. public class ExampleMod extends JavaPlugin implements Listener {
    2. private ItemStack expectedCursor;
    3. private long expectedTime;
    4.  
    5. @Override
    6. public void onEnable() {
    7. getServer().getPluginManager().registerEvents(this, this);
    8.  
    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());
    19.  
    20. // Undo the stupid "item meta" cleanup
    21. event.getPacket().getItemModifier().write(0, stack);
    22.  
    23. // Update the next event handler
    24. expectedTime = System.currentTimeMillis();
    25. expectedCursor = stack;
    26.  
    27. } catch (IOException e) {
    28. e.printStackTrace();
    29. }
    30. }
    31. });
    32. }
    33.  
    34. @EventHandler(priority = EventPriority.LOWEST)
    35. public void onCreativeInventory(InventoryCreativeEvent e) {
    36. if ((System.currentTimeMillis() - expectedTime) < 50) {
    37. e.setCursor(expectedCursor);
    38. }
    39. }
    40.  
    41. private ItemStack readItemStack(DataInputStream input, StreamSerializer serializer) throws IOException {
    42. ItemStack result = null;
    43. short type = input.readShort();
    44.  
    45. if (type >= 0) {
    46. byte amount = input.readByte();
    47. short damage = input.readShort();
    48.  
    49. result = new ItemStack(type, amount, damage);
    50. NbtCompound tag = serializer.deserializeCompound(input);
    51.  
    52. if (tag != null) {
    53. result = MinecraftReflection.getBukkitItemStack(result);
    54. NbtFactory.setItemTag(result, tag);
    55. }
    56. }
    57. return result;
    58. }
    59.  
    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);
    65.  
    66. attributes.add(Attribute.newBuilder().name("Health")
    67. .type(AttributeType.GENERIC_MAX_HEALTH).amount(20).build());
    68.  
    69. attributes.add(Attribute.newBuilder().name("Speed")
    70. .type(AttributeType.GENERIC_MOVEMENT_SPEED).amount(2).build());
    71.  
    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

    Comphenix

    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

    KingFaris11

    This looks amazing. :O Thanks!
     
  16. Offline

    SmellyPenguin

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

    RainoBoy97

    Comphenix
    Nice!

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

    Comphenix

    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

    SmellyPenguin

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

    Comphenix

    By modifying the NBT data manually?

    Perhaps you could post a code snippet?
     
  21. Offline

    SmellyPenguin

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

    Comphenix

    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

    SmellyPenguin

    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

    netizen539


    =( 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

    Comphenix

    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

    Comphenix

    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

    GaaTavares

    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

    chasechocolate

  30. Offline

    GaaTavares

    Yeah i know, but how i can convert o an int?
    int damage = ?
    Current code:
    Code:java
    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