Duplication issue with consumables
Here is a very easy demonstration of the dupe bug https://www.youtube.com/watch?v=VTkNY9gDtnw&feature=youtu.be.
All that is required is to have 2 stacks of the same consumable, one larger than the other (the one you want to dupe). Start by eating/consuming the big stack and before the animation is finished, switch hands to the smaller stack, then continue consuming until the animation is complete. Then the player must log out and log back in, and for best chances, the items should be thrown all on the ground. Then the duped items can be picked up and used like any other item.
The reason this occurs is that the currently held item stack is overwritten with the item stack that the consuming originally started the animation from. The logging out and throwing the items on the ground is required due to the fact that itemstacks in both slots are literally the same object and some reloading is needed to "unlink" them.
Here are my proposed changes with Spigot mappings in the EntityLiving class
public void c(EnumHand enumhand) { this.c(enumhand, false); } // forwarder public void c(EnumHand enumhand, boolean flag) { // new override flag ItemStack itemstack = this.b(enumhand); if (!itemstack.isEmpty() && !this.isHandRaised() || flag) { // use override flag this.activeItem = itemstack; this.bo = itemstack.k(); if (!this.world.isClientSide) { this.c(1, true); this.c(2, enumhand == EnumHand.OFF_HAND); } } }
protected void q() { if (!this.activeItem.isEmpty() && this.isHandRaised()) { this.c(this.getRaisedHand(), true); // set active item to be same as raised hand to prevent overwritting with wrong item this.b(this.activeItem, 16); this.a(this.getRaisedHand(), this.activeItem.a(this.world, this)); this.dp(); } }
I believe that it may be possible for the client to de-sync from the server if the client swaps to another stack at the very last moment (although I am really not sure because I have not tested client modification alongside a server modification). In Paper I solved this by sending an inventory update in q().
For reference here is are the changes I made for Paper https://github.com/PaperMC/Paper/pull/2477/files