[Tutorial] Metadata - What it is and how to use it

Discussion in 'Resources' started by AoH_Ruthless, Jun 5, 2014.

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

    AoH_Ruthless

    Not many people on the Bukkit Forums, especially in PD where I spend the majority of my time on, are aware of metadata in the Bukkit API. This thread will cover what it is and various uses of it.

    So what is Metadata?

    Metadata is basically a concept related to several classes in the Bukkit API whose sole purpose is to provide plugin-specific data to Minecraft-related concepts. So, you can apply metadata values, which are like tags, on various Minecraft concepts that you can check for anywhere else in your plugin. That's very neat and organized and is a lot more efficient than other approaches to various tasks.

    Is everything Metadatable?


    No, not everything can be attached with a metadata tag. Because we're talking about Minecraft concepts here, players, blocks, and other entities are usually what we see as being metadatable (can be applied with metadata).

    How is Metadata used?

    Let's say we want to spawn an entity and set it's owner to a player. I do not want to use any of that NMS or Reflection crap (I'm not saying it's bad to use it, but it is complicated), so I'm stuck. Right? Wrong. You can add metadata to the entity and then check for it later to see if that entity is owned by a player. For this code example, I'm going to use a zombie.

    Code:java
    1. package com.valygard.aohruthless.metadatatutorial;
    2.  
    3. import org.bukkit.Bukkit;
    4. import org.bukkit.entity.EntityType;
    5. import org.bukkit.entity.Player;
    6. import org.bukkit.entity.Zombie;
    7. import org.bukkit.metadata.FixedMetadataValue;
    8.  
    9. /**
    10. * To put some context into it, I use metadata in relation to zombies in my King
    11. * of the Hill plugin. This has saved me lots of time and code from using NMS /
    12. * Reflection where it was unnecessary.
    13. *
    14. * @author Anand
    15. *
    16. */
    17. public class MetadataTutorial {
    18.  
    19. /**
    20.   * This static method will spawn a zombie on the player and add metadata.
    21.   * Note: Adding metadata does not make the zombie stop attacking the player,
    22.   * you will need to listen for that in an EntityTargetEvent.
    23.   *
    24.   * @param plugin
    25.   * this is your main class. Replace "MainClass" with the class
    26.   * that extends JavaPlugin.
    27.   * @param p
    28.   * this is the player we want to make the owner of the zombie.
    29.   */
    30. public static void spawnZombie(MainClass plugin, Player p) {
    31. Zombie z = (Zombie) p.getWorld().spawnEntity(p.getLocation(),
    32. EntityType.ZOMBIE);
    33.  
    34. /*
    35.   * Setting the metadata.
    36.   *
    37.   * LivingEntity#setMetadata(String s, MetadataValue mv); The string is
    38.   * the metadata tag that we will use to get the zombie anywhere else in
    39.   * the plugin.
    40.   *
    41.   * There are two types of metadata: LazyMetadataValues, and
    42.   * FixedMetadataValues which extend lazy ones. We will be working with
    43.   * FixedMetadataValues.
    44.   *
    45.   * A FixedMetadataValue is, well, fixed. It is unchanging and therefore
    46.   * very reliable.
    47.   *
    48.   * You will need to call a new FixedMetadataValue, which requires a
    49.   * plugin argument and an arbitrary string. This string does not matter
    50.   * and you can name it whatever you want. I recommend that your plugin
    51.   * directly points your main class but Plugin, and JavaPlugin variable
    52.   * types also work.
    53.   */
    54. z.setMetadata(p.getName(), new FixedMetadataValue(plugin, "yes!"));
    55. }
    56.  
    57. /**
    58.   * Metadata is useless unless we can check if the zombie has metadata to
    59.   * begin with.
    60.   *
    61.   * @param z
    62.   * the zombie to check
    63.   * @return the player, or null if none was found online.
    64.   */
    65. public static Player getPlayerWithZombie(Zombie z) {
    66. for (Player p : Bukkit.getOnlinePlayers()) {
    67. /*
    68.   * Remember how we set metadata. We had a string argument, and a
    69.   * metadata value. If the zombie has a metadata cache with this
    70.   * string value, we have a match.
    71.   *
    72.   * So right away with a few lines of code we are able to retrieve a
    73.   * player who the zombie belongs to.
    74.   */
    75. if (z.hasMetadata(p.getName())) {
    76. return p;
    77. }
    78. }
    79. return null;
    80. }
    81.  
    82. /**
    83.   * Maybe we want to remove the player as a zombie owner. We can do that
    84.   * because the Metadata API allows us to remove metadata with just one line
    85.   * of code.
    86.   *
    87.   * @param z
    88.   * the zombie who has the metadata to be removed.
    89.   * @param owner
    90.   * the player whose name is the metadata.
    91.   * @param plugin
    92.   * we need a plugin argument to remove metadata.
    93.   */
    94. public static void setOwnerless(Zombie z, Player owner, MainClass plugin) {
    95. if (z.hasMetadata(owner.getName())) {
    96. /*
    97.   * Remember that string argument? We remove a zombie's metadata
    98.   * based on this string argument, so we don't accidentally avoid all
    99.   * metadata tags from other plugins or even elsewhere in this
    100.   * plugin. (Yes! The plot thickens: You can have multiple metadata
    101.   * tags)
    102.   *
    103.   * We also need the plugin argument from which we set metadata.
    104.   */
    105. z.removeMetadata(owner.getName(), plugin);
    106. }
    107. }
    108.  
    109. }
    110.  




    This page is still a work in progress as I get time to finish it to it's fullest!

    Reserved for further use.

    EDIT by Moderator: merged posts, please use the edit button instead of double posting.
     
    Last edited by a moderator: Jun 30, 2016
    LegitJava likes this.
  2. Offline

    xTigerRebornx

    AoH_Ruthless
    Suggestion: Include a tutorial for grabbing the Object you've put into the FixedMetadataValue. While Metadata is nice to work with this way, its much more powerful with this. Say, you could have your FixedMetadataValue's key (first arguement in LivingEntity#setMetadata()) as the Player's name, but what if you had it as a constant key defined by your plugin (like Owner), then you could attach more then just a Player name and access this without having to loop through the Players to check for that key. This allows for much more, such as making the Zombies owner something other then a Player (like, another Entity that can represent an opposing "Boss Entity")

    For example, in my plugin MetadataTP, it attaches a TeleportRequest to a Player, it uses a constant key (while I may have not defined this in the best way, it gets a point across), allowing me to freely grab/set the Metadata for later use without the need for a 'Player name', and it also allows me to store more then one thing within that Metadata.

    PS: If you haven't noticed, I love the Metadata API and wish everyone knew about it and used it.

    Edit: My plugin's source doesn't show a 'safe' way of actually getting this Object, I use unchecked casting and grab the MetadataValue from its Collection without actually checking its owning plugin, I expect the OP to show a safe way of getting it :p
     
    AoH_Ruthless likes this.
  3. Offline

    AoH_Ruthless

    xTigerRebornx
    I will be sure to incorporate this. In fact, I actually made this tutorial both at my chagrin at the lack of Metadata tutorials and "stalking" your MetadataTP plugin page, in which your vision is that more people are aware of the cool things that can be done with Metadata. So I took it upon myself to make this tutorial :)
     
  4. Offline

    xTigerRebornx

    AoH_Ruthless Good to hear you'll add it, be sure to read the edit I added to that post, it gives a brief explanation of the correct way to get the Object, as my way was just for ease-of-access (since I didn't design this plugin for a production server and I doubt that there will be a plugin other then mine that uses the key that is hardcoded into my plugin)
    If you ever need help, or would like me to contribute, feel free to ask, as I'd love to contribute to this

    EDIT: I may just create my own 'tutorial' for this, and explain other things and cover more ground
     
Thread Status:
Not open for further replies.

Share This Page