Minecraft 1.20.5+ provides a lot more flexibility now to configure how items are matched in villager trades in the form of the DataComponentPredicate. I.e. it is possible to specify which components to match, which to ignore, etc.
The Bukkit API is currently not yet exposing this flexibility.
Currently, when creating a MerchantRecipe based on ItemStack ingredients, the resulting trade requires all components to be present, including components that are not explicitly specified on the item (their default component state is then required, which is not the same as not matching the component).
Side note: One might maybe even consider this a bug, since this behavior differs to previous Minecraft versions. Example: An item stack without enchantments set (i.e. the enchantments component is not present, rather than present and empty) currently results in a MerchantRecipe that requires the provided item to not have any enchantments. In previous server versions (e.g. 1.19.4), the resulting trade would ignore the enchantments lists instead.
Is this change in behavior intended, or could this be considered a bug? -> I created a separate ticket for this: SPIGOT-7907
But regardless of the default behavior for converting a given ItemStack to a corresponding DataComponentPredicate: It might make sense to expose this new flexibility of DataComponentPredicate to plugins, to be for example used for the definition of MerchantRecipe, but maybe also as a standalone API (i.e. plugins could create DataComponentPredicates and match items against them, without using those as part of MerchantRecipes).
Since ItemMeta already supports differentiating between whether certain data is present vs empty (Edit: At least in some cases): One simple solution could be to just provide some matching method on it that matches a given item just like the DataComponentPredicate matches components (supersedes SPIGOT-3178).
And if we would change the default of how we convert ItemStacks to MerchantRecipes back to not match non-specified components again, we might not need any new API to represent DataComponentPredicates, nor new parameters that control how an ItemStack is converted to a MerchantRecipe.
Edit: This idea of using ItemMeta to represent both actual item data and representing the item data of DataComponentPredicates might require some additional adaptations, because there are some differences, and ItemMeta in its current form doesn't properly support this yet for all properties. Example: Actual item data doesn't support/differentiate between empty and non-present enchantments, but DataComponentPredicates do. So to be able use ItemMeta for DataComponentPredicates, we would need to properly differentiate between null (unset) and an empty enchantments map in ItemMeta, but still treat those two states the same when comparing item meta via equals/isSimilar or applying the ItemMeta to an ItemStack. The ItemMeta implementation actually already works like this internally, but API users cannot properly set and differentiate these two states yet (e.g. hasEnchantments doesn't differentiate between null and empty, and there is no direct way for plugins to set the enchantments to either null or empty). So some ItemMeta API adaptations might be required, also for other properties, to eventually be able to properly use it also as representation for DataComponentPredicates.
- is duplicated by
-
SPIGOT-3178 MetaData.contains(MetaData, boolean)
- Closed
- relates to
-
SPIGOT-7907 MC 1.20.5: Change in MerchantRecipe item matching
- Resolved