SpigotMC/Spigot — pull request #229 by NathanWolf (2014-09-03 15:13:23+00:00)
Title: Add custom Item metadata API, item NBT storage - Adds BUKKIT-3221  

## Spigot PR

This PR is a copy of one pending Bukkit approval. The original PR garnered a lot of attention, and seemed like it was going to get approved - mainly because storing custom item data will be a requirement to support 1.8's vanilla map making features.

However, I'm not sure at this point if anything is getting pulled by Bukkit, or what. So I thought I'd try here!

My main goal with this PR is to facilitate storage and serialization of arbitrary ItemStack NBT tags.

The original PR has evolved (by request) into a Metadatable interface on ItemMeta that uses NBT for data storage, so that developers have access to a persistent Item data store. We decided to put custom Bukkit plugin data in a special path (see below), so that this does not become an "NBT API"- the NBT part is only for storage, and plugins don't have direct access to root NBT tags, they must use the associated APIs.

I am open to changing any and all of this, including getting rid of the API entirely. The original PR didn't have an associated API, and used an interface more Configuration-like than Metadata-like. My main goal is to allow custom data attached to items by plugins to survive, and to get serialized in a way that doesn't interfere with internal/vanilla NBT data.

## The Issue

There is currently no API method to track an ItemStack through its lifecycle for the purpose of creating a custom item.

## Justification for this PR

The ability to create custom items by tagging them with arbitrary data could add lot of depth to what Plugin developers are able to offer.

There are various methods employed to accomplish this (protocol hacking, direct NBT editing, name/lore data storage) but they all have downsides and don't interact well with each other or the API.

The item "glow" API requested by BUKKIT-4767 is also added here, it was a very clean and easy fit into the metadata framework provided by the bulk of this PR, and will hopefully make testing all of this in conjunction easier.

This PR provides also provides a mechanism to store unknown or custom NBT data on items, which may be important given the addition of custom item data in 1.8.

## PR Breakdown

### Bukkit

The ItemMeta interface now extends Metadatable. This is a different kind of persistent metadata store that can not store arbitrary Object instances. I wanted to make that clear and hopefully avoid confusion, so I made a new PersistentMetadataValue type that must be used when storing custom item data.

Basic types, Lists and Maps can be stored, as can ConfigurationSerializeable objects.

ItemStack also contains two "hasMetadata" methods which can be used to do efficient first-pass checks for custom data without the expense of unpacking the ItemMeta structure.

### CraftBukkit

Custom data will be stored in a "bukkit" NBT tag on the NMS ItemStack. This is an implementation detail that could change in the future, but at present is the easiest and safest method for storing relatively small amounts of structured data on an item.

The "bukkit" tag itself is reserved for internal Bukkit use. This PR also implements the item "glow" API requested by BUKKIT-4767, using a custom "bukkit.glow" flag to maintain state independently of enchantments.

Custom Plugin metadata is stored in "bukkit.plugins..". No effort is made to preserve data attached to items that is registered to an unloaded plugin.

## Testing Results and Materials

A JUnit test was provided in the original CB PR which attempts to exercise the API as much as possible. I'm not sure how to include that here- should it be part of a patch?

There is a plugin that can be used for testing, available here:

https://github.com/NathanWolf/Test-ItemMetaData/tree/Metadatable
http://mine.elmakers.com/Test-ItemMetaData.jar

This plugin has several commands available for adding custom data, testing with enchants, glow effect, and checking for data.

### Plugin Commands

*All of the following must be used in-game.*

invpush: Push your entire inventory into a serialized stack. Useful for testing item serialization.
invpop: Pop your stored inventory off the stack. Will drop any items you have to the ground.

*All of the following must be used while holding an item*

itemcheck: Display information about an item, including any custom data
itemclone: Make a copy of an item
itemunenchant: Remove all enchantments from an item
itemfly: Tag an item with some special data that also makes you fly when you swing it
itemunfly: Remove the special testing/fly data.
itemglow: Make an item glow
itemunglow: Make an item not glow, unless it's enchanted

After you've used /itemfly, the item will have its custom data updated each time you swing it. Use /itemcheck to verify the data is getting updated properly.

## Relevant PR(s)

B-1064: https://github.com/Bukkit/Bukkit/pull/1064 - Original Bukkit PR
C-1376 :https://github.com/Bukkit/CraftBukkit/pull/1376 - Original CraftBukkit PR

## JIRA Ticket
https://bukkit.atlassian.net/browse/BUKKIT-3221
Also resolves these tickets:
https://bukkit.atlassian.net/browse/BUKKIT-4864
https://bukkit.atlassian.net/browse/BUKKIT-4767