Player: Move rollback responsibility to network for interact/break block

Custom player implementations might not need rollbacks (f.e. Specter).
This commit is contained in:
Dylan K. Taylor 2019-05-09 14:54:56 +01:00
parent ca7c23c137
commit 51a8c2be9d
2 changed files with 36 additions and 29 deletions

View File

@ -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;
}

View File

@ -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){