[SPIGOT-3178] MetaData.contains(MetaData, boolean) Created: 11/Apr/17 Updated: 10/Jul/24 Resolved: 10/Jul/24 |
|
Status: | Closed |
Project: | Spigot |
Component/s: | None |
Affects Version/s: | None |
Fix Version/s: | None |
Type: | New Feature | Priority: | Minor |
Reporter: | blablubbabc | Assignee: | Unassigned |
Resolution: | Duplicate | Votes: | 1 |
Labels: | None |
Issue Links: |
|
Description |
I am currently trying to check in a plugin if an item contains specific metadata, which a player or admin can specify by providing an ItemStack, similar to minecraft's testFor command: In minecraft they parse the nbt data from the command and then check if the data of entities contains the same data. (their implementation can be found here: GameProfileSerializer.a(NBTBase paramNBTBase1, NBTBase paramNBTBase2, boolean paramBoolean)) This is different to ItemStack.isSimilar or MetaData.equals because those check for equality, while I am interested in checking if an item has certain data, specified by a player or admin. Matching items are however allowed to additionally have other data. Example: If the specified MetaData contains enchantments, then it checks if the MetaData of other items contains those enchantments, without checking if all their enchantments are the same.
One could write and maintain the code which checks for all the different meta data attributes (for all the different item types, etc.). I am trying to avoid doing that in my plugin. It would be nice to have that directly in craftbukkit instead, where it could be easily maintained whenever new metadata is added. Currently I am using MetaData.serialize to get a Map representation of the ItemStack's metadata and then go through that map similar to how GameProfileSerializer.a(NBTBase paramNBTBase1, NBTBase paramNBTBase2, boolean paramBoolean) works. This however has a few drawbacks as well:
Now, I am proposing a method MetaData#contains(MetaData otherData, boolean checkListsContain) which checks if the MetaData contains the given other MetaData. With the additional boolean parameter one can decide whether to check if lists (ex. lore, ..) are completely equal, or whether it checks if the lists contain the entries which can be found in the corresponding lists of the given other MetaData. (Similar to the boolean parameter in GameProfileSerializer.a(NBTBase paramNBTBase1, NBTBase paramNBTBase2, boolean paramBoolean)). The implementation would then check for every data in the given otherData, if the MetaData contains the data. Example: if (otherData.hasDisplayName()) return this.hasDisplayName() && this.getDisplayName().equals(otherData.getDisplayName()) Example for lore: if (otherData.hasLore()) return this.hasLore() && checkListContains ? this.getLore().containsAll(otherData.getLore()) : this.getLore().equals(otherData.getLore()) The unhandledTags could be compared by using minecraft's GameProfileSerializer.a(NBTBase paramNBTBase1, NBTBase paramNBTBase2, boolean paramBoolean) method.
I would be willing to create a pull request for this if you would be willing to accept such an addition. |
Comments |
Comment by blablubbabc [ 10/Jul/24 ] |
Superseded: A solution for MC 1.20.5+ should probably be based on the new DataComponentPredicate instead. |
Comment by blablubbabc [ 10/Jul/24 ] |
Closed in favor of https://hub.spigotmc.org/jira/browse/SPIGOT-7828 (MC 1.20.5 added a new DataComponentPredicate to handle item data matching) |
Comment by blablubbabc [ 11/May/18 ] |
Any chance to get this added? |
Comment by blablubbabc [ 12/Apr/17 ] |
I created pull requests for it: https://hub.spigotmc.org/stash/projects/SPIGOT/repos/bukkit/pull-requests/269/ https://hub.spigotmc.org/stash/projects/SPIGOT/repos/craftbukkit/pull-requests/363/
It relies on the corresponding minecraft method this is supposed to mimic so there is actually no maintainance needed now. Another usecase for this method (with the 'checkLists' parameter set to false) would be to check if an item matches the required item of an minecraft merchant trading recipe. Currently most shop plugins are probably comparing for full item equality with isSimilar. If they would want to mimic minecraft's trading behavior, they could now use this new method to implement the item comparison. |
Comment by blablubbabc [ 11/Apr/17 ] |
Also the unhandledTags cannot be checked by a plugin. And if this 1 line of code per item-meta addition is too much of an effort to maintain, one could even use CraftItemMeta.applyTo(NBTCompound) and minecraft's own GameProfileSerializer.a(NBTBase paramNBTBase1, NBTBase paramNBTBase2, boolean paramBoolean) method to implement it. Contra:
Pro:
|
Comment by blablubbabc [ 11/Apr/17 ] |
There isn't much of additional effort in maintaining this inside the server, because you already have to update the MetaData.equals() method whenever new item meta data is added to minecraft. So when new meta data is added to minecraft and you already have to add a line of code to the equals method, you would now simply add a very similar line of code to the contains method as well.
|
Comment by md_5 [ 11/Apr/17 ] |
>One could write and maintain the code which checks for all the different meta data attributes (for all the different item types, etc.). I am trying to avoid doing that in my plugin. It would be nice to have that directly in craftbukkit instead, where it could be easily maintained whenever new metadata is added. If you want to do burden shifting on this large a scale there needs to be a compelling reason for it. It's not any easier at all to implement into the server, yet it's a non trivial piece of code that would need to be maintained by us every update for apparently just your /testfor command. It's also not unit testable which is a massive pain because it means if there is ever a lapse in it after an update, its just another bug report in a very busy time window. |