diff --git a/src/pocketmine/Player.php b/src/pocketmine/Player.php index a56d9469b..8f3f97ef2 100644 --- a/src/pocketmine/Player.php +++ b/src/pocketmine/Player.php @@ -175,7 +175,11 @@ class Player extends Human implements CommandSender, ChunkLoader, IPlayer{ * * @return bool */ - public static function isValidUserName(string $name) : bool{ + public static function isValidUserName(?string $name) : bool{ + if($name === null){ + return false; + } + $lname = strtolower($name); $len = strlen($name); return $lname !== "rcon" and $lname !== "console" and $len >= 1 and $len <= 16 and preg_match("/[^A-Za-z0-9_ ]/", $name) === 0; @@ -1979,6 +1983,11 @@ class Player extends Human implements CommandSender, ChunkLoader, IPlayer{ return true; } + if(!self::isValidUserName($packet->username)){ + $this->close("", "disconnectionScreen.invalidName"); + return true; + } + $this->username = TextFormat::clean($packet->username); $this->displayName = $this->username; $this->iusername = strtolower($this->username); @@ -1992,11 +2001,6 @@ class Player extends Human implements CommandSender, ChunkLoader, IPlayer{ $this->uuid = UUID::fromString($packet->clientUUID); $this->rawUUID = $this->uuid->toBinary(); - if(!Player::isValidUserName($packet->username)){ - $this->close("", "disconnectionScreen.invalidName"); - return true; - } - $skin = new Skin( $packet->clientData["SkinId"], base64_decode($packet->clientData["SkinData"] ?? ""), @@ -2040,11 +2044,7 @@ class Player extends Human implements CommandSender, ChunkLoader, IPlayer{ $pk = new PlayStatusPacket(); $pk->status = $status; $pk->protocol = $this->protocol; - if($immediate){ - $this->directDataPacket($pk); - }else{ - $this->dataPacket($pk); - } + $this->sendDataPacket($pk, false, $immediate); } public function handleResourcePackClientResponse(ResourcePackClientResponsePacket $packet) : bool{ @@ -2580,9 +2580,7 @@ class Player extends Human implements CommandSender, ChunkLoader, IPlayer{ public function handleBlockPickRequest(BlockPickRequestPacket $packet) : bool{ $block = $this->level->getBlockAt($packet->blockX, $packet->blockY, $packet->blockZ); - //TODO: this doesn't handle crops correctly (need more API work) - $item = Item::get($block->getItemId(), $block->getVariant()); - + $item = $block->getPickedItem(); if($packet->addUserData){ $tile = $this->getLevel()->getTile($block); if($tile instanceof Tile){ @@ -2622,13 +2620,20 @@ class Player extends Human implements CommandSender, ChunkLoader, IPlayer{ if($this->lastBreak !== PHP_INT_MAX or $pos->distanceSquared($this) > 10000){ break; } + $target = $this->level->getBlock($pos); + $ev = new PlayerInteractEvent($this, $this->inventory->getItemInHand(), $target, null, $packet->face, $target->getId() === 0 ? PlayerInteractEvent::LEFT_CLICK_AIR : PlayerInteractEvent::LEFT_CLICK_BLOCK); + if($this->level->checkSpawnProtection($this, $target)){ + $ev->setCancelled(); + } + $this->getServer()->getPluginManager()->callEvent($ev); if($ev->isCancelled()){ $this->inventory->sendHeldItem($this); break; } + $block = $target->getSide($packet->face); if($block->getId() === Block::FIRE){ $this->level->setBlock($block, BlockFactory::get(Block::AIR)); diff --git a/src/pocketmine/Server.php b/src/pocketmine/Server.php index 8f63c1f96..e586c49a9 100644 --- a/src/pocketmine/Server.php +++ b/src/pocketmine/Server.php @@ -1917,17 +1917,9 @@ class Server{ $pk->encode(); } - if($immediate){ - foreach($identifiers as $i){ - if(isset($this->players[$i])){ - $this->players[$i]->directDataPacket($pk); - } - } - }else{ - foreach($identifiers as $i){ - if(isset($this->players[$i])){ - $this->players[$i]->dataPacket($pk); - } + foreach($identifiers as $i){ + if(isset($this->players[$i])){ + $this->players[$i]->sendDataPacket($pk, false, $immediate); } } diff --git a/src/pocketmine/block/Beetroot.php b/src/pocketmine/block/Beetroot.php index d8f2e0571..1fb15267f 100644 --- a/src/pocketmine/block/Beetroot.php +++ b/src/pocketmine/block/Beetroot.php @@ -50,4 +50,8 @@ class Beetroot extends Crops{ ItemFactory::get(Item::BEETROOT_SEEDS, 0, 1) ]; } + + public function getPickedItem() : Item{ + return ItemFactory::get(Item::BEETROOT_SEEDS); + } } \ No newline at end of file diff --git a/src/pocketmine/block/Block.php b/src/pocketmine/block/Block.php index cd19e73be..dfafecf0f 100644 --- a/src/pocketmine/block/Block.php +++ b/src/pocketmine/block/Block.php @@ -67,7 +67,7 @@ class Block extends Position implements BlockIds, Metadatable{ protected $itemId; /** @var AxisAlignedBB */ - public $boundingBox = null; + protected $boundingBox = null; /** @var AxisAlignedBB[]|null */ @@ -425,6 +425,14 @@ class Block extends Position implements BlockIds, Metadatable{ ]; } + /** + * Returns the item that players will equip when middle-clicking on this block. + * @return Item + */ + public function getPickedItem() : Item{ + return ItemFactory::get($this->getItemId(), $this->getVariant()); + } + /** * Returns the time in ticks which the block will fuel a furnace for. * @return int diff --git a/src/pocketmine/block/Carrot.php b/src/pocketmine/block/Carrot.php index 7c41eb1b1..ae07e7fb9 100644 --- a/src/pocketmine/block/Carrot.php +++ b/src/pocketmine/block/Carrot.php @@ -43,4 +43,8 @@ class Carrot extends Crops{ ItemFactory::get(Item::CARROT, 0, $this->meta >= 0x07 ? mt_rand(1, 4) : 1) ]; } + + public function getPickedItem() : Item{ + return ItemFactory::get(Item::CARROT); + } } \ No newline at end of file diff --git a/src/pocketmine/block/MelonStem.php b/src/pocketmine/block/MelonStem.php index fde7f63d7..642d11932 100644 --- a/src/pocketmine/block/MelonStem.php +++ b/src/pocketmine/block/MelonStem.php @@ -88,4 +88,8 @@ class MelonStem extends Crops{ ItemFactory::get(Item::MELON_SEEDS, 0, mt_rand(0, 2)) ]; } + + public function getPickedItem() : Item{ + return ItemFactory::get(Item::MELON_SEEDS); + } } \ No newline at end of file diff --git a/src/pocketmine/block/Potato.php b/src/pocketmine/block/Potato.php index c18aeaafa..861438c08 100644 --- a/src/pocketmine/block/Potato.php +++ b/src/pocketmine/block/Potato.php @@ -43,4 +43,8 @@ class Potato extends Crops{ ItemFactory::get(Item::POTATO, 0, $this->getDamage() >= 0x07 ? mt_rand(1, 4) : 1) ]; } + + public function getPickedItem() : Item{ + return ItemFactory::get(Item::POTATO); + } } \ No newline at end of file diff --git a/src/pocketmine/block/PumpkinStem.php b/src/pocketmine/block/PumpkinStem.php index d2aaa2c5a..dd21a30e5 100644 --- a/src/pocketmine/block/PumpkinStem.php +++ b/src/pocketmine/block/PumpkinStem.php @@ -88,4 +88,8 @@ class PumpkinStem extends Crops{ ItemFactory::get(Item::PUMPKIN_SEEDS, 0, mt_rand(0, 2)) ]; } + + public function getPickedItem() : Item{ + return ItemFactory::get(Item::PUMPKIN_SEEDS); + } } \ No newline at end of file diff --git a/src/pocketmine/block/Wheat.php b/src/pocketmine/block/Wheat.php index 622026719..1a854c29a 100644 --- a/src/pocketmine/block/Wheat.php +++ b/src/pocketmine/block/Wheat.php @@ -50,4 +50,8 @@ class Wheat extends Crops{ ]; } } + + public function getPickedItem() : Item{ + return ItemFactory::get(Item::WHEAT_SEEDS); + } } \ No newline at end of file diff --git a/src/pocketmine/entity/Living.php b/src/pocketmine/entity/Living.php index f58b82ca5..1bc23a9db 100644 --- a/src/pocketmine/entity/Living.php +++ b/src/pocketmine/entity/Living.php @@ -463,9 +463,12 @@ abstract class Living extends Entity implements Damageable{ if($effect->canTick()){ $effect->applyEffect($this); } - $effect->setDuration($effect->getDuration() - $tickDiff); - if($effect->getDuration() <= 0){ + + $duration = $effect->getDuration() - $tickDiff; + if($duration <= 0){ $this->removeEffect($effect->getId()); + }else{ + $effect->setDuration($duration); } } } diff --git a/src/pocketmine/item/ItemFactory.php b/src/pocketmine/item/ItemFactory.php index 533870036..19433e68e 100644 --- a/src/pocketmine/item/ItemFactory.php +++ b/src/pocketmine/item/ItemFactory.php @@ -353,11 +353,8 @@ class ItemFactory{ $meta = $b[1] & 0xFFFF; } - if(defined(Item::class . "::" . strtoupper($b[0]))){ - $item = self::get(constant(Item::class . "::" . strtoupper($b[0])), $meta); - if($item->getId() === Item::AIR and strtoupper($b[0]) !== "AIR" and is_numeric($b[0])){ - $item = self::get(((int) $b[0]) & 0xFFFF, $meta); - } + if(defined(ItemIds::class . "::" . strtoupper($b[0]))){ + $item = self::get(constant(ItemIds::class . "::" . strtoupper($b[0])), $meta); }elseif(is_numeric($b[0])){ $item = self::get(((int) $b[0]) & 0xFFFF, $meta); }else{ diff --git a/src/pocketmine/level/Level.php b/src/pocketmine/level/Level.php index 47a029651..32ede6860 100644 --- a/src/pocketmine/level/Level.php +++ b/src/pocketmine/level/Level.php @@ -1585,7 +1585,7 @@ class Level implements ChunkManager, Metadatable{ * * @return bool true if spawn protection cancelled the action, false if not. */ - protected function checkSpawnProtection(Player $player, Vector3 $vector) : bool{ + public function checkSpawnProtection(Player $player, Vector3 $vector) : bool{ if(!$player->hasPermission("pocketmine.spawnprotect.bypass") and ($distance = $this->server->getSpawnRadius()) > -1){ $t = new Vector2($vector->x, $vector->z); $s = new Vector2($this->getSpawnLocation()->x, $this->getSpawnLocation()->z); diff --git a/src/pocketmine/network/mcpe/protocol/LoginPacket.php b/src/pocketmine/network/mcpe/protocol/LoginPacket.php index cb1cc97f0..6abc1c093 100644 --- a/src/pocketmine/network/mcpe/protocol/LoginPacket.php +++ b/src/pocketmine/network/mcpe/protocol/LoginPacket.php @@ -28,6 +28,7 @@ namespace pocketmine\network\mcpe\protocol; use pocketmine\network\mcpe\NetworkSession; use pocketmine\utils\BinaryStream; +use pocketmine\utils\MainLogger; use pocketmine\utils\Utils; class LoginPacket extends DataPacket{ @@ -73,9 +74,24 @@ class LoginPacket extends DataPacket{ $this->offset -= 6; $this->protocol = $this->getInt(); } - return; //Do not attempt to continue decoding for non-accepted protocols } + try{ + $this->decodeConnectionRequest(); + }catch(\Throwable $e){ + if($this->protocol === ProtocolInfo::CURRENT_PROTOCOL){ + throw $e; + } + + $logger = MainLogger::getLogger(); + $logger->debug(get_class($e) . " was thrown while decoding connection request in login (protocol version " . ($this->protocol ?? "unknown") . "): " . $e->getMessage()); + foreach(\pocketmine\getTrace(0, $e->getTrace()) as $line){ + $logger->debug($line); + } + } + } + + protected function decodeConnectionRequest() : void{ $buffer = new BinaryStream($this->getString()); $this->chainData = json_decode($buffer->get($buffer->getLInt()), true);