ExecutableItems: Trades break due to random attribute modifier ordering
xProMDFKx opened this issue · 13 comments
Preliminaries:
- Shopkeepers version:
Shopkeepers 2.22.3
- Spigot version:
![image](https://github.com/user-attachments/assets/6b0db565-e3b6-4a9e-9973-fb67df9e67c6)
- I have checked that my issue/question does not get answered by:
- The documentation.
- The FAQ.
- The Known Issues.
- I have checked all open and closed issues, but none seems to fit my issue/question.
Reproduction on a fresh and up-to-date Spigot server:
I was able
to reproduce my issue on a freshly set up and up-to-date Spigot server (currently ![image](https://github.com/user-attachments/assets/db921927-03ff-452d-8e39-6a051598a77d)
) with the latest version of Shopkeepers (currently `2.22.3), with no other plugins and with no kinds of other server or client mods. (except ExecutableItems)
The issue:
Basically i want to make a boxpvp server, where shopkeepers are something EXTREMLY IMPORTANT, those items from shopkeepers i make with ExecutableItems, but before that - one of my friends that is also a server owner said that if you use ExecutableItems in Shopkeepers then the trades are getting bugged after some days, but I didn't believe him and said to try it myself and here I am, i made a full boxpvp server with a lot of items and i made the traders, after that i didn't edit anything on the custom items and after some gameplay, the items are bugging, i mean if i give to myself that item from ExecutableItems then i can't make trade anymore with it.
I also contacted the guys from ExecutableItems and they said that is a Shopkeepers issue, to check it i tried to use the comand /ei take with a "bugged item" and a non-bugged item and the command work on both, so the issue is clearly Shopkeepers, is like the plugin is not keeping the item data from ExecutableItem and just changes it randomly
So is there any solution for this? Cause as you can see, everything is the same.. but still trade do not work for one of that item, and again - that's not only on me, i have other friends who had the same issue on 1.21 with just items randomly bugging
Which server version are you using? I think Spigot already preserves the attribute modifier order since ~2019
Also there is the data get block from a chest with 2 "similar items", but one works in trading and one not:
[16:19:11 INFO]: 13, 62, -12 has the following block data: {z: -12, id: "minecraft:chest", y: 62, x: 13, Items: [{count: 1, Slot: 0b, components: {"minecraft:attribute_modifiers": {show_in_tooltip: 0b, modifiers: [{type: "minecraft:generic.attack_damage", amount: 8.0d, operation: "add_value", id: "minecraft:base_attack_damage", slot: "mainhand"}, {type: "minecraft:generic.attack_speed", amount: -3.200000047683716d, operation: "add_value", id: "minecraft:base_attack_speed", slot: "mainhand"}]}, "minecraft:lore": ['{"extra":[{"bold":false,"color":"white","italic":false,"obfuscated":false,"strikethrough":false,"text":"","underlined":false}],"text":""}', '{"extra":[{"bold":false,"color":"white","italic":false,"obfuscated":false,"strikethrough":false,"text":" ","underlined":false},{"color":"white","italic":false,"text":"ɴɪᴠᴇʟᴜʟ ᴀᴄᴛᴜᴀʟ: "},{"bold":false,"color":"#FF8322","italic":false,"obfuscated":false,"strikethrough":false,"text":"II","underlined":false}],"text":""}', '{"extra":[{"bold":false,"color":"white","italic":false,"obfuscated":false,"strikethrough":false,"text":" ","underlined":false},{"color":"white","italic":false,"text":"ʀᴀʀɪᴛᴀᴛᴇ: "},{"bold":false,"color":"#FF8322","italic":false,"obfuscated":false,"strikethrough":false,"text":"★","underlined":false},{"bold":false,"color":"#FF9948","italic":false,"obfuscated":false,"strikethrough":false,"text":"☆","underlined":false},{"bold":false,"color":"#FFAE6F","italic":false,"obfuscated":false,"strikethrough":false,"text":"☆","underlined":false},{"bold":false,"color":"#FFC495","italic":false,"obfuscated":false,"strikethrough":false,"text":"☆","underlined":false},{"bold":false,"color":"#FFD9BB","italic":false,"obfuscated":false,"strikethrough":false,"text":"☆","underlined":false}],"text":""}', '{"extra":[{"bold":false,"color":"white","italic":false,"obfuscated":false,"strikethrough":false,"text":"","underlined":false}],"text":""}', '{"extra":[{"bold":false,"color":"white","italic":false,"obfuscated":false,"strikethrough":false,"text":" ᴇɴᴄʜᴀɴᴛ-ᴜʀɪ ɪᴛᴇᴍ:","underlined":false}],"text":""}', '{"extra":[{"bold":false,"color":"white","italic":false,"obfuscated":false,"strikethrough":false,"text":"","underlined":false}],"text":""}', '{"extra":[{"bold":false,"color":"#FFD9BB","italic":false,"obfuscated":false,"strikethrough":false,"text":" Efficiency III","underlined":false}],"text":""}', '{"extra":[{"bold":false,"color":"#FFC89C","italic":false,"obfuscated":false,"strikethrough":false,"text":" Unbreaking II","underlined":false}],"text":""}', '{"extra":[{"bold":false,"color":"white","italic":false,"obfuscated":false,"strikethrough":false,"text":"","underlined":false}],"text":""}', '{"extra":[{"bold":false,"color":"white","italic":false,"obfuscated":false,"strikethrough":false,"text":"Item de tip: ","underlined":false},{"bold":true,"color":"#FF8322","italic":false,"obfuscated":false,"strikethrough":false,"text":"C","underlined":false},{"bold":true,"color":"#FF9441","italic":false,"obfuscated":false,"strikethrough":false,"text":"U","underlined":false},{"bold":true,"color":"#FFA55F","italic":false,"obfuscated":false,"strikethrough":false,"text":"S","underlined":false},{"bold":true,"color":"#FFB77E","italic":false,"obfuscated":false,"strikethrough":false,"text":"T","underlined":false},{"bold":true,"color":"#FFC89C","italic":false,"obfuscated":false,"strikethrough":false,"text":"O","underlined":false},{"bold":true,"color":"#FFD9BB","italic":false,"obfuscated":false,"strikethrough":false,"text":"M","underlined":false}],"text":""}'], "minecraft:enchantments": {show_in_tooltip: 0b, levels: {"minecraft:unbreaking": 2, "minecraft:efficiency": 3}}, "minecraft:custom_name": '{"extra":[{"bold":true,"color":"#FF8322","italic":false,"obfuscated":false,"strikethrough":false,"text":"T","underlined":false},{"bold":true,"color":"#FF882B","italic":false,"obfuscated":false,"strikethrough":false,"text":"O","underlined":false},{"bold":true,"color":"#FF8D34","italic":false,"obfuscated":false,"strikethrough":false,"text":"P","underlined":false},{"bold":true,"color":"#FF923D","italic":false,"obfuscated":false,"strikethrough":false,"text":"O","underlined":false},{"bold":true,"color":"#FF9746","italic":false,"obfuscated":false,"strikethrough":false,"text":"R ","underlined":false},{"bold":true,"color":"#FFA158","italic":false,"obfuscated":false,"strikethrough":false,"text":"D","underlined":false},{"bold":true,"color":"#FFA661","italic":false,"obfuscated":false,"strikethrough":false,"text":"E ","underlined":false},{"bold":true,"color":"#FFB173","italic":false,"obfuscated":false,"strikethrough":false,"text":"I","underlined":false},{"bold":true,"color":"#FFB67C","italic":false,"obfuscated":false,"strikethrough":false,"text":"N","underlined":false},{"bold":true,"color":"#FFBB85","italic":false,"obfuscated":false,"strikethrough":false,"text":"C","underlined":false},{"bold":true,"color":"#FFC08E","italic":false,"obfuscated":false,"strikethrough":false,"text":"E","underlined":false},{"bold":true,"color":"#FFC597","italic":false,"obfuscated":false,"strikethrough":false,"text":"P","underlined":false},{"bold":true,"color":"#FFCAA0","italic":false,"obfuscated":false,"strikethrough":false,"text":"A","underlined":false},{"bold":true,"color":"#FFCFA9","italic":false,"obfuscated":false,"strikethrough":false,"text":"T","underlined":false},{"bold":true,"color":"#FFD4B2","italic":false,"obfuscated":false,"strikethrough":false,"text":"O","underlined":false},{"bold":true,"color":"#FFD9BB","italic":false,"obfuscated":false,"strikethrough":false,"text":"R","underlined":false}],"text":""}', "minecraft:custom_data": {PublicBukkitValues: {"score:usage": 1, "executableitems:ei-id": "topor_incepator_nivel_2"}}, "minecraft:hide_additional_tooltip": {}}, id: "minecraft:stone_axe"}, {count: 1, Slot: 1b, components: {"minecraft:attribute_modifiers": {show_in_tooltip: 0b, modifiers: [{type: "minecraft:generic.attack_speed", amount: -3.200000047683716d, operation: "add_value", id: "minecraft:base_attack_speed", slot: "mainhand"}, {type: "minecraft:generic.attack_damage", amount: 8.0d, operation: "add_value", id: "minecraft:base_attack_damage", slot: "mainhand"}]}, "minecraft:lore": ['{"extra":[{"bold":false,"color":"white","italic":false,"obfuscated":false,"strikethrough":false,"text":"","underlined":false}],"text":""}', '{"extra":[{"bold":false,"color":"white","italic":false,"obfuscated":false,"strikethrough":false,"text":" ","underlined":false},{"color":"white","italic":false,"text":"ɴɪᴠᴇʟᴜʟ ᴀᴄᴛᴜᴀʟ: "},{"bold":false,"color":"#FF8322","italic":false,"obfuscated":false,"strikethrough":false,"text":"II","underlined":false}],"text":""}', '{"extra":[{"bold":false,"color":"white","italic":false,"obfuscated":false,"strikethrough":false,"text":" ","underlined":false},{"color":"white","italic":false,"text":"ʀᴀʀɪᴛᴀᴛᴇ: "},{"bold":false,"color":"#FF8322","italic":false,"obfuscated":false,"strikethrough":false,"text":"★","underlined":false},{"bold":false,"color":"#FF9948","italic":false,"obfuscated":false,"strikethrough":false,"text":"☆","underlined":false},{"bold":false,"color":"#FFAE6F","italic":false,"obfuscated":false,"strikethrough":false,"text":"☆","underlined":false},{"bold":false,"color":"#FFC495","italic":false,"obfuscated":false,"strikethrough":false,"text":"☆","underlined":false},{"bold":false,"color":"#FFD9BB","italic":false,"obfuscated":false,"strikethrough":false,"text":"☆","underlined":false}],"text":""}', '{"extra":[{"bold":false,"color":"white","italic":false,"obfuscated":false,"strikethrough":false,"text":"","underlined":false}],"text":""}', '{"extra":[{"bold":false,"color":"white","italic":false,"obfuscated":false,"strikethrough":false,"text":" ᴇɴᴄʜᴀɴᴛ-ᴜʀɪ ɪᴛᴇᴍ:","underlined":false}],"text":""}', '{"extra":[{"bold":false,"color":"white","italic":false,"obfuscated":false,"strikethrough":false,"text":"","underlined":false}],"text":""}', '{"extra":[{"bold":false,"color":"#FFD9BB","italic":false,"obfuscated":false,"strikethrough":false,"text":" Efficiency III","underlined":false}],"text":""}', '{"extra":[{"bold":false,"color":"#FFC89C","italic":false,"obfuscated":false,"strikethrough":false,"text":" Unbreaking II","underlined":false}],"text":""}', '{"extra":[{"bold":false,"color":"white","italic":false,"obfuscated":false,"strikethrough":false,"text":"","underlined":false}],"text":""}', '{"extra":[{"bold":false,"color":"white","italic":false,"obfuscated":false,"strikethrough":false,"text":"Item de tip: ","underlined":false},{"bold":true,"color":"#FF8322","italic":false,"obfuscated":false,"strikethrough":false,"text":"C","underlined":false},{"bold":true,"color":"#FF9441","italic":false,"obfuscated":false,"strikethrough":false,"text":"U","underlined":false},{"bold":true,"color":"#FFA55F","italic":false,"obfuscated":false,"strikethrough":false,"text":"S","underlined":false},{"bold":true,"color":"#FFB77E","italic":false,"obfuscated":false,"strikethrough":false,"text":"T","underlined":false},{"bold":true,"color":"#FFC89C","italic":false,"obfuscated":false,"strikethrough":false,"text":"O","underlined":false},{"bold":true,"color":"#FFD9BB","italic":false,"obfuscated":false,"strikethrough":false,"text":"M","underlined":false}],"text":""}'], "minecraft:enchantments": {show_in_tooltip: 0b, levels: {"minecraft:unbreaking": 2, "minecraft:efficiency": 3}}, "minecraft:custom_name": '{"extra":[{"bold":true,"color":"#FF8322","italic":false,"obfuscated":false,"strikethrough":false,"text":"T","underlined":false},{"bold":true,"color":"#FF882B","italic":false,"obfuscated":false,"strikethrough":false,"text":"O","underlined":false},{"bold":true,"color":"#FF8D34","italic":false,"obfuscated":false,"strikethrough":false,"text":"P","underlined":false},{"bold":true,"color":"#FF923D","italic":false,"obfuscated":false,"strikethrough":false,"text":"O","underlined":false},{"bold":true,"color":"#FF9746","italic":false,"obfuscated":false,"strikethrough":false,"text":"R ","underlined":false},{"bold":true,"color":"#FFA158","italic":false,"obfuscated":false,"strikethrough":false,"text":"D","underlined":false},{"bold":true,"color":"#FFA661","italic":false,"obfuscated":false,"strikethrough":false,"text":"E ","underlined":false},{"bold":true,"color":"#FFB173","italic":false,"obfuscated":false,"strikethrough":false,"text":"I","underlined":false},{"bold":true,"color":"#FFB67C","italic":false,"obfuscated":false,"strikethrough":false,"text":"N","underlined":false},{"bold":true,"color":"#FFBB85","italic":false,"obfuscated":false,"strikethrough":false,"text":"C","underlined":false},{"bold":true,"color":"#FFC08E","italic":false,"obfuscated":false,"strikethrough":false,"text":"E","underlined":false},{"bold":true,"color":"#FFC597","italic":false,"obfuscated":false,"strikethrough":false,"text":"P","underlined":false},{"bold":true,"color":"#FFCAA0","italic":false,"obfuscated":false,"strikethrough":false,"text":"A","underlined":false},{"bold":true,"color":"#FFCFA9","italic":false,"obfuscated":false,"strikethrough":false,"text":"T","underlined":false},{"bold":true,"color":"#FFD4B2","italic":false,"obfuscated":false,"strikethrough":false,"text":"O","underlined":false},{"bold":true,"color":"#FFD9BB","italic":false,"obfuscated":false,"strikethrough":false,"text":"R","underlined":false}],"text":""}', "minecraft:custom_data": {PublicBukkitValues: {"score:usage": 1, "executableitems:ei-id": "topor_incepator_nivel_2"}}, "minecraft:hide_additional_tooltip": {}}, id: "minecraft:stone_axe"}]
The only difference seems to be in the order of the attribute modifiers:
modifiers: [{type: "minecraft:generic.attack_damage", amount: 8.0d, operation: "add_value", id: "minecraft:base_attack_damage", slot: "mainhand"}, {type: "minecraft:generic.attack_speed", amount: -3.200000047683716d, operation: "add_value", id: "minecraft:base_attack_speed", slot: "mainhand"}]
vs
modifiers: [{type: "minecraft:generic.attack_speed", amount: -3.200000047683716d, operation: "add_value", id: "minecraft:base_attack_speed", slot: "mainhand"}, {type: "minecraft:generic.attack_damage", amount: 8.0d, operation: "add_value", id: "minecraft:base_attack_damage", slot: "mainhand"}]
I still have to check this, but it could be that this is a Spigot issue. I.e. maybe the order didn't matter in older Minecraft versions, but now it does, but Spigot doesn't property preserve it when a plugin such as Shopkeepers saves and loads the item.
Seems like ExceutableItems is not properly preserving the order of attributes here: https://github.com/Ssomar-Developement/SCore/blob/main/src/main/java/com/ssomar/score/features/custom/attributes/group/AttributesGroupFeature.java#L38
They are using a HashMap
to store the attributes loaded from the item config file, which does not guarantee a particular ordering (so you can get random differences just by reloading / restarting the plugin/server). I haven't checked if there are other places where the attribute order might get broken, but this would be my initial guess.
-> Report this to them, and check again if this particular issue with items not matching due to random changes in the attribute modifier ordering is then resolved.
I just tested this, and the attribute modifier order is preserved fine inside Shopkeepers on Spigot 1.21. So now the question is how you ended up with different modifier orders.
I think that is exactly as you said, cause i also have another /paper dumpitem from 2 similar items and it looks like this:
First item:
message (1).txt
Second item:
message.txt
any custom items
is like the plugin is not keeping the item data from ExecutableItem and just changes it randomly
The Shopkeepers plugin does not implement the saving and loading of items itself, but relies in Spigot's item serialization API. Unless there is an issue in Spigot's item serialization, or the custom item plugin in question uses some item data that is not properly supported by the Spigot item serialization (both of those cases would be something to fix inside the Spigot server), all item data is preserved as is.
However, in order to be able to report any issue to the responsible party or find a workaround, we first need to identify the particular issue. So I need the following in order to investigate the issue:
- The exact server version (
/version
output that mentions both the server type and exact build number). - If you are not using Spigot or a not using the latest Spigot build, also try to reproduce the issue on an up-to-date Spigot server, ideally with only the minimal set of plugins required to reproduce the issue. Because this will match the setup that I use to try to reproduce the issue.
- Please provide an example item, and the step by step instructions on how to reproduce the issue ("it randomly breaks after a few days" is nothing I can investigate).
- Try to keep the example item minimal in item data, because I need to identify the exact data changes between the original item and the item after your reproduction steps, which is easier if the item has only minimal data to begin with.
- If you can reproduce the issue with a custom item created with only Minecraft's
/give
command, that makes it even easier for me to reproduce the issue, and rules out ExecutableItems being the problem. - If you already have cases currently where some newly created item is not being accepted by some shopkeeper: Move both of those items to a chest and then use Minecraft's
/data get block <x y z>
to get the NBT data of those items. Paste this data here, so I can check for differences.
You can also setup a second trade inside the affected shopkeeper for the new item, and send me the data of this shopkeeper from yoursave.yml
file.
Regarding ExecutableItems / custom items plugins in particular:
- If you / the ExecutableItems plugin make changes to how the items are created, e.g. if you edit the item config files, or if the plugin made some changes to the item creation after a plugin update: The corresponding items inside the Shopkeepers will not automatically update to match those new items. There is an existing ticket about updating the item data inside the Shopkeepers to match the latest revisions of the ExecutableItems: #852
- If the items created by ExecutableItems contain any kind of unique item data (e.g. unique identifiers, timestamps, 'item owner/creator', usage counters, etc.): Those item properties are matched just like any other item data inside Shopkeeper trades, i.e. items with different data will not be accepted in trades. This behavior is 'working as intended'. There are no plans to make changes to the item comparison logic.
Reply to the last ExecutableItems 2 points:
Is it possible for items to bug because of that string from an EI item:
usage: 1
usageLimit: -1
?
Reply to the last ExecutableItems 2 points:
Is it possible for items to bug because of that string from an EI item:
usage: 1 usageLimit: -1
?
I am not familiar with ExecutableItems and how those options affect the resulting item. But if this results in the item containing a usage counter that can dynamically change in certain situations, then yes, you will not be able to properly use such items in trades: Trades require that the item you pass matches the item you setup the trade with. The same applies to vanilla trades.
It is possible for the trade to ignore certain item tags (might currently be broken on Spigot 1.20.5+/1.21, at least for certain tags), by removing those tags from the item you setup the trade with. I.e. if you setup the trade with an item that has no usage
tag at all, players can use the trade regardless of whether the item they use contains a usage
tag. But setting this up is a bit inconvenient, and only really applicable for admin shops: You would need to use Minecraft's /data
command or some third-party plugin to manually edit the item data before you use it to setup the trade.
Apparently fixed with the latest ExecutableItems update: https://www.spigotmc.org/resources/custom-items-plugin-executable-items.77578/update?update=556191