diff --git a/src/pocketmine/Player.php b/src/pocketmine/Player.php index f7a7723d0..f609c56cd 100644 --- a/src/pocketmine/Player.php +++ b/src/pocketmine/Player.php @@ -112,7 +112,6 @@ use pocketmine\network\mcpe\protocol\AddPlayerPacket; use pocketmine\network\mcpe\protocol\AdventureSettingsPacket; use pocketmine\network\mcpe\protocol\AnimatePacket; use pocketmine\network\mcpe\protocol\AvailableCommandsPacket; -use pocketmine\network\mcpe\protocol\BatchPacket; use pocketmine\network\mcpe\protocol\BlockEntityDataPacket; use pocketmine\network\mcpe\protocol\BlockEventPacket; use pocketmine\network\mcpe\protocol\BlockPickRequestPacket; @@ -1955,11 +1954,6 @@ class Player extends Human implements CommandSender, InventoryHolder, ChunkLoade return false; } - public function handleBatch(BatchPacket $packet) : bool{ - $this->server->getNetwork()->processBatch($packet, $this); - return true; - } - public function handleResourcePacksInfo(ResourcePacksInfoPacket $packet) : bool{ return false; } @@ -2237,6 +2231,7 @@ class Player extends Human implements CommandSender, InventoryHolder, ChunkLoade $item = $this->inventory->getItem($packet->inventorySlot); if(!$item->equals($packet->item)){ + $this->server->getLogger()->debug("Tried to equip " . $packet->item . " but have " . $item . " in target slot"); $this->inventory->sendContents($this); return false; } @@ -3317,6 +3312,9 @@ class Player extends Human implements CommandSender, InventoryHolder, ChunkLoade $timings = Timings::getReceiveDataPacketTimings($packet); $timings->startTiming(); + $packet->decode(); + assert($packet->feof(), "Still " . strlen(substr($packet->buffer, $packet->offset)) . " bytes unread in " . get_class($packet)); + $this->server->getPluginManager()->callEvent($ev = new DataPacketReceiveEvent($this, $packet)); if(!$ev->isCancelled() and !$packet->handle($this)){ $this->server->getLogger()->debug("Unhandled " . get_class($packet) . " received from " . $this->getName()); @@ -3580,6 +3578,13 @@ class Player extends Human implements CommandSender, InventoryHolder, ChunkLoade return $this->username; } + /** + * @return string + */ + public function getLowerCaseName() : string{ + return $this->iusername; + } + public function kill(){ if(!$this->spawned){ return; diff --git a/src/pocketmine/Server.php b/src/pocketmine/Server.php index a00839d69..a882b9b97 100644 --- a/src/pocketmine/Server.php +++ b/src/pocketmine/Server.php @@ -158,6 +158,9 @@ class Server{ private $currentTPS = 20; private $currentUse = 0; + /** @var bool */ + private $doTitleTick = true; + private $sendUsageTicker = 0; private $dispatchSignals = false; @@ -817,7 +820,7 @@ class Server{ public function getPlayerExact($name){ $name = strtolower($name); foreach($this->getOnlinePlayers() as $player){ - if(strtolower($player->getName()) === $name){ + if($player->getLowerCaseName() === $name){ return $player; } } @@ -834,7 +837,7 @@ class Server{ $partialName = strtolower($partialName); $matchedPlayers = []; foreach($this->getOnlinePlayers() as $player){ - if(strtolower($player->getName()) === $partialName){ + if($player->getLowerCaseName() === $partialName){ $matchedPlayers = [$player]; break; }elseif(stripos($player->getName(), $partialName) !== false){ @@ -1466,6 +1469,8 @@ class Server{ $this->alwaysTickPlayers = (int) $this->getProperty("level-settings.always-tick-players", false); $this->baseTickRate = (int) $this->getProperty("level-settings.base-tick-rate", 1); + $this->doTitleTick = (bool) $this->getProperty("console.title-tick", true); + $this->scheduler = new ServerScheduler(); if($this->getConfigBoolean("enable-rcon", false) === true){ @@ -1546,7 +1551,7 @@ class Server{ Attribute::init(); $this->craftingManager = new CraftingManager(); - $this->resourceManager = new ResourcePackManager($this, \pocketmine\PATH . "resource_packs" . DIRECTORY_SEPARATOR); + $this->resourceManager = new ResourcePackManager($this, $this->getDataPath() . "resource_packs" . DIRECTORY_SEPARATOR); $this->pluginManager = new PluginManager($this, $this->commandMap); $this->pluginManager->subscribeToPermission(Server::BROADCAST_CHANNEL_ADMINISTRATIVE, $this->consoleSender); @@ -2262,7 +2267,9 @@ class Server{ } public function sendUsage($type = SendUsageTask::TYPE_STATUS){ - $this->scheduler->scheduleAsyncTask(new SendUsageTask($this, $type, $this->uniquePlayers)); + if($this->getProperty("anonymous-statistics.enabled", true)){ + $this->scheduler->scheduleAsyncTask(new SendUsageTask($this, $type, $this->uniquePlayers)); + } $this->uniquePlayers = []; } @@ -2296,10 +2303,6 @@ class Server{ } private function titleTick(){ - if(!Terminal::hasFormattingCodes()){ - return; - } - $d = Utils::getRealMemoryUsage(); $u = Utils::getMemoryUsage(true); @@ -2375,7 +2378,9 @@ class Server{ } if(($this->tickCounter & 0b1111) === 0){ - $this->titleTick(); + if($this->doTitleTick and Terminal::hasFormattingCodes()){ + $this->titleTick(); + } $this->currentTPS = 20; $this->currentUse = 0; @@ -2440,4 +2445,13 @@ class Server{ return true; } + + /** + * Called when something attempts to serialize the server instance. + * + * @throws \BadMethodCallException because Server instances cannot be serialized + */ + public function __sleep(){ + throw new \BadMethodCallException("Cannot serialize Server instance"); + } } diff --git a/src/pocketmine/block/GlowingObsidian.php b/src/pocketmine/block/GlowingObsidian.php index e3ee02ba8..26b55cfd2 100644 --- a/src/pocketmine/block/GlowingObsidian.php +++ b/src/pocketmine/block/GlowingObsidian.php @@ -22,7 +22,7 @@ namespace pocketmine\block; -class GlowingObsidian extends Transparent{ +class GlowingObsidian extends Solid{ protected $id = self::GLOWING_OBSIDIAN; diff --git a/src/pocketmine/block/RedstoneTorch.php b/src/pocketmine/block/RedstoneTorch.php index ca7f7f352..32e4bb77a 100644 --- a/src/pocketmine/block/RedstoneTorch.php +++ b/src/pocketmine/block/RedstoneTorch.php @@ -32,4 +32,8 @@ class RedstoneTorch extends Torch{ public function getName(){ return "Redstone Torch"; } + + public function getLightLevel(){ + return 7; + } } diff --git a/src/pocketmine/block/Torch.php b/src/pocketmine/block/Torch.php index c71bd957a..78cf35e82 100644 --- a/src/pocketmine/block/Torch.php +++ b/src/pocketmine/block/Torch.php @@ -34,7 +34,7 @@ class Torch extends Flowable{ } public function getLightLevel(){ - return 15; + return 14; } public function getName(){ diff --git a/src/pocketmine/command/SimpleCommandMap.php b/src/pocketmine/command/SimpleCommandMap.php index 48e30d1ac..ae959c8ad 100644 --- a/src/pocketmine/command/SimpleCommandMap.php +++ b/src/pocketmine/command/SimpleCommandMap.php @@ -136,7 +136,7 @@ class SimpleCommandMap implements CommandMap{ if($label === null){ $label = $command->getName(); } - $label = strtolower(trim($label)); + $label = trim($label); $fallbackPrefix = strtolower(trim($fallbackPrefix)); $registered = $this->registerAlias($command, false, $fallbackPrefix, $label); @@ -188,7 +188,7 @@ class SimpleCommandMap implements CommandMap{ * @return Command|null */ public function matchCommand(string &$commandName, array &$args){ - $count = max(count($args), 255); + $count = min(count($args), 255); for($i = 0; $i < $count; ++$i){ $commandName .= array_shift($args); diff --git a/src/pocketmine/entity/Human.php b/src/pocketmine/entity/Human.php index e330d740b..ac56f66ad 100644 --- a/src/pocketmine/entity/Human.php +++ b/src/pocketmine/entity/Human.php @@ -443,7 +443,9 @@ class Human extends Creature implements ProjectileSource, InventoryHolder{ $slotCount = $this->inventory->getSize() + $this->inventory->getHotbarSize(); for($slot = $this->inventory->getHotbarSize(); $slot < $slotCount; ++$slot){ $item = $this->inventory->getItem($slot - 9); - $this->namedtag->Inventory[$slot] = $item->nbtSerialize($slot); + if($item->getId() !== ItemItem::AIR){ + $this->namedtag->Inventory[$slot] = $item->nbtSerialize($slot); + } } //Armor diff --git a/src/pocketmine/event/LevelTimings.php b/src/pocketmine/event/LevelTimings.php index ef78dcbd2..52a0ce6fb 100644 --- a/src/pocketmine/event/LevelTimings.php +++ b/src/pocketmine/event/LevelTimings.php @@ -25,6 +25,13 @@ use pocketmine\level\Level; class LevelTimings{ + /** @var TimingsHandler */ + public $setBlock; + /** @var TimingsHandler */ + public $doBlockLightUpdates; + /** @var TimingsHandler */ + public $doBlockSkyLightUpdates; + /** @var TimingsHandler */ public $mobSpawn; /** @var TimingsHandler */ @@ -79,6 +86,10 @@ class LevelTimings{ public function __construct(Level $level){ $name = $level->getFolderName() . " - "; + $this->setBlock = new TimingsHandler("** " . $name . "setBlock"); + $this->doBlockLightUpdates = new TimingsHandler("** " . $name . "doBlockLightUpdates"); + $this->doBlockSkyLightUpdates = new TimingsHandler("** " . $name . "doBlockSkyLightUpdates"); + $this->mobSpawn = new TimingsHandler("** " . $name . "mobSpawn"); $this->doChunkUnload = new TimingsHandler("** " . $name . "doChunkUnload"); $this->doTickPending = new TimingsHandler("** " . $name . "doTickPending"); diff --git a/src/pocketmine/item/Item.php b/src/pocketmine/item/Item.php index c5ef917a8..356466d68 100644 --- a/src/pocketmine/item/Item.php +++ b/src/pocketmine/item/Item.php @@ -65,13 +65,19 @@ class Item implements ItemIds, \JsonSerializable{ /** @var \SplFixedArray */ public static $list = null; + /** @var Block|null */ protected $block; + /** @var int */ protected $id; + /** @var int */ protected $meta; + /** @var string */ private $tags = ""; + /** @var CompoundTag|null */ private $cachedNBT = null; + /** @var int */ public $count; - protected $durability = 0; + /** @var string */ protected $name; public function canBeActivated(){ @@ -1007,4 +1013,12 @@ class Item implements ItemIds, \JsonSerializable{ return $item; } + public function __clone(){ + if($this->block !== null){ + $this->block = clone $this->block; + } + + $this->cachedNBT = null; + } + } diff --git a/src/pocketmine/item/ItemBlock.php b/src/pocketmine/item/ItemBlock.php index 4bcac3f9d..8a61b31aa 100644 --- a/src/pocketmine/item/ItemBlock.php +++ b/src/pocketmine/item/ItemBlock.php @@ -37,10 +37,6 @@ class ItemBlock extends Item{ $this->block->setDamage($this->meta !== -1 ? $this->meta : 0); } - public function __clone(){ - $this->block = clone $this->block; - } - public function getBlock() : Block{ return $this->block; } diff --git a/src/pocketmine/level/Level.php b/src/pocketmine/level/Level.php index 50dd643b1..88c45b98c 100644 --- a/src/pocketmine/level/Level.php +++ b/src/pocketmine/level/Level.php @@ -1254,17 +1254,42 @@ class Level implements ChunkManager, Metadatable{ } public function updateBlockSkyLight(int $x, int $y, int $z){ + $this->timings->doBlockSkyLightUpdates->startTiming(); //TODO + $this->timings->doBlockSkyLightUpdates->stopTiming(); + } + + /** + * Returns the highest light level available in the positions adjacent to the specified block coordinates. + * + * @param int $x + * @param int $y + * @param int $z + * + * @return int + */ + public function getHighestAdjacentBlockLight(int $x, int $y, int $z) : int{ + return max([ + $this->getBlockLightAt($x + 1, $y, $z), + $this->getBlockLightAt($x - 1, $y, $z), + $this->getBlockLightAt($x, $y + 1, $z), + $this->getBlockLightAt($x, $y - 1, $z), + $this->getBlockLightAt($x, $y, $z + 1), + $this->getBlockLightAt($x, $y, $z - 1) + ]); } public function updateBlockLight(int $x, int $y, int $z){ + $this->timings->doBlockLightUpdates->startTiming(); + $lightPropagationQueue = new \SplQueue(); $lightRemovalQueue = new \SplQueue(); $visited = []; $removalVisited = []; + $id = $this->getBlockIdAt($x, $y, $z); $oldLevel = $this->getBlockLightAt($x, $y, $z); - $newLevel = (int) Block::$light[$this->getBlockIdAt($x, $y, $z)]; + $newLevel = max(Block::$light[$id], $this->getHighestAdjacentBlockLight($x, $y, $z) - Block::$lightFilter[$id]); if($oldLevel !== $newLevel){ $this->setBlockLightAt($x, $y, $z, $newLevel); @@ -1296,7 +1321,7 @@ class Level implements ChunkManager, Metadatable{ /** @var Vector3 $node */ $node = $lightPropagationQueue->dequeue(); - $lightLevel = $this->getBlockLightAt($node->x, $node->y, $node->z) - (int) Block::$lightFilter[$this->getBlockIdAt($node->x, $node->y, $node->z)]; + $lightLevel = $this->getBlockLightAt($node->x, $node->y, $node->z); if($lightLevel >= 1){ $this->computeSpreadBlockLight($node->x - 1, $node->y, $node->z, $lightLevel, $lightPropagationQueue, $visited); @@ -1307,6 +1332,8 @@ class Level implements ChunkManager, Metadatable{ $this->computeSpreadBlockLight($node->x, $node->y, $node->z + 1, $lightLevel, $lightPropagationQueue, $visited); } } + + $this->timings->doBlockLightUpdates->stopTiming(); } private function computeRemoveBlockLight(int $x, int $y, int $z, int $currentLight, \SplQueue $queue, \SplQueue $spreadQueue, array &$visited, array &$spreadVisited){ @@ -1333,6 +1360,7 @@ class Level implements ChunkManager, Metadatable{ private function computeSpreadBlockLight(int $x, int $y, int $z, int $currentLight, \SplQueue $queue, array &$visited){ if($y < 0) return; $current = $this->getBlockLightAt($x, $y, $z); + $currentLight -= Block::$lightFilter[$this->getBlockIdAt($x, $y, $z)]; if($current < $currentLight){ $this->setBlockLightAt($x, $y, $z, $currentLight); @@ -1370,6 +1398,8 @@ class Level implements ChunkManager, Metadatable{ return false; } + $this->timings->setBlock->startTiming(); + if($this->getChunk($pos->x >> 4, $pos->z >> 4, true)->setBlock($pos->x & 0x0f, $pos->y & Level::Y_MASK, $pos->z & 0x0f, $block->getId(), $block->getDamage())){ if(!($pos instanceof Position)){ $pos = $this->temporalPosition->setComponents($pos->x, $pos->y, $pos->z); @@ -1409,9 +1439,13 @@ class Level implements ChunkManager, Metadatable{ $this->updateAround($pos); } + $this->timings->setBlock->stopTiming(); + return true; } + $this->timings->setBlock->stopTiming(); + return false; } @@ -1476,7 +1510,7 @@ class Level implements ChunkManager, Metadatable{ if(($player->isSurvival() and $item instanceof Item and !$target->isBreakable($item)) or $player->isSpectator()){ $ev->setCancelled(); - }elseif(!$player->isOp() and ($distance = $this->server->getSpawnRadius()) > -1){ + }elseif(!$player->hasPermission("pocketmine.spawnprotect.bypass") and ($distance = $this->server->getSpawnRadius()) > -1){ $t = new Vector2($target->x, $target->z); $s = new Vector2($this->getSpawnLocation()->x, $this->getSpawnLocation()->z); if(count($this->server->getOps()->getAll()) > 0 and $t->distance($s) <= $distance){ //set it to cancelled so plugins can bypass this @@ -1613,7 +1647,7 @@ class Level implements ChunkManager, Metadatable{ if($player !== null){ $ev = new PlayerInteractEvent($player, $item, $target, $face, $target->getId() === 0 ? PlayerInteractEvent::RIGHT_CLICK_AIR : PlayerInteractEvent::RIGHT_CLICK_BLOCK); - if(!$player->isOp() and ($distance = $this->server->getSpawnRadius()) > -1){ + if(!$player->hasPermission("pocketmine.spawnprotect.bypass") and ($distance = $this->server->getSpawnRadius()) > -1){ $t = new Vector2($target->x, $target->z); $s = new Vector2($this->getSpawnLocation()->x, $this->getSpawnLocation()->z); if(count($this->server->getOps()->getAll()) > 0 and $t->distance($s) <= $distance){ //set it to cancelled so plugins can bypass this @@ -1703,7 +1737,7 @@ class Level implements ChunkManager, Metadatable{ if($player !== null){ $ev = new BlockPlaceEvent($player, $hand, $block, $target, $item); - if(!$player->isOp() and ($distance = $this->server->getSpawnRadius()) > -1){ + if(!$player->hasPermission("pocketmine.spawnprotect.bypass") and ($distance = $this->server->getSpawnRadius()) > -1){ $t = new Vector2($target->x, $target->z); $s = new Vector2($this->getSpawnLocation()->x, $this->getSpawnLocation()->z); if(count($this->server->getOps()->getAll()) > 0 and $t->distance($s) <= $distance){ //set it to cancelled so plugins can bypass this diff --git a/src/pocketmine/math/Vector3.php b/src/pocketmine/math/Vector3.php index 36801282a..395ee9c1c 100644 --- a/src/pocketmine/math/Vector3.php +++ b/src/pocketmine/math/Vector3.php @@ -250,7 +250,7 @@ class Vector3{ if($f < 0 or $f > 1){ return null; }else{ - return new Vector3($this->x + $xDiff * $f, $this->y + $yDiff * $f, $this->z + $zDiff * $f); + return new Vector3($x, $this->y + $yDiff * $f, $this->z + $zDiff * $f); } } @@ -277,7 +277,7 @@ class Vector3{ if($f < 0 or $f > 1){ return null; }else{ - return new Vector3($this->x + $xDiff * $f, $this->y + $yDiff * $f, $this->z + $zDiff * $f); + return new Vector3($this->x + $xDiff * $f, $y, $this->z + $zDiff * $f); } } @@ -304,7 +304,7 @@ class Vector3{ if($f < 0 or $f > 1){ return null; }else{ - return new Vector3($this->x + $xDiff * $f, $this->y + $yDiff * $f, $this->z + $zDiff * $f); + return new Vector3($this->x + $xDiff * $f, $this->y + $yDiff * $f, $z); } } diff --git a/src/pocketmine/network/Network.php b/src/pocketmine/network/Network.php index 8c6be605c..1c3336269 100644 --- a/src/pocketmine/network/Network.php +++ b/src/pocketmine/network/Network.php @@ -57,24 +57,24 @@ use pocketmine\network\mcpe\protocol\EntityEventPacket; use pocketmine\network\mcpe\protocol\ExplodePacket; use pocketmine\network\mcpe\protocol\FullChunkDataPacket; use pocketmine\network\mcpe\protocol\HurtArmorPacket; -use pocketmine\network\mcpe\protocol\MapInfoRequestPacket; -use pocketmine\network\mcpe\protocol\PlaySoundPacket; -use pocketmine\network\mcpe\protocol\ProtocolInfo; use pocketmine\network\mcpe\protocol\InteractPacket; use pocketmine\network\mcpe\protocol\InventoryActionPacket; use pocketmine\network\mcpe\protocol\ItemFrameDropItemPacket; use pocketmine\network\mcpe\protocol\LevelEventPacket; use pocketmine\network\mcpe\protocol\LevelSoundEventPacket; use pocketmine\network\mcpe\protocol\LoginPacket; -use pocketmine\network\mcpe\protocol\MobEquipmentPacket; +use pocketmine\network\mcpe\protocol\MapInfoRequestPacket; use pocketmine\network\mcpe\protocol\MobArmorEquipmentPacket; +use pocketmine\network\mcpe\protocol\MobEquipmentPacket; use pocketmine\network\mcpe\protocol\MoveEntityPacket; use pocketmine\network\mcpe\protocol\MovePlayerPacket; use pocketmine\network\mcpe\protocol\PlayerActionPacket; use pocketmine\network\mcpe\protocol\PlayerFallPacket; use pocketmine\network\mcpe\protocol\PlayerInputPacket; use pocketmine\network\mcpe\protocol\PlayerListPacket; +use pocketmine\network\mcpe\protocol\PlaySoundPacket; use pocketmine\network\mcpe\protocol\PlayStatusPacket; +use pocketmine\network\mcpe\protocol\ProtocolInfo; use pocketmine\network\mcpe\protocol\RemoveBlockPacket; use pocketmine\network\mcpe\protocol\RemoveEntityPacket; use pocketmine\network\mcpe\protocol\ReplaceItemInSlotPacket; @@ -108,9 +108,7 @@ use pocketmine\network\mcpe\protocol\UnknownPacket; use pocketmine\network\mcpe\protocol\UpdateBlockPacket; use pocketmine\network\mcpe\protocol\UpdateTradePacket; use pocketmine\network\mcpe\protocol\UseItemPacket; -use pocketmine\Player; use pocketmine\Server; -use pocketmine\utils\BinaryStream; class Network{ @@ -237,50 +235,6 @@ class Network{ return $this->server; } - /** - * Decodes a batch packet and does handling for it. - * - * TODO: Move this out of here - * - * @param BatchPacket $packet - * @param Player $player - * - * @throws \InvalidArgumentException|\InvalidStateException - */ - public function processBatch(BatchPacket $packet, Player $p){ - $rawLen = strlen($packet->payload); - if($rawLen === 0){ - throw new \InvalidArgumentException("BatchPacket payload is empty or packet decode error"); - }elseif($rawLen < 3){ - throw new \InvalidArgumentException("Not enough bytes, expected zlib header"); - } - - $str = zlib_decode($packet->payload, 1024 * 1024 * 64); //Max 64MB - $len = strlen($str); - - if($len === 0){ - throw new \InvalidStateException("Decoded BatchPacket payload is empty"); - } - - $stream = new BinaryStream($str); - - while($stream->offset < $len){ - $buf = $stream->getString(); - - if(($pk = $this->getPacket(ord($buf{0}))) !== null){ - if(!$pk->canBeBatched()){ - throw new \InvalidStateException("Received invalid " . get_class($pk) . " inside BatchPacket"); - } - - $pk->setBuffer($buf, 1); - - $pk->decode(); - assert($pk->feof(), "Still " . strlen(substr($pk->buffer, $pk->offset)) . " bytes unread in " . get_class($pk)); - $p->handleDataPacket($pk); - } - } - } - /** * @param $id * diff --git a/src/pocketmine/network/mcpe/NetworkSession.php b/src/pocketmine/network/mcpe/NetworkSession.php index a0c0ecfc3..1d1892e0c 100644 --- a/src/pocketmine/network/mcpe/NetworkSession.php +++ b/src/pocketmine/network/mcpe/NetworkSession.php @@ -32,7 +32,6 @@ use pocketmine\network\mcpe\protocol\AddPlayerPacket; use pocketmine\network\mcpe\protocol\AdventureSettingsPacket; use pocketmine\network\mcpe\protocol\AnimatePacket; use pocketmine\network\mcpe\protocol\AvailableCommandsPacket; -use pocketmine\network\mcpe\protocol\BatchPacket; use pocketmine\network\mcpe\protocol\BlockEntityDataPacket; use pocketmine\network\mcpe\protocol\BlockEventPacket; use pocketmine\network\mcpe\protocol\BlockPickRequestPacket; @@ -49,6 +48,7 @@ use pocketmine\network\mcpe\protocol\ContainerSetDataPacket; use pocketmine\network\mcpe\protocol\ContainerSetSlotPacket; use pocketmine\network\mcpe\protocol\CraftingDataPacket; use pocketmine\network\mcpe\protocol\CraftingEventPacket; +use pocketmine\network\mcpe\protocol\DataPacket; use pocketmine\network\mcpe\protocol\DisconnectPacket; use pocketmine\network\mcpe\protocol\DropItemPacket; use pocketmine\network\mcpe\protocol\EntityEventPacket; @@ -108,9 +108,17 @@ use pocketmine\network\mcpe\protocol\UpdateAttributesPacket; use pocketmine\network\mcpe\protocol\UpdateBlockPacket; use pocketmine\network\mcpe\protocol\UpdateTradePacket; use pocketmine\network\mcpe\protocol\UseItemPacket; +use pocketmine\Server; interface NetworkSession{ + /** + * @return Server + */ + public function getServer(); + + public function handleDataPacket(DataPacket $pk); + public function handleLogin(LoginPacket $packet) : bool; public function handlePlayStatus(PlayStatusPacket $packet) : bool; @@ -121,8 +129,6 @@ interface NetworkSession{ public function handleDisconnect(DisconnectPacket $packet) : bool; - public function handleBatch(BatchPacket $packet) : bool; - public function handleResourcePacksInfo(ResourcePacksInfoPacket $packet) : bool; public function handleResourcePackStack(ResourcePackStackPacket $packet) : bool; diff --git a/src/pocketmine/network/mcpe/RakLibInterface.php b/src/pocketmine/network/mcpe/RakLibInterface.php index 9a5b12275..a613d8a41 100644 --- a/src/pocketmine/network/mcpe/RakLibInterface.php +++ b/src/pocketmine/network/mcpe/RakLibInterface.php @@ -132,11 +132,7 @@ class RakLibInterface implements ServerInstance, AdvancedSourceInterface{ try{ if($packet->buffer !== ""){ $pk = $this->getPacket($packet->buffer); - if($pk !== null){ - $pk->decode(); - assert($pk->feof(), "Still " . strlen(substr($pk->buffer, $pk->offset)) . " bytes unread!"); - $this->players[$identifier]->handleDataPacket($pk); - } + $this->players[$identifier]->handleDataPacket($pk); } }catch(\Throwable $e){ if(\pocketmine\DEBUG > 1 and isset($pk)){ diff --git a/src/pocketmine/network/mcpe/protocol/BatchPacket.php b/src/pocketmine/network/mcpe/protocol/BatchPacket.php index 4f952548e..2257655a0 100644 --- a/src/pocketmine/network/mcpe/protocol/BatchPacket.php +++ b/src/pocketmine/network/mcpe/protocol/BatchPacket.php @@ -45,7 +45,32 @@ class BatchPacket extends DataPacket{ } public function handle(NetworkSession $session) : bool{ - return $session->handleBatch($this); + if(strlen($this->payload) < 2){ + throw new \InvalidStateException("Not enough bytes in payload, expected zlib header"); + } + + $str = zlib_decode($this->payload, 1024 * 1024 * 64); //Max 64MB + $len = strlen($str); + + if($len === 0){ + throw new \InvalidStateException("Decoded BatchPacket payload is empty"); + } + + $this->setBuffer($str, 0); + + $network = $session->getServer()->getNetwork(); + while(!$this->feof()){ + $buf = $this->getString(); + $pk = $network->getPacket(ord($buf{0})); + if(!$pk->canBeBatched()){ + throw new \InvalidArgumentException("Received invalid " . get_class($pk) . " inside BatchPacket"); + } + + $pk->setBuffer($buf, 1); + $session->handleDataPacket($pk); + } + + return true; } } \ No newline at end of file diff --git a/src/pocketmine/permission/DefaultPermissions.php b/src/pocketmine/permission/DefaultPermissions.php index b1aa2f682..079db04ff 100644 --- a/src/pocketmine/permission/DefaultPermissions.php +++ b/src/pocketmine/permission/DefaultPermissions.php @@ -47,12 +47,13 @@ abstract class DefaultPermissions{ $parent = self::registerPermission(new Permission(self::ROOT, "Allows using all PocketMine commands and utilities")); $broadcasts = self::registerPermission(new Permission(self::ROOT . ".broadcast", "Allows the user to receive all broadcast messages"), $parent); - self::registerPermission(new Permission(self::ROOT . ".broadcast.admin", "Allows the user to receive administrative broadcasts", Permission::DEFAULT_OP), $broadcasts); self::registerPermission(new Permission(self::ROOT . ".broadcast.user", "Allows the user to receive user broadcasts", Permission::DEFAULT_TRUE), $broadcasts); - $broadcasts->recalculatePermissibles(); + $spawnprotect = self::registerPermission(new Permission(self::ROOT . ".spawnprotect.bypass", "Allows the user to edit blocks within the protected spawn radius", Permission::DEFAULT_OP), $parent); + $spawnprotect->recalculatePermissibles(); + $commands = self::registerPermission(new Permission(self::ROOT . ".command", "Allows using all PocketMine commands"), $parent); $whitelist = self::registerPermission(new Permission(self::ROOT . ".command.whitelist", "Allows the user to modify the server whitelist", Permission::DEFAULT_OP), $commands); diff --git a/src/pocketmine/resources/pocketmine.yml b/src/pocketmine/resources/pocketmine.yml index 9b8df9222..132890293 100644 --- a/src/pocketmine/resources/pocketmine.yml +++ b/src/pocketmine/resources/pocketmine.yml @@ -185,6 +185,11 @@ timings: #Choose the host to use for viewing your timings results. host: mcpetimings.com +console: + #Choose whether to enable server stats reporting on the console title. + #NOTE: The title ticker will be disabled regardless if console colours are not enabled. + title-tick: true + aliases: #Examples: #showtheversion: version