It is possible to create a server-client desynced item via advancement reward- & tick function execution due to a difference in tick execution order between server and client.
Recreating this takes 4 things:
Any consumable item.
An advancement triggered via
minecraft:consume_item
A reward function “storing“ the consumed item
A tick function “restoring“ the stored item to its original slot
The item can be generated using /give @s minecraft:stick[minecraft:use_remainder={"id":"minecraft:feather"},minecraft:consumable={"consume_seconds":0.5}]
. While the use_remainder
is not necessary, it does make the specifics of the bug more visible and easier to verify.
The advancement is simply:
{
"criteria": {
"use_item": {
"trigger": "minecraft:consume_item"
}
},
"rewards": {
"function": "namespace:store_item"
}
}
with its reward function putting a copy of the item into the players offhand:
item replace entity @s weapon.offhand from entity @s weapon.mainhand
Lastly a tick function “restoring” the item for all players with the advancement and revoking it after so we don’t get stuck in a loop:
execute as @a[advancements={namespace:consumed_item=true}] run item replace entity @s weapon.mainhand from entity @s weapon.offhand
execute as @a[advancements={namespace:consumed_item=true}] run advancement revoke @s only namespace:consumed_item
With all this in place, consuming the item in the mainhand now puts a desynced item back into the players hand. It appears as the original items use remainder but querying it’s data using /data get entity @s SelectedItem
reveals that it’s actually the original item itself. In this example the client thinks the player has a feather in their hand while the server knows that it’s actually a stick. This discrepancy is resolved the moment the player moves the item or drops it out of their inventory.
Interestingly this desync does not occur when the original items consume_seconds
are 0.0
. In such a case both the client and server know that the held item afterwards is a stick.
The expectation of how this would work after a fix is that both the server and client agree on the held item after all functions have run their course, specifically agree that the now “restored“ item in this example is a stick, the way it currently works when `{"consume_seconds":0.0}
`.
Linked issues
Comments 0
No comments.