From c47ecb55c0a4a2492f1288736ffe87795d5b538a Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Sun, 2 May 2021 13:22:31 +0100 Subject: [PATCH] Sign: Do not allow edits by any player except the one who placed it, and only while that player is online signs now become finalized if: - the player quits and rejoins (because the entity runtime ID of the player will not be the same) - the chunk is unloaded and reloaded (because the tagged entity runtime ID is not saved). closes #4198 --- src/pocketmine/block/SignPost.php | 5 ++++- src/pocketmine/tile/Sign.php | 22 ++++++++++++++++++++++ 2 files changed, 26 insertions(+), 1 deletion(-) diff --git a/src/pocketmine/block/SignPost.php b/src/pocketmine/block/SignPost.php index c63307446..945d20a7e 100644 --- a/src/pocketmine/block/SignPost.php +++ b/src/pocketmine/block/SignPost.php @@ -68,7 +68,10 @@ class SignPost extends Transparent{ $this->getLevelNonNull()->setBlock($blockReplace, BlockFactory::get(Block::WALL_SIGN, $this->meta), true); } - Tile::createTile(Tile::SIGN, $this->getLevelNonNull(), TileSign::createNBT($this, $face, $item, $player)); + $sign = Tile::createTile(Tile::SIGN, $this->getLevelNonNull(), TileSign::createNBT($this, $face, $item, $player)); + if($player !== null && $sign instanceof TileSign){ + $sign->setEditorEntityRuntimeId($player->getId()); + } return true; } diff --git a/src/pocketmine/tile/Sign.php b/src/pocketmine/tile/Sign.php index edfcf3735..747172be3 100644 --- a/src/pocketmine/tile/Sign.php +++ b/src/pocketmine/tile/Sign.php @@ -52,6 +52,9 @@ class Sign extends Spawnable{ /** @var string[] */ protected $text = ["", "", "", ""]; + /** @var int|null */ + protected $editorEntityRuntimeId = null; + protected function readSaveData(CompoundTag $nbt) : void{ if($nbt->hasTag(self::TAG_TEXT_BLOB, StringTag::class)){ //MCPE 1.2 save format $this->text = self::fixTextBlob($nbt->getString(self::TAG_TEXT_BLOB)); @@ -132,6 +135,22 @@ class Sign extends Spawnable{ return $this->text; } + /** + * Returns the entity runtime ID of the player who placed this sign. Only the player whose entity ID matches this + * one may edit the sign text. + * This is needed because as of 1.16.220, there is still no reliable way to detect when the MCPE client closed the + * sign edit GUI, so we have no way to know when the text is finalized. This limits editing of the text to only the + * player who placed it, and only while that player is online. + * We can say for sure that the sign is finalized if either of the following occurs: + * - The player quits (after rejoin, the player's entity runtimeID will be different). + * - The chunk is unloaded (on next load, the entity runtimeID will be null, because it's not saved). + */ + public function getEditorEntityRuntimeId() : ?int{ return $this->editorEntityRuntimeId; } + + public function setEditorEntityRuntimeId(?int $editorEntityRuntimeId) : void{ + $this->editorEntityRuntimeId = $editorEntityRuntimeId; + } + protected function addAdditionalSpawnData(CompoundTag $nbt) : void{ $nbt->setString(self::TAG_TEXT_BLOB, implode("\n", $this->text)); } @@ -158,6 +177,9 @@ class Sign extends Spawnable{ $removeFormat = $player->getRemoveFormat(); $ev = new SignChangeEvent($this->getBlock(), $player, array_map(function(string $line) use ($removeFormat) : string{ return TextFormat::clean($line, $removeFormat); }, $lines)); + if($this->editorEntityRuntimeId === null || $this->editorEntityRuntimeId !== $player->getId()){ + $ev->setCancelled(); + } $ev->call(); if(!$ev->isCancelled()){