diff --git a/src/pocketmine/Player.php b/src/pocketmine/Player.php index fa90bc91f..b171a01fc 100644 --- a/src/pocketmine/Player.php +++ b/src/pocketmine/Player.php @@ -24,7 +24,6 @@ declare(strict_types=1); namespace pocketmine; use pocketmine\block\Bed; -use pocketmine\block\Block; use pocketmine\block\BlockFactory; use pocketmine\block\BlockLegacyIds; use pocketmine\block\UnknownBlock; @@ -117,7 +116,6 @@ use pocketmine\world\format\Chunk; use pocketmine\world\Position; use pocketmine\world\World; use function abs; -use function array_merge; use function assert; use function ceil; use function count; @@ -1952,7 +1950,7 @@ class Player extends Human implements CommandSender, ChunkLoader, ChunkListener, * * @param Vector3 $pos * - * @return bool if the block was successfully broken. + * @return bool if the block was successfully broken, false if a rollback needs to take place. */ public function breakBlock(Vector3 $pos) : bool{ $this->doCloseInventory(); @@ -1969,16 +1967,6 @@ class Player extends Human implements CommandSender, ChunkLoader, ChunkListener, } } - $this->inventory->sendContents($this); - $this->inventory->sendHeldItem($this); - - $target = $this->world->getBlock($pos); - /** @var Block[] $blocks */ - $blocks = $target->getAllSides(); - $blocks[] = $target; - - $this->world->sendBlocks([$this], $blocks); - return false; } @@ -2005,20 +1993,6 @@ class Player extends Human implements CommandSender, ChunkLoader, ChunkListener, } } - $this->inventory->sendHeldItem($this); - - if($pos->distanceSquared($this) > 10000){ - return true; - } - - $target = $this->world->getBlock($pos); - $block = $target->getSide($face); - - /** @var Block[] $blocks */ - $blocks = array_merge($target->getAllSides(), $block->getAllSides()); //getAllSides() on each of these will include $target and $block because they are next to each other - - $this->world->sendBlocks([$this], $blocks); - return false; } diff --git a/src/pocketmine/network/mcpe/handler/SimpleSessionHandler.php b/src/pocketmine/network/mcpe/handler/SimpleSessionHandler.php index 380ee768f..8ff6c6ae3 100644 --- a/src/pocketmine/network/mcpe/handler/SimpleSessionHandler.php +++ b/src/pocketmine/network/mcpe/handler/SimpleSessionHandler.php @@ -23,6 +23,7 @@ declare(strict_types=1); namespace pocketmine\network\mcpe\handler; +use pocketmine\block\Block; use pocketmine\block\ItemFrame; use pocketmine\block\Sign; use pocketmine\block\utils\SignText; @@ -78,6 +79,7 @@ use pocketmine\network\mcpe\protocol\types\ReleaseItemTransactionData; use pocketmine\network\mcpe\protocol\types\UseItemOnEntityTransactionData; use pocketmine\network\mcpe\protocol\types\UseItemTransactionData; use pocketmine\Player; +use function array_push; use function base64_encode; use function fmod; use function implode; @@ -267,10 +269,17 @@ class SimpleSessionHandler extends SessionHandler{ return true; } //TODO: end hack for client spam bug - $this->player->interactBlock($data->getBlockPos(), $data->getFace(), $clickPos); + + $blockPos = $data->getBlockPos(); + if(!$this->player->interactBlock($blockPos, $data->getFace(), $clickPos)){ + $this->onFailedBlockAction($blockPos, $data->getFace()); + } return true; case UseItemTransactionData::ACTION_BREAK_BLOCK: - $this->player->breakBlock($data->getBlockPos()); + $blockPos = $data->getBlockPos(); + if(!$this->player->breakBlock($blockPos)){ + $this->onFailedBlockAction($blockPos, null); + } return true; case UseItemTransactionData::ACTION_CLICK_AIR: $this->player->useHeldItem(); @@ -280,6 +289,30 @@ class SimpleSessionHandler extends SessionHandler{ return false; } + /** + * Internal function used to execute rollbacks when an action fails on a block. + * + * @param Vector3 $blockPos + * @param int|null $face + */ + private function onFailedBlockAction(Vector3 $blockPos, ?int $face) : void{ + $this->player->getInventory()->sendHeldItem($this->player); + if($blockPos->distanceSquared($this->player) < 10000){ + $target = $this->player->getWorld()->getBlock($blockPos); + + $blocks = $target->getAllSides(); + if($face !== null){ + $sideBlock = $target->getSide($face); + + /** @var Block[] $blocks */ + array_push($blocks, ...$sideBlock->getAllSides()); //getAllSides() on each of these will include $target and $sideBlock because they are next to each other + }else{ + $blocks[] = $target; + } + $this->player->getWorld()->sendBlocks([$this->player], $blocks); + } + } + private function handleUseItemOnEntityTransaction(UseItemOnEntityTransactionData $data) : bool{ $target = $this->player->getWorld()->getEntity($data->getEntityRuntimeId()); if($target === null){