pmmp / PocketMine-MP

A server software for Minecraft: Bedrock Edition in PHP
https://pmmp.io
GNU Lesser General Public License v3.0
3.27k stars 1.54k forks source link

Failed inventory transaction does not rollback cursor inventory on client's end #4059

Closed Muqsit closed 3 years ago

Muqsit commented 3 years ago

Issue description

Steps to reproduce the issue

  1. Cancel an InventoryTransactionEvent where the inventory transaction involves a cursor inventory. The video shows the transaction rolling back (causing the item to be placed back in the chest), however the cursor inventory still holds the item ("ghost item"). On interacting with an inventory slot, the server corrects back the contents of the cursor inventory.

https://user-images.githubusercontent.com/15074389/109976664-da9a4900-7d1d-11eb-8f5d-bdca1510a30d.mp4

OS and versions

Plugins

Debugging

While the server does send the client an inventory update... https://github.com/pmmp/PocketMine-MP/blob/bbae02264ddf02c3b4f0b1e2ec2ac337e3516f40/src/network/mcpe/handler/InGamePacketHandler.php#L327) ...it seems like InvManager::syncContents() does not trigger a slot update for PlayerCursorInventory on client's end. InvManager::syncSlot() on the other hand seems to do the trick.

/**
 * @param InventoryTransactionEvent $event
 * @priority MONITOR
 * @handleCancelled true
 */
public function fixCursorInventoryNotUpdatingClientSide(InventoryTransactionEvent $event) : void{
    if($event->isCancelled()){
        $transaction = $event->getTransaction();
        $inv_manager = $transaction->getSource()->getNetworkSession()->getInvManager();
        foreach($transaction->getActions() as $action){
            if($action instanceof SlotChangeAction){
                $inv_manager->syncSlot($action->getInventory(), $action->getSlot());
            }
        }
    }
}

https://user-images.githubusercontent.com/15074389/109978759-061e3300-7d20-11eb-91d7-b42626d08416.mp4

dktapps commented 3 years ago

This has been broken since 1.13 because of the clusterfuck with "UI inventory".

ghost commented 3 years ago

It is also possible to fix by setting the players cursor inventory to air when the transaction is failed