mirror of
https://github.com/pmmp/PocketMine-MP.git
synced 2025-05-11 08:19:45 +00:00
Revamp Sign API, flatten API into blocks
This commit is contained in:
parent
f680a239f7
commit
5cca4b5e31
@ -92,21 +92,17 @@ use pocketmine\level\Level;
|
||||
use pocketmine\level\Position;
|
||||
use pocketmine\math\Vector3;
|
||||
use pocketmine\metadata\MetadataValue;
|
||||
use pocketmine\nbt\NbtDataException;
|
||||
use pocketmine\nbt\tag\ByteTag;
|
||||
use pocketmine\nbt\tag\CompoundTag;
|
||||
use pocketmine\nbt\tag\DoubleTag;
|
||||
use pocketmine\nbt\tag\ListTag;
|
||||
use pocketmine\network\BadPacketException;
|
||||
use pocketmine\network\mcpe\CompressBatchPromise;
|
||||
use pocketmine\network\mcpe\NetworkCipher;
|
||||
use pocketmine\network\mcpe\NetworkNbtSerializer;
|
||||
use pocketmine\network\mcpe\NetworkSession;
|
||||
use pocketmine\network\mcpe\ProcessLoginTask;
|
||||
use pocketmine\network\mcpe\protocol\AdventureSettingsPacket;
|
||||
use pocketmine\network\mcpe\protocol\AnimatePacket;
|
||||
use pocketmine\network\mcpe\protocol\AvailableCommandsPacket;
|
||||
use pocketmine\network\mcpe\protocol\BlockEntityDataPacket;
|
||||
use pocketmine\network\mcpe\protocol\BookEditPacket;
|
||||
use pocketmine\network\mcpe\protocol\ChunkRadiusUpdatedPacket;
|
||||
use pocketmine\network\mcpe\protocol\ClientboundPacket;
|
||||
@ -134,7 +130,6 @@ use pocketmine\permission\PermissionAttachment;
|
||||
use pocketmine\permission\PermissionAttachmentInfo;
|
||||
use pocketmine\permission\PermissionManager;
|
||||
use pocketmine\plugin\Plugin;
|
||||
use pocketmine\tile\Spawnable;
|
||||
use pocketmine\tile\Tile;
|
||||
use pocketmine\timings\Timings;
|
||||
use pocketmine\utils\TextFormat;
|
||||
@ -2457,36 +2452,6 @@ class Player extends Human implements CommandSender, ChunkLoader, ChunkListener,
|
||||
return $handled;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param BlockEntityDataPacket $packet
|
||||
*
|
||||
* @return bool
|
||||
* @throws BadPacketException
|
||||
*/
|
||||
public function handleBlockEntityData(BlockEntityDataPacket $packet) : bool{
|
||||
$this->doCloseInventory();
|
||||
|
||||
$pos = new Vector3($packet->x, $packet->y, $packet->z);
|
||||
if($pos->distanceSquared($this) > 10000){
|
||||
return true;
|
||||
}
|
||||
|
||||
$t = $this->level->getTile($pos);
|
||||
if($t instanceof Spawnable){
|
||||
$nbt = new NetworkNbtSerializer();
|
||||
try{
|
||||
$compound = $nbt->read($packet->namedtag);
|
||||
}catch(NbtDataException $e){
|
||||
throw new BadPacketException($e->getMessage(), 0, $e);
|
||||
}
|
||||
if(!$t->updateCompoundTag($compound, $this)){
|
||||
$this->level->sendBlocks([$this], [$pos]);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public function handleBookEdit(BookEditPacket $packet) : bool{
|
||||
/** @var WritableBook $oldBook */
|
||||
$oldBook = $this->inventory->getItem($packet->inventorySlot);
|
||||
|
@ -23,11 +23,17 @@ declare(strict_types=1);
|
||||
|
||||
namespace pocketmine\block;
|
||||
|
||||
use pocketmine\block\utils\SignText;
|
||||
use pocketmine\event\block\SignChangeEvent;
|
||||
use pocketmine\item\Item;
|
||||
use pocketmine\math\AxisAlignedBB;
|
||||
use pocketmine\math\Facing;
|
||||
use pocketmine\math\Vector3;
|
||||
use pocketmine\Player;
|
||||
use pocketmine\tile\Sign as TileSign;
|
||||
use pocketmine\utils\TextFormat;
|
||||
use function array_map;
|
||||
use function assert;
|
||||
use function floor;
|
||||
|
||||
class SignPost extends Transparent{
|
||||
@ -35,6 +41,14 @@ class SignPost extends Transparent{
|
||||
/** @var int */
|
||||
protected $rotation = 0;
|
||||
|
||||
/** @var SignText */
|
||||
protected $text;
|
||||
|
||||
public function __construct(BlockIdentifier $idInfo, string $name){
|
||||
parent::__construct($idInfo, $name);
|
||||
$this->text = new SignText();
|
||||
}
|
||||
|
||||
protected function writeStateToMeta() : int{
|
||||
return $this->rotation;
|
||||
}
|
||||
@ -43,6 +57,21 @@ class SignPost extends Transparent{
|
||||
$this->rotation = $stateMeta;
|
||||
}
|
||||
|
||||
public function readStateFromWorld() : void{
|
||||
parent::readStateFromWorld();
|
||||
$tile = $this->level->getTile($this);
|
||||
if($tile instanceof TileSign){
|
||||
$this->text = $tile->getText();
|
||||
}
|
||||
}
|
||||
|
||||
public function writeStateToWorld() : void{
|
||||
parent::writeStateToWorld();
|
||||
$tile = $this->level->getTile($this);
|
||||
assert($tile instanceof TileSign);
|
||||
$tile->setText($this->text);
|
||||
}
|
||||
|
||||
public function getStateBitmask() : int{
|
||||
return 0b1111;
|
||||
}
|
||||
@ -82,4 +111,36 @@ class SignPost extends Transparent{
|
||||
public function getToolType() : int{
|
||||
return BlockToolType::TYPE_AXE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an object containing information about the sign text.
|
||||
*
|
||||
* @return SignText
|
||||
*/
|
||||
public function getText() : SignText{
|
||||
return $this->text;
|
||||
}
|
||||
|
||||
/**
|
||||
* Called by the player controller (network session) to update the sign text, firing events as appropriate.
|
||||
*
|
||||
* @param Player $author
|
||||
* @param SignText $text
|
||||
*
|
||||
* @return bool if the sign update was successful.
|
||||
*/
|
||||
public function updateText(Player $author, SignText $text) : bool{
|
||||
$removeFormat = $author->getRemoveFormat();
|
||||
$ev = new SignChangeEvent($this, $author, new SignText(array_map(function(string $line) use ($removeFormat){
|
||||
return TextFormat::clean($line, $removeFormat);
|
||||
}, $text->getLines())));
|
||||
$ev->call();
|
||||
if(!$ev->isCancelled()){
|
||||
$this->text = clone $ev->getNewText();
|
||||
$this->level->setBlock($this, $this);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@ -23,32 +23,44 @@ declare(strict_types=1);
|
||||
|
||||
namespace pocketmine\event\block;
|
||||
|
||||
use pocketmine\block\Block;
|
||||
use pocketmine\block\SignPost;
|
||||
use pocketmine\block\utils\SignText;
|
||||
use pocketmine\event\Cancellable;
|
||||
use pocketmine\event\CancellableTrait;
|
||||
use pocketmine\Player;
|
||||
use function count;
|
||||
|
||||
/**
|
||||
* Called when a sign is changed by a player.
|
||||
* Called when a sign's text is changed by a player.
|
||||
*/
|
||||
class SignChangeEvent extends BlockEvent implements Cancellable{
|
||||
use CancellableTrait;
|
||||
|
||||
/** @var SignPost */
|
||||
private $sign;
|
||||
|
||||
/** @var Player */
|
||||
private $player;
|
||||
/** @var string[] */
|
||||
private $lines = [];
|
||||
|
||||
/** @var SignText */
|
||||
private $text;
|
||||
|
||||
/**
|
||||
* @param Block $theBlock
|
||||
* @param Player $thePlayer
|
||||
* @param string[] $theLines
|
||||
* @param SignPost $sign
|
||||
* @param Player $player
|
||||
* @param SignText $text
|
||||
*/
|
||||
public function __construct(Block $theBlock, Player $thePlayer, array $theLines){
|
||||
parent::__construct($theBlock);
|
||||
$this->player = $thePlayer;
|
||||
$this->setLines($theLines);
|
||||
public function __construct(SignPost $sign, Player $player, SignText $text){
|
||||
parent::__construct($sign);
|
||||
$this->sign = $sign;
|
||||
$this->player = $player;
|
||||
$this->text = $text;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return SignPost
|
||||
*/
|
||||
public function getSign() : SignPost{
|
||||
return $this->sign;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -59,49 +71,29 @@ class SignChangeEvent extends BlockEvent implements Cancellable{
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string[]
|
||||
* Returns the text currently on the sign.
|
||||
*
|
||||
* @return SignText
|
||||
*/
|
||||
public function getLines() : array{
|
||||
return $this->lines;
|
||||
public function getOldText() : SignText{
|
||||
return $this->sign->getText();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $index 0-3
|
||||
* Returns the text which will be on the sign after the event.
|
||||
*
|
||||
* @return string
|
||||
*
|
||||
* @throws \InvalidArgumentException if the index is out of bounds
|
||||
* @return SignText
|
||||
*/
|
||||
public function getLine(int $index) : string{
|
||||
if($index < 0 or $index > 3){
|
||||
throw new \InvalidArgumentException("Index must be in the range 0-3!");
|
||||
}
|
||||
|
||||
return $this->lines[$index];
|
||||
public function getNewText() : SignText{
|
||||
return $this->text;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string[] $lines
|
||||
* Sets the text to be written on the sign after the event.
|
||||
*
|
||||
* @throws \InvalidArgumentException if there are more or less than 4 lines in the passed array
|
||||
* @param SignText $text
|
||||
*/
|
||||
public function setLines(array $lines) : void{
|
||||
if(count($lines) !== 4){
|
||||
throw new \InvalidArgumentException("Array size must be 4!");
|
||||
}
|
||||
$this->lines = $lines;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $index 0-3
|
||||
* @param string $line
|
||||
*
|
||||
* @throws \InvalidArgumentException if the index is out of bounds
|
||||
*/
|
||||
public function setLine(int $index, string $line) : void{
|
||||
if($index < 0 or $index > 3){
|
||||
throw new \InvalidArgumentException("Index must be in the range 0-3!");
|
||||
}
|
||||
$this->lines[$index] = $line;
|
||||
public function setNewText(SignText $text) : void{
|
||||
$this->text = $text;
|
||||
}
|
||||
}
|
||||
|
@ -24,12 +24,17 @@ declare(strict_types=1);
|
||||
namespace pocketmine\network\mcpe\handler;
|
||||
|
||||
use pocketmine\block\ItemFrame;
|
||||
use pocketmine\block\SignPost;
|
||||
use pocketmine\block\utils\SignText;
|
||||
use pocketmine\inventory\transaction\action\InventoryAction;
|
||||
use pocketmine\inventory\transaction\CraftingTransaction;
|
||||
use pocketmine\inventory\transaction\InventoryTransaction;
|
||||
use pocketmine\inventory\transaction\TransactionValidationException;
|
||||
use pocketmine\math\Vector3;
|
||||
use pocketmine\nbt\NbtDataException;
|
||||
use pocketmine\nbt\tag\StringTag;
|
||||
use pocketmine\network\BadPacketException;
|
||||
use pocketmine\network\mcpe\NetworkNbtSerializer;
|
||||
use pocketmine\network\mcpe\protocol\AdventureSettingsPacket;
|
||||
use pocketmine\network\mcpe\protocol\AnimatePacket;
|
||||
use pocketmine\network\mcpe\protocol\BlockEntityDataPacket;
|
||||
@ -72,6 +77,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 base64_encode;
|
||||
use function implode;
|
||||
use function json_decode;
|
||||
use function json_encode;
|
||||
@ -385,7 +391,37 @@ class SimpleSessionHandler extends SessionHandler{
|
||||
}
|
||||
|
||||
public function handleBlockEntityData(BlockEntityDataPacket $packet) : bool{
|
||||
return $this->player->handleBlockEntityData($packet);
|
||||
$pos = new Vector3($packet->x, $packet->y, $packet->z);
|
||||
if($pos->distanceSquared($this->player) > 10000){
|
||||
return false;
|
||||
}
|
||||
|
||||
$block = $this->player->getLevel()->getBlock($pos);
|
||||
try{
|
||||
$nbt = (new NetworkNbtSerializer())->read($packet->namedtag);
|
||||
}catch(NbtDataException $e){
|
||||
throw new BadPacketException($e->getMessage(), 0, $e);
|
||||
}
|
||||
|
||||
if($block instanceof SignPost){
|
||||
if($nbt->hasTag("Text", StringTag::class)){
|
||||
try{
|
||||
$text = SignText::fromBlob($nbt->getString("Text"));
|
||||
}catch(\InvalidArgumentException $e){
|
||||
throw new BadPacketException("Invalid sign text update: " . $e->getMessage(), 0, $e);
|
||||
}
|
||||
|
||||
if(!$block->updateText($this->player, $text)){
|
||||
$this->player->getLevel()->sendBlocks([$this->player], [$block]);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
$this->player->getServer()->getLogger()->debug("Invalid sign update data from " . $this->player->getName() . ": " . base64_encode($packet->namedtag));
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public function handlePlayerInput(PlayerInputPacket $packet) : bool{
|
||||
|
@ -23,139 +23,78 @@ declare(strict_types=1);
|
||||
|
||||
namespace pocketmine\tile;
|
||||
|
||||
use pocketmine\event\block\SignChangeEvent;
|
||||
use pocketmine\block\SignPost;
|
||||
use pocketmine\block\utils\SignText;
|
||||
use pocketmine\level\Level;
|
||||
use pocketmine\math\Vector3;
|
||||
use pocketmine\nbt\tag\CompoundTag;
|
||||
use pocketmine\nbt\tag\StringTag;
|
||||
use pocketmine\Player;
|
||||
use pocketmine\utils\TextFormat;
|
||||
use function array_map;
|
||||
use function array_pad;
|
||||
use function array_slice;
|
||||
use function explode;
|
||||
use function implode;
|
||||
use function mb_check_encoding;
|
||||
use function mb_scrub;
|
||||
use function sprintf;
|
||||
|
||||
/**
|
||||
* @deprecated
|
||||
* @see SignPost
|
||||
*/
|
||||
class Sign extends Spawnable{
|
||||
public const TAG_TEXT_BLOB = "Text";
|
||||
public const TAG_TEXT_LINE = "Text%d"; //sprintf()able
|
||||
|
||||
private static function fixTextBlob(string $blob) : array{
|
||||
public static function fixTextBlob(string $blob) : array{
|
||||
return array_slice(array_pad(explode("\n", $blob), 4, ""), 0, 4);
|
||||
}
|
||||
|
||||
/** @var string[] */
|
||||
protected $text = ["", "", "", ""];
|
||||
/** @var SignText */
|
||||
protected $text;
|
||||
|
||||
public function __construct(Level $level, Vector3 $pos){
|
||||
$this->text = new SignText();
|
||||
parent::__construct($level, $pos);
|
||||
}
|
||||
|
||||
public 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));
|
||||
$this->text = SignText::fromBlob(mb_scrub($nbt->getString(self::TAG_TEXT_BLOB), 'UTF-8'));
|
||||
}else{
|
||||
for($i = 1; $i <= 4; ++$i){
|
||||
$textKey = sprintf(self::TAG_TEXT_LINE, $i);
|
||||
$this->text = new SignText();
|
||||
for($i = 0; $i < SignText::LINE_COUNT; ++$i){
|
||||
$textKey = sprintf(self::TAG_TEXT_LINE, $i + 1);
|
||||
if($nbt->hasTag($textKey, StringTag::class)){
|
||||
$this->text[$i - 1] = $nbt->getString($textKey);
|
||||
$this->text->setLine($i, mb_scrub($nbt->getString($textKey), 'UTF-8'));
|
||||
}
|
||||
}
|
||||
}
|
||||
$this->text = array_map(function(string $line) : string{
|
||||
return mb_scrub($line, 'UTF-8');
|
||||
}, $this->text);
|
||||
}
|
||||
|
||||
protected function writeSaveData(CompoundTag $nbt) : void{
|
||||
$nbt->setString(self::TAG_TEXT_BLOB, implode("\n", $this->text));
|
||||
$nbt->setString(self::TAG_TEXT_BLOB, implode("\n", $this->text->getLines()));
|
||||
|
||||
for($i = 1; $i <= 4; ++$i){ //Backwards-compatibility
|
||||
$textKey = sprintf(self::TAG_TEXT_LINE, $i);
|
||||
$nbt->setString($textKey, $this->getLine($i - 1));
|
||||
for($i = 0; $i < SignText::LINE_COUNT; ++$i){ //Backwards-compatibility
|
||||
$textKey = sprintf(self::TAG_TEXT_LINE, $i + 1);
|
||||
$nbt->setString($textKey, $this->text->getLine($i));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Changes contents of the specific lines to the string provided.
|
||||
* Leaves contents of the specific lines as is if null is provided.
|
||||
*
|
||||
* @param null|string $line1
|
||||
* @param null|string $line2
|
||||
* @param null|string $line3
|
||||
* @param null|string $line4
|
||||
* @return SignText
|
||||
*/
|
||||
public function setText(?string $line1 = "", ?string $line2 = "", ?string $line3 = "", ?string $line4 = "") : void{
|
||||
if($line1 !== null){
|
||||
$this->setLine(0, $line1);
|
||||
}
|
||||
if($line2 !== null){
|
||||
$this->setLine(1, $line2);
|
||||
}
|
||||
if($line3 !== null){
|
||||
$this->setLine(2, $line3);
|
||||
}
|
||||
if($line4 !== null){
|
||||
$this->setLine(3, $line4);
|
||||
}
|
||||
|
||||
$this->onChanged();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $index 0-3
|
||||
* @param string $line
|
||||
*/
|
||||
public function setLine(int $index, string $line) : void{
|
||||
if($index < 0 or $index > 3){
|
||||
throw new \InvalidArgumentException("Index must be in the range 0-3!");
|
||||
}
|
||||
if(!mb_check_encoding($line, 'UTF-8')){
|
||||
throw new \InvalidArgumentException("Text must be valid UTF-8");
|
||||
}
|
||||
|
||||
$this->text[$index] = $line;
|
||||
$this->onChanged();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $index 0-3
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getLine(int $index) : string{
|
||||
if($index < 0 or $index > 3){
|
||||
throw new \InvalidArgumentException("Index must be in the range 0-3!");
|
||||
}
|
||||
return $this->text[$index];
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string[]
|
||||
*/
|
||||
public function getText() : array{
|
||||
public function getText() : SignText{
|
||||
return $this->text;
|
||||
}
|
||||
|
||||
protected function addAdditionalSpawnData(CompoundTag $nbt) : void{
|
||||
$nbt->setString(self::TAG_TEXT_BLOB, implode("\n", $this->text));
|
||||
/**
|
||||
* @param SignText $text
|
||||
*/
|
||||
public function setText(SignText $text) : void{
|
||||
$this->text = $text;
|
||||
$this->onChanged();
|
||||
}
|
||||
|
||||
public function updateCompoundTag(CompoundTag $nbt, Player $player) : bool{
|
||||
if($nbt->hasTag(self::TAG_TEXT_BLOB, StringTag::class)){
|
||||
$lines = self::fixTextBlob($nbt->getString(self::TAG_TEXT_BLOB));
|
||||
}else{
|
||||
return false;
|
||||
}
|
||||
|
||||
$removeFormat = $player->getRemoveFormat();
|
||||
|
||||
$ev = new SignChangeEvent($this->getBlock(), $player, array_map(function(string $line) use ($removeFormat){ return TextFormat::clean($line, $removeFormat); }, $lines));
|
||||
$ev->call();
|
||||
|
||||
if(!$ev->isCancelled()){
|
||||
$this->setText(...$ev->getLines());
|
||||
|
||||
return true;
|
||||
}else{
|
||||
return false;
|
||||
}
|
||||
protected function addAdditionalSpawnData(CompoundTag $nbt) : void{
|
||||
$nbt->setString(self::TAG_TEXT_BLOB, implode("\n", $this->text->getLines()));
|
||||
}
|
||||
}
|
||||
|
@ -27,7 +27,6 @@ use pocketmine\nbt\tag\CompoundTag;
|
||||
use pocketmine\nbt\tag\IntTag;
|
||||
use pocketmine\nbt\tag\StringTag;
|
||||
use pocketmine\network\mcpe\NetworkNbtSerializer;
|
||||
use pocketmine\Player;
|
||||
use function get_class;
|
||||
|
||||
abstract class Spawnable extends Tile{
|
||||
@ -104,17 +103,4 @@ abstract class Spawnable extends Tile{
|
||||
* @param CompoundTag $nbt
|
||||
*/
|
||||
abstract protected function addAdditionalSpawnData(CompoundTag $nbt) : void;
|
||||
|
||||
/**
|
||||
* Called when a player updates a block entity's NBT data
|
||||
* for example when writing on a sign.
|
||||
*
|
||||
* @param CompoundTag $nbt
|
||||
* @param Player $player
|
||||
*
|
||||
* @return bool indication of success, will respawn the tile to the player if false.
|
||||
*/
|
||||
public function updateCompoundTag(CompoundTag $nbt, Player $player) : bool{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user