From 932c489de153dbc1491f6f0e7f893f216ec834d7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=3D=3FUTF-8=3Fq=3FFabian=3D20Fa=3DC3=3D9Fbender=3F=3D?= Date: Wed, 1 May 2019 18:52:03 +0100 Subject: [PATCH 01/90] Rename addTitle/addSubTitle/addActionBarMessage prefixes to "send", deprecated old variants closes #2896 these deprecated methods will be removed in 4.0. --- src/pocketmine/Player.php | 42 +++++++++++++++++-- src/pocketmine/Server.php | 2 +- .../command/defaults/TitleCommand.php | 6 +-- 3 files changed, 42 insertions(+), 8 deletions(-) diff --git a/src/pocketmine/Player.php b/src/pocketmine/Player.php index 2997ce568..d2d9926b5 100644 --- a/src/pocketmine/Player.php +++ b/src/pocketmine/Player.php @@ -3259,7 +3259,8 @@ class Player extends Human implements CommandSender, ChunkLoader, IPlayer{ } /** - * Adds a title text to the user's screen, with an optional subtitle. + * @deprecated + * @see Player::sendTitle() * * @param string $title * @param string $subtitle @@ -3268,28 +3269,61 @@ class Player extends Human implements CommandSender, ChunkLoader, IPlayer{ * @param int $fadeOut Duration in ticks for fade-out. */ public function addTitle(string $title, string $subtitle = "", int $fadeIn = -1, int $stay = -1, int $fadeOut = -1){ + $this->sendTitle($title, $subtitle, $fadeIn, $stay, $fadeOut); + } + + /** + * Adds a title text to the user's screen, with an optional subtitle. + * + * @param string $title + * @param string $subtitle + * @param int $fadeIn Duration in ticks for fade-in. If -1 is given, client-sided defaults will be used. + * @param int $stay Duration in ticks to stay on screen for + * @param int $fadeOut Duration in ticks for fade-out. + */ + public function sendTitle(string $title, string $subtitle = "", int $fadeIn = -1, int $stay = -1, int $fadeOut = -1) : void{ $this->setTitleDuration($fadeIn, $stay, $fadeOut); if($subtitle !== ""){ - $this->addSubTitle($subtitle); + $this->sendSubTitle($subtitle); } $this->sendTitleText($title, SetTitlePacket::TYPE_SET_TITLE); } + /** + * @deprecated + * @see Player::sendSubTitle() + * + * @param string $subtitle + */ + public function addSubTitle(string $subtitle){ + $this->sendSubTitle($subtitle); + } + /** * Sets the subtitle message, without sending a title. * * @param string $subtitle */ - public function addSubTitle(string $subtitle){ + public function sendSubTitle(string $subtitle) : void{ $this->sendTitleText($subtitle, SetTitlePacket::TYPE_SET_SUBTITLE); } + /** + * @deprecated + * @see Player::sendActionBarMessage() + * + * @param string $message + */ + public function addActionBarMessage(string $message){ + $this->sendActionBarMessage($message); + } + /** * Adds small text to the user's screen. * * @param string $message */ - public function addActionBarMessage(string $message){ + public function sendActionBarMessage(string $message) : void{ $this->sendTitleText($message, SetTitlePacket::TYPE_SET_ACTIONBAR_MESSAGE); } diff --git a/src/pocketmine/Server.php b/src/pocketmine/Server.php index c5911d8b8..c336caf34 100644 --- a/src/pocketmine/Server.php +++ b/src/pocketmine/Server.php @@ -1872,7 +1872,7 @@ class Server{ /** @var Player[] $recipients */ foreach($recipients as $recipient){ - $recipient->addTitle($title, $subtitle, $fadeIn, $stay, $fadeOut); + $recipient->sendTitle($title, $subtitle, $fadeIn, $stay, $fadeOut); } return count($recipients); diff --git a/src/pocketmine/command/defaults/TitleCommand.php b/src/pocketmine/command/defaults/TitleCommand.php index 667eeee08..030888912 100644 --- a/src/pocketmine/command/defaults/TitleCommand.php +++ b/src/pocketmine/command/defaults/TitleCommand.php @@ -68,21 +68,21 @@ class TitleCommand extends VanillaCommand{ throw new InvalidCommandSyntaxException(); } - $player->addTitle(implode(" ", array_slice($args, 2))); + $player->sendTitle(implode(" ", array_slice($args, 2))); break; case "subtitle": if(count($args) < 3){ throw new InvalidCommandSyntaxException(); } - $player->addSubTitle(implode(" ", array_slice($args, 2))); + $player->sendSubTitle(implode(" ", array_slice($args, 2))); break; case "actionbar": if(count($args) < 3){ throw new InvalidCommandSyntaxException(); } - $player->addActionBarMessage(implode(" ", array_slice($args, 2))); + $player->sendActionBarMessage(implode(" ", array_slice($args, 2))); break; case "times": if(count($args) < 5){ From 4d54dc30c19759c77eb7bf6dfeb300c8f2d863fa Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Sun, 16 Jun 2019 14:11:08 +0100 Subject: [PATCH 02/90] crafting: deprecate some stuff that's been removed on bleeding edge --- src/pocketmine/inventory/CraftingManager.php | 8 +++++--- src/pocketmine/inventory/FurnaceRecipe.php | 5 +++++ src/pocketmine/inventory/Recipe.php | 5 +++++ src/pocketmine/inventory/ShapedRecipe.php | 5 +++++ src/pocketmine/inventory/ShapelessRecipe.php | 5 +++++ 5 files changed, 25 insertions(+), 3 deletions(-) diff --git a/src/pocketmine/inventory/CraftingManager.php b/src/pocketmine/inventory/CraftingManager.php index 528b364a9..33dba506f 100644 --- a/src/pocketmine/inventory/CraftingManager.php +++ b/src/pocketmine/inventory/CraftingManager.php @@ -60,7 +60,7 @@ class CraftingManager{ if($recipe["block"] !== "crafting_table"){ //TODO: filter others out for now to avoid breaking economics break; } - $this->registerRecipe(new ShapelessRecipe( + $this->registerShapelessRecipe(new ShapelessRecipe( array_map($itemDeserializerFunc, $recipe["input"]), array_map($itemDeserializerFunc, $recipe["output"]) )); @@ -69,7 +69,7 @@ class CraftingManager{ if($recipe["block"] !== "crafting_table"){ //TODO: filter others out for now to avoid breaking economics break; } - $this->registerRecipe(new ShapedRecipe( + $this->registerShapedRecipe(new ShapedRecipe( $recipe["shape"], array_map($itemDeserializerFunc, $recipe["input"]), array_map($itemDeserializerFunc, $recipe["output"]) @@ -79,7 +79,7 @@ class CraftingManager{ if($recipe["block"] !== "furnace"){ //TODO: filter others out for now to avoid breaking economics break; } - $this->registerRecipe(new FurnaceRecipe( + $this->registerFurnaceRecipe(new FurnaceRecipe( Item::jsonDeserialize($recipe["output"]), Item::jsonDeserialize($recipe["input"])) ); @@ -300,6 +300,8 @@ class CraftingManager{ } /** + * @deprecated + * * @param Recipe $recipe */ public function registerRecipe(Recipe $recipe) : void{ diff --git a/src/pocketmine/inventory/FurnaceRecipe.php b/src/pocketmine/inventory/FurnaceRecipe.php index c8ed4be61..8e81fe03f 100644 --- a/src/pocketmine/inventory/FurnaceRecipe.php +++ b/src/pocketmine/inventory/FurnaceRecipe.php @@ -63,6 +63,11 @@ class FurnaceRecipe implements Recipe{ return clone $this->output; } + /** + * @deprecated + * + * @param CraftingManager $manager + */ public function registerToCraftingManager(CraftingManager $manager) : void{ $manager->registerFurnaceRecipe($this); } diff --git a/src/pocketmine/inventory/Recipe.php b/src/pocketmine/inventory/Recipe.php index 883eea6d9..bdd72e01f 100644 --- a/src/pocketmine/inventory/Recipe.php +++ b/src/pocketmine/inventory/Recipe.php @@ -25,5 +25,10 @@ namespace pocketmine\inventory; interface Recipe{ + /** + * @deprecated + * + * @param CraftingManager $manager + */ public function registerToCraftingManager(CraftingManager $manager) : void; } diff --git a/src/pocketmine/inventory/ShapedRecipe.php b/src/pocketmine/inventory/ShapedRecipe.php index 04103cbfb..434eb36d5 100644 --- a/src/pocketmine/inventory/ShapedRecipe.php +++ b/src/pocketmine/inventory/ShapedRecipe.php @@ -187,6 +187,11 @@ class ShapedRecipe implements CraftingRecipe{ return $this->shape; } + /** + * @deprecated + * + * @param CraftingManager $manager + */ public function registerToCraftingManager(CraftingManager $manager) : void{ $manager->registerShapedRecipe($this); } diff --git a/src/pocketmine/inventory/ShapelessRecipe.php b/src/pocketmine/inventory/ShapelessRecipe.php index fcf303d43..170faab54 100644 --- a/src/pocketmine/inventory/ShapelessRecipe.php +++ b/src/pocketmine/inventory/ShapelessRecipe.php @@ -111,6 +111,11 @@ class ShapelessRecipe implements CraftingRecipe{ return $count; } + /** + * @deprecated + * + * @param CraftingManager $manager + */ public function registerToCraftingManager(CraftingManager $manager) : void{ $manager->registerShapelessRecipe($this); } From 4e5a80c4817615aad59ac7371205f6556dbbff7a Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Sun, 16 Jun 2019 14:12:49 +0100 Subject: [PATCH 03/90] Recipe: deprecate interface --- src/pocketmine/inventory/Recipe.php | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/pocketmine/inventory/Recipe.php b/src/pocketmine/inventory/Recipe.php index bdd72e01f..f97e985b9 100644 --- a/src/pocketmine/inventory/Recipe.php +++ b/src/pocketmine/inventory/Recipe.php @@ -23,6 +23,9 @@ declare(strict_types=1); namespace pocketmine\inventory; +/** + * @deprecated + */ interface Recipe{ /** From eedea4998bf77d9d6436e7f000de37596fe8d91e Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Sat, 29 Dec 2018 11:28:25 +0000 Subject: [PATCH 04/90] Terminal: Added write() and writeLine() to allow easily emitting Minecraft-formatted text to the console --- src/pocketmine/utils/MainLogger.php | 2 +- src/pocketmine/utils/Terminal.php | 19 +++++++++++++++++++ 2 files changed, 20 insertions(+), 1 deletion(-) diff --git a/src/pocketmine/utils/MainLogger.php b/src/pocketmine/utils/MainLogger.php index 83d0f379b..06d11da64 100644 --- a/src/pocketmine/utils/MainLogger.php +++ b/src/pocketmine/utils/MainLogger.php @@ -307,7 +307,7 @@ class MainLogger extends \AttachableThreadedLogger{ } $this->synchronized(function() use ($message, $level, $time) : void{ - echo Terminal::toANSI($message) . PHP_EOL; + Terminal::writeLine($message); foreach($this->attachments as $attachment){ $attachment->call($level, $message); diff --git a/src/pocketmine/utils/Terminal.php b/src/pocketmine/utils/Terminal.php index dd52d6951..a3f6058c9 100644 --- a/src/pocketmine/utils/Terminal.php +++ b/src/pocketmine/utils/Terminal.php @@ -263,4 +263,23 @@ abstract class Terminal{ return $newString; } + + /** + * Emits a string containing Minecraft colour codes to the console formatted with native colours. + * + * @param string $line + */ + public static function write(string $line) : void{ + echo self::toANSI($line); + } + + /** + * Emits a string containing Minecraft colour codes to the console formatted with native colours, followed by a + * newline character. + * + * @param string $line + */ + public static function writeLine(string $line) : void{ + echo self::toANSI($line) . PHP_EOL; + } } From eaa78fe84992ac869c64056fc410135a64b9f9c3 Mon Sep 17 00:00:00 2001 From: "Jack M. Taylor" <32965703+JackMD@users.noreply.github.com> Date: Thu, 14 Feb 2019 15:58:19 +0500 Subject: [PATCH 05/90] backport 205e13d88: Config: add getPath() (#2758) Config->getPath() returns the path of the config i.e. the place where the config file is located. --- src/pocketmine/utils/Config.php | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/pocketmine/utils/Config.php b/src/pocketmine/utils/Config.php index 13d47f4d8..9fbd06bb6 100644 --- a/src/pocketmine/utils/Config.php +++ b/src/pocketmine/utils/Config.php @@ -248,6 +248,15 @@ class Config{ } } + /** + * Returns the path of the config. + * + * @return string + */ + public function getPath() : string{ + return $this->file; + } + /** * Sets the options for the JSON encoding when saving * From 680cdb8e3e5f76eb0ad1f4d15264ea0eec0e4c76 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Sun, 3 Mar 2019 17:39:13 +0000 Subject: [PATCH 06/90] backport f5dbbea5f: Utils: added recursiveUnlink() --- src/pocketmine/utils/Utils.php | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/src/pocketmine/utils/Utils.php b/src/pocketmine/utils/Utils.php index ef2fb0d34..a2fdf85a0 100644 --- a/src/pocketmine/utils/Utils.php +++ b/src/pocketmine/utils/Utils.php @@ -54,6 +54,8 @@ use function gettype; use function hexdec; use function implode; use function is_array; +use function is_dir; +use function is_file; use function is_object; use function is_readable; use function is_string; @@ -72,6 +74,8 @@ use function preg_match_all; use function preg_replace; use function proc_close; use function proc_open; +use function rmdir; +use function scandir; use function sha1; use function spl_object_hash; use function str_pad; @@ -85,11 +89,13 @@ use function strtolower; use function substr; use function sys_get_temp_dir; use function trim; +use function unlink; use function xdebug_get_function_stack; use const PHP_EOL; use const PHP_INT_MAX; use const PHP_INT_SIZE; use const PHP_MAXPATHLEN; +use const SCANDIR_SORT_NONE; use const STR_PAD_LEFT; use const STR_PAD_RIGHT; @@ -734,4 +740,22 @@ class Utils{ throw new \TypeError("Declaration of callable `" . CallbackType::createFromCallable($subject) . "` must be compatible with `" . $sigType . "`"); } } + + public static function recursiveUnlink(string $dir) : void{ + if(is_dir($dir)){ + $objects = scandir($dir, SCANDIR_SORT_NONE); + foreach($objects as $object){ + if($object !== "." and $object !== ".."){ + if(is_dir($dir . "/" . $object)){ + self::recursiveUnlink($dir . "/" . $object); + }else{ + unlink($dir . "/" . $object); + } + } + } + rmdir($dir); + }elseif(is_file($dir)){ + unlink($dir); + } + } } From a8433697adb44026bf236646f56d193108455824 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Sat, 29 Dec 2018 11:54:44 +0000 Subject: [PATCH 07/90] backport aaaddd1fd: Terminal: stick a RESET on the end when writing a newline --- src/pocketmine/utils/Terminal.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pocketmine/utils/Terminal.php b/src/pocketmine/utils/Terminal.php index a3f6058c9..67e89226b 100644 --- a/src/pocketmine/utils/Terminal.php +++ b/src/pocketmine/utils/Terminal.php @@ -280,6 +280,6 @@ abstract class Terminal{ * @param string $line */ public static function writeLine(string $line) : void{ - echo self::toANSI($line) . PHP_EOL; + echo self::toANSI($line) . self::$FORMAT_RESET . PHP_EOL; } } From 4635b93f4dc261e529db26e4442e82daab8b334f Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Sun, 24 Mar 2019 18:57:32 +0000 Subject: [PATCH 08/90] backport 23071d257 + deprecations: Extract process-related functions from Utils into a separate Process class --- src/pocketmine/MemoryManager.php | 3 +- src/pocketmine/PocketMine.php | 7 +- src/pocketmine/Server.php | 11 +- .../command/defaults/StatusCommand.php | 8 +- .../event/server/LowMemoryEvent.php | 4 +- src/pocketmine/scheduler/SendUsageTask.php | 5 +- src/pocketmine/utils/Process.php | 170 ++++++++++++++++++ src/pocketmine/utils/ServerKiller.php | 2 +- src/pocketmine/utils/Utils.php | 125 +++---------- 9 files changed, 218 insertions(+), 117 deletions(-) create mode 100644 src/pocketmine/utils/Process.php diff --git a/src/pocketmine/MemoryManager.php b/src/pocketmine/MemoryManager.php index d6e03a393..77ecca9d4 100644 --- a/src/pocketmine/MemoryManager.php +++ b/src/pocketmine/MemoryManager.php @@ -27,6 +27,7 @@ use pocketmine\event\server\LowMemoryEvent; use pocketmine\scheduler\DumpWorkerMemoryTask; use pocketmine\scheduler\GarbageCollectionTask; use pocketmine\timings\Timings; +use pocketmine\utils\Process; use pocketmine\utils\Utils; use function arsort; use function count; @@ -236,7 +237,7 @@ class MemoryManager{ if(($this->memoryLimit > 0 or $this->globalMemoryLimit > 0) and ++$this->checkTicker >= $this->checkRate){ $this->checkTicker = 0; - $memory = Utils::getMemoryUsage(true); + $memory = Process::getMemoryUsage(true); $trigger = false; if($this->memoryLimit > 0 and $memory[0] > $this->memoryLimit){ $trigger = 0; diff --git a/src/pocketmine/PocketMine.php b/src/pocketmine/PocketMine.php index 732026434..4b79ed5da 100644 --- a/src/pocketmine/PocketMine.php +++ b/src/pocketmine/PocketMine.php @@ -29,6 +29,7 @@ namespace { namespace pocketmine { use pocketmine\utils\MainLogger; + use pocketmine\utils\Process; use pocketmine\utils\ServerKiller; use pocketmine\utils\Terminal; use pocketmine\utils\Timezone; @@ -238,9 +239,9 @@ namespace pocketmine { $gitHash = str_repeat("00", 20); if(\Phar::running(true) === ""){ - if(Utils::execute("git rev-parse HEAD", $out) === 0 and $out !== false and strlen($out = trim($out)) === 40){ + if(Process::execute("git rev-parse HEAD", $out) === 0 and $out !== false and strlen($out = trim($out)) === 40){ $gitHash = trim($out); - if(Utils::execute("git diff --quiet") === 1 or Utils::execute("git diff --cached --quiet") === 1){ //Locally-modified + if(Process::execute("git diff --quiet") === 1 or Process::execute("git diff --cached --quiet") === 1){ //Locally-modified $gitHash .= "-dirty"; } } @@ -283,7 +284,7 @@ namespace pocketmine { if(\pocketmine\DEBUG > 1){ echo "Some threads could not be stopped, performing a force-kill" . PHP_EOL . PHP_EOL; } - Utils::kill(getmypid()); + Process::kill(getmypid()); } }while(false); diff --git a/src/pocketmine/Server.php b/src/pocketmine/Server.php index 8de8151d4..3468c6c83 100644 --- a/src/pocketmine/Server.php +++ b/src/pocketmine/Server.php @@ -101,6 +101,7 @@ use pocketmine\updater\AutoUpdater; use pocketmine\utils\Config; use pocketmine\utils\Internet; use pocketmine\utils\MainLogger; +use pocketmine\utils\Process; use pocketmine\utils\Terminal; use pocketmine\utils\TextFormat; use pocketmine\utils\Utils; @@ -2150,7 +2151,7 @@ class Server{ }catch(\Throwable $e){ $this->logger->logException($e); $this->logger->emergency("Crashed while crashing, killing process"); - @Utils::kill(getmypid()); + @Process::kill(getmypid()); } } @@ -2326,7 +2327,7 @@ class Server{ echo "--- Waiting $spacing seconds to throttle automatic restart (you can kill the process safely now) ---" . PHP_EOL; sleep($spacing); } - @Utils::kill(getmypid()); + @Process::kill(getmypid()); exit(1); } @@ -2507,10 +2508,10 @@ class Server{ private function titleTick(){ Timings::$titleTickTimer->startTiming(); - $d = Utils::getRealMemoryUsage(); + $d = Process::getRealMemoryUsage(); - $u = Utils::getMemoryUsage(true); - $usage = sprintf("%g/%g/%g/%g MB @ %d threads", round(($u[0] / 1024) / 1024, 2), round(($d[0] / 1024) / 1024, 2), round(($u[1] / 1024) / 1024, 2), round(($u[2] / 1024) / 1024, 2), Utils::getThreadCount()); + $u = Process::getMemoryUsage(true); + $usage = sprintf("%g/%g/%g/%g MB @ %d threads", round(($u[0] / 1024) / 1024, 2), round(($d[0] / 1024) / 1024, 2), round(($u[1] / 1024) / 1024, 2), round(($u[2] / 1024) / 1024, 2), Process::getThreadCount()); echo "\x1b]0;" . $this->getName() . " " . $this->getPocketMineVersion() . diff --git a/src/pocketmine/command/defaults/StatusCommand.php b/src/pocketmine/command/defaults/StatusCommand.php index d43f7df28..9fb0253bb 100644 --- a/src/pocketmine/command/defaults/StatusCommand.php +++ b/src/pocketmine/command/defaults/StatusCommand.php @@ -24,8 +24,8 @@ declare(strict_types=1); namespace pocketmine\command\defaults; use pocketmine\command\CommandSender; +use pocketmine\utils\Process; use pocketmine\utils\TextFormat; -use pocketmine\utils\Utils; use function count; use function floor; use function microtime; @@ -48,8 +48,8 @@ class StatusCommand extends VanillaCommand{ return true; } - $rUsage = Utils::getRealMemoryUsage(); - $mUsage = Utils::getMemoryUsage(true); + $rUsage = Process::getRealMemoryUsage(); + $mUsage = Process::getMemoryUsage(true); $server = $sender->getServer(); $sender->sendMessage(TextFormat::GREEN . "---- " . TextFormat::WHITE . "Server status" . TextFormat::GREEN . " ----"); @@ -94,7 +94,7 @@ class StatusCommand extends VanillaCommand{ $sender->sendMessage(TextFormat::GOLD . "Network upload: " . TextFormat::RED . round($server->getNetwork()->getUpload() / 1024, 2) . " kB/s"); $sender->sendMessage(TextFormat::GOLD . "Network download: " . TextFormat::RED . round($server->getNetwork()->getDownload() / 1024, 2) . " kB/s"); - $sender->sendMessage(TextFormat::GOLD . "Thread count: " . TextFormat::RED . Utils::getThreadCount()); + $sender->sendMessage(TextFormat::GOLD . "Thread count: " . TextFormat::RED . Process::getThreadCount()); $sender->sendMessage(TextFormat::GOLD . "Main thread memory: " . TextFormat::RED . number_format(round(($mUsage[0] / 1024) / 1024, 2), 2) . " MB."); $sender->sendMessage(TextFormat::GOLD . "Total memory: " . TextFormat::RED . number_format(round(($mUsage[1] / 1024) / 1024, 2), 2) . " MB."); diff --git a/src/pocketmine/event/server/LowMemoryEvent.php b/src/pocketmine/event/server/LowMemoryEvent.php index 5e7412b1f..aaaaded62 100644 --- a/src/pocketmine/event/server/LowMemoryEvent.php +++ b/src/pocketmine/event/server/LowMemoryEvent.php @@ -23,7 +23,7 @@ declare(strict_types=1); namespace pocketmine\event\server; -use pocketmine\utils\Utils; +use pocketmine\utils\Process; /** @@ -87,6 +87,6 @@ class LowMemoryEvent extends ServerEvent{ * @return int */ public function getMemoryFreed() : int{ - return $this->getMemory() - ($this->isGlobal() ? Utils::getMemoryUsage(true)[1] : Utils::getMemoryUsage(true)[0]); + return $this->getMemory() - ($this->isGlobal() ? Process::getMemoryUsage(true)[1] : Process::getMemoryUsage(true)[0]); } } diff --git a/src/pocketmine/scheduler/SendUsageTask.php b/src/pocketmine/scheduler/SendUsageTask.php index 7edd523f7..a566364a9 100644 --- a/src/pocketmine/scheduler/SendUsageTask.php +++ b/src/pocketmine/scheduler/SendUsageTask.php @@ -26,6 +26,7 @@ namespace pocketmine\scheduler; use pocketmine\network\mcpe\protocol\ProtocolInfo; use pocketmine\Server; use pocketmine\utils\Internet; +use pocketmine\utils\Process; use pocketmine\utils\Utils; use pocketmine\utils\UUID; use pocketmine\utils\VersionString; @@ -135,12 +136,12 @@ class SendUsageTask extends AsyncTask{ "historyList" => array_values($playerList) ]; - $info = Utils::getMemoryUsage(true); + $info = Process::getMemoryUsage(true); $data["system"] = [ "mainMemory" => $info[0], "totalMemory" => $info[1], "availableMemory" => $info[2], - "threadCount" => Utils::getThreadCount() + "threadCount" => Process::getThreadCount() ]; break; diff --git a/src/pocketmine/utils/Process.php b/src/pocketmine/utils/Process.php new file mode 100644 index 000000000..f5df0f703 --- /dev/null +++ b/src/pocketmine/utils/Process.php @@ -0,0 +1,170 @@ + 0){ + $VmRSS = $matches[1] * 1024; + } + + if(preg_match("/VmSize:[ \t]+([0-9]+) kB/", $status, $matches) > 0){ + $VmSize = $matches[1] * 1024; + } + } + + //TODO: more OS + + if($VmRSS === null){ + $VmRSS = memory_get_usage(); + } + + if(!$advanced){ + return $VmRSS; + } + + if($VmSize === null){ + $VmSize = memory_get_usage(true); + } + + return [$reserved, $VmRSS, $VmSize]; + } + + /** + * @return int[] + */ + public static function getRealMemoryUsage() : array{ + $stack = 0; + $heap = 0; + + if(Utils::getOS() === "linux" or Utils::getOS() === "android"){ + $mappings = file("/proc/self/maps"); + foreach($mappings as $line){ + if(preg_match("#([a-z0-9]+)\\-([a-z0-9]+) [rwxp\\-]{4} [a-z0-9]+ [^\\[]*\\[([a-zA-z0-9]+)\\]#", trim($line), $matches) > 0){ + if(strpos($matches[3], "heap") === 0){ + $heap += hexdec($matches[2]) - hexdec($matches[1]); + }elseif(strpos($matches[3], "stack") === 0){ + $stack += hexdec($matches[2]) - hexdec($matches[1]); + } + } + } + } + + return [$heap, $stack]; + } + + + public static function getThreadCount() : int{ + if(Utils::getOS() === "linux" or Utils::getOS() === "android"){ + if(preg_match("/Threads:[ \t]+([0-9]+)/", file_get_contents("/proc/self/status"), $matches) > 0){ + return (int) $matches[1]; + } + } + + //TODO: more OS + + return count(ThreadManager::getInstance()->getAll()) + 3; //RakLib + MainLogger + Main Thread + } + + public static function kill($pid) : void{ + if(MainLogger::isRegisteredStatic()){ + MainLogger::getLogger()->syncFlushBuffer(); + } + switch(Utils::getOS()){ + case "win": + exec("taskkill.exe /F /PID " . ((int) $pid) . " > NUL"); + break; + case "mac": + case "linux": + default: + if(function_exists("posix_kill")){ + posix_kill($pid, 9); //SIGKILL + }else{ + exec("kill -9 " . ((int) $pid) . " > /dev/null 2>&1"); + } + } + } + + /** + * @param string $command Command to execute + * @param string|null &$stdout Reference parameter to write stdout to + * @param string|null &$stderr Reference parameter to write stderr to + * + * @return int process exit code + */ + public static function execute(string $command, string &$stdout = null, string &$stderr = null) : int{ + $process = proc_open($command, [ + ["pipe", "r"], + ["pipe", "w"], + ["pipe", "w"] + ], $pipes); + + if($process === false){ + $stderr = "Failed to open process"; + $stdout = ""; + + return -1; + } + + $stdout = stream_get_contents($pipes[1]); + $stderr = stream_get_contents($pipes[2]); + + foreach($pipes as $p){ + fclose($p); + } + + return proc_close($process); + } +} diff --git a/src/pocketmine/utils/ServerKiller.php b/src/pocketmine/utils/ServerKiller.php index ff3ecd448..539f00af8 100644 --- a/src/pocketmine/utils/ServerKiller.php +++ b/src/pocketmine/utils/ServerKiller.php @@ -48,7 +48,7 @@ class ServerKiller extends Thread{ }); if(time() - $start >= $this->time){ echo "\nTook too long to stop, server was killed forcefully!\n"; - @Utils::kill(getmypid()); + @Process::kill(getmypid()); } } diff --git a/src/pocketmine/utils/Utils.php b/src/pocketmine/utils/Utils.php index a2fdf85a0..d4d89f1e5 100644 --- a/src/pocketmine/utils/Utils.php +++ b/src/pocketmine/utils/Utils.php @@ -28,7 +28,6 @@ declare(strict_types=1); namespace pocketmine\utils; use DaveRandom\CallbackValidator\CallbackType; -use pocketmine\ThreadManager; use function array_combine; use function array_map; use function array_reverse; @@ -42,7 +41,6 @@ use function dechex; use function error_reporting; use function exec; use function explode; -use function fclose; use function file; use function file_exists; use function file_get_contents; @@ -51,7 +49,6 @@ use function get_current_user; use function get_loaded_extensions; use function getenv; use function gettype; -use function hexdec; use function implode; use function is_array; use function is_dir; @@ -60,20 +57,16 @@ use function is_object; use function is_readable; use function is_string; use function json_decode; -use function memory_get_usage; use function ob_end_clean; use function ob_get_contents; use function ob_start; use function ord; use function php_uname; use function phpversion; -use function posix_kill; use function preg_grep; use function preg_match; use function preg_match_all; use function preg_replace; -use function proc_close; -use function proc_open; use function rmdir; use function scandir; use function sha1; @@ -81,7 +74,6 @@ use function spl_object_hash; use function str_pad; use function str_replace; use function str_split; -use function stream_get_contents; use function stripos; use function strlen; use function strpos; @@ -289,74 +281,35 @@ class Utils{ } /** + * @deprecated + * @see Process::getRealMemoryUsage() + * * @return int[] */ public static function getRealMemoryUsage() : array{ - $stack = 0; - $heap = 0; - - if(Utils::getOS() === "linux" or Utils::getOS() === "android"){ - $mappings = file("/proc/self/maps"); - foreach($mappings as $line){ - if(preg_match("#([a-z0-9]+)\\-([a-z0-9]+) [rwxp\\-]{4} [a-z0-9]+ [^\\[]*\\[([a-zA-z0-9]+)\\]#", trim($line), $matches) > 0){ - if(strpos($matches[3], "heap") === 0){ - $heap += hexdec($matches[2]) - hexdec($matches[1]); - }elseif(strpos($matches[3], "stack") === 0){ - $stack += hexdec($matches[2]) - hexdec($matches[1]); - } - } - } - } - - return [$heap, $stack]; + return Process::getRealMemoryUsage(); } /** + * @deprecated + * @see Process::getMemoryUsage() + * * @param bool $advanced * * @return int[]|int */ public static function getMemoryUsage(bool $advanced = false){ - $reserved = memory_get_usage(); - $VmSize = null; - $VmRSS = null; - if(Utils::getOS() === "linux" or Utils::getOS() === "android"){ - $status = file_get_contents("/proc/self/status"); - if(preg_match("/VmRSS:[ \t]+([0-9]+) kB/", $status, $matches) > 0){ - $VmRSS = $matches[1] * 1024; - } - - if(preg_match("/VmSize:[ \t]+([0-9]+) kB/", $status, $matches) > 0){ - $VmSize = $matches[1] * 1024; - } - } - - //TODO: more OS - - if($VmRSS === null){ - $VmRSS = memory_get_usage(); - } - - if(!$advanced){ - return $VmRSS; - } - - if($VmSize === null){ - $VmSize = memory_get_usage(true); - } - - return [$reserved, $VmRSS, $VmSize]; + return Process::getMemoryUsage($advanced); } + /** + * @deprecated + * @see Process::getThreadCount() + * + * @return int + */ public static function getThreadCount() : int{ - if(Utils::getOS() === "linux" or Utils::getOS() === "android"){ - if(preg_match("/Threads:[ \t]+([0-9]+)/", file_get_contents("/proc/self/status"), $matches) > 0){ - return (int) $matches[1]; - } - } - //TODO: more OS - - return count(ThreadManager::getInstance()->getAll()) + 3; //RakLib + MainLogger + Main Thread + return Process::getThreadCount(); } /** @@ -520,6 +473,9 @@ class Utils{ /** + * @deprecated + * @see Process::execute() + * * @param string $command Command to execute * @param string|null &$stdout Reference parameter to write stdout to * @param string|null &$stderr Reference parameter to write stderr to @@ -527,27 +483,7 @@ class Utils{ * @return int process exit code */ public static function execute(string $command, string &$stdout = null, string &$stderr = null) : int{ - $process = proc_open($command, [ - ["pipe", "r"], - ["pipe", "w"], - ["pipe", "w"] - ], $pipes); - - if($process === false){ - $stderr = "Failed to open process"; - $stdout = ""; - - return -1; - } - - $stdout = stream_get_contents($pipes[1]); - $stderr = stream_get_contents($pipes[2]); - - foreach($pipes as $p){ - fclose($p); - } - - return proc_close($process); + return Process::execute($command, $stdout, $stderr); } public static function decodeJWT(string $token) : array{ @@ -556,23 +492,14 @@ class Utils{ return json_decode(base64_decode(strtr($payloadB64, '-_', '+/'), true), true); } + /** + * @deprecated + * @see Process::kill() + * + * @param int $pid + */ public static function kill($pid) : void{ - if(MainLogger::isRegisteredStatic()){ - MainLogger::getLogger()->syncFlushBuffer(); - } - switch(Utils::getOS()){ - case "win": - exec("taskkill.exe /F /PID " . ((int) $pid) . " > NUL"); - break; - case "mac": - case "linux": - default: - if(function_exists("posix_kill")){ - posix_kill($pid, 9); //SIGKILL - }else{ - exec("kill -9 " . ((int) $pid) . " > /dev/null 2>&1"); - } - } + Process::kill($pid); } /** From ec5598dbb179d3e3eea303c650772206f369b565 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Fri, 12 Oct 2018 16:35:51 +0100 Subject: [PATCH 09/90] Deprecate things removed in acb794e72 and 97c836f19 --- src/pocketmine/event/entity/EntityDespawnEvent.php | 6 ++++++ src/pocketmine/event/entity/EntitySpawnEvent.php | 7 +++++++ 2 files changed, 13 insertions(+) diff --git a/src/pocketmine/event/entity/EntityDespawnEvent.php b/src/pocketmine/event/entity/EntityDespawnEvent.php index 0f456e360..e5d239c39 100644 --- a/src/pocketmine/event/entity/EntityDespawnEvent.php +++ b/src/pocketmine/event/entity/EntityDespawnEvent.php @@ -46,6 +46,7 @@ class EntityDespawnEvent extends EntityEvent{ } /** + * @deprecated * @return int */ public function getType() : int{ @@ -53,6 +54,7 @@ class EntityDespawnEvent extends EntityEvent{ } /** + * @deprecated * @return bool */ public function isCreature() : bool{ @@ -60,6 +62,7 @@ class EntityDespawnEvent extends EntityEvent{ } /** + * @deprecated * @return bool */ public function isHuman() : bool{ @@ -67,6 +70,7 @@ class EntityDespawnEvent extends EntityEvent{ } /** + * @deprecated * @return bool */ public function isProjectile() : bool{ @@ -74,6 +78,7 @@ class EntityDespawnEvent extends EntityEvent{ } /** + * @deprecated * @return bool */ public function isVehicle() : bool{ @@ -81,6 +86,7 @@ class EntityDespawnEvent extends EntityEvent{ } /** + * @deprecated * @return bool */ public function isItem() : bool{ diff --git a/src/pocketmine/event/entity/EntitySpawnEvent.php b/src/pocketmine/event/entity/EntitySpawnEvent.php index 20a068b87..fe1f800ae 100644 --- a/src/pocketmine/event/entity/EntitySpawnEvent.php +++ b/src/pocketmine/event/entity/EntitySpawnEvent.php @@ -47,6 +47,7 @@ class EntitySpawnEvent extends EntityEvent{ } /** + * @deprecated * @return Position */ public function getPosition() : Position{ @@ -54,6 +55,7 @@ class EntitySpawnEvent extends EntityEvent{ } /** + * @deprecated * @return int */ public function getType() : int{ @@ -61,6 +63,7 @@ class EntitySpawnEvent extends EntityEvent{ } /** + * @deprecated * @return bool */ public function isCreature() : bool{ @@ -68,6 +71,7 @@ class EntitySpawnEvent extends EntityEvent{ } /** + * @deprecated * @return bool */ public function isHuman() : bool{ @@ -75,6 +79,7 @@ class EntitySpawnEvent extends EntityEvent{ } /** + * @deprecated * @return bool */ public function isProjectile() : bool{ @@ -82,6 +87,7 @@ class EntitySpawnEvent extends EntityEvent{ } /** + * @deprecated * @return bool */ public function isVehicle() : bool{ @@ -89,6 +95,7 @@ class EntitySpawnEvent extends EntityEvent{ } /** + * @deprecated * @return bool */ public function isItem() : bool{ From 0fabc0c1990f1b7cd9718a96c9594db4d953dd5a Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Thu, 21 Mar 2019 19:53:14 +0000 Subject: [PATCH 10/90] backport b8d1eb20b: EntityDeathEvent: add XP amount API, closes #2690 --- src/pocketmine/Player.php | 5 ++-- src/pocketmine/entity/Living.php | 5 ++-- .../event/entity/EntityDeathEvent.php | 26 ++++++++++++++++++- .../event/player/PlayerDeathEvent.php | 5 ++-- 4 files changed, 32 insertions(+), 9 deletions(-) diff --git a/src/pocketmine/Player.php b/src/pocketmine/Player.php index 8aeb09f79..c722aba87 100644 --- a/src/pocketmine/Player.php +++ b/src/pocketmine/Player.php @@ -3665,7 +3665,7 @@ class Player extends Human implements CommandSender, ChunkLoader, IPlayer{ //main inventory and drops the rest on the ground. $this->doCloseInventory(); - $ev = new PlayerDeathEvent($this, $this->getDrops()); + $ev = new PlayerDeathEvent($this, $this->getDrops(), null, $this->getXpDropAmount()); $ev->call(); if(!$ev->getKeepInventory()){ @@ -3682,8 +3682,7 @@ class Player extends Human implements CommandSender, ChunkLoader, IPlayer{ } } - //TODO: allow this number to be manipulated during PlayerDeathEvent - $this->level->dropExperience($this, $this->getXpDropAmount()); + $this->level->dropExperience($this, $ev->getXpDropAmount()); $this->setXpAndProgress(0, 0); if($ev->getDeathMessage() != ""){ diff --git a/src/pocketmine/entity/Living.php b/src/pocketmine/entity/Living.php index c9030152f..9e0b428af 100644 --- a/src/pocketmine/entity/Living.php +++ b/src/pocketmine/entity/Living.php @@ -639,15 +639,14 @@ abstract class Living extends Entity implements Damageable{ } protected function onDeath() : void{ - $ev = new EntityDeathEvent($this, $this->getDrops()); + $ev = new EntityDeathEvent($this, $this->getDrops(), $this->getXpDropAmount()); $ev->call(); foreach($ev->getDrops() as $item){ $this->getLevel()->dropItem($this, $item); } //TODO: check death conditions (must have been damaged by player < 5 seconds from death) - //TODO: allow this number to be manipulated during EntityDeathEvent - $this->level->dropExperience($this, $this->getXpDropAmount()); + $this->level->dropExperience($this, $ev->getXpDropAmount()); } protected function onDeathUpdate(int $tickDiff) : bool{ diff --git a/src/pocketmine/event/entity/EntityDeathEvent.php b/src/pocketmine/event/entity/EntityDeathEvent.php index c4ca6111d..aeb7e5574 100644 --- a/src/pocketmine/event/entity/EntityDeathEvent.php +++ b/src/pocketmine/event/entity/EntityDeathEvent.php @@ -29,14 +29,18 @@ use pocketmine\item\Item; class EntityDeathEvent extends EntityEvent{ /** @var Item[] */ private $drops = []; + /** @var int */ + private $xp; /** * @param Living $entity * @param Item[] $drops + * @param int $xp */ - public function __construct(Living $entity, array $drops = []){ + public function __construct(Living $entity, array $drops = [], int $xp = 0){ $this->entity = $entity; $this->drops = $drops; + $this->xp = $xp; } /** @@ -59,4 +63,24 @@ class EntityDeathEvent extends EntityEvent{ public function setDrops(array $drops) : void{ $this->drops = $drops; } + + /** + * Returns how much experience is dropped due to this entity's death. + * @return int + */ + public function getXpDropAmount() : int{ + return $this->xp; + } + + /** + * @param int $xp + * + * @throws \InvalidArgumentException + */ + public function setXpDropAmount(int $xp) : void{ + if($xp < 0){ + throw new \InvalidArgumentException("XP drop amount must not be negative"); + } + $this->xp = $xp; + } } diff --git a/src/pocketmine/event/player/PlayerDeathEvent.php b/src/pocketmine/event/player/PlayerDeathEvent.php index fa93a8ae2..25e8d12ca 100644 --- a/src/pocketmine/event/player/PlayerDeathEvent.php +++ b/src/pocketmine/event/player/PlayerDeathEvent.php @@ -46,9 +46,10 @@ class PlayerDeathEvent extends EntityDeathEvent{ * @param Player $entity * @param Item[] $drops * @param string|TextContainer|null $deathMessage Null will cause the default vanilla message to be used + * @param int $xp */ - public function __construct(Player $entity, array $drops, $deathMessage = null){ - parent::__construct($entity, $drops); + public function __construct(Player $entity, array $drops, $deathMessage = null, int $xp = 0){ + parent::__construct($entity, $drops, $xp); $this->deathMessage = $deathMessage ?? self::deriveMessage($entity->getDisplayName(), $entity->getLastDamageCause()); } From b38c81c96ff3a3b8d5735eb53b9abcb9c9e17ca2 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Fri, 22 Mar 2019 18:11:32 +0000 Subject: [PATCH 11/90] backport f84a1729c: Inventory: added swap() function --- src/pocketmine/inventory/BaseInventory.php | 7 +++++++ src/pocketmine/inventory/Inventory.php | 8 ++++++++ 2 files changed, 15 insertions(+) diff --git a/src/pocketmine/inventory/BaseInventory.php b/src/pocketmine/inventory/BaseInventory.php index 6f32492fc..bc6f7dcfb 100644 --- a/src/pocketmine/inventory/BaseInventory.php +++ b/src/pocketmine/inventory/BaseInventory.php @@ -378,6 +378,13 @@ abstract class BaseInventory implements Inventory{ } } + public function swap(int $slot1, int $slot2) : void{ + $i1 = $this->getItem($slot1); + $i2 = $this->getItem($slot2); + $this->setItem($slot1, $i2); + $this->setItem($slot2, $i1); + } + /** * @return Player[] */ diff --git a/src/pocketmine/inventory/Inventory.php b/src/pocketmine/inventory/Inventory.php index 94677a75e..1bf84060f 100644 --- a/src/pocketmine/inventory/Inventory.php +++ b/src/pocketmine/inventory/Inventory.php @@ -215,6 +215,14 @@ interface Inventory{ */ public function clearAll(bool $send = true) : void; + /** + * Swaps the specified slots. + * + * @param int $slot1 + * @param int $slot2 + */ + public function swap(int $slot1, int $slot2) : void; + /** * Gets all the Players viewing the inventory * Players will view their inventory at all times, even when not open. From 6afc68952996a80dcc50b7038d1ba19e16f8b547 Mon Sep 17 00:00:00 2001 From: Luke Date: Sat, 22 Jun 2019 16:00:18 +0100 Subject: [PATCH 12/90] Add Level->getTimeOfDay(), closes #2908 (#2979) --- src/pocketmine/block/Bed.php | 2 +- src/pocketmine/level/Level.php | 11 ++++++++++- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/src/pocketmine/block/Bed.php b/src/pocketmine/block/Bed.php index 626d7a63a..9a5870bc2 100644 --- a/src/pocketmine/block/Bed.php +++ b/src/pocketmine/block/Bed.php @@ -146,7 +146,7 @@ class Bed extends Transparent{ return true; } - $time = $this->getLevel()->getTime() % Level::TIME_FULL; + $time = $this->getLevel()->getTimeOfDay(); $isNight = ($time >= Level::TIME_NIGHT and $time < Level::TIME_SUNRISE); diff --git a/src/pocketmine/level/Level.php b/src/pocketmine/level/Level.php index b42ae887e..13d30a58e 100644 --- a/src/pocketmine/level/Level.php +++ b/src/pocketmine/level/Level.php @@ -936,7 +936,7 @@ class Level implements ChunkManager, Metadatable{ } if($resetTime){ - $time = $this->getTime() % Level::TIME_FULL; + $time = $this->getTimeOfDay(); if($time >= Level::TIME_NIGHT and $time < Level::TIME_SUNRISE){ $this->setTime($this->getTime() + Level::TIME_FULL - $time); @@ -3005,6 +3005,15 @@ class Level implements ChunkManager, Metadatable{ return $this->time; } + /** + * Returns the current time of day + * + * @return int + */ + public function getTimeOfDay() : int{ + return $this->time % self::TIME_FULL; + } + /** * Returns the Level name * From 9e993aa83fafe8434c5aef1ec7e0e0190bd2f9d3 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Mon, 1 Jul 2019 17:19:19 +0100 Subject: [PATCH 13/90] ClosureTask: drop requirement for void return type this creates unnecessary boilerplate for many inline usages. --- src/pocketmine/scheduler/ClosureTask.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pocketmine/scheduler/ClosureTask.php b/src/pocketmine/scheduler/ClosureTask.php index f023173d4..84d44d2a2 100644 --- a/src/pocketmine/scheduler/ClosureTask.php +++ b/src/pocketmine/scheduler/ClosureTask.php @@ -45,7 +45,7 @@ class ClosureTask extends Task{ * @param \Closure $closure Must accept only ONE parameter, $currentTick */ public function __construct(\Closure $closure){ - Utils::validateCallableSignature(function(int $currentTick) : void{}, $closure); + Utils::validateCallableSignature(function(int $currentTick){}, $closure); $this->closure = $closure; } From cb247a5f28958e4af48ad3897fb3c222e76ecf44 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Fri, 26 Jul 2019 19:52:26 +0100 Subject: [PATCH 14/90] AsyncTask: Deprecate methods removed in 2c4f2810d2654375c2b834fe12999b465bfa2caf --- src/pocketmine/scheduler/AsyncTask.php | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/pocketmine/scheduler/AsyncTask.php b/src/pocketmine/scheduler/AsyncTask.php index b34cc34f2..0edd4cef4 100644 --- a/src/pocketmine/scheduler/AsyncTask.php +++ b/src/pocketmine/scheduler/AsyncTask.php @@ -127,6 +127,7 @@ abstract class AsyncTask extends Collectable{ } /** + * @deprecated * @see AsyncWorker::getFromThreadStore() * * @param string $identifier @@ -141,6 +142,7 @@ abstract class AsyncTask extends Collectable{ } /** + * @deprecated * @see AsyncWorker::saveToThreadStore() * * @param string $identifier @@ -154,6 +156,7 @@ abstract class AsyncTask extends Collectable{ } /** + * @deprecated * @see AsyncWorker::removeFromThreadStore() * * @param string $identifier From 6566dd8c8fa40d88b5484df414147d407d4ae6e4 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Sat, 27 Jul 2019 14:44:40 +0100 Subject: [PATCH 15/90] AsyncPool: Remove useless warning about complex data leftovers this is automatically cleaned up anyway, so this warning is just redundant noise. --- src/pocketmine/scheduler/AsyncPool.php | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/pocketmine/scheduler/AsyncPool.php b/src/pocketmine/scheduler/AsyncPool.php index 8174b230c..a0b6200b0 100644 --- a/src/pocketmine/scheduler/AsyncPool.php +++ b/src/pocketmine/scheduler/AsyncPool.php @@ -28,7 +28,6 @@ use pocketmine\utils\Utils; use function array_keys; use function assert; use function count; -use function get_class; use function spl_object_hash; use function time; use const PHP_INT_MAX; @@ -318,9 +317,6 @@ class AsyncPool{ */ $task->checkProgressUpdates($this->server); $task->onCompletion($this->server); - if($task->removeDanglingStoredObjects()){ - $this->logger->notice("AsyncTask " . get_class($task) . " stored local complex data but did not remove them after completion"); - } } $this->removeTask($task); From cde2c10c1d66e19f6b1fae4109dcba1579e156ee Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Sat, 27 Jul 2019 15:09:42 +0100 Subject: [PATCH 16/90] AsyncTask: partial backport of 6ac0c517f54dc83fc23f41a6797c14e1f4b457a1 (simplify TLS) - deprecated AsyncTask::peekLocal() - AsyncTask::fetchLocal() no longer deletes stored data --- src/pocketmine/scheduler/AsyncTask.php | 69 ++++++++------------------ 1 file changed, 21 insertions(+), 48 deletions(-) diff --git a/src/pocketmine/scheduler/AsyncTask.php b/src/pocketmine/scheduler/AsyncTask.php index c14fd09e0..0e3a4d991 100644 --- a/src/pocketmine/scheduler/AsyncTask.php +++ b/src/pocketmine/scheduler/AsyncTask.php @@ -51,7 +51,7 @@ abstract class AsyncTask extends Collectable{ * @var \SplObjectStorage|null * Used to store objects on the main thread which should not be serialized. */ - private static $localObjectStorage; + private static $threadLocalStorage; /** @var AsyncWorker $worker */ public $worker = null; @@ -229,9 +229,6 @@ abstract class AsyncTask extends Collectable{ * * Scalar types can be stored directly in class properties instead of using this storage. * - * Objects stored in this storage MUST be retrieved through {@link AsyncTask::fetchLocal} when {@link AsyncTask::onCompletion} is called. - * Otherwise, a NOTICE level message will be raised and the reference will be removed after onCompletion exits. - * * WARNING: THIS METHOD SHOULD ONLY BE CALLED FROM THE MAIN THREAD! * * @param mixed $complexData the data to store @@ -243,26 +240,19 @@ abstract class AsyncTask extends Collectable{ throw new \BadMethodCallException("Objects can only be stored from the parent thread"); } - if(self::$localObjectStorage === null){ - self::$localObjectStorage = new \SplObjectStorage(); //lazy init + if(self::$threadLocalStorage === null){ + self::$threadLocalStorage = new \SplObjectStorage(); //lazy init } - if(isset(self::$localObjectStorage[$this])){ + if(isset(self::$threadLocalStorage[$this])){ throw new \InvalidStateException("Already storing complex data for this async task"); } - self::$localObjectStorage[$this] = $complexData; + self::$threadLocalStorage[$this] = $complexData; } /** - * Returns and removes mixed data in thread-local storage on the parent thread. Call this method from - * {@link AsyncTask::onCompletion} to fetch the data stored in the object store, if any. - * - * If no data was stored in the local store, or if the data was already retrieved by a previous call to fetchLocal, - * do NOT call this method, or an exception will be thrown. - * - * Do not call this method from {@link AsyncTask::onProgressUpdate}, because this method deletes stored data, which - * means that you will not be able to retrieve it again afterwards. Use {@link AsyncTask::peekLocal} instead to - * retrieve stored data without removing it from the store. + * Returns data previously stored in thread-local storage on the parent thread. Use this during progress updates or + * task completion to retrieve data you stored using {@link AsyncTask::storeLocal}. * * WARNING: THIS METHOD SHOULD ONLY BE CALLED FROM THE MAIN THREAD! * @@ -272,25 +262,20 @@ abstract class AsyncTask extends Collectable{ * @throws \BadMethodCallException if called from any thread except the main thread */ protected function fetchLocal(){ - try{ - return $this->peekLocal(); - }finally{ - if(self::$localObjectStorage !== null){ - unset(self::$localObjectStorage[$this]); - } + if($this->worker !== null and $this->worker === \Thread::getCurrentThread()){ + throw new \BadMethodCallException("Objects can only be retrieved from the parent thread"); } + + if(self::$threadLocalStorage === null or !isset(self::$threadLocalStorage[$this])){ + throw new \InvalidStateException("No complex data stored for this async task"); + } + + return self::$threadLocalStorage[$this]; } /** - * Returns mixed data in thread-local storage on the parent thread **without clearing** it. Call this method from - * {@link AsyncTask::onProgressUpdate} to fetch the data stored if you need to be able to access the data later on, - * such as in another progress update. - * - * Use {@link AsyncTask::fetchLocal} instead from {@link AsyncTask::onCompletion}, because this method does not delete - * the data, and not clearing the data will result in a warning for memory leak after {@link AsyncTask::onCompletion} - * finished executing. - * - * WARNING: THIS METHOD SHOULD ONLY BE CALLED FROM THE MAIN THREAD! + * @deprecated + * @see AsyncTask::fetchLocal() * * @return mixed * @@ -298,27 +283,15 @@ abstract class AsyncTask extends Collectable{ * @throws \BadMethodCallException if called from any thread except the main thread */ protected function peekLocal(){ - if($this->worker !== null and $this->worker === \Thread::getCurrentThread()){ - throw new \BadMethodCallException("Objects can only be retrieved from the parent thread"); - } - - if(self::$localObjectStorage === null or !isset(self::$localObjectStorage[$this])){ - throw new \InvalidStateException("No complex data stored for this async task"); - } - - return self::$localObjectStorage[$this]; + return $this->fetchLocal(); } /** * @internal Called by the AsyncPool to destroy any leftover stored objects that this task failed to retrieve. - * @return bool */ - public function removeDanglingStoredObjects() : bool{ - if(self::$localObjectStorage !== null and isset(self::$localObjectStorage[$this])){ - unset(self::$localObjectStorage[$this]); - return true; + public function removeDanglingStoredObjects() : void{ + if(self::$threadLocalStorage !== null and isset(self::$threadLocalStorage[$this])){ + unset(self::$threadLocalStorage[$this]); } - - return false; } } From eeddaced9f67896d2357fbce66d2548c97122722 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Fri, 2 Aug 2019 16:34:00 +0100 Subject: [PATCH 17/90] PluginManager: Remove useless deprecation warning message this message just confuses end users and is of little use to a developer. It doesn't make any sense to make a special case for events when we have lots of other deprecated things to think about anyway which won't be shown warnings for. --- src/pocketmine/plugin/PluginManager.php | 10 ---------- src/pocketmine/resources/pocketmine.yml | 2 -- 2 files changed, 12 deletions(-) diff --git a/src/pocketmine/plugin/PluginManager.php b/src/pocketmine/plugin/PluginManager.php index 7936542fd..7711a2abf 100644 --- a/src/pocketmine/plugin/PluginManager.php +++ b/src/pocketmine/plugin/PluginManager.php @@ -792,16 +792,6 @@ class PluginManager{ throw new PluginException($event . " is not an Event"); } - $tags = Utils::parseDocComment((string) (new \ReflectionClass($event))->getDocComment()); - if(isset($tags["deprecated"]) and $this->server->getProperty("settings.deprecated-verbose", true)){ - $this->server->getLogger()->warning($this->server->getLanguage()->translateString("pocketmine.plugin.deprecatedEvent", [ - $plugin->getName(), - $event, - get_class($listener) . "->" . ($executor instanceof MethodEventExecutor ? $executor->getMethod() : "") - ])); - } - - if(!$plugin->isEnabled()){ throw new PluginException("Plugin attempted to register " . $event . " while not enabled"); } diff --git a/src/pocketmine/resources/pocketmine.yml b/src/pocketmine/resources/pocketmine.yml index 7a605e8ff..f63dc75e2 100644 --- a/src/pocketmine/resources/pocketmine.yml +++ b/src/pocketmine/resources/pocketmine.yml @@ -9,8 +9,6 @@ settings: shutdown-message: "Server closed" #Allow listing plugins via Query query-plugins: true - #Show a console message when a plugin uses deprecated API methods - deprecated-verbose: true #Enable plugin and core profiling by default enable-profiling: false #Will only add results when tick measurement is below or equal to given value (default 20) From 4cfceeeb8e434978b111fa33a6ec158bab3e4adc Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Fri, 29 Nov 2019 12:03:07 +0000 Subject: [PATCH 18/90] bootstrap: fix merge error introduced by cb76f8a5dfba79857ecfd71d2953b759a03671e7 this error is harmless since it points to a deprecated function, but it showed up as conflicted in master merge. --- src/pocketmine/PocketMine.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pocketmine/PocketMine.php b/src/pocketmine/PocketMine.php index 97a602a5b..10de566e7 100644 --- a/src/pocketmine/PocketMine.php +++ b/src/pocketmine/PocketMine.php @@ -190,7 +190,7 @@ namespace pocketmine { if(\Phar::running(true) === ""){ if(Process::execute("git rev-parse HEAD", $out) === 0 and $out !== false and strlen($out = trim($out)) === 40){ $gitHash = trim($out); - if(Process::execute("git diff --quiet") === 1 or Utils::execute("git diff --cached --quiet") === 1){ //Locally-modified + if(Process::execute("git diff --quiet") === 1 or Process::execute("git diff --cached --quiet") === 1){ //Locally-modified $gitHash .= "-dirty"; } } From 2d51971b8436f3646c09dab5ce3655a60be98262 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Mon, 10 Feb 2020 11:40:47 +0000 Subject: [PATCH 19/90] Revert "ClosureTask: drop requirement for void return type" This reverts commit 9e993aa83fafe8434c5aef1ec7e0e0190bd2f9d3. apparently PHPStan isn't cool with this ... --- src/pocketmine/scheduler/ClosureTask.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pocketmine/scheduler/ClosureTask.php b/src/pocketmine/scheduler/ClosureTask.php index 57f560e77..78610ef71 100644 --- a/src/pocketmine/scheduler/ClosureTask.php +++ b/src/pocketmine/scheduler/ClosureTask.php @@ -49,7 +49,7 @@ class ClosureTask extends Task{ * @phpstan-param \Closure(int) : void $closure */ public function __construct(\Closure $closure){ - Utils::validateCallableSignature(function(int $currentTick){}, $closure); + Utils::validateCallableSignature(function(int $currentTick) : void{}, $closure); $this->closure = $closure; } From 15b76a24b7a6bbba113047ffb71e9439a2566cc1 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Mon, 10 Feb 2020 12:21:07 +0000 Subject: [PATCH 20/90] scrub useless phpdoc --- src/pocketmine/Player.php | 6 ------ src/pocketmine/event/entity/EntityDeathEvent.php | 4 ---- src/pocketmine/event/player/PlayerDeathEvent.php | 1 - src/pocketmine/inventory/FurnaceRecipe.php | 2 -- src/pocketmine/inventory/Inventory.php | 3 --- src/pocketmine/inventory/Recipe.php | 2 -- src/pocketmine/inventory/ShapedRecipe.php | 2 -- src/pocketmine/inventory/ShapelessRecipe.php | 2 -- src/pocketmine/level/Level.php | 2 -- src/pocketmine/utils/Config.php | 2 -- src/pocketmine/utils/Process.php | 2 -- src/pocketmine/utils/Terminal.php | 4 ---- src/pocketmine/utils/Utils.php | 2 -- 13 files changed, 34 deletions(-) diff --git a/src/pocketmine/Player.php b/src/pocketmine/Player.php index c6672be00..142aab122 100644 --- a/src/pocketmine/Player.php +++ b/src/pocketmine/Player.php @@ -3236,8 +3236,6 @@ class Player extends Human implements CommandSender, ChunkLoader, IPlayer{ /** * Adds a title text to the user's screen, with an optional subtitle. * - * @param string $title - * @param string $subtitle * @param int $fadeIn Duration in ticks for fade-in. If -1 is given, client-sided defaults will be used. * @param int $stay Duration in ticks to stay on screen for * @param int $fadeOut Duration in ticks for fade-out. @@ -3262,8 +3260,6 @@ class Player extends Human implements CommandSender, ChunkLoader, IPlayer{ /** * Sets the subtitle message, without sending a title. - * - * @param string $subtitle */ public function sendSubTitle(string $subtitle) : void{ $this->sendTitleText($subtitle, SetTitlePacket::TYPE_SET_SUBTITLE); @@ -3281,8 +3277,6 @@ class Player extends Human implements CommandSender, ChunkLoader, IPlayer{ /** * Adds small text to the user's screen. - * - * @param string $message */ public function sendActionBarMessage(string $message) : void{ $this->sendTitleText($message, SetTitlePacket::TYPE_SET_ACTIONBAR_MESSAGE); diff --git a/src/pocketmine/event/entity/EntityDeathEvent.php b/src/pocketmine/event/entity/EntityDeathEvent.php index 3dfd9cb1a..4eb9953ab 100644 --- a/src/pocketmine/event/entity/EntityDeathEvent.php +++ b/src/pocketmine/event/entity/EntityDeathEvent.php @@ -34,7 +34,6 @@ class EntityDeathEvent extends EntityEvent{ /** * @param Item[] $drops - * @param int $xp */ public function __construct(Living $entity, array $drops = [], int $xp = 0){ $this->entity = $entity; @@ -65,15 +64,12 @@ class EntityDeathEvent extends EntityEvent{ /** * Returns how much experience is dropped due to this entity's death. - * @return int */ public function getXpDropAmount() : int{ return $this->xp; } /** - * @param int $xp - * * @throws \InvalidArgumentException */ public function setXpDropAmount(int $xp) : void{ diff --git a/src/pocketmine/event/player/PlayerDeathEvent.php b/src/pocketmine/event/player/PlayerDeathEvent.php index 9d7e65903..84d539a11 100644 --- a/src/pocketmine/event/player/PlayerDeathEvent.php +++ b/src/pocketmine/event/player/PlayerDeathEvent.php @@ -46,7 +46,6 @@ class PlayerDeathEvent extends EntityDeathEvent{ /** * @param Item[] $drops * @param string|TextContainer|null $deathMessage Null will cause the default vanilla message to be used - * @param int $xp */ public function __construct(Player $entity, array $drops, $deathMessage = null, int $xp = 0){ parent::__construct($entity, $drops, $xp); diff --git a/src/pocketmine/inventory/FurnaceRecipe.php b/src/pocketmine/inventory/FurnaceRecipe.php index 5e1175e44..185f05ee7 100644 --- a/src/pocketmine/inventory/FurnaceRecipe.php +++ b/src/pocketmine/inventory/FurnaceRecipe.php @@ -55,8 +55,6 @@ class FurnaceRecipe implements Recipe{ /** * @deprecated - * - * @param CraftingManager $manager */ public function registerToCraftingManager(CraftingManager $manager) : void{ $manager->registerFurnaceRecipe($this); diff --git a/src/pocketmine/inventory/Inventory.php b/src/pocketmine/inventory/Inventory.php index 0fba616d4..dd81b272a 100644 --- a/src/pocketmine/inventory/Inventory.php +++ b/src/pocketmine/inventory/Inventory.php @@ -154,9 +154,6 @@ interface Inventory{ /** * Swaps the specified slots. - * - * @param int $slot1 - * @param int $slot2 */ public function swap(int $slot1, int $slot2) : void; diff --git a/src/pocketmine/inventory/Recipe.php b/src/pocketmine/inventory/Recipe.php index f97e985b9..917c32400 100644 --- a/src/pocketmine/inventory/Recipe.php +++ b/src/pocketmine/inventory/Recipe.php @@ -30,8 +30,6 @@ interface Recipe{ /** * @deprecated - * - * @param CraftingManager $manager */ public function registerToCraftingManager(CraftingManager $manager) : void; } diff --git a/src/pocketmine/inventory/ShapedRecipe.php b/src/pocketmine/inventory/ShapedRecipe.php index beb293026..a8126c55c 100644 --- a/src/pocketmine/inventory/ShapedRecipe.php +++ b/src/pocketmine/inventory/ShapedRecipe.php @@ -178,8 +178,6 @@ class ShapedRecipe implements CraftingRecipe{ /** * @deprecated - * - * @param CraftingManager $manager */ public function registerToCraftingManager(CraftingManager $manager) : void{ $manager->registerShapedRecipe($this); diff --git a/src/pocketmine/inventory/ShapelessRecipe.php b/src/pocketmine/inventory/ShapelessRecipe.php index aa3e8c38e..f277bf226 100644 --- a/src/pocketmine/inventory/ShapelessRecipe.php +++ b/src/pocketmine/inventory/ShapelessRecipe.php @@ -107,8 +107,6 @@ class ShapelessRecipe implements CraftingRecipe{ /** * @deprecated - * - * @param CraftingManager $manager */ public function registerToCraftingManager(CraftingManager $manager) : void{ $manager->registerShapelessRecipe($this); diff --git a/src/pocketmine/level/Level.php b/src/pocketmine/level/Level.php index c298ec4b8..b1d11c6cb 100644 --- a/src/pocketmine/level/Level.php +++ b/src/pocketmine/level/Level.php @@ -2842,8 +2842,6 @@ class Level implements ChunkManager, Metadatable{ /** * Returns the current time of day - * - * @return int */ public function getTimeOfDay() : int{ return $this->time % self::TIME_FULL; diff --git a/src/pocketmine/utils/Config.php b/src/pocketmine/utils/Config.php index 0c984c619..c58acff71 100644 --- a/src/pocketmine/utils/Config.php +++ b/src/pocketmine/utils/Config.php @@ -246,8 +246,6 @@ class Config{ /** * Returns the path of the config. - * - * @return string */ public function getPath() : string{ return $this->file; diff --git a/src/pocketmine/utils/Process.php b/src/pocketmine/utils/Process.php index bd95da3cf..3472647bf 100644 --- a/src/pocketmine/utils/Process.php +++ b/src/pocketmine/utils/Process.php @@ -46,8 +46,6 @@ final class Process{ } /** - * @param bool $advanced - * * @return int[]|int */ public static function getMemoryUsage(bool $advanced = false){ diff --git a/src/pocketmine/utils/Terminal.php b/src/pocketmine/utils/Terminal.php index 94d4be6d6..c5117d286 100644 --- a/src/pocketmine/utils/Terminal.php +++ b/src/pocketmine/utils/Terminal.php @@ -292,8 +292,6 @@ abstract class Terminal{ /** * Emits a string containing Minecraft colour codes to the console formatted with native colours. - * - * @param string $line */ public static function write(string $line) : void{ echo self::toANSI($line); @@ -302,8 +300,6 @@ abstract class Terminal{ /** * Emits a string containing Minecraft colour codes to the console formatted with native colours, followed by a * newline character. - * - * @param string $line */ public static function writeLine(string $line) : void{ echo self::toANSI($line) . self::$FORMAT_RESET . PHP_EOL; diff --git a/src/pocketmine/utils/Utils.php b/src/pocketmine/utils/Utils.php index e2871ccdf..643f9ee27 100644 --- a/src/pocketmine/utils/Utils.php +++ b/src/pocketmine/utils/Utils.php @@ -293,8 +293,6 @@ class Utils{ /** * @deprecated * @see Process::getThreadCount() - * - * @return int */ public static function getThreadCount() : int{ return Process::getThreadCount(); From 20d1a048ddf146eb93c0a8196b6b4bb1f2b660fd Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Mon, 10 Feb 2020 12:21:56 +0000 Subject: [PATCH 21/90] fixup imports --- src/pocketmine/PocketMine.php | 1 - src/pocketmine/utils/Process.php | 1 + 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pocketmine/PocketMine.php b/src/pocketmine/PocketMine.php index d09b78d35..47fcc7e32 100644 --- a/src/pocketmine/PocketMine.php +++ b/src/pocketmine/PocketMine.php @@ -24,7 +24,6 @@ declare(strict_types=1); namespace pocketmine { use pocketmine\utils\Git; - use pocketmine\utils\Internet; use pocketmine\utils\MainLogger; use pocketmine\utils\Process; use pocketmine\utils\ServerKiller; diff --git a/src/pocketmine/utils/Process.php b/src/pocketmine/utils/Process.php index 3472647bf..8bf17fb18 100644 --- a/src/pocketmine/utils/Process.php +++ b/src/pocketmine/utils/Process.php @@ -32,6 +32,7 @@ use function file_get_contents; use function function_exists; use function hexdec; use function memory_get_usage; +use function posix_kill; use function preg_match; use function proc_close; use function proc_open; From 19bd283807d5a543fceaae6312d1d0aca06c3fff Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Mon, 10 Feb 2020 12:23:11 +0000 Subject: [PATCH 22/90] Process: drop a blank line --- src/pocketmine/utils/Process.php | 1 - 1 file changed, 1 deletion(-) diff --git a/src/pocketmine/utils/Process.php b/src/pocketmine/utils/Process.php index 8bf17fb18..47520344a 100644 --- a/src/pocketmine/utils/Process.php +++ b/src/pocketmine/utils/Process.php @@ -104,7 +104,6 @@ final class Process{ return [$heap, $stack]; } - public static function getThreadCount() : int{ if(Utils::getOS() === "linux" or Utils::getOS() === "android"){ if(preg_match("/Threads:[ \t]+([0-9]+)/", file_get_contents("/proc/self/status"), $matches) > 0){ From c19ab976107446b629e586add9983db83496f0e6 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Thu, 27 Feb 2020 17:37:45 +0000 Subject: [PATCH 23/90] AddActorPacket: move BC hack to higher level we shouldn't hack the protocol impl for BC. --- src/pocketmine/entity/Entity.php | 2 +- .../network/mcpe/protocol/AddActorPacket.php | 12 +++--------- 2 files changed, 4 insertions(+), 10 deletions(-) diff --git a/src/pocketmine/entity/Entity.php b/src/pocketmine/entity/Entity.php index cfb8be6b7..8838433ba 100644 --- a/src/pocketmine/entity/Entity.php +++ b/src/pocketmine/entity/Entity.php @@ -1914,7 +1914,7 @@ abstract class Entity extends Location implements Metadatable, EntityIds{ protected function sendSpawnPacket(Player $player) : void{ $pk = new AddActorPacket(); $pk->entityRuntimeId = $this->getId(); - $pk->type = static::NETWORK_ID; + $pk->type = AddActorPacket::LEGACY_ID_MAP_BC[static::NETWORK_ID]; $pk->position = $this->asVector3(); $pk->motion = $this->getMotion(); $pk->yaw = $this->yaw; diff --git a/src/pocketmine/network/mcpe/protocol/AddActorPacket.php b/src/pocketmine/network/mcpe/protocol/AddActorPacket.php index e3122dc05..cb0e72374 100644 --- a/src/pocketmine/network/mcpe/protocol/AddActorPacket.php +++ b/src/pocketmine/network/mcpe/protocol/AddActorPacket.php @@ -148,7 +148,7 @@ class AddActorPacket extends DataPacket{ public $entityUniqueId = null; //TODO /** @var int */ public $entityRuntimeId; - /** @var int */ + /** @var string */ public $type; /** @var Vector3 */ public $position; @@ -174,10 +174,7 @@ class AddActorPacket extends DataPacket{ protected function decodePayload(){ $this->entityUniqueId = $this->getEntityUniqueId(); $this->entityRuntimeId = $this->getEntityRuntimeId(); - $this->type = array_search($t = $this->getString(), self::LEGACY_ID_MAP_BC, true); - if($this->type === false){ - throw new \UnexpectedValueException("Can't map ID $t to legacy ID"); - } + $this->type = $this->getString(); $this->position = $this->getVector3(); $this->motion = $this->getVector3(); $this->pitch = $this->getLFloat(); @@ -212,10 +209,7 @@ class AddActorPacket extends DataPacket{ protected function encodePayload(){ $this->putEntityUniqueId($this->entityUniqueId ?? $this->entityRuntimeId); $this->putEntityRuntimeId($this->entityRuntimeId); - if(!isset(self::LEGACY_ID_MAP_BC[$this->type])){ - throw new \InvalidArgumentException("Unknown entity numeric ID $this->type"); - } - $this->putString(self::LEGACY_ID_MAP_BC[$this->type]); + $this->putString($this->type); $this->putVector3($this->position); $this->putVector3Nullable($this->motion); $this->putLFloat($this->pitch); From 8ec0a4d0d60b218acf13dfc20137728e5b4943d2 Mon Sep 17 00:00:00 2001 From: jasonwynn10 Date: Tue, 10 Mar 2020 06:12:56 -0400 Subject: [PATCH 24/90] Allow specifying compatible OS in plugin manifest (#3192) --- src/pocketmine/plugin/PluginDescription.php | 11 +++++++++++ src/pocketmine/plugin/PluginManager.php | 8 ++++++++ 2 files changed, 19 insertions(+) diff --git a/src/pocketmine/plugin/PluginDescription.php b/src/pocketmine/plugin/PluginDescription.php index cc321cbf6..a3280d5b1 100644 --- a/src/pocketmine/plugin/PluginDescription.php +++ b/src/pocketmine/plugin/PluginDescription.php @@ -24,6 +24,7 @@ declare(strict_types=1); namespace pocketmine\plugin; use pocketmine\permission\Permission; +use pocketmine\utils\Utils; use function array_map; use function array_values; use function constant; @@ -55,6 +56,8 @@ class PluginDescription{ private $api; /** @var int[] */ private $compatibleMcpeProtocols = []; + /** @var string[] */ + private $compatibleOperatingSystems = []; /** * @var string[][] * @phpstan-var array> @@ -114,6 +117,7 @@ class PluginDescription{ $this->api = array_map("\strval", (array) ($plugin["api"] ?? [])); $this->compatibleMcpeProtocols = array_map("\intval", (array) ($plugin["mcpe-protocol"] ?? [])); + $this->compatibleOperatingSystems = array_map("\strval", (array) ($plugin["os"] ?? [])); if(isset($plugin["commands"]) and is_array($plugin["commands"])){ $this->commands = $plugin["commands"]; @@ -184,6 +188,13 @@ class PluginDescription{ public function getCompatibleMcpeProtocols() : array{ return $this->compatibleMcpeProtocols; } + + /** + * @return string[] + */ + public function getCompatibleOperatingSystems() : array{ + return $this->compatibleOperatingSystems; + } /** * @return string[] diff --git a/src/pocketmine/plugin/PluginManager.php b/src/pocketmine/plugin/PluginManager.php index e1c060775..56cbdd72c 100644 --- a/src/pocketmine/plugin/PluginManager.php +++ b/src/pocketmine/plugin/PluginManager.php @@ -258,6 +258,14 @@ class PluginManager{ continue; } + if(count($description->getCompatibleOperatingSystems()) > 0 and !in_array(Utils::getOS(), $description->getCompatibleOperatingSystems(), true)) { + $this->server->getLogger()->error($this->server->getLanguage()->translateString("pocketmine.plugin.loadError", [ + $name, + $this->server->getLanguage()->translateString("%pocketmine.plugin.incompatibleOS", [implode(", ", $description->getCompatibleOperatingSystems())]) + ])); + continue; + } + if(count($pluginMcpeProtocols = $description->getCompatibleMcpeProtocols()) > 0){ $serverMcpeProtocols = [ProtocolInfo::CURRENT_PROTOCOL]; if(count(array_intersect($pluginMcpeProtocols, $serverMcpeProtocols)) === 0){ From dc757c25c857582e1053760b0baf25598c81c824 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Tue, 10 Mar 2020 12:14:38 +0000 Subject: [PATCH 25/90] cleanup CS from 8ec0a4d0d60b218acf13dfc20137728e5b4943d2 --- src/pocketmine/plugin/PluginDescription.php | 3 +-- src/pocketmine/plugin/PluginManager.php | 1 + 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/pocketmine/plugin/PluginDescription.php b/src/pocketmine/plugin/PluginDescription.php index a3280d5b1..e604dfd06 100644 --- a/src/pocketmine/plugin/PluginDescription.php +++ b/src/pocketmine/plugin/PluginDescription.php @@ -24,7 +24,6 @@ declare(strict_types=1); namespace pocketmine\plugin; use pocketmine\permission\Permission; -use pocketmine\utils\Utils; use function array_map; use function array_values; use function constant; @@ -188,7 +187,7 @@ class PluginDescription{ public function getCompatibleMcpeProtocols() : array{ return $this->compatibleMcpeProtocols; } - + /** * @return string[] */ diff --git a/src/pocketmine/plugin/PluginManager.php b/src/pocketmine/plugin/PluginManager.php index 56cbdd72c..1b33e21fd 100644 --- a/src/pocketmine/plugin/PluginManager.php +++ b/src/pocketmine/plugin/PluginManager.php @@ -50,6 +50,7 @@ use function file_exists; use function get_class; use function gettype; use function implode; +use function in_array; use function is_a; use function is_array; use function is_bool; From 5a9a576bfa5aeac8fc7026f9264ab6a92966004a Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Tue, 10 Mar 2020 12:45:52 +0000 Subject: [PATCH 26/90] AddActorPacket: remove unused import --- src/pocketmine/network/mcpe/protocol/AddActorPacket.php | 1 - 1 file changed, 1 deletion(-) diff --git a/src/pocketmine/network/mcpe/protocol/AddActorPacket.php b/src/pocketmine/network/mcpe/protocol/AddActorPacket.php index cb0e72374..fd4802b68 100644 --- a/src/pocketmine/network/mcpe/protocol/AddActorPacket.php +++ b/src/pocketmine/network/mcpe/protocol/AddActorPacket.php @@ -30,7 +30,6 @@ use pocketmine\entity\EntityIds; use pocketmine\math\Vector3; use pocketmine\network\mcpe\NetworkSession; use pocketmine\network\mcpe\protocol\types\EntityLink; -use function array_search; use function count; class AddActorPacket extends DataPacket{ From 3907a2b6ba58fa49022e3e7c8256731dfa2e0d00 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Fri, 13 Mar 2020 17:32:17 +0000 Subject: [PATCH 27/90] Process: split getMemoryUsage() into 2 functions this isn't released yet so it's OK to change. phpstan level 7 doesn't like these kinds of ambiguous return types because there's no way for it to tell which type is returned without a return type specifying extension, and it's easier to just change the API than to make PHPStan understand it. --- src/pocketmine/MemoryManager.php | 2 +- src/pocketmine/Server.php | 2 +- src/pocketmine/command/defaults/StatusCommand.php | 2 +- src/pocketmine/event/server/LowMemoryEvent.php | 3 ++- src/pocketmine/scheduler/SendUsageTask.php | 2 +- src/pocketmine/utils/Process.php | 13 +++++++------ src/pocketmine/utils/Utils.php | 3 ++- 7 files changed, 15 insertions(+), 12 deletions(-) diff --git a/src/pocketmine/MemoryManager.php b/src/pocketmine/MemoryManager.php index 6d2206063..4f3d2226b 100644 --- a/src/pocketmine/MemoryManager.php +++ b/src/pocketmine/MemoryManager.php @@ -226,7 +226,7 @@ class MemoryManager{ if(($this->memoryLimit > 0 or $this->globalMemoryLimit > 0) and ++$this->checkTicker >= $this->checkRate){ $this->checkTicker = 0; - $memory = Process::getMemoryUsage(true); + $memory = Process::getAdvancedMemoryUsage(); $trigger = false; if($this->memoryLimit > 0 and $memory[0] > $this->memoryLimit){ $trigger = 0; diff --git a/src/pocketmine/Server.php b/src/pocketmine/Server.php index 4fd6c2476..ebb7663e3 100644 --- a/src/pocketmine/Server.php +++ b/src/pocketmine/Server.php @@ -2325,7 +2325,7 @@ class Server{ Timings::$titleTickTimer->startTiming(); $d = Process::getRealMemoryUsage(); - $u = Process::getMemoryUsage(true); + $u = Process::getAdvancedMemoryUsage(); $usage = sprintf("%g/%g/%g/%g MB @ %d threads", round(($u[0] / 1024) / 1024, 2), round(($d[0] / 1024) / 1024, 2), round(($u[1] / 1024) / 1024, 2), round(($u[2] / 1024) / 1024, 2), Process::getThreadCount()); echo "\x1b]0;" . $this->getName() . " " . diff --git a/src/pocketmine/command/defaults/StatusCommand.php b/src/pocketmine/command/defaults/StatusCommand.php index 9fb0253bb..60d49c2dc 100644 --- a/src/pocketmine/command/defaults/StatusCommand.php +++ b/src/pocketmine/command/defaults/StatusCommand.php @@ -49,7 +49,7 @@ class StatusCommand extends VanillaCommand{ } $rUsage = Process::getRealMemoryUsage(); - $mUsage = Process::getMemoryUsage(true); + $mUsage = Process::getAdvancedMemoryUsage(); $server = $sender->getServer(); $sender->sendMessage(TextFormat::GREEN . "---- " . TextFormat::WHITE . "Server status" . TextFormat::GREEN . " ----"); diff --git a/src/pocketmine/event/server/LowMemoryEvent.php b/src/pocketmine/event/server/LowMemoryEvent.php index 46f0c8022..7c7a090a6 100644 --- a/src/pocketmine/event/server/LowMemoryEvent.php +++ b/src/pocketmine/event/server/LowMemoryEvent.php @@ -75,6 +75,7 @@ class LowMemoryEvent extends ServerEvent{ * Amount of memory already freed */ public function getMemoryFreed() : int{ - return $this->getMemory() - ($this->isGlobal() ? Process::getMemoryUsage(true)[1] : Process::getMemoryUsage(true)[0]); + $usage = Process::getAdvancedMemoryUsage(); + return $this->getMemory() - ($this->isGlobal() ? $usage[1] : $usage[0]); } } diff --git a/src/pocketmine/scheduler/SendUsageTask.php b/src/pocketmine/scheduler/SendUsageTask.php index a92c0eb7f..4e8bee608 100644 --- a/src/pocketmine/scheduler/SendUsageTask.php +++ b/src/pocketmine/scheduler/SendUsageTask.php @@ -136,7 +136,7 @@ class SendUsageTask extends AsyncTask{ "historyList" => array_values($playerList) ]; - $info = Process::getMemoryUsage(true); + $info = Process::getAdvancedMemoryUsage(); $data["system"] = [ "mainMemory" => $info[0], "totalMemory" => $info[1], diff --git a/src/pocketmine/utils/Process.php b/src/pocketmine/utils/Process.php index 47520344a..ca3f13ac6 100644 --- a/src/pocketmine/utils/Process.php +++ b/src/pocketmine/utils/Process.php @@ -47,9 +47,10 @@ final class Process{ } /** - * @return int[]|int + * @return int[] + * @phpstan-return array{int,int,int} */ - public static function getMemoryUsage(bool $advanced = false){ + public static function getAdvancedMemoryUsage(){ $reserved = memory_get_usage(); $VmSize = null; $VmRSS = null; @@ -70,10 +71,6 @@ final class Process{ $VmRSS = memory_get_usage(); } - if(!$advanced){ - return $VmRSS; - } - if($VmSize === null){ $VmSize = memory_get_usage(true); } @@ -81,6 +78,10 @@ final class Process{ return [$reserved, $VmRSS, $VmSize]; } + public static function getMemoryUsage() : int{ + return self::getAdvancedMemoryUsage()[1]; + } + /** * @return int[] */ diff --git a/src/pocketmine/utils/Utils.php b/src/pocketmine/utils/Utils.php index 643f9ee27..7cbc03610 100644 --- a/src/pocketmine/utils/Utils.php +++ b/src/pocketmine/utils/Utils.php @@ -283,11 +283,12 @@ class Utils{ /** * @deprecated * @see Process::getMemoryUsage() + * @see Process::getAdvancedMemoryUsage() * * @return int[]|int */ public static function getMemoryUsage(bool $advanced = false){ - return Process::getMemoryUsage($advanced); + return $advanced ? Process::getAdvancedMemoryUsage() : Process::getMemoryUsage(); } /** From f8ce01e2fd710fc5a6c2830069c52d176d948e52 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Fri, 13 Mar 2020 17:54:25 +0000 Subject: [PATCH 28/90] ItemFactory: extract fromStringSingle() from fromString() on PM4, the multiple functionality is removed, but on PM3 this is a problem for phpstan. --- .../command/defaults/GiveCommand.php | 2 +- src/pocketmine/item/Item.php | 2 +- src/pocketmine/item/ItemFactory.php | 42 ++++++++++--------- src/pocketmine/level/Level.php | 4 +- src/pocketmine/level/generator/Flat.php | 2 +- tests/phpunit/item/ItemTest.php | 2 +- 6 files changed, 29 insertions(+), 25 deletions(-) diff --git a/src/pocketmine/command/defaults/GiveCommand.php b/src/pocketmine/command/defaults/GiveCommand.php index 8e2138aa0..fc9a96b93 100644 --- a/src/pocketmine/command/defaults/GiveCommand.php +++ b/src/pocketmine/command/defaults/GiveCommand.php @@ -62,7 +62,7 @@ class GiveCommand extends VanillaCommand{ } try{ - $item = ItemFactory::fromString($args[1]); + $item = ItemFactory::fromStringSingle($args[1]); }catch(\InvalidArgumentException $e){ $sender->sendMessage(new TranslationContainer(TextFormat::RED . "%commands.give.item.notFound", [$args[1]])); return true; diff --git a/src/pocketmine/item/Item.php b/src/pocketmine/item/Item.php index 5edd234e8..83be88cf9 100644 --- a/src/pocketmine/item/Item.php +++ b/src/pocketmine/item/Item.php @@ -852,7 +852,7 @@ class Item implements ItemIds, \JsonSerializable{ $item = ItemFactory::get($idTag->getValue(), $meta, $count); }elseif($idTag instanceof StringTag){ //PC item save format try{ - $item = ItemFactory::fromString($idTag->getValue()); + $item = ItemFactory::fromStringSingle($idTag->getValue()); }catch(\InvalidArgumentException $e){ //TODO: improve error handling return ItemFactory::get(Item::AIR, 0, 0); diff --git a/src/pocketmine/item/ItemFactory.php b/src/pocketmine/item/ItemFactory.php index cf1c63774..2d537231f 100644 --- a/src/pocketmine/item/ItemFactory.php +++ b/src/pocketmine/item/ItemFactory.php @@ -354,32 +354,36 @@ class ItemFactory{ if($multiple){ $blocks = []; foreach(explode(",", $str) as $b){ - $blocks[] = self::fromString($b, false); + $blocks[] = self::fromStringSingle($b); } return $blocks; }else{ - $b = explode(":", str_replace([" ", "minecraft:"], ["_", ""], trim($str))); - if(!isset($b[1])){ - $meta = 0; - }elseif(is_numeric($b[1])){ - $meta = (int) $b[1]; - }else{ - throw new \InvalidArgumentException("Unable to parse \"" . $b[1] . "\" from \"" . $str . "\" as a valid meta value"); - } - - if(is_numeric($b[0])){ - $item = self::get((int) $b[0], $meta); - }elseif(defined(ItemIds::class . "::" . strtoupper($b[0]))){ - $item = self::get(constant(ItemIds::class . "::" . strtoupper($b[0])), $meta); - }else{ - throw new \InvalidArgumentException("Unable to resolve \"" . $str . "\" to a valid item"); - } - - return $item; + return self::fromStringSingle($str); } } + public static function fromStringSingle(string $str) : Item{ + $b = explode(":", str_replace([" ", "minecraft:"], ["_", ""], trim($str))); + if(!isset($b[1])){ + $meta = 0; + }elseif(is_numeric($b[1])){ + $meta = (int) $b[1]; + }else{ + throw new \InvalidArgumentException("Unable to parse \"" . $b[1] . "\" from \"" . $str . "\" as a valid meta value"); + } + + if(is_numeric($b[0])){ + $item = self::get((int) $b[0], $meta); + }elseif(defined(ItemIds::class . "::" . strtoupper($b[0]))){ + $item = self::get(constant(ItemIds::class . "::" . strtoupper($b[0])), $meta); + }else{ + throw new \InvalidArgumentException("Unable to resolve \"" . $str . "\" to a valid item"); + } + + return $item; + } + /** * Returns whether the specified item ID is already registered in the item factory. */ diff --git a/src/pocketmine/level/Level.php b/src/pocketmine/level/Level.php index c883a222f..1a8b6b35e 100644 --- a/src/pocketmine/level/Level.php +++ b/src/pocketmine/level/Level.php @@ -1764,7 +1764,7 @@ class Level implements ChunkManager, Metadatable{ if($tag instanceof ListTag){ foreach($tag as $v){ if($v instanceof StringTag){ - $entry = ItemFactory::fromString($v->getValue()); + $entry = ItemFactory::fromStringSingle($v->getValue()); if($entry->getId() > 0 and $entry->getBlock()->getId() === $target->getId()){ $canBreak = true; break; @@ -1919,7 +1919,7 @@ class Level implements ChunkManager, Metadatable{ if($tag instanceof ListTag){ foreach($tag as $v){ if($v instanceof StringTag){ - $entry = ItemFactory::fromString($v->getValue()); + $entry = ItemFactory::fromStringSingle($v->getValue()); if($entry->getId() > 0 and $entry->getBlock()->getId() === $blockClicked->getId()){ $canPlace = true; break; diff --git a/src/pocketmine/level/generator/Flat.php b/src/pocketmine/level/generator/Flat.php index 24c4888d3..681b4ad0a 100644 --- a/src/pocketmine/level/generator/Flat.php +++ b/src/pocketmine/level/generator/Flat.php @@ -120,7 +120,7 @@ class Flat extends Generator{ $cnt = $matches[1] !== "" ? (int) $matches[1] : 1; try{ - $b = ItemFactory::fromString($matches[2])->getBlock(); + $b = ItemFactory::fromStringSingle($matches[2])->getBlock(); }catch(\InvalidArgumentException $e){ throw new InvalidGeneratorOptionsException("Invalid preset layer \"$line\": " . $e->getMessage(), 0, $e); } diff --git a/tests/phpunit/item/ItemTest.php b/tests/phpunit/item/ItemTest.php index d84449269..817840f6c 100644 --- a/tests/phpunit/item/ItemTest.php +++ b/tests/phpunit/item/ItemTest.php @@ -84,7 +84,7 @@ class ItemTest extends TestCase{ * @param int $meta */ public function testFromStringSingle(string $string, int $id, int $meta) : void{ - $item = ItemFactory::fromString($string); + $item = ItemFactory::fromStringSingle($string); self::assertEquals($id, $item->getId()); self::assertEquals($meta, $item->getDamage()); From 35490ca41cf895cd77644e39d3a232f1be2bc4f1 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Sun, 15 Mar 2020 15:46:03 +0000 Subject: [PATCH 29/90] CrashDump: do not assume that file() always returns array phpstan level 7 prep --- src/pocketmine/CrashDump.php | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/pocketmine/CrashDump.php b/src/pocketmine/CrashDump.php index 321210dcd..fc67be6c8 100644 --- a/src/pocketmine/CrashDump.php +++ b/src/pocketmine/CrashDump.php @@ -288,9 +288,11 @@ class CrashDump{ if($this->server->getProperty("auto-report.send-code", true) !== false and file_exists($error["fullFile"])){ $file = @file($error["fullFile"], FILE_IGNORE_NEW_LINES); - for($l = max(0, $error["line"] - 10); $l < $error["line"] + 10 and isset($file[$l]); ++$l){ - $this->addLine("[" . ($l + 1) . "] " . $file[$l]); - $this->data["code"][$l + 1] = $file[$l]; + if($file !== false){ + for($l = max(0, $error["line"] - 10); $l < $error["line"] + 10 and isset($file[$l]); ++$l){ + $this->addLine("[" . ($l + 1) . "] " . $file[$l]); + $this->data["code"][$l + 1] = $file[$l]; + } } } From 9c86763322d06c7c7a9b133c77107d16cbb73f01 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Sun, 15 Mar 2020 15:47:07 +0000 Subject: [PATCH 30/90] CrashDump: do not assume that error_get_last() always returns array this returns NULL if there was no error before the shutdown handler was triggered (usually caused by a plugin calling exit() prematurely). --- src/pocketmine/CrashDump.php | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/pocketmine/CrashDump.php b/src/pocketmine/CrashDump.php index fc67be6c8..776989d24 100644 --- a/src/pocketmine/CrashDump.php +++ b/src/pocketmine/CrashDump.php @@ -228,7 +228,10 @@ class CrashDump{ if(isset($lastExceptionError)){ $error = $lastExceptionError; }else{ - $error = (array) error_get_last(); + $error = error_get_last(); + if($error === null){ + throw new \RuntimeException("Crash error information missing - did something use exit()?"); + } $error["trace"] = Utils::currentTrace(3); //Skipping CrashDump->baseCrash, CrashDump->construct, Server->crashDump $errorConversion = [ E_ERROR => "E_ERROR", From 5c7b05c2ba7a7202666b0b0246f68cbe78f28a93 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Sun, 15 Mar 2020 15:48:09 +0000 Subject: [PATCH 31/90] CrashDump: do not assign possibly-false return value of fopen() directly to non-union field this would become a problem with typed properties, and also phpstan level 7 doesn't like it. --- src/pocketmine/CrashDump.php | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/pocketmine/CrashDump.php b/src/pocketmine/CrashDump.php index 776989d24..49c0ff170 100644 --- a/src/pocketmine/CrashDump.php +++ b/src/pocketmine/CrashDump.php @@ -117,10 +117,11 @@ class CrashDump{ mkdir($this->server->getDataPath() . "crashdumps"); } $this->path = $this->server->getDataPath() . "crashdumps/" . date("D_M_j-H.i.s-T_Y", $this->time) . ".log"; - $this->fp = @fopen($this->path, "wb"); - if(!is_resource($this->fp)){ + $fp = @fopen($this->path, "wb"); + if(!is_resource($fp)){ throw new \RuntimeException("Could not create Crash Dump"); } + $this->fp = $fp; $this->data["format_version"] = self::FORMAT_VERSION; $this->data["time"] = $this->time; $this->addLine($this->server->getName() . " Crash Dump " . date("D M j H:i:s T Y", $this->time)); From 06a9c98ded924c7857ea1830c5f0aa656b0b932c Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Sun, 15 Mar 2020 15:49:04 +0000 Subject: [PATCH 32/90] MemoryManager: fix strict-rules error on phpstan level 7 --- src/pocketmine/MemoryManager.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/pocketmine/MemoryManager.php b/src/pocketmine/MemoryManager.php index 4f3d2226b..344a1fe2f 100644 --- a/src/pocketmine/MemoryManager.php +++ b/src/pocketmine/MemoryManager.php @@ -404,8 +404,8 @@ class MemoryManager{ "properties" => [] ]; - if($reflection->getParentClass()){ - $info["parent"] = $reflection->getParentClass()->getName(); + if(($parent = $reflection->getParentClass()) !== false){ + $info["parent"] = $parent->getName(); } if(count($reflection->getInterfaceNames()) > 0){ From 6422ed772257393f6418006e63a27eee61c24280 Mon Sep 17 00:00:00 2001 From: Twisted Date: Sat, 11 Apr 2020 23:27:17 +0100 Subject: [PATCH 33/90] Added RakLibInterface::setPacketLimit() (#3398) --- src/pocketmine/network/mcpe/RakLibInterface.php | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/pocketmine/network/mcpe/RakLibInterface.php b/src/pocketmine/network/mcpe/RakLibInterface.php index c9d28370c..d8a67bfdf 100644 --- a/src/pocketmine/network/mcpe/RakLibInterface.php +++ b/src/pocketmine/network/mcpe/RakLibInterface.php @@ -226,6 +226,10 @@ class RakLibInterface implements ServerInstance, AdvancedSourceInterface{ $this->interface->sendOption("portChecking", $name); } + public function setPacketLimit(int $limit) : void{ + $this->interface->sendOption("packetLimit", $limit); + } + public function handleOption(string $option, string $value) : void{ if($option === "bandwidth"){ $v = unserialize($value); From a2543ff80d2906bccda1a4e2fdbd9d8e7d147fb3 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Tue, 14 Apr 2020 11:08:37 +0100 Subject: [PATCH 34/90] Position: add getLevelNonNull() this allows assuming that a position has a valid world in places where it's never expected to not be valid. Since this is the vast majority of usages, it eliminates a lot of possible null-pointer warnings given by static analysers. TODO: Consider whether we can make Position->getLevel/World use this behaviour out of the box in the next major version. --- src/pocketmine/Player.php | 10 +++--- src/pocketmine/block/Anvil.php | 2 +- src/pocketmine/block/BaseRail.php | 4 +-- src/pocketmine/block/Bed.php | 14 ++++---- src/pocketmine/block/Block.php | 6 ++-- src/pocketmine/block/BoneBlock.php | 2 +- src/pocketmine/block/BurningFurnace.php | 8 ++--- src/pocketmine/block/Cactus.php | 14 ++++---- src/pocketmine/block/Cake.php | 4 +-- src/pocketmine/block/Carpet.php | 4 +-- src/pocketmine/block/Chest.php | 10 +++--- src/pocketmine/block/Crops.php | 8 ++--- src/pocketmine/block/Dandelion.php | 4 +-- src/pocketmine/block/DeadBush.php | 2 +- src/pocketmine/block/Dirt.php | 4 +-- src/pocketmine/block/Door.php | 8 ++--- src/pocketmine/block/DoublePlant.php | 6 ++-- src/pocketmine/block/EnchantingTable.php | 4 +-- src/pocketmine/block/EnderChest.php | 8 ++--- src/pocketmine/block/Fallable.php | 2 +- src/pocketmine/block/FenceGate.php | 4 +-- src/pocketmine/block/Fire.php | 2 +- src/pocketmine/block/Flower.php | 4 +-- src/pocketmine/block/FlowerPot.php | 12 +++---- src/pocketmine/block/GlazedTerracotta.php | 2 +- src/pocketmine/block/GlowingRedstoneOre.php | 2 +- src/pocketmine/block/Grass.php | 6 ++-- src/pocketmine/block/HayBale.php | 2 +- src/pocketmine/block/Ice.php | 2 +- src/pocketmine/block/ItemFrame.php | 4 +-- src/pocketmine/block/Ladder.php | 2 +- src/pocketmine/block/Lava.php | 4 +-- src/pocketmine/block/Leaves.php | 8 ++--- src/pocketmine/block/MelonStem.php | 4 +-- src/pocketmine/block/Mycelium.php | 4 +-- src/pocketmine/block/NetherWartPlant.php | 6 ++-- src/pocketmine/block/Pumpkin.php | 2 +- src/pocketmine/block/PumpkinStem.php | 4 +-- src/pocketmine/block/Quartz.php | 2 +- src/pocketmine/block/RedMushroom.php | 4 +-- src/pocketmine/block/RedstoneOre.php | 6 ++-- src/pocketmine/block/Sapling.php | 10 +++--- src/pocketmine/block/SignPost.php | 8 ++--- src/pocketmine/block/Skull.php | 4 +-- src/pocketmine/block/Slab.php | 12 +++---- src/pocketmine/block/SnowLayer.php | 6 ++-- src/pocketmine/block/Stair.php | 2 +- src/pocketmine/block/StandingBanner.php | 8 ++--- src/pocketmine/block/Sugarcane.php | 20 +++++------ src/pocketmine/block/TNT.php | 4 +-- src/pocketmine/block/TallGrass.php | 4 +-- src/pocketmine/block/Torch.php | 6 ++-- src/pocketmine/block/Trapdoor.php | 4 +-- src/pocketmine/block/Vine.php | 2 +- src/pocketmine/block/WallBanner.php | 2 +- src/pocketmine/block/WallSign.php | 2 +- src/pocketmine/block/Water.php | 4 +-- src/pocketmine/block/WaterLily.php | 4 +-- src/pocketmine/block/Wood.php | 2 +- src/pocketmine/entity/Entity.php | 4 +-- src/pocketmine/entity/Living.php | 4 +-- src/pocketmine/entity/object/FallingBlock.php | 6 ++-- .../entity/EntityDamageByChildEntityEvent.php | 2 +- .../entity/EntityDamageByEntityEvent.php | 2 +- src/pocketmine/inventory/ChestInventory.php | 6 ++-- .../inventory/EnderChestInventory.php | 2 +- src/pocketmine/inventory/PlayerInventory.php | 2 +- src/pocketmine/item/ChorusFruit.php | 5 ++- src/pocketmine/item/PaintingItem.php | 2 +- src/pocketmine/level/Explosion.php | 2 +- src/pocketmine/level/Location.php | 2 +- src/pocketmine/level/Position.php | 16 ++++++++- src/pocketmine/tile/Chest.php | 4 +-- src/pocketmine/tile/Furnace.php | 4 +-- src/pocketmine/tile/Tile.php | 2 +- .../utils/AssumptionFailedError.php | 33 +++++++++++++++++++ 76 files changed, 229 insertions(+), 183 deletions(-) create mode 100644 src/pocketmine/utils/AssumptionFailedError.php diff --git a/src/pocketmine/Player.php b/src/pocketmine/Player.php index c48de117b..ff3c62bd0 100644 --- a/src/pocketmine/Player.php +++ b/src/pocketmine/Player.php @@ -1207,7 +1207,7 @@ class Player extends Human implements CommandSender, ChunkLoader, IPlayer{ if(!($pos instanceof Position)){ $level = $this->level; }else{ - $level = $pos->getLevel(); + $level = $pos->getLevelNonNull(); } $this->spawnPosition = new Position($pos->x, $pos->y, $pos->z, $level); $pk = new SetSpawnPositionPacket(); @@ -2244,7 +2244,7 @@ class Player extends Human implements CommandSender, ChunkLoader, IPlayer{ public function handleLevelSoundEvent(LevelSoundEventPacket $packet) : bool{ //TODO: add events so plugins can change this - $this->getLevel()->broadcastPacketToViewers($this, $packet); + $this->getLevelNonNull()->broadcastPacketToViewers($this, $packet); return true; } @@ -2706,7 +2706,7 @@ class Player extends Human implements CommandSender, ChunkLoader, IPlayer{ $item = $block->getPickedItem(); if($packet->addUserData){ - $tile = $this->getLevel()->getTile($block); + $tile = $this->getLevelNonNull()->getTile($block); if($tile instanceof Tile){ $nbt = $tile->getCleanedNBT(); if($nbt instanceof CompoundTag){ @@ -3583,7 +3583,7 @@ class Player extends Human implements CommandSender, ChunkLoader, IPlayer{ } if($this->hasValidSpawnPosition()){ - $this->namedtag->setString("SpawnLevel", $this->spawnPosition->getLevel()->getFolderName()); + $this->namedtag->setString("SpawnLevel", $this->spawnPosition->getLevelNonNull()->getFolderName()); $this->namedtag->setInt("SpawnX", $this->spawnPosition->getFloorX()); $this->namedtag->setInt("SpawnY", $this->spawnPosition->getFloorY()); $this->namedtag->setInt("SpawnZ", $this->spawnPosition->getFloorZ()); @@ -3666,7 +3666,7 @@ class Player extends Human implements CommandSender, ChunkLoader, IPlayer{ $ev = new PlayerRespawnEvent($this, $this->getSpawn()); $ev->call(); - $realSpawn = Position::fromObject($ev->getRespawnPosition()->add(0.5, 0, 0.5), $ev->getRespawnPosition()->getLevel()); + $realSpawn = Position::fromObject($ev->getRespawnPosition()->add(0.5, 0, 0.5), $ev->getRespawnPosition()->getLevelNonNull()); $this->teleport($realSpawn); $this->setSprinting(false); diff --git a/src/pocketmine/block/Anvil.php b/src/pocketmine/block/Anvil.php index 2eb8880af..7fa7cfc1a 100644 --- a/src/pocketmine/block/Anvil.php +++ b/src/pocketmine/block/Anvil.php @@ -110,6 +110,6 @@ class Anvil extends Fallable{ public function place(Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, Player $player = null) : bool{ $direction = ($player !== null ? $player->getDirection() : 0) & 0x03; $this->meta = $this->getVariant() | $direction; - return $this->getLevel()->setBlock($blockReplace, $this, true, true); + return $this->getLevelNonNull()->setBlock($blockReplace, $this, true, true); } } diff --git a/src/pocketmine/block/BaseRail.php b/src/pocketmine/block/BaseRail.php index c5fb8b2e3..1cd8cf167 100644 --- a/src/pocketmine/block/BaseRail.php +++ b/src/pocketmine/block/BaseRail.php @@ -91,7 +91,7 @@ abstract class BaseRail extends Flowable{ } public function place(Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, Player $player = null) : bool{ - if(!$blockReplace->getSide(Vector3::SIDE_DOWN)->isTransparent() and $this->getLevel()->setBlock($blockReplace, $this, true, true)){ + if(!$blockReplace->getSide(Vector3::SIDE_DOWN)->isTransparent() and $this->getLevelNonNull()->setBlock($blockReplace, $this, true, true)){ $this->tryReconnect(); return true; } @@ -279,7 +279,7 @@ abstract class BaseRail extends Flowable{ isset(self::ASCENDING_SIDES[$this->meta & 0x07]) and $this->getSide(self::ASCENDING_SIDES[$this->meta & 0x07])->isTransparent() )){ - $this->getLevel()->useBreakOn($this); + $this->getLevelNonNull()->useBreakOn($this); } } diff --git a/src/pocketmine/block/Bed.php b/src/pocketmine/block/Bed.php index 803f07ea3..166b1c35b 100644 --- a/src/pocketmine/block/Bed.php +++ b/src/pocketmine/block/Bed.php @@ -83,7 +83,7 @@ class Bed extends Transparent{ $this->meta &= ~self::BITFLAG_OCCUPIED; } - $this->getLevel()->setBlock($this, $this, false, false); + $this->getLevelNonNull()->setBlock($this, $this, false, false); if(($other = $this->getOtherHalf()) !== null and $other->isOccupied() !== $occupied){ $other->setOccupied($occupied); @@ -137,7 +137,7 @@ class Bed extends Transparent{ return true; } - $time = $this->getLevel()->getTimeOfDay(); + $time = $this->getLevelNonNull()->getTimeOfDay(); $isNight = ($time >= Level::TIME_NIGHT and $time < Level::TIME_SUNRISE); @@ -168,11 +168,11 @@ class Bed extends Transparent{ $meta = (($player instanceof Player ? $player->getDirection() : 0) - 1) & 0x03; $next = $this->getSide(self::getOtherHalfSide($meta)); if($next->canBeReplaced() and !$next->getSide(Vector3::SIDE_DOWN)->isTransparent()){ - $this->getLevel()->setBlock($blockReplace, BlockFactory::get($this->id, $meta), true, true); - $this->getLevel()->setBlock($next, BlockFactory::get($this->id, $meta | self::BITFLAG_HEAD), true, true); + $this->getLevelNonNull()->setBlock($blockReplace, BlockFactory::get($this->id, $meta), true, true); + $this->getLevelNonNull()->setBlock($next, BlockFactory::get($this->id, $meta | self::BITFLAG_HEAD), true, true); - Tile::createTile(Tile::BED, $this->getLevel(), TileBed::createNBT($this, $face, $item, $player)); - Tile::createTile(Tile::BED, $this->getLevel(), TileBed::createNBT($next, $face, $item, $player)); + Tile::createTile(Tile::BED, $this->getLevelNonNull(), TileBed::createNBT($this, $face, $item, $player)); + Tile::createTile(Tile::BED, $this->getLevelNonNull(), TileBed::createNBT($next, $face, $item, $player)); return true; } @@ -194,7 +194,7 @@ class Bed extends Transparent{ } private function getItem() : Item{ - $tile = $this->getLevel()->getTile($this); + $tile = $this->getLevelNonNull()->getTile($this); if($tile instanceof TileBed){ return ItemFactory::get($this->getItemId(), $tile->getColor()); } diff --git a/src/pocketmine/block/Block.php b/src/pocketmine/block/Block.php index df18785e1..f5583753e 100644 --- a/src/pocketmine/block/Block.php +++ b/src/pocketmine/block/Block.php @@ -154,7 +154,7 @@ class Block extends Position implements BlockIds, Metadatable{ * Places the Block, using block space and block target, and side. Returns if the block has been placed. */ public function place(Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, Player $player = null) : bool{ - return $this->getLevel()->setBlock($this, $this, true, true); + return $this->getLevelNonNull()->setBlock($this, $this, true, true); } /** @@ -204,7 +204,7 @@ class Block extends Position implements BlockIds, Metadatable{ * Do the actions needed so the block is broken with the Item */ public function onBreak(Item $item, Player $player = null) : bool{ - return $this->getLevel()->setBlock($this, BlockFactory::get(Block::AIR), true, true); + return $this->getLevelNonNull()->setBlock($this, BlockFactory::get(Block::AIR), true, true); } /** @@ -479,7 +479,7 @@ class Block extends Position implements BlockIds, Metadatable{ */ public function getSide(int $side, int $step = 1){ if($this->isValid()){ - return $this->getLevel()->getBlock(Vector3::getSide($side, $step)); + return $this->getLevelNonNull()->getBlock(Vector3::getSide($side, $step)); } return BlockFactory::get(Block::AIR, 0, Position::fromObject(Vector3::getSide($side, $step))); diff --git a/src/pocketmine/block/BoneBlock.php b/src/pocketmine/block/BoneBlock.php index 696565fae..364e8332b 100644 --- a/src/pocketmine/block/BoneBlock.php +++ b/src/pocketmine/block/BoneBlock.php @@ -55,7 +55,7 @@ class BoneBlock extends Solid{ public function place(Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, Player $player = null) : bool{ $this->meta = PillarRotationHelper::getMetaFromFace($this->meta, $face); - return $this->getLevel()->setBlock($blockReplace, $this, true, true); + return $this->getLevelNonNull()->setBlock($blockReplace, $this, true, true); } public function getVariantBitmask() : int{ diff --git a/src/pocketmine/block/BurningFurnace.php b/src/pocketmine/block/BurningFurnace.php index c189f5b65..fdb61536c 100644 --- a/src/pocketmine/block/BurningFurnace.php +++ b/src/pocketmine/block/BurningFurnace.php @@ -68,18 +68,18 @@ class BurningFurnace extends Solid{ 3 => 3 ]; $this->meta = $faces[$player instanceof Player ? $player->getDirection() : 0]; - $this->getLevel()->setBlock($blockReplace, $this, true, true); + $this->getLevelNonNull()->setBlock($blockReplace, $this, true, true); - Tile::createTile(Tile::FURNACE, $this->getLevel(), TileFurnace::createNBT($this, $face, $item, $player)); + Tile::createTile(Tile::FURNACE, $this->getLevelNonNull(), TileFurnace::createNBT($this, $face, $item, $player)); return true; } public function onActivate(Item $item, Player $player = null) : bool{ if($player instanceof Player){ - $furnace = $this->getLevel()->getTile($this); + $furnace = $this->getLevelNonNull()->getTile($this); if(!($furnace instanceof TileFurnace)){ - $furnace = Tile::createTile(Tile::FURNACE, $this->getLevel(), TileFurnace::createNBT($this)); + $furnace = Tile::createTile(Tile::FURNACE, $this->getLevelNonNull(), TileFurnace::createNBT($this)); if(!($furnace instanceof TileFurnace)){ return true; } diff --git a/src/pocketmine/block/Cactus.php b/src/pocketmine/block/Cactus.php index 30effe652..2fd5fbff7 100644 --- a/src/pocketmine/block/Cactus.php +++ b/src/pocketmine/block/Cactus.php @@ -72,12 +72,12 @@ class Cactus extends Transparent{ public function onNearbyBlockChange() : void{ $down = $this->getSide(Vector3::SIDE_DOWN); if($down->getId() !== self::SAND and $down->getId() !== self::CACTUS){ - $this->getLevel()->useBreakOn($this); + $this->getLevelNonNull()->useBreakOn($this); }else{ for($side = 2; $side <= 5; ++$side){ $b = $this->getSide($side); if($b->isSolid()){ - $this->getLevel()->useBreakOn($this); + $this->getLevelNonNull()->useBreakOn($this); break; } } @@ -92,23 +92,23 @@ class Cactus extends Transparent{ if($this->getSide(Vector3::SIDE_DOWN)->getId() !== self::CACTUS){ if($this->meta === 0x0f){ for($y = 1; $y < 3; ++$y){ - $b = $this->getLevel()->getBlockAt($this->x, $this->y + $y, $this->z); + $b = $this->getLevelNonNull()->getBlockAt($this->x, $this->y + $y, $this->z); if($b->getId() === self::AIR){ $ev = new BlockGrowEvent($b, BlockFactory::get(Block::CACTUS)); $ev->call(); if($ev->isCancelled()){ break; } - $this->getLevel()->setBlock($b, $ev->getNewState(), true); + $this->getLevelNonNull()->setBlock($b, $ev->getNewState(), true); }else{ break; } } $this->meta = 0; - $this->getLevel()->setBlock($this, $this); + $this->getLevelNonNull()->setBlock($this, $this); }else{ ++$this->meta; - $this->getLevel()->setBlock($this, $this); + $this->getLevelNonNull()->setBlock($this, $this); } } } @@ -121,7 +121,7 @@ class Cactus extends Transparent{ $block2 = $this->getSide(Vector3::SIDE_WEST); $block3 = $this->getSide(Vector3::SIDE_EAST); if(!$block0->isSolid() and !$block1->isSolid() and !$block2->isSolid() and !$block3->isSolid()){ - $this->getLevel()->setBlock($this, $this, true); + $this->getLevelNonNull()->setBlock($this, $this, true); return true; } diff --git a/src/pocketmine/block/Cake.php b/src/pocketmine/block/Cake.php index 9ac80f6a7..8cb3165ec 100644 --- a/src/pocketmine/block/Cake.php +++ b/src/pocketmine/block/Cake.php @@ -66,7 +66,7 @@ class Cake extends Transparent implements FoodSource{ public function place(Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, Player $player = null) : bool{ $down = $this->getSide(Vector3::SIDE_DOWN); if($down->getId() !== self::AIR){ - $this->getLevel()->setBlock($blockReplace, $this, true, true); + $this->getLevelNonNull()->setBlock($blockReplace, $this, true, true); return true; } @@ -76,7 +76,7 @@ class Cake extends Transparent implements FoodSource{ public function onNearbyBlockChange() : void{ if($this->getSide(Vector3::SIDE_DOWN)->getId() === self::AIR){ //Replace with common break method - $this->getLevel()->setBlock($this, BlockFactory::get(Block::AIR), true); + $this->getLevelNonNull()->setBlock($this, BlockFactory::get(Block::AIR), true); } } diff --git a/src/pocketmine/block/Carpet.php b/src/pocketmine/block/Carpet.php index 225f9db09..bd700f8d8 100644 --- a/src/pocketmine/block/Carpet.php +++ b/src/pocketmine/block/Carpet.php @@ -64,7 +64,7 @@ class Carpet extends Flowable{ public function place(Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, Player $player = null) : bool{ $down = $this->getSide(Vector3::SIDE_DOWN); if($down->getId() !== self::AIR){ - $this->getLevel()->setBlock($blockReplace, $this, true, true); + $this->getLevelNonNull()->setBlock($blockReplace, $this, true, true); return true; } @@ -74,7 +74,7 @@ class Carpet extends Flowable{ public function onNearbyBlockChange() : void{ if($this->getSide(Vector3::SIDE_DOWN)->getId() === self::AIR){ - $this->getLevel()->useBreakOn($this); + $this->getLevelNonNull()->useBreakOn($this); } } diff --git a/src/pocketmine/block/Chest.php b/src/pocketmine/block/Chest.php index 47d96e33f..af2b8e498 100644 --- a/src/pocketmine/block/Chest.php +++ b/src/pocketmine/block/Chest.php @@ -81,7 +81,7 @@ class Chest extends Transparent{ } $c = $this->getSide($side); if($c->getId() === $this->id and $c->getDamage() === $this->meta){ - $tile = $this->getLevel()->getTile($c); + $tile = $this->getLevelNonNull()->getTile($c); if($tile instanceof TileChest and !$tile->isPaired()){ $chest = $tile; break; @@ -89,8 +89,8 @@ class Chest extends Transparent{ } } - $this->getLevel()->setBlock($blockReplace, $this, true, true); - $tile = Tile::createTile(Tile::CHEST, $this->getLevel(), TileChest::createNBT($this, $face, $item, $player)); + $this->getLevelNonNull()->setBlock($blockReplace, $this, true, true); + $tile = Tile::createTile(Tile::CHEST, $this->getLevelNonNull(), TileChest::createNBT($this, $face, $item, $player)); if($chest instanceof TileChest and $tile instanceof TileChest){ $chest->pairWith($tile); @@ -103,12 +103,12 @@ class Chest extends Transparent{ public function onActivate(Item $item, Player $player = null) : bool{ if($player instanceof Player){ - $t = $this->getLevel()->getTile($this); + $t = $this->getLevelNonNull()->getTile($this); $chest = null; if($t instanceof TileChest){ $chest = $t; }else{ - $chest = Tile::createTile(Tile::CHEST, $this->getLevel(), TileChest::createNBT($this)); + $chest = Tile::createTile(Tile::CHEST, $this->getLevelNonNull(), TileChest::createNBT($this)); if(!($chest instanceof TileChest)){ return true; } diff --git a/src/pocketmine/block/Crops.php b/src/pocketmine/block/Crops.php index eaebfe0a2..81afd0c17 100644 --- a/src/pocketmine/block/Crops.php +++ b/src/pocketmine/block/Crops.php @@ -33,7 +33,7 @@ abstract class Crops extends Flowable{ public function place(Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, Player $player = null) : bool{ if($blockReplace->getSide(Vector3::SIDE_DOWN)->getId() === Block::FARMLAND){ - $this->getLevel()->setBlock($blockReplace, $this, true, true); + $this->getLevelNonNull()->setBlock($blockReplace, $this, true, true); return true; } @@ -52,7 +52,7 @@ abstract class Crops extends Flowable{ $ev = new BlockGrowEvent($this, $block); $ev->call(); if(!$ev->isCancelled()){ - $this->getLevel()->setBlock($this, $ev->getNewState(), true, true); + $this->getLevelNonNull()->setBlock($this, $ev->getNewState(), true, true); } $item->pop(); @@ -65,7 +65,7 @@ abstract class Crops extends Flowable{ public function onNearbyBlockChange() : void{ if($this->getSide(Vector3::SIDE_DOWN)->getId() !== Block::FARMLAND){ - $this->getLevel()->useBreakOn($this); + $this->getLevelNonNull()->useBreakOn($this); } } @@ -81,7 +81,7 @@ abstract class Crops extends Flowable{ $ev = new BlockGrowEvent($this, $block); $ev->call(); if(!$ev->isCancelled()){ - $this->getLevel()->setBlock($this, $ev->getNewState(), true, true); + $this->getLevelNonNull()->setBlock($this, $ev->getNewState(), true, true); } } } diff --git a/src/pocketmine/block/Dandelion.php b/src/pocketmine/block/Dandelion.php index 3071df931..6ffb28a7f 100644 --- a/src/pocketmine/block/Dandelion.php +++ b/src/pocketmine/block/Dandelion.php @@ -42,7 +42,7 @@ class Dandelion extends Flowable{ public function place(Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, Player $player = null) : bool{ $down = $this->getSide(Vector3::SIDE_DOWN); if($down->getId() === Block::GRASS or $down->getId() === Block::DIRT or $down->getId() === Block::FARMLAND){ - $this->getLevel()->setBlock($blockReplace, $this, true, true); + $this->getLevelNonNull()->setBlock($blockReplace, $this, true, true); return true; } @@ -52,7 +52,7 @@ class Dandelion extends Flowable{ public function onNearbyBlockChange() : void{ if($this->getSide(Vector3::SIDE_DOWN)->isTransparent()){ - $this->getLevel()->useBreakOn($this); + $this->getLevelNonNull()->useBreakOn($this); } } diff --git a/src/pocketmine/block/DeadBush.php b/src/pocketmine/block/DeadBush.php index c42abcd9f..8ee1b0977 100644 --- a/src/pocketmine/block/DeadBush.php +++ b/src/pocketmine/block/DeadBush.php @@ -51,7 +51,7 @@ class DeadBush extends Flowable{ public function onNearbyBlockChange() : void{ if($this->getSide(Vector3::SIDE_DOWN)->isTransparent()){ - $this->getLevel()->useBreakOn($this); + $this->getLevelNonNull()->useBreakOn($this); } } diff --git a/src/pocketmine/block/Dirt.php b/src/pocketmine/block/Dirt.php index 96f8da27c..9b00df1e5 100644 --- a/src/pocketmine/block/Dirt.php +++ b/src/pocketmine/block/Dirt.php @@ -54,9 +54,9 @@ class Dirt extends Solid{ if($item instanceof Hoe){ $item->applyDamage(1); if($this->meta === 1){ - $this->getLevel()->setBlock($this, BlockFactory::get(Block::DIRT), true); + $this->getLevelNonNull()->setBlock($this, BlockFactory::get(Block::DIRT), true); }else{ - $this->getLevel()->setBlock($this, BlockFactory::get(Block::FARMLAND), true); + $this->getLevelNonNull()->setBlock($this, BlockFactory::get(Block::FARMLAND), true); } return true; diff --git a/src/pocketmine/block/Door.php b/src/pocketmine/block/Door.php index d100a4c70..d4de03dc4 100644 --- a/src/pocketmine/block/Door.php +++ b/src/pocketmine/block/Door.php @@ -201,9 +201,9 @@ abstract class Door extends Transparent{ public function onNearbyBlockChange() : void{ if($this->getSide(Vector3::SIDE_DOWN)->getId() === self::AIR){ //Replace with common break method - $this->getLevel()->setBlock($this, BlockFactory::get(Block::AIR), false); + $this->getLevelNonNull()->setBlock($this, BlockFactory::get(Block::AIR), false); if($this->getSide(Vector3::SIDE_UP) instanceof Door){ - $this->getLevel()->setBlock($this->getSide(Vector3::SIDE_UP), BlockFactory::get(Block::AIR), false); + $this->getLevelNonNull()->setBlock($this->getSide(Vector3::SIDE_UP), BlockFactory::get(Block::AIR), false); } } } @@ -230,8 +230,8 @@ abstract class Door extends Transparent{ } $this->setDamage($player->getDirection() & 0x03); - $this->getLevel()->setBlock($blockReplace, $this, true, true); //Bottom - $this->getLevel()->setBlock($blockUp, BlockFactory::get($this->getId(), $metaUp), true); //Top + $this->getLevelNonNull()->setBlock($blockReplace, $this, true, true); //Bottom + $this->getLevelNonNull()->setBlock($blockUp, BlockFactory::get($this->getId(), $metaUp), true); //Top return true; } diff --git a/src/pocketmine/block/DoublePlant.php b/src/pocketmine/block/DoublePlant.php index ccb8c1cbd..5894560d1 100644 --- a/src/pocketmine/block/DoublePlant.php +++ b/src/pocketmine/block/DoublePlant.php @@ -57,8 +57,8 @@ class DoublePlant extends Flowable{ public function place(Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, Player $player = null) : bool{ $id = $blockReplace->getSide(Vector3::SIDE_DOWN)->getId(); if(($id === Block::GRASS or $id === Block::DIRT) and $blockReplace->getSide(Vector3::SIDE_UP)->canBeReplaced()){ - $this->getLevel()->setBlock($blockReplace, $this, false, false); - $this->getLevel()->setBlock($blockReplace->getSide(Vector3::SIDE_UP), BlockFactory::get($this->id, $this->meta | self::BITFLAG_TOP), false, false); + $this->getLevelNonNull()->setBlock($blockReplace, $this, false, false); + $this->getLevelNonNull()->setBlock($blockReplace->getSide(Vector3::SIDE_UP), BlockFactory::get($this->id, $this->meta | self::BITFLAG_TOP), false, false); return true; } @@ -85,7 +85,7 @@ class DoublePlant extends Flowable{ public function onNearbyBlockChange() : void{ if(!$this->isValidHalfPlant() or (($this->meta & self::BITFLAG_TOP) === 0 and $this->getSide(Vector3::SIDE_DOWN)->isTransparent())){ - $this->getLevel()->useBreakOn($this); + $this->getLevelNonNull()->useBreakOn($this); } } diff --git a/src/pocketmine/block/EnchantingTable.php b/src/pocketmine/block/EnchantingTable.php index 5574677c4..2724ff51e 100644 --- a/src/pocketmine/block/EnchantingTable.php +++ b/src/pocketmine/block/EnchantingTable.php @@ -40,9 +40,9 @@ class EnchantingTable extends Transparent{ } public function place(Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, Player $player = null) : bool{ - $this->getLevel()->setBlock($blockReplace, $this, true, true); + $this->getLevelNonNull()->setBlock($blockReplace, $this, true, true); - Tile::createTile(Tile::ENCHANT_TABLE, $this->getLevel(), TileEnchantTable::createNBT($this, $face, $item, $player)); + Tile::createTile(Tile::ENCHANT_TABLE, $this->getLevelNonNull(), TileEnchantTable::createNBT($this, $face, $item, $player)); return true; } diff --git a/src/pocketmine/block/EnderChest.php b/src/pocketmine/block/EnderChest.php index 1f1f5e6dd..00438b472 100644 --- a/src/pocketmine/block/EnderChest.php +++ b/src/pocketmine/block/EnderChest.php @@ -69,8 +69,8 @@ class EnderChest extends Chest{ $this->meta = $faces[$player instanceof Player ? $player->getDirection() : 0]; - $this->getLevel()->setBlock($blockReplace, $this, true, true); - Tile::createTile(Tile::ENDER_CHEST, $this->getLevel(), TileEnderChest::createNBT($this, $face, $item, $player)); + $this->getLevelNonNull()->setBlock($blockReplace, $this, true, true); + Tile::createTile(Tile::ENDER_CHEST, $this->getLevelNonNull(), TileEnderChest::createNBT($this, $face, $item, $player)); return true; } @@ -78,12 +78,12 @@ class EnderChest extends Chest{ public function onActivate(Item $item, Player $player = null) : bool{ if($player instanceof Player){ - $t = $this->getLevel()->getTile($this); + $t = $this->getLevelNonNull()->getTile($this); $enderChest = null; if($t instanceof TileEnderChest){ $enderChest = $t; }else{ - $enderChest = Tile::createTile(Tile::ENDER_CHEST, $this->getLevel(), TileEnderChest::createNBT($this)); + $enderChest = Tile::createTile(Tile::ENDER_CHEST, $this->getLevelNonNull(), TileEnderChest::createNBT($this)); if(!($enderChest instanceof TileEnderChest)){ return true; } diff --git a/src/pocketmine/block/Fallable.php b/src/pocketmine/block/Fallable.php index 10cba9554..15d87b97d 100644 --- a/src/pocketmine/block/Fallable.php +++ b/src/pocketmine/block/Fallable.php @@ -37,7 +37,7 @@ abstract class Fallable extends Solid{ $nbt->setInt("TileID", $this->getId()); $nbt->setByte("Data", $this->getDamage()); - $fall = Entity::createEntity("FallingSand", $this->getLevel(), $nbt); + $fall = Entity::createEntity("FallingSand", $this->getLevelNonNull(), $nbt); if($fall !== null){ $fall->spawnToAll(); diff --git a/src/pocketmine/block/FenceGate.php b/src/pocketmine/block/FenceGate.php index 5f5a4d391..66b135f70 100644 --- a/src/pocketmine/block/FenceGate.php +++ b/src/pocketmine/block/FenceGate.php @@ -69,7 +69,7 @@ class FenceGate extends Transparent{ public function place(Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, Player $player = null) : bool{ $this->meta = ($player instanceof Player ? ($player->getDirection() - 1) & 0x03 : 0); - $this->getLevel()->setBlock($blockReplace, $this, true, true); + $this->getLevelNonNull()->setBlock($blockReplace, $this, true, true); return true; } @@ -85,7 +85,7 @@ class FenceGate extends Transparent{ $this->meta |= (($player->getDirection() - 1) & 0x02); } - $this->getLevel()->setBlock($this, $this, true); + $this->getLevelNonNull()->setBlock($this, $this, true); $this->level->addSound(new DoorSound($this)); return true; } diff --git a/src/pocketmine/block/Fire.php b/src/pocketmine/block/Fire.php index f89b2f887..832ab6194 100644 --- a/src/pocketmine/block/Fire.php +++ b/src/pocketmine/block/Fire.php @@ -82,7 +82,7 @@ class Fire extends Flowable{ public function onNearbyBlockChange() : void{ if(!$this->getSide(Vector3::SIDE_DOWN)->isSolid() and !$this->hasAdjacentFlammableBlocks()){ - $this->getLevel()->setBlock($this, BlockFactory::get(Block::AIR), true); + $this->getLevelNonNull()->setBlock($this, BlockFactory::get(Block::AIR), true); }else{ $this->level->scheduleDelayedBlockUpdate($this, mt_rand(30, 40)); } diff --git a/src/pocketmine/block/Flower.php b/src/pocketmine/block/Flower.php index 4bb3ee7ce..7a1b5baf9 100644 --- a/src/pocketmine/block/Flower.php +++ b/src/pocketmine/block/Flower.php @@ -62,7 +62,7 @@ class Flower extends Flowable{ public function place(Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, Player $player = null) : bool{ $down = $this->getSide(Vector3::SIDE_DOWN); if($down->getId() === Block::GRASS or $down->getId() === Block::DIRT or $down->getId() === Block::FARMLAND){ - $this->getLevel()->setBlock($blockReplace, $this, true); + $this->getLevelNonNull()->setBlock($blockReplace, $this, true); return true; } @@ -72,7 +72,7 @@ class Flower extends Flowable{ public function onNearbyBlockChange() : void{ if($this->getSide(Vector3::SIDE_DOWN)->isTransparent()){ - $this->getLevel()->useBreakOn($this); + $this->getLevelNonNull()->useBreakOn($this); } } diff --git a/src/pocketmine/block/FlowerPot.php b/src/pocketmine/block/FlowerPot.php index cc5d3b9ed..5e1a41d48 100644 --- a/src/pocketmine/block/FlowerPot.php +++ b/src/pocketmine/block/FlowerPot.php @@ -62,19 +62,19 @@ class FlowerPot extends Flowable{ return false; } - $this->getLevel()->setBlock($blockReplace, $this, true, true); - Tile::createTile(Tile::FLOWER_POT, $this->getLevel(), TileFlowerPot::createNBT($this, $face, $item, $player)); + $this->getLevelNonNull()->setBlock($blockReplace, $this, true, true); + Tile::createTile(Tile::FLOWER_POT, $this->getLevelNonNull(), TileFlowerPot::createNBT($this, $face, $item, $player)); return true; } public function onNearbyBlockChange() : void{ if($this->getSide(Vector3::SIDE_DOWN)->isTransparent()){ - $this->getLevel()->useBreakOn($this); + $this->getLevelNonNull()->useBreakOn($this); } } public function onActivate(Item $item, Player $player = null) : bool{ - $pot = $this->getLevel()->getTile($this); + $pot = $this->getLevelNonNull()->getTile($this); if(!($pot instanceof TileFlowerPot)){ return false; } @@ -83,7 +83,7 @@ class FlowerPot extends Flowable{ } $this->setDamage(self::STATE_FULL); //specific damage value is unnecessary, it just needs to be non-zero to show an item. - $this->getLevel()->setBlock($this, $this, true, false); + $this->getLevelNonNull()->setBlock($this, $this, true, false); $pot->setItem($item->pop()); return true; @@ -96,7 +96,7 @@ class FlowerPot extends Flowable{ public function getDropsForCompatibleTool(Item $item) : array{ $items = parent::getDropsForCompatibleTool($item); - $tile = $this->getLevel()->getTile($this); + $tile = $this->getLevelNonNull()->getTile($this); if($tile instanceof TileFlowerPot){ $item = $tile->getItem(); if($item->getId() !== Item::AIR){ diff --git a/src/pocketmine/block/GlazedTerracotta.php b/src/pocketmine/block/GlazedTerracotta.php index 9e3862666..e2ae343bf 100644 --- a/src/pocketmine/block/GlazedTerracotta.php +++ b/src/pocketmine/block/GlazedTerracotta.php @@ -53,7 +53,7 @@ class GlazedTerracotta extends Solid{ $this->meta = $faces[(~($player->getDirection() - 1)) & 0x03]; } - return $this->getLevel()->setBlock($blockReplace, $this, true, true); + return $this->getLevelNonNull()->setBlock($blockReplace, $this, true, true); } public function getVariantBitmask() : int{ diff --git a/src/pocketmine/block/GlowingRedstoneOre.php b/src/pocketmine/block/GlowingRedstoneOre.php index 0825bf546..94a3ce8ad 100644 --- a/src/pocketmine/block/GlowingRedstoneOre.php +++ b/src/pocketmine/block/GlowingRedstoneOre.php @@ -53,6 +53,6 @@ class GlowingRedstoneOre extends RedstoneOre{ } public function onRandomTick() : void{ - $this->getLevel()->setBlock($this, BlockFactory::get(Block::REDSTONE_ORE, $this->meta), false, false); + $this->getLevelNonNull()->setBlock($this, BlockFactory::get(Block::REDSTONE_ORE, $this->meta), false, false); } } diff --git a/src/pocketmine/block/Grass.php b/src/pocketmine/block/Grass.php index afd4b54ad..8313cc78c 100644 --- a/src/pocketmine/block/Grass.php +++ b/src/pocketmine/block/Grass.php @@ -100,17 +100,17 @@ class Grass extends Solid{ public function onActivate(Item $item, Player $player = null) : bool{ if($item->getId() === Item::DYE and $item->getDamage() === 0x0F){ $item->pop(); - TallGrassObject::growGrass($this->getLevel(), $this, new Random(mt_rand()), 8, 2); + TallGrassObject::growGrass($this->getLevelNonNull(), $this, new Random(mt_rand()), 8, 2); return true; }elseif($item instanceof Hoe){ $item->applyDamage(1); - $this->getLevel()->setBlock($this, BlockFactory::get(Block::FARMLAND)); + $this->getLevelNonNull()->setBlock($this, BlockFactory::get(Block::FARMLAND)); return true; }elseif($item instanceof Shovel and $this->getSide(Vector3::SIDE_UP)->getId() === Block::AIR){ $item->applyDamage(1); - $this->getLevel()->setBlock($this, BlockFactory::get(Block::GRASS_PATH)); + $this->getLevelNonNull()->setBlock($this, BlockFactory::get(Block::GRASS_PATH)); return true; } diff --git a/src/pocketmine/block/HayBale.php b/src/pocketmine/block/HayBale.php index 7dd2989da..a97c769ae 100644 --- a/src/pocketmine/block/HayBale.php +++ b/src/pocketmine/block/HayBale.php @@ -46,7 +46,7 @@ class HayBale extends Solid{ public function place(Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, Player $player = null) : bool{ $this->meta = PillarRotationHelper::getMetaFromFace($this->meta, $face); - $this->getLevel()->setBlock($blockReplace, $this, true, true); + $this->getLevelNonNull()->setBlock($blockReplace, $this, true, true); return true; } diff --git a/src/pocketmine/block/Ice.php b/src/pocketmine/block/Ice.php index 3c214cf3b..3e9953b50 100644 --- a/src/pocketmine/block/Ice.php +++ b/src/pocketmine/block/Ice.php @@ -57,7 +57,7 @@ class Ice extends Transparent{ public function onBreak(Item $item, Player $player = null) : bool{ if(($player === null or $player->isSurvival()) and !$item->hasEnchantment(Enchantment::SILK_TOUCH)){ - return $this->getLevel()->setBlock($this, BlockFactory::get(Block::WATER), true); + return $this->getLevelNonNull()->setBlock($this, BlockFactory::get(Block::WATER), true); } return parent::onBreak($item, $player); } diff --git a/src/pocketmine/block/ItemFrame.php b/src/pocketmine/block/ItemFrame.php index 6644c682b..cdb3ca89a 100644 --- a/src/pocketmine/block/ItemFrame.php +++ b/src/pocketmine/block/ItemFrame.php @@ -46,7 +46,7 @@ class ItemFrame extends Flowable{ public function onActivate(Item $item, Player $player = null) : bool{ $tile = $this->level->getTile($this); if(!($tile instanceof TileItemFrame)){ - $tile = Tile::createTile(Tile::ITEM_FRAME, $this->getLevel(), TileItemFrame::createNBT($this)); + $tile = Tile::createTile(Tile::ITEM_FRAME, $this->getLevelNonNull(), TileItemFrame::createNBT($this)); if(!($tile instanceof TileItemFrame)){ return true; } @@ -88,7 +88,7 @@ class ItemFrame extends Flowable{ $this->meta = $faces[$face]; $this->level->setBlock($blockReplace, $this, true, true); - Tile::createTile(Tile::ITEM_FRAME, $this->getLevel(), TileItemFrame::createNBT($this, $face, $item, $player)); + Tile::createTile(Tile::ITEM_FRAME, $this->getLevelNonNull(), TileItemFrame::createNBT($this, $face, $item, $player)); return true; diff --git a/src/pocketmine/block/Ladder.php b/src/pocketmine/block/Ladder.php index d2aab6a85..2de51c5ad 100644 --- a/src/pocketmine/block/Ladder.php +++ b/src/pocketmine/block/Ladder.php @@ -100,7 +100,7 @@ class Ladder extends Transparent{ ]; if(isset($faces[$face])){ $this->meta = $faces[$face]; - $this->getLevel()->setBlock($blockReplace, $this, true, true); + $this->getLevelNonNull()->setBlock($blockReplace, $this, true, true); return true; } diff --git a/src/pocketmine/block/Lava.php b/src/pocketmine/block/Lava.php index aa111d28a..086fd6666 100644 --- a/src/pocketmine/block/Lava.php +++ b/src/pocketmine/block/Lava.php @@ -115,8 +115,8 @@ class Lava extends Liquid{ } public function place(Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, Player $player = null) : bool{ - $ret = $this->getLevel()->setBlock($this, $this, true, false); - $this->getLevel()->scheduleDelayedBlockUpdate($this, $this->tickRate()); + $ret = $this->getLevelNonNull()->setBlock($this, $this, true, false); + $this->getLevelNonNull()->scheduleDelayedBlockUpdate($this, $this->tickRate()); return $ret; } diff --git a/src/pocketmine/block/Leaves.php b/src/pocketmine/block/Leaves.php index 788e4a781..6eeb83e49 100644 --- a/src/pocketmine/block/Leaves.php +++ b/src/pocketmine/block/Leaves.php @@ -139,7 +139,7 @@ class Leaves extends Transparent{ public function onNearbyBlockChange() : void{ if(($this->meta & 0b00001100) === 0){ $this->meta |= 0x08; - $this->getLevel()->setBlock($this, $this, true, false); + $this->getLevelNonNull()->setBlock($this, $this, true, false); } } @@ -155,16 +155,16 @@ class Leaves extends Transparent{ $ev = new LeavesDecayEvent($this); $ev->call(); if($ev->isCancelled() or $this->findLog($this, $visited, 0)){ - $this->getLevel()->setBlock($this, $this, false, false); + $this->getLevelNonNull()->setBlock($this, $this, false, false); }else{ - $this->getLevel()->useBreakOn($this); + $this->getLevelNonNull()->useBreakOn($this); } } } public function place(Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, Player $player = null) : bool{ $this->meta |= 0x04; - return $this->getLevel()->setBlock($this, $this, true); + return $this->getLevelNonNull()->setBlock($this, $this, true); } public function getVariantBitmask() : int{ diff --git a/src/pocketmine/block/MelonStem.php b/src/pocketmine/block/MelonStem.php index d8bf91caa..420059529 100644 --- a/src/pocketmine/block/MelonStem.php +++ b/src/pocketmine/block/MelonStem.php @@ -49,7 +49,7 @@ class MelonStem extends Crops{ $ev = new BlockGrowEvent($this, $block); $ev->call(); if(!$ev->isCancelled()){ - $this->getLevel()->setBlock($this, $ev->getNewState(), true); + $this->getLevelNonNull()->setBlock($this, $ev->getNewState(), true); } }else{ for($side = 2; $side <= 5; ++$side){ @@ -64,7 +64,7 @@ class MelonStem extends Crops{ $ev = new BlockGrowEvent($side, BlockFactory::get(Block::MELON_BLOCK)); $ev->call(); if(!$ev->isCancelled()){ - $this->getLevel()->setBlock($side, $ev->getNewState(), true); + $this->getLevelNonNull()->setBlock($side, $ev->getNewState(), true); } } } diff --git a/src/pocketmine/block/Mycelium.php b/src/pocketmine/block/Mycelium.php index edb42d0d1..26b1ea366 100644 --- a/src/pocketmine/block/Mycelium.php +++ b/src/pocketmine/block/Mycelium.php @@ -64,13 +64,13 @@ class Mycelium extends Solid{ $x = mt_rand($this->x - 1, $this->x + 1); $y = mt_rand($this->y - 2, $this->y + 2); $z = mt_rand($this->z - 1, $this->z + 1); - $block = $this->getLevel()->getBlockAt($x, $y, $z); + $block = $this->getLevelNonNull()->getBlockAt($x, $y, $z); if($block->getId() === Block::DIRT){ if($block->getSide(Vector3::SIDE_UP) instanceof Transparent){ $ev = new BlockSpreadEvent($block, $this, BlockFactory::get(Block::MYCELIUM)); $ev->call(); if(!$ev->isCancelled()){ - $this->getLevel()->setBlock($block, $ev->getNewState()); + $this->getLevelNonNull()->setBlock($block, $ev->getNewState()); } } } diff --git a/src/pocketmine/block/NetherWartPlant.php b/src/pocketmine/block/NetherWartPlant.php index 7428730ac..3ab129b57 100644 --- a/src/pocketmine/block/NetherWartPlant.php +++ b/src/pocketmine/block/NetherWartPlant.php @@ -46,7 +46,7 @@ class NetherWartPlant extends Flowable{ public function place(Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, Player $player = null) : bool{ $down = $this->getSide(Vector3::SIDE_DOWN); if($down->getId() === Block::SOUL_SAND){ - $this->getLevel()->setBlock($blockReplace, $this, false, true); + $this->getLevelNonNull()->setBlock($blockReplace, $this, false, true); return true; } @@ -56,7 +56,7 @@ class NetherWartPlant extends Flowable{ public function onNearbyBlockChange() : void{ if($this->getSide(Vector3::SIDE_DOWN)->getId() !== Block::SOUL_SAND){ - $this->getLevel()->useBreakOn($this); + $this->getLevelNonNull()->useBreakOn($this); } } @@ -71,7 +71,7 @@ class NetherWartPlant extends Flowable{ $ev = new BlockGrowEvent($this, $block); $ev->call(); if(!$ev->isCancelled()){ - $this->getLevel()->setBlock($this, $ev->getNewState(), false, true); + $this->getLevelNonNull()->setBlock($this, $ev->getNewState(), false, true); } } } diff --git a/src/pocketmine/block/Pumpkin.php b/src/pocketmine/block/Pumpkin.php index 811dd06e5..e5ce7e4b2 100644 --- a/src/pocketmine/block/Pumpkin.php +++ b/src/pocketmine/block/Pumpkin.php @@ -51,7 +51,7 @@ class Pumpkin extends Solid{ if($player instanceof Player){ $this->meta = ((int) $player->getDirection() + 1) % 4; } - $this->getLevel()->setBlock($blockReplace, $this, true, true); + $this->getLevelNonNull()->setBlock($blockReplace, $this, true, true); return true; } diff --git a/src/pocketmine/block/PumpkinStem.php b/src/pocketmine/block/PumpkinStem.php index 8a6ca57b5..aa06ac367 100644 --- a/src/pocketmine/block/PumpkinStem.php +++ b/src/pocketmine/block/PumpkinStem.php @@ -49,7 +49,7 @@ class PumpkinStem extends Crops{ $ev = new BlockGrowEvent($this, $block); $ev->call(); if(!$ev->isCancelled()){ - $this->getLevel()->setBlock($this, $ev->getNewState(), true); + $this->getLevelNonNull()->setBlock($this, $ev->getNewState(), true); } }else{ for($side = 2; $side <= 5; ++$side){ @@ -64,7 +64,7 @@ class PumpkinStem extends Crops{ $ev = new BlockGrowEvent($side, BlockFactory::get(Block::PUMPKIN)); $ev->call(); if(!$ev->isCancelled()){ - $this->getLevel()->setBlock($side, $ev->getNewState(), true); + $this->getLevelNonNull()->setBlock($side, $ev->getNewState(), true); } } } diff --git a/src/pocketmine/block/Quartz.php b/src/pocketmine/block/Quartz.php index d21c62ecf..bfaaea46f 100644 --- a/src/pocketmine/block/Quartz.php +++ b/src/pocketmine/block/Quartz.php @@ -58,7 +58,7 @@ class Quartz extends Solid{ if($this->getVariant() !== self::NORMAL){ $this->meta = PillarRotationHelper::getMetaFromFace($this->meta, $face); } - return $this->getLevel()->setBlock($blockReplace, $this, true, true); + return $this->getLevelNonNull()->setBlock($blockReplace, $this, true, true); } public function getToolType() : int{ diff --git a/src/pocketmine/block/RedMushroom.php b/src/pocketmine/block/RedMushroom.php index 5c4d5296b..d9d48b62a 100644 --- a/src/pocketmine/block/RedMushroom.php +++ b/src/pocketmine/block/RedMushroom.php @@ -45,14 +45,14 @@ class RedMushroom extends Flowable{ public function onNearbyBlockChange() : void{ if($this->getSide(Vector3::SIDE_DOWN)->isTransparent()){ - $this->getLevel()->useBreakOn($this); + $this->getLevelNonNull()->useBreakOn($this); } } public function place(Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, Player $player = null) : bool{ $down = $this->getSide(Vector3::SIDE_DOWN); if(!$down->isTransparent()){ - $this->getLevel()->setBlock($blockReplace, $this, true, true); + $this->getLevelNonNull()->setBlock($blockReplace, $this, true, true); return true; } diff --git a/src/pocketmine/block/RedstoneOre.php b/src/pocketmine/block/RedstoneOre.php index 0557d0be9..a9fab687c 100644 --- a/src/pocketmine/block/RedstoneOre.php +++ b/src/pocketmine/block/RedstoneOre.php @@ -47,16 +47,16 @@ class RedstoneOre extends Solid{ } public function place(Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, Player $player = null) : bool{ - return $this->getLevel()->setBlock($this, $this, true, false); + return $this->getLevelNonNull()->setBlock($this, $this, true, false); } public function onActivate(Item $item, Player $player = null) : bool{ - $this->getLevel()->setBlock($this, BlockFactory::get(Block::GLOWING_REDSTONE_ORE, $this->meta)); + $this->getLevelNonNull()->setBlock($this, BlockFactory::get(Block::GLOWING_REDSTONE_ORE, $this->meta)); return false; //this shouldn't prevent block placement } public function onNearbyBlockChange() : void{ - $this->getLevel()->setBlock($this, BlockFactory::get(Block::GLOWING_REDSTONE_ORE, $this->meta)); + $this->getLevelNonNull()->setBlock($this, BlockFactory::get(Block::GLOWING_REDSTONE_ORE, $this->meta)); } public function getToolType() : int{ diff --git a/src/pocketmine/block/Sapling.php b/src/pocketmine/block/Sapling.php index 682f2251a..2fdeb3ebf 100644 --- a/src/pocketmine/block/Sapling.php +++ b/src/pocketmine/block/Sapling.php @@ -59,7 +59,7 @@ class Sapling extends Flowable{ public function place(Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, Player $player = null) : bool{ $down = $this->getSide(Vector3::SIDE_DOWN); if($down->getId() === self::GRASS or $down->getId() === self::DIRT or $down->getId() === self::FARMLAND){ - $this->getLevel()->setBlock($blockReplace, $this, true, true); + $this->getLevelNonNull()->setBlock($blockReplace, $this, true, true); return true; } @@ -70,7 +70,7 @@ class Sapling extends Flowable{ public function onActivate(Item $item, Player $player = null) : bool{ if($item->getId() === Item::DYE and $item->getDamage() === 0x0F){ //Bonemeal //TODO: change log type - Tree::growTree($this->getLevel(), $this->x, $this->y, $this->z, new Random(mt_rand()), $this->getVariant()); + Tree::growTree($this->getLevelNonNull(), $this->x, $this->y, $this->z, new Random(mt_rand()), $this->getVariant()); $item->pop(); @@ -82,7 +82,7 @@ class Sapling extends Flowable{ public function onNearbyBlockChange() : void{ if($this->getSide(Vector3::SIDE_DOWN)->isTransparent()){ - $this->getLevel()->useBreakOn($this); + $this->getLevelNonNull()->useBreakOn($this); } } @@ -93,10 +93,10 @@ class Sapling extends Flowable{ public function onRandomTick() : void{ if($this->level->getFullLightAt($this->x, $this->y, $this->z) >= 8 and mt_rand(1, 7) === 1){ if(($this->meta & 0x08) === 0x08){ - Tree::growTree($this->getLevel(), $this->x, $this->y, $this->z, new Random(mt_rand()), $this->getVariant()); + Tree::growTree($this->getLevelNonNull(), $this->x, $this->y, $this->z, new Random(mt_rand()), $this->getVariant()); }else{ $this->meta |= 0x08; - $this->getLevel()->setBlock($this, $this, true); + $this->getLevelNonNull()->setBlock($this, $this, true); } } } diff --git a/src/pocketmine/block/SignPost.php b/src/pocketmine/block/SignPost.php index bba195a22..c63307446 100644 --- a/src/pocketmine/block/SignPost.php +++ b/src/pocketmine/block/SignPost.php @@ -62,13 +62,13 @@ class SignPost extends Transparent{ if($face === Vector3::SIDE_UP){ $this->meta = $player !== null ? (floor((($player->yaw + 180) * 16 / 360) + 0.5) & 0x0f) : 0; - $this->getLevel()->setBlock($blockReplace, $this, true); + $this->getLevelNonNull()->setBlock($blockReplace, $this, true); }else{ $this->meta = $face; - $this->getLevel()->setBlock($blockReplace, BlockFactory::get(Block::WALL_SIGN, $this->meta), true); + $this->getLevelNonNull()->setBlock($blockReplace, BlockFactory::get(Block::WALL_SIGN, $this->meta), true); } - Tile::createTile(Tile::SIGN, $this->getLevel(), TileSign::createNBT($this, $face, $item, $player)); + Tile::createTile(Tile::SIGN, $this->getLevelNonNull(), TileSign::createNBT($this, $face, $item, $player)); return true; } @@ -78,7 +78,7 @@ class SignPost extends Transparent{ public function onNearbyBlockChange() : void{ if($this->getSide(Vector3::SIDE_DOWN)->getId() === self::AIR){ - $this->getLevel()->useBreakOn($this); + $this->getLevelNonNull()->useBreakOn($this); } } diff --git a/src/pocketmine/block/Skull.php b/src/pocketmine/block/Skull.php index 3dfd1b04b..dfeb2f711 100644 --- a/src/pocketmine/block/Skull.php +++ b/src/pocketmine/block/Skull.php @@ -65,8 +65,8 @@ class Skull extends Flowable{ } $this->meta = $face; - $this->getLevel()->setBlock($blockReplace, $this, true); - Tile::createTile(Tile::SKULL, $this->getLevel(), TileSkull::createNBT($this, $face, $item, $player)); + $this->getLevelNonNull()->setBlock($blockReplace, $this, true); + Tile::createTile(Tile::SKULL, $this->getLevelNonNull(), TileSkull::createNBT($this, $face, $item, $player)); return true; } diff --git a/src/pocketmine/block/Slab.php b/src/pocketmine/block/Slab.php index dcfa75923..3657cb1d3 100644 --- a/src/pocketmine/block/Slab.php +++ b/src/pocketmine/block/Slab.php @@ -56,11 +56,11 @@ abstract class Slab extends Transparent{ $this->meta &= 0x07; if($face === Vector3::SIDE_DOWN){ if($blockClicked->getId() === $this->id and ($blockClicked->getDamage() & 0x08) === 0x08 and $blockClicked->getVariant() === $this->getVariant()){ - $this->getLevel()->setBlock($blockClicked, BlockFactory::get($this->getDoubleSlabId(), $this->getVariant()), true); + $this->getLevelNonNull()->setBlock($blockClicked, BlockFactory::get($this->getDoubleSlabId(), $this->getVariant()), true); return true; }elseif($blockReplace->getId() === $this->id and $blockReplace->getVariant() === $this->getVariant()){ - $this->getLevel()->setBlock($blockReplace, BlockFactory::get($this->getDoubleSlabId(), $this->getVariant()), true); + $this->getLevelNonNull()->setBlock($blockReplace, BlockFactory::get($this->getDoubleSlabId(), $this->getVariant()), true); return true; }else{ @@ -68,18 +68,18 @@ abstract class Slab extends Transparent{ } }elseif($face === Vector3::SIDE_UP){ if($blockClicked->getId() === $this->id and ($blockClicked->getDamage() & 0x08) === 0 and $blockClicked->getVariant() === $this->getVariant()){ - $this->getLevel()->setBlock($blockClicked, BlockFactory::get($this->getDoubleSlabId(), $this->getVariant()), true); + $this->getLevelNonNull()->setBlock($blockClicked, BlockFactory::get($this->getDoubleSlabId(), $this->getVariant()), true); return true; }elseif($blockReplace->getId() === $this->id and $blockReplace->getVariant() === $this->getVariant()){ - $this->getLevel()->setBlock($blockReplace, BlockFactory::get($this->getDoubleSlabId(), $this->getVariant()), true); + $this->getLevelNonNull()->setBlock($blockReplace, BlockFactory::get($this->getDoubleSlabId(), $this->getVariant()), true); return true; } }else{ //TODO: collision if($blockReplace->getId() === $this->id){ if($blockReplace->getVariant() === $this->getVariant()){ - $this->getLevel()->setBlock($blockReplace, BlockFactory::get($this->getDoubleSlabId(), $this->getVariant()), true); + $this->getLevelNonNull()->setBlock($blockReplace, BlockFactory::get($this->getDoubleSlabId(), $this->getVariant()), true); return true; } @@ -95,7 +95,7 @@ abstract class Slab extends Transparent{ if($blockReplace->getId() === $this->id and $blockClicked->getVariant() !== $this->getVariant()){ return false; } - $this->getLevel()->setBlock($blockReplace, $this, true, true); + $this->getLevelNonNull()->setBlock($blockReplace, $this, true, true); return true; } diff --git a/src/pocketmine/block/SnowLayer.php b/src/pocketmine/block/SnowLayer.php index ab8168e82..21453ab9f 100644 --- a/src/pocketmine/block/SnowLayer.php +++ b/src/pocketmine/block/SnowLayer.php @@ -60,7 +60,7 @@ class SnowLayer extends Flowable{ public function place(Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, Player $player = null) : bool{ if($blockReplace->getSide(Vector3::SIDE_DOWN)->isSolid()){ //TODO: fix placement - $this->getLevel()->setBlock($blockReplace, $this, true); + $this->getLevelNonNull()->setBlock($blockReplace, $this, true); return true; } @@ -70,7 +70,7 @@ class SnowLayer extends Flowable{ public function onNearbyBlockChange() : void{ if(!$this->getSide(Vector3::SIDE_DOWN)->isSolid()){ - $this->getLevel()->setBlock($this, BlockFactory::get(Block::AIR), false, false); + $this->getLevelNonNull()->setBlock($this, BlockFactory::get(Block::AIR), false, false); } } @@ -80,7 +80,7 @@ class SnowLayer extends Flowable{ public function onRandomTick() : void{ if($this->level->getBlockLightAt($this->x, $this->y, $this->z) >= 12){ - $this->getLevel()->setBlock($this, BlockFactory::get(Block::AIR), false, false); + $this->getLevelNonNull()->setBlock($this, BlockFactory::get(Block::AIR), false, false); } } diff --git a/src/pocketmine/block/Stair.php b/src/pocketmine/block/Stair.php index cf9328aac..352bacd82 100644 --- a/src/pocketmine/block/Stair.php +++ b/src/pocketmine/block/Stair.php @@ -93,7 +93,7 @@ abstract class Stair extends Transparent{ if(($clickVector->y > 0.5 and $face !== Vector3::SIDE_UP) or $face === Vector3::SIDE_DOWN){ $this->meta |= 0x04; //Upside-down stairs } - $this->getLevel()->setBlock($blockReplace, $this, true, true); + $this->getLevelNonNull()->setBlock($blockReplace, $this, true, true); return true; } diff --git a/src/pocketmine/block/StandingBanner.php b/src/pocketmine/block/StandingBanner.php index bc8c9012c..090f5c83a 100644 --- a/src/pocketmine/block/StandingBanner.php +++ b/src/pocketmine/block/StandingBanner.php @@ -62,13 +62,13 @@ class StandingBanner extends Transparent{ if($face !== Vector3::SIDE_DOWN){ if($face === Vector3::SIDE_UP and $player !== null){ $this->meta = floor((($player->yaw + 180) * 16 / 360) + 0.5) & 0x0f; - $this->getLevel()->setBlock($blockReplace, $this, true); + $this->getLevelNonNull()->setBlock($blockReplace, $this, true); }else{ $this->meta = $face; - $this->getLevel()->setBlock($blockReplace, BlockFactory::get(Block::WALL_BANNER, $this->meta), true); + $this->getLevelNonNull()->setBlock($blockReplace, BlockFactory::get(Block::WALL_BANNER, $this->meta), true); } - Tile::createTile(Tile::BANNER, $this->getLevel(), TileBanner::createNBT($this, $face, $item, $player)); + Tile::createTile(Tile::BANNER, $this->getLevelNonNull(), TileBanner::createNBT($this, $face, $item, $player)); return true; } @@ -77,7 +77,7 @@ class StandingBanner extends Transparent{ public function onNearbyBlockChange() : void{ if($this->getSide(Vector3::SIDE_DOWN)->getId() === self::AIR){ - $this->getLevel()->useBreakOn($this); + $this->getLevelNonNull()->useBreakOn($this); } } diff --git a/src/pocketmine/block/Sugarcane.php b/src/pocketmine/block/Sugarcane.php index ad4e95aff..cdda01f8e 100644 --- a/src/pocketmine/block/Sugarcane.php +++ b/src/pocketmine/block/Sugarcane.php @@ -46,20 +46,20 @@ class Sugarcane extends Flowable{ if($item->getId() === Item::DYE and $item->getDamage() === 0x0F){ //Bonemeal if($this->getSide(Vector3::SIDE_DOWN)->getId() !== self::SUGARCANE_BLOCK){ for($y = 1; $y < 3; ++$y){ - $b = $this->getLevel()->getBlockAt($this->x, $this->y + $y, $this->z); + $b = $this->getLevelNonNull()->getBlockAt($this->x, $this->y + $y, $this->z); if($b->getId() === self::AIR){ $ev = new BlockGrowEvent($b, BlockFactory::get(Block::SUGARCANE_BLOCK)); $ev->call(); if($ev->isCancelled()){ break; } - $this->getLevel()->setBlock($b, $ev->getNewState(), true); + $this->getLevelNonNull()->setBlock($b, $ev->getNewState(), true); }else{ break; } } $this->meta = 0; - $this->getLevel()->setBlock($this, $this, true); + $this->getLevelNonNull()->setBlock($this, $this, true); } $item->pop(); @@ -73,7 +73,7 @@ class Sugarcane extends Flowable{ public function onNearbyBlockChange() : void{ $down = $this->getSide(Vector3::SIDE_DOWN); if($down->isTransparent() and $down->getId() !== self::SUGARCANE_BLOCK){ - $this->getLevel()->useBreakOn($this); + $this->getLevelNonNull()->useBreakOn($this); } } @@ -85,17 +85,17 @@ class Sugarcane extends Flowable{ if($this->getSide(Vector3::SIDE_DOWN)->getId() !== self::SUGARCANE_BLOCK){ if($this->meta === 0x0F){ for($y = 1; $y < 3; ++$y){ - $b = $this->getLevel()->getBlockAt($this->x, $this->y + $y, $this->z); + $b = $this->getLevelNonNull()->getBlockAt($this->x, $this->y + $y, $this->z); if($b->getId() === self::AIR){ - $this->getLevel()->setBlock($b, BlockFactory::get(Block::SUGARCANE_BLOCK), true); + $this->getLevelNonNull()->setBlock($b, BlockFactory::get(Block::SUGARCANE_BLOCK), true); break; } } $this->meta = 0; - $this->getLevel()->setBlock($this, $this, true); + $this->getLevelNonNull()->setBlock($this, $this, true); }else{ ++$this->meta; - $this->getLevel()->setBlock($this, $this, true); + $this->getLevelNonNull()->setBlock($this, $this, true); } } } @@ -103,7 +103,7 @@ class Sugarcane extends Flowable{ public function place(Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, Player $player = null) : bool{ $down = $this->getSide(Vector3::SIDE_DOWN); if($down->getId() === self::SUGARCANE_BLOCK){ - $this->getLevel()->setBlock($blockReplace, BlockFactory::get(Block::SUGARCANE_BLOCK), true); + $this->getLevelNonNull()->setBlock($blockReplace, BlockFactory::get(Block::SUGARCANE_BLOCK), true); return true; }elseif($down->getId() === self::GRASS or $down->getId() === self::DIRT or $down->getId() === self::SAND){ @@ -112,7 +112,7 @@ class Sugarcane extends Flowable{ $block2 = $down->getSide(Vector3::SIDE_WEST); $block3 = $down->getSide(Vector3::SIDE_EAST); if(($block0 instanceof Water) or ($block1 instanceof Water) or ($block2 instanceof Water) or ($block3 instanceof Water)){ - $this->getLevel()->setBlock($blockReplace, BlockFactory::get(Block::SUGARCANE_BLOCK), true); + $this->getLevelNonNull()->setBlock($blockReplace, BlockFactory::get(Block::SUGARCANE_BLOCK), true); return true; } diff --git a/src/pocketmine/block/TNT.php b/src/pocketmine/block/TNT.php index 44cfb6fbc..6c5f8252f 100644 --- a/src/pocketmine/block/TNT.php +++ b/src/pocketmine/block/TNT.php @@ -78,13 +78,13 @@ class TNT extends Solid{ * @return void */ public function ignite(int $fuse = 80){ - $this->getLevel()->setBlock($this, BlockFactory::get(Block::AIR), true); + $this->getLevelNonNull()->setBlock($this, BlockFactory::get(Block::AIR), true); $mot = (new Random())->nextSignedFloat() * M_PI * 2; $nbt = Entity::createBaseNBT($this->add(0.5, 0, 0.5), new Vector3(-sin($mot) * 0.02, 0.2, -cos($mot) * 0.02)); $nbt->setShort("Fuse", $fuse); - $tnt = Entity::createEntity("PrimedTNT", $this->getLevel(), $nbt); + $tnt = Entity::createEntity("PrimedTNT", $this->getLevelNonNull(), $nbt); if($tnt !== null){ $tnt->spawnToAll(); diff --git a/src/pocketmine/block/TallGrass.php b/src/pocketmine/block/TallGrass.php index 7bcd619fa..a072cfcba 100644 --- a/src/pocketmine/block/TallGrass.php +++ b/src/pocketmine/block/TallGrass.php @@ -53,7 +53,7 @@ class TallGrass extends Flowable{ public function place(Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, Player $player = null) : bool{ $down = $this->getSide(Vector3::SIDE_DOWN)->getId(); if($down === self::GRASS or $down === self::DIRT){ - $this->getLevel()->setBlock($blockReplace, $this, true); + $this->getLevelNonNull()->setBlock($blockReplace, $this, true); return true; } @@ -63,7 +63,7 @@ class TallGrass extends Flowable{ public function onNearbyBlockChange() : void{ if($this->getSide(Vector3::SIDE_DOWN)->isTransparent()){ //Replace with common break method - $this->getLevel()->setBlock($this, BlockFactory::get(Block::AIR), true, true); + $this->getLevelNonNull()->setBlock($this, BlockFactory::get(Block::AIR), true, true); } } diff --git a/src/pocketmine/block/Torch.php b/src/pocketmine/block/Torch.php index e88767cfd..d95f3b119 100644 --- a/src/pocketmine/block/Torch.php +++ b/src/pocketmine/block/Torch.php @@ -57,7 +57,7 @@ class Torch extends Flowable{ $face = $faces[$meta] ?? Vector3::SIDE_DOWN; if($this->getSide($face)->isTransparent() and !($face === Vector3::SIDE_DOWN and ($below->getId() === self::FENCE or $below->getId() === self::COBBLESTONE_WALL))){ - $this->getLevel()->useBreakOn($this); + $this->getLevelNonNull()->useBreakOn($this); } } @@ -73,12 +73,12 @@ class Torch extends Flowable{ Vector3::SIDE_EAST => 1 ]; $this->meta = $faces[$face]; - $this->getLevel()->setBlock($blockReplace, $this, true, true); + $this->getLevelNonNull()->setBlock($blockReplace, $this, true, true); return true; }elseif(!$below->isTransparent() or $below->getId() === self::FENCE or $below->getId() === self::COBBLESTONE_WALL){ $this->meta = 0; - $this->getLevel()->setBlock($blockReplace, $this, true, true); + $this->getLevelNonNull()->setBlock($blockReplace, $this, true, true); return true; } diff --git a/src/pocketmine/block/Trapdoor.php b/src/pocketmine/block/Trapdoor.php index 25c747cbd..0cbbd1564 100644 --- a/src/pocketmine/block/Trapdoor.php +++ b/src/pocketmine/block/Trapdoor.php @@ -136,7 +136,7 @@ class Trapdoor extends Transparent{ if(($clickVector->y > 0.5 and $face !== self::SIDE_UP) or $face === self::SIDE_DOWN){ $this->meta |= self::MASK_UPPER; //top half of block } - $this->getLevel()->setBlock($blockReplace, $this, true, true); + $this->getLevelNonNull()->setBlock($blockReplace, $this, true, true); return true; } @@ -146,7 +146,7 @@ class Trapdoor extends Transparent{ public function onActivate(Item $item, Player $player = null) : bool{ $this->meta ^= self::MASK_OPENED; - $this->getLevel()->setBlock($this, $this, true); + $this->getLevelNonNull()->setBlock($this, $this, true); $this->level->addSound(new DoorSound($this)); return true; } diff --git a/src/pocketmine/block/Vine.php b/src/pocketmine/block/Vine.php index dadc7a329..5473fd247 100644 --- a/src/pocketmine/block/Vine.php +++ b/src/pocketmine/block/Vine.php @@ -150,7 +150,7 @@ class Vine extends Flowable{ $this->meta |= $blockReplace->meta; } - $this->getLevel()->setBlock($blockReplace, $this, true, true); + $this->getLevelNonNull()->setBlock($blockReplace, $this, true, true); return true; } diff --git a/src/pocketmine/block/WallBanner.php b/src/pocketmine/block/WallBanner.php index a0a16ea44..90a9b0271 100644 --- a/src/pocketmine/block/WallBanner.php +++ b/src/pocketmine/block/WallBanner.php @@ -33,7 +33,7 @@ class WallBanner extends StandingBanner{ public function onNearbyBlockChange() : void{ if($this->getSide($this->meta ^ 0x01)->getId() === self::AIR){ - $this->getLevel()->useBreakOn($this); + $this->getLevelNonNull()->useBreakOn($this); } } } diff --git a/src/pocketmine/block/WallSign.php b/src/pocketmine/block/WallSign.php index 58b0d8a82..9714ad5eb 100644 --- a/src/pocketmine/block/WallSign.php +++ b/src/pocketmine/block/WallSign.php @@ -33,7 +33,7 @@ class WallSign extends SignPost{ public function onNearbyBlockChange() : void{ if($this->getSide($this->meta ^ 0x01)->getId() === self::AIR){ - $this->getLevel()->useBreakOn($this); + $this->getLevelNonNull()->useBreakOn($this); } } } diff --git a/src/pocketmine/block/Water.php b/src/pocketmine/block/Water.php index 8f490c4aa..b893ba9b2 100644 --- a/src/pocketmine/block/Water.php +++ b/src/pocketmine/block/Water.php @@ -75,8 +75,8 @@ class Water extends Liquid{ } public function place(Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, Player $player = null) : bool{ - $ret = $this->getLevel()->setBlock($this, $this, true, false); - $this->getLevel()->scheduleDelayedBlockUpdate($this, $this->tickRate()); + $ret = $this->getLevelNonNull()->setBlock($this, $this, true, false); + $this->getLevelNonNull()->scheduleDelayedBlockUpdate($this, $this->tickRate()); return $ret; } diff --git a/src/pocketmine/block/WaterLily.php b/src/pocketmine/block/WaterLily.php index 8d4ebc7cf..ea9010fc2 100644 --- a/src/pocketmine/block/WaterLily.php +++ b/src/pocketmine/block/WaterLily.php @@ -59,7 +59,7 @@ class WaterLily extends Flowable{ if($blockClicked instanceof Water){ $up = $blockClicked->getSide(Vector3::SIDE_UP); if($up->getId() === Block::AIR){ - $this->getLevel()->setBlock($up, $this, true, true); + $this->getLevelNonNull()->setBlock($up, $this, true, true); return true; } } @@ -69,7 +69,7 @@ class WaterLily extends Flowable{ public function onNearbyBlockChange() : void{ if(!($this->getSide(Vector3::SIDE_DOWN) instanceof Water)){ - $this->getLevel()->useBreakOn($this); + $this->getLevelNonNull()->useBreakOn($this); } } diff --git a/src/pocketmine/block/Wood.php b/src/pocketmine/block/Wood.php index 2c309aed6..707256c6e 100644 --- a/src/pocketmine/block/Wood.php +++ b/src/pocketmine/block/Wood.php @@ -56,7 +56,7 @@ class Wood extends Solid{ public function place(Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, Player $player = null) : bool{ $this->meta = PillarRotationHelper::getMetaFromFace($this->meta, $face); - return $this->getLevel()->setBlock($blockReplace, $this, true, true); + return $this->getLevelNonNull()->setBlock($blockReplace, $this, true, true); } public function getVariantBitmask() : int{ diff --git a/src/pocketmine/entity/Entity.php b/src/pocketmine/entity/Entity.php index 8838433ba..d1bdb9e98 100644 --- a/src/pocketmine/entity/Entity.php +++ b/src/pocketmine/entity/Entity.php @@ -1743,7 +1743,7 @@ abstract class Entity extends Location implements Metadatable, EntityIds{ } if($pos instanceof Position and $pos->level !== null and $pos->level !== $this->level){ - if(!$this->switchLevel($pos->getLevel())){ + if(!$this->switchLevel($pos->getLevelNonNull())){ return false; } } @@ -1849,7 +1849,7 @@ abstract class Entity extends Location implements Metadatable, EntityIds{ $pitch = $pitch ?? $pos->pitch; } $from = Position::fromObject($this, $this->level); - $to = Position::fromObject($pos, $pos instanceof Position ? $pos->getLevel() : $this->level); + $to = Position::fromObject($pos, $pos instanceof Position ? $pos->getLevelNonNull() : $this->level); $ev = new EntityTeleportEvent($this, $from, $to); $ev->call(); if($ev->isCancelled()){ diff --git a/src/pocketmine/entity/Living.php b/src/pocketmine/entity/Living.php index 9d9f0e1b8..79e4cfabc 100644 --- a/src/pocketmine/entity/Living.php +++ b/src/pocketmine/entity/Living.php @@ -191,7 +191,7 @@ abstract class Living extends Entity implements Damageable{ public function hasLineOfSight(Entity $entity) : bool{ //TODO: head height return true; - //return $this->getLevel()->rayTraceBlocks(Vector3::createVector($this->x, $this->y + $this->height, $this->z), Vector3::createVector($entity->x, $entity->y + $entity->height, $entity->z)) === null; + //return $this->getLevelNonNull()->rayTraceBlocks(Vector3::createVector($this->x, $this->y + $this->height, $this->z), Vector3::createVector($entity->x, $entity->y + $entity->height, $entity->z)) === null; } /** @@ -615,7 +615,7 @@ abstract class Living extends Entity implements Damageable{ $ev = new EntityDeathEvent($this, $this->getDrops(), $this->getXpDropAmount()); $ev->call(); foreach($ev->getDrops() as $item){ - $this->getLevel()->dropItem($this, $item); + $this->getLevelNonNull()->dropItem($this, $item); } //TODO: check death conditions (must have been damaged by player < 5 seconds from death) diff --git a/src/pocketmine/entity/object/FallingBlock.php b/src/pocketmine/entity/object/FallingBlock.php index c96723a61..c44d25d98 100644 --- a/src/pocketmine/entity/object/FallingBlock.php +++ b/src/pocketmine/entity/object/FallingBlock.php @@ -98,7 +98,7 @@ class FallingBlock extends Entity{ $hasUpdate = parent::entityBaseTick($tickDiff); if(!$this->isFlaggedForDespawn()){ - $pos = Position::fromObject($this->add(-$this->width / 2, $this->height, -$this->width / 2)->floor(), $this->getLevel()); + $pos = Position::fromObject($this->add(-$this->width / 2, $this->height, -$this->width / 2)->floor(), $this->getLevelNonNull()); $this->block->position($pos); @@ -113,12 +113,12 @@ class FallingBlock extends Entity{ $block = $this->level->getBlock($pos); if(($block->isTransparent() and !$block->canBeReplaced()) or ($this->onGround and abs($this->y - $this->getFloorY()) > 0.001)){ //FIXME: anvils are supposed to destroy torches - $this->getLevel()->dropItem($this, ItemFactory::get($this->getBlock(), $this->getDamage())); + $this->getLevelNonNull()->dropItem($this, ItemFactory::get($this->getBlock(), $this->getDamage())); }else{ $ev = new EntityBlockChangeEvent($this, $block, $blockTarget ?? $this->block); $ev->call(); if(!$ev->isCancelled()){ - $this->getLevel()->setBlock($pos, $ev->getTo(), true); + $this->getLevelNonNull()->setBlock($pos, $ev->getTo(), true); } } $hasUpdate = true; diff --git a/src/pocketmine/event/entity/EntityDamageByChildEntityEvent.php b/src/pocketmine/event/entity/EntityDamageByChildEntityEvent.php index 764d844da..1ad1e5b0e 100644 --- a/src/pocketmine/event/entity/EntityDamageByChildEntityEvent.php +++ b/src/pocketmine/event/entity/EntityDamageByChildEntityEvent.php @@ -44,6 +44,6 @@ class EntityDamageByChildEntityEvent extends EntityDamageByEntityEvent{ * Returns the entity which caused the damage, or null if the entity has been killed or closed. */ public function getChild() : ?Entity{ - return $this->getEntity()->getLevel()->getServer()->findEntity($this->childEntityEid); + return $this->getEntity()->getLevelNonNull()->getServer()->findEntity($this->childEntityEid); } } diff --git a/src/pocketmine/event/entity/EntityDamageByEntityEvent.php b/src/pocketmine/event/entity/EntityDamageByEntityEvent.php index 3bef428ad..28241e6d2 100644 --- a/src/pocketmine/event/entity/EntityDamageByEntityEvent.php +++ b/src/pocketmine/event/entity/EntityDamageByEntityEvent.php @@ -62,7 +62,7 @@ class EntityDamageByEntityEvent extends EntityDamageEvent{ * Returns the attacking entity, or null if the attacker has been killed or closed. */ public function getDamager() : ?Entity{ - return $this->getEntity()->getLevel()->getServer()->findEntity($this->damagerEntityId); + return $this->getEntity()->getLevelNonNull()->getServer()->findEntity($this->damagerEntityId); } public function getKnockBack() : float{ diff --git a/src/pocketmine/inventory/ChestInventory.php b/src/pocketmine/inventory/ChestInventory.php index b7cd3765e..0f45ef431 100644 --- a/src/pocketmine/inventory/ChestInventory.php +++ b/src/pocketmine/inventory/ChestInventory.php @@ -74,7 +74,7 @@ class ChestInventory extends ContainerInventory{ if(count($this->getViewers()) === 1 and $this->getHolder()->isValid()){ //TODO: this crap really shouldn't be managed by the inventory $this->broadcastBlockEventPacket(true); - $this->getHolder()->getLevel()->broadcastLevelSoundEvent($this->getHolder()->add(0.5, 0.5, 0.5), $this->getOpenSound()); + $this->getHolder()->getLevelNonNull()->broadcastLevelSoundEvent($this->getHolder()->add(0.5, 0.5, 0.5), $this->getOpenSound()); } } @@ -82,7 +82,7 @@ class ChestInventory extends ContainerInventory{ if(count($this->getViewers()) === 1 and $this->getHolder()->isValid()){ //TODO: this crap really shouldn't be managed by the inventory $this->broadcastBlockEventPacket(false); - $this->getHolder()->getLevel()->broadcastLevelSoundEvent($this->getHolder()->add(0.5, 0.5, 0.5), $this->getCloseSound()); + $this->getHolder()->getLevelNonNull()->broadcastLevelSoundEvent($this->getHolder()->add(0.5, 0.5, 0.5), $this->getCloseSound()); } parent::onClose($who); } @@ -96,6 +96,6 @@ class ChestInventory extends ContainerInventory{ $pk->z = (int) $holder->z; $pk->eventType = 1; //it's always 1 for a chest $pk->eventData = $isOpen ? 1 : 0; - $holder->getLevel()->broadcastPacketToViewers($holder, $pk); + $holder->getLevelNonNull()->broadcastPacketToViewers($holder, $pk); } } diff --git a/src/pocketmine/inventory/EnderChestInventory.php b/src/pocketmine/inventory/EnderChestInventory.php index 5203a589e..6c8a7c6ce 100644 --- a/src/pocketmine/inventory/EnderChestInventory.php +++ b/src/pocketmine/inventory/EnderChestInventory.php @@ -56,7 +56,7 @@ class EnderChestInventory extends ChestInventory{ */ public function setHolderPosition(EnderChest $enderChest){ $this->holder->setComponents($enderChest->getFloorX(), $enderChest->getFloorY(), $enderChest->getFloorZ()); - $this->holder->setLevel($enderChest->getLevel()); + $this->holder->setLevel($enderChest->getLevelNonNull()); } protected function getOpenSound() : int{ diff --git a/src/pocketmine/inventory/PlayerInventory.php b/src/pocketmine/inventory/PlayerInventory.php index 4fa1ebed7..7d7d159c6 100644 --- a/src/pocketmine/inventory/PlayerInventory.php +++ b/src/pocketmine/inventory/PlayerInventory.php @@ -173,7 +173,7 @@ class PlayerInventory extends BaseInventory{ $this->sendSlot($this->getHeldItemIndex(), $target); } }else{ - $this->getHolder()->getLevel()->getServer()->broadcastPacket($target, $pk); + $this->getHolder()->getLevelNonNull()->getServer()->broadcastPacket($target, $pk); if(in_array($this->getHolder(), $target, true)){ $this->sendSlot($this->getHeldItemIndex(), $this->getHolder()); } diff --git a/src/pocketmine/item/ChorusFruit.php b/src/pocketmine/item/ChorusFruit.php index f6744a167..d66192aa8 100644 --- a/src/pocketmine/item/ChorusFruit.php +++ b/src/pocketmine/item/ChorusFruit.php @@ -50,11 +50,10 @@ class ChorusFruit extends Food{ } public function onConsume(Living $consumer){ - $level = $consumer->getLevel(); - assert($level !== null); + $level = $consumer->getLevelNonNull(); $minX = $consumer->getFloorX() - 8; - $minY = min($consumer->getFloorY(), $consumer->getLevel()->getWorldHeight()) - 8; + $minY = min($consumer->getFloorY(), $consumer->getLevelNonNull()->getWorldHeight()) - 8; $minZ = $consumer->getFloorZ() - 8; $maxX = $minX + 16; diff --git a/src/pocketmine/item/PaintingItem.php b/src/pocketmine/item/PaintingItem.php index 115dba494..208e0d7d2 100644 --- a/src/pocketmine/item/PaintingItem.php +++ b/src/pocketmine/item/PaintingItem.php @@ -93,7 +93,7 @@ class PaintingItem extends Item{ $nbt->setInt("TileY", $blockClicked->getFloorY()); $nbt->setInt("TileZ", $blockClicked->getFloorZ()); - $entity = Entity::createEntity("Painting", $blockReplace->getLevel(), $nbt); + $entity = Entity::createEntity("Painting", $blockReplace->getLevelNonNull(), $nbt); if($entity instanceof Entity){ $this->pop(); diff --git a/src/pocketmine/level/Explosion.php b/src/pocketmine/level/Explosion.php index 4af974365..72101a075 100644 --- a/src/pocketmine/level/Explosion.php +++ b/src/pocketmine/level/Explosion.php @@ -74,7 +74,7 @@ class Explosion{ throw new \InvalidArgumentException("Position does not have a valid world"); } $this->source = $center; - $this->level = $center->getLevel(); + $this->level = $center->getLevelNonNull(); if($size <= 0){ throw new \InvalidArgumentException("Explosion radius must be greater than 0, got $size"); diff --git a/src/pocketmine/level/Location.php b/src/pocketmine/level/Location.php index a3394e31a..15362ac3e 100644 --- a/src/pocketmine/level/Location.php +++ b/src/pocketmine/level/Location.php @@ -75,7 +75,7 @@ class Location extends Position{ } public function __toString(){ - return "Location (level=" . ($this->isValid() ? $this->getLevel()->getName() : "null") . ", x=$this->x, y=$this->y, z=$this->z, yaw=$this->yaw, pitch=$this->pitch)"; + return "Location (level=" . ($this->isValid() ? $this->getLevelNonNull()->getName() : "null") . ", x=$this->x, y=$this->y, z=$this->z, yaw=$this->yaw, pitch=$this->pitch)"; } public function equals(Vector3 $v) : bool{ diff --git a/src/pocketmine/level/Position.php b/src/pocketmine/level/Position.php index 19e4fcdb5..29832f54d 100644 --- a/src/pocketmine/level/Position.php +++ b/src/pocketmine/level/Position.php @@ -25,6 +25,7 @@ namespace pocketmine\level; use pocketmine\math\Vector3; use pocketmine\utils\MainLogger; +use pocketmine\utils\AssumptionFailedError; use function assert; class Position extends Vector3{ @@ -71,6 +72,19 @@ class Position extends Vector3{ return $this->level; } + /** + * Returns the position's world if valid. Throws an error if the world is unexpectedly null. + * + * @throws AssumptionFailedError + */ + public function getLevelNonNull() : Level{ + $world = $this->getLevel(); + if($world === null){ + throw new AssumptionFailedError("Position world is null"); + } + return $world; + } + /** * Sets the target Level of the position. * @@ -112,7 +126,7 @@ class Position extends Vector3{ } public function __toString(){ - return "Position(level=" . ($this->isValid() ? $this->getLevel()->getName() : "null") . ",x=" . $this->x . ",y=" . $this->y . ",z=" . $this->z . ")"; + return "Position(level=" . ($this->isValid() ? $this->getLevelNonNull()->getName() : "null") . ",x=" . $this->x . ",y=" . $this->y . ",z=" . $this->z . ")"; } public function equals(Vector3 $v) : bool{ diff --git a/src/pocketmine/tile/Chest.php b/src/pocketmine/tile/Chest.php index 8066d69d9..41468fb1c 100644 --- a/src/pocketmine/tile/Chest.php +++ b/src/pocketmine/tile/Chest.php @@ -121,7 +121,7 @@ class Chest extends Spawnable implements InventoryHolder, Container, Nameable{ * @return void */ protected function checkPairing(){ - if($this->isPaired() and !$this->getLevel()->isInLoadedTerrain(new Vector3($this->pairX, $this->y, $this->pairZ))){ + if($this->isPaired() and !$this->getLevelNonNull()->isInLoadedTerrain(new Vector3($this->pairX, $this->y, $this->pairZ))){ //paired to a tile in an unloaded chunk $this->doubleInventory = null; @@ -160,7 +160,7 @@ class Chest extends Spawnable implements InventoryHolder, Container, Nameable{ public function getPair() : ?Chest{ if($this->isPaired()){ - $tile = $this->getLevel()->getTileAt($this->pairX, $this->y, $this->pairZ); + $tile = $this->getLevelNonNull()->getTileAt($this->pairX, $this->y, $this->pairZ); if($tile instanceof Chest){ return $tile; } diff --git a/src/pocketmine/tile/Furnace.php b/src/pocketmine/tile/Furnace.php index 984141c7a..920b93249 100644 --- a/src/pocketmine/tile/Furnace.php +++ b/src/pocketmine/tile/Furnace.php @@ -148,7 +148,7 @@ class Furnace extends Spawnable implements InventoryHolder, Container, Nameable{ $this->maxTime = $this->burnTime = $ev->getBurnTime(); if($this->getBlock()->getId() === Block::FURNACE){ - $this->getLevel()->setBlock($this, BlockFactory::get(Block::BURNING_FURNACE, $this->getBlock()->getDamage()), true); + $this->getLevelNonNull()->setBlock($this, BlockFactory::get(Block::BURNING_FURNACE, $this->getBlock()->getDamage()), true); } if($this->burnTime > 0 and $ev->isBurning()){ @@ -211,7 +211,7 @@ class Furnace extends Spawnable implements InventoryHolder, Container, Nameable{ $ret = true; }else{ if($this->getBlock()->getId() === Block::BURNING_FURNACE){ - $this->getLevel()->setBlock($this, BlockFactory::get(Block::FURNACE, $this->getBlock()->getDamage()), true); + $this->getLevelNonNull()->setBlock($this, BlockFactory::get(Block::FURNACE, $this->getBlock()->getDamage()), true); } $this->burnTime = $this->cookTime = $this->maxTime = 0; } diff --git a/src/pocketmine/tile/Tile.php b/src/pocketmine/tile/Tile.php index ac044a840..6ade66bb9 100644 --- a/src/pocketmine/tile/Tile.php +++ b/src/pocketmine/tile/Tile.php @@ -168,7 +168,7 @@ abstract class Tile extends Position{ parent::__construct($nbt->getInt(self::TAG_X), $nbt->getInt(self::TAG_Y), $nbt->getInt(self::TAG_Z), $level); $this->readSaveData($nbt); - $this->getLevel()->addTile($this); + $this->getLevelNonNull()->addTile($this); } public function getId() : int{ diff --git a/src/pocketmine/utils/AssumptionFailedError.php b/src/pocketmine/utils/AssumptionFailedError.php new file mode 100644 index 000000000..df7d2d464 --- /dev/null +++ b/src/pocketmine/utils/AssumptionFailedError.php @@ -0,0 +1,33 @@ + Date: Wed, 15 Apr 2020 09:32:48 +0100 Subject: [PATCH 35/90] Player: allow provision of a custom cooldown duration for items this would be more useful to plugins, so that it's not necessary to extend any item classes for this trivial purpose. --- src/pocketmine/Player.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/pocketmine/Player.php b/src/pocketmine/Player.php index ff3c62bd0..b1b0cbf2a 100644 --- a/src/pocketmine/Player.php +++ b/src/pocketmine/Player.php @@ -902,8 +902,8 @@ class Player extends Human implements CommandSender, ChunkLoader, IPlayer{ /** * Resets the player's cooldown time for the given item back to the maximum. */ - public function resetItemCooldown(Item $item) : void{ - $ticks = $item->getCooldownTicks(); + public function resetItemCooldown(Item $item, ?int $ticks = null) : void{ + $ticks = $ticks ?? $item->getCooldownTicks(); if($ticks > 0){ $this->usedItemsCooldown[$item->getId()] = $this->server->getTick() + $ticks; } From 53dbbd5f97876b3bc9f64841917a55552d3e76b3 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Wed, 15 Apr 2020 09:37:17 +0100 Subject: [PATCH 36/90] Internet: account for socket_create() maybe failing in getInternalIP() --- src/pocketmine/utils/Internet.php | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/pocketmine/utils/Internet.php b/src/pocketmine/utils/Internet.php index 9b85f0eff..1f93e2f43 100644 --- a/src/pocketmine/utils/Internet.php +++ b/src/pocketmine/utils/Internet.php @@ -116,7 +116,10 @@ class Internet{ * @throws InternetException */ public static function getInternalIP() : string{ - $sock = socket_create(AF_INET, SOCK_DGRAM, SOL_UDP); + $sock = @socket_create(AF_INET, SOCK_DGRAM, SOL_UDP); + if($sock === false){ + throw new InternetException("Failed to get internal IP: " . trim(socket_strerror(socket_last_error()))); + } try{ if(!@socket_connect($sock, "8.8.8.8", 65534)){ throw new InternetException("Failed to get internal IP: " . trim(socket_strerror(socket_last_error($sock)))); From cb6b59a52ab02cc330748b57798b0ae5650d9a24 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Wed, 15 Apr 2020 09:38:39 +0100 Subject: [PATCH 37/90] Internet: curl_init() may return false on error (unclear on reasons) --- src/pocketmine/utils/Internet.php | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/pocketmine/utils/Internet.php b/src/pocketmine/utils/Internet.php index 1f93e2f43..2194399f6 100644 --- a/src/pocketmine/utils/Internet.php +++ b/src/pocketmine/utils/Internet.php @@ -208,6 +208,9 @@ class Internet{ } $ch = curl_init($page); + if($ch === false){ + throw new InternetException("Unable to create new cURL session"); + } curl_setopt_array($ch, $extraOpts + [ CURLOPT_SSL_VERIFYPEER => false, From e3ebf8bb61e3edef7f0a5c73c0855fb433afc913 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Wed, 15 Apr 2020 09:39:38 +0100 Subject: [PATCH 38/90] Internet::getIP() returns string|false, not string|bool --- src/pocketmine/utils/Internet.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pocketmine/utils/Internet.php b/src/pocketmine/utils/Internet.php index 2194399f6..84225eb50 100644 --- a/src/pocketmine/utils/Internet.php +++ b/src/pocketmine/utils/Internet.php @@ -72,7 +72,7 @@ class Internet{ * * @param bool $force default false, force IP check even when cached * - * @return string|bool + * @return string|false */ public static function getIP(bool $force = false){ if(!self::$online){ From ccad97727fe1bca3fda8027e62baf020368e5cfa Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Wed, 15 Apr 2020 09:44:14 +0100 Subject: [PATCH 39/90] UUID: properly account for garbage inputs which aren't valid hexadecimal this would previously throw a TypeError and crash. --- src/pocketmine/utils/UUID.php | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/pocketmine/utils/UUID.php b/src/pocketmine/utils/UUID.php index d5792bc0d..aa771f2e0 100644 --- a/src/pocketmine/utils/UUID.php +++ b/src/pocketmine/utils/UUID.php @@ -61,7 +61,12 @@ class UUID{ * Creates an UUID from an hexadecimal representation */ public static function fromString(string $uuid, int $version = null) : UUID{ - return self::fromBinary(hex2bin(str_replace("-", "", trim($uuid))), $version); + //TODO: should we be stricter about the notation (8-4-4-4-12)? + $binary = @hex2bin(str_replace("-", "", trim($uuid))); + if($binary === false){ + throw new \InvalidArgumentException("Invalid hex string UUID representation"); + } + return self::fromBinary($binary, $version); } /** From 7e9c38a9d9620cf6617f507695de7836b9c5730a Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Wed, 15 Apr 2020 09:47:52 +0100 Subject: [PATCH 40/90] Timezone::parseOffset() returns string|false, not string|bool --- src/pocketmine/utils/Timezone.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pocketmine/utils/Timezone.php b/src/pocketmine/utils/Timezone.php index 11d260925..0328cff56 100644 --- a/src/pocketmine/utils/Timezone.php +++ b/src/pocketmine/utils/Timezone.php @@ -188,7 +188,7 @@ abstract class Timezone{ /** * @param string $offset In the format of +09:00, +02:00, -04:00 etc. * - * @return string|bool + * @return string|false */ private static function parseOffset($offset){ //Make signed offsets unsigned for date_parse From cf538d83bf29d058fcba5f0005f4a42fb3e9e2bd Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Wed, 15 Apr 2020 09:48:20 +0100 Subject: [PATCH 41/90] Timezone: shut phpstan up about impossible ini_get() errors --- src/pocketmine/utils/Timezone.php | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/pocketmine/utils/Timezone.php b/src/pocketmine/utils/Timezone.php index 0328cff56..dd82ba6f3 100644 --- a/src/pocketmine/utils/Timezone.php +++ b/src/pocketmine/utils/Timezone.php @@ -48,7 +48,11 @@ use function trim; abstract class Timezone{ public static function get() : string{ - return ini_get('date.timezone'); + $tz = ini_get('date.timezone'); + if($tz === false){ + throw new AssumptionFailedError('date.timezone INI entry should always exist'); + } + return $tz; } /** @@ -57,7 +61,7 @@ abstract class Timezone{ public static function init() : array{ $messages = []; do{ - $timezone = ini_get("date.timezone"); + $timezone = self::get(); if($timezone !== ""){ /* * This is here so that people don't come to us complaining and fill up the issue tracker when they put From 2281fe4e67c5d5a8b4599ebe33cb625cc0615deb Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Wed, 15 Apr 2020 10:15:38 +0100 Subject: [PATCH 42/90] Account for reflection filename being false (in the case of classes/functions defined by builtins) --- src/pocketmine/utils/Utils.php | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/src/pocketmine/utils/Utils.php b/src/pocketmine/utils/Utils.php index 7cbc03610..b7caa7b5d 100644 --- a/src/pocketmine/utils/Utils.php +++ b/src/pocketmine/utils/Utils.php @@ -138,7 +138,12 @@ class Utils{ //non-class function return $func->getName(); } - return "closure@" . self::cleanPath($func->getFileName()) . "#L" . $func->getStartLine(); + $filename = $func->getFileName(); + + return "closure@" . ($filename !== false ? + self::cleanPath($filename) . "#L" . $func->getStartLine() : + "internal" + ); } /** @@ -149,7 +154,12 @@ class Utils{ public static function getNiceClassName(object $obj) : string{ $reflect = new \ReflectionClass($obj); if($reflect->isAnonymous()){ - return "anonymous@" . self::cleanPath($reflect->getFileName()) . "#L" . $reflect->getStartLine(); + $filename = $reflect->getFileName(); + + return "anonymous@" . ($filename !== false ? + self::cleanPath($filename) . "#L" . $reflect->getStartLine() : + "internal" + ); } return $reflect->getName(); From 917c744266e4d03232a1c4e08212371c1b2afbdb Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Wed, 15 Apr 2020 10:18:02 +0100 Subject: [PATCH 43/90] Properly handle error conditions in Utils::decodeJWT() --- src/pocketmine/utils/Utils.php | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/src/pocketmine/utils/Utils.php b/src/pocketmine/utils/Utils.php index b7caa7b5d..e17322de6 100644 --- a/src/pocketmine/utils/Utils.php +++ b/src/pocketmine/utils/Utils.php @@ -480,9 +480,18 @@ class Utils{ * @phpstan-return array */ public static function decodeJWT(string $token) : array{ - list($headB64, $payloadB64, $sigB64) = explode(".", $token); + [$headB64, $payloadB64, $sigB64] = explode(".", $token); - return json_decode(base64_decode(strtr($payloadB64, '-_', '+/'), true), true); + $rawPayloadJSON = base64_decode(strtr($payloadB64, '-_', '+/'), true); + if($rawPayloadJSON === false){ + throw new \InvalidArgumentException("Payload base64 is invalid and cannot be decoded"); + } + $decodedPayload = json_decode($rawPayloadJSON, true); + if(!is_array($decodedPayload)){ + throw new \InvalidArgumentException("Decoded payload should be array, " . gettype($decodedPayload) . " received"); + } + + return $decodedPayload; } /** From 372202b3dc271a3349e9c4778631eb736b55cb18 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Wed, 15 Apr 2020 10:19:51 +0100 Subject: [PATCH 44/90] Utils: use type-safe checks to ensure file validity this gives the same results while keeping phpstan happy. --- src/pocketmine/utils/Utils.php | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/pocketmine/utils/Utils.php b/src/pocketmine/utils/Utils.php index e17322de6..deac099b7 100644 --- a/src/pocketmine/utils/Utils.php +++ b/src/pocketmine/utils/Utils.php @@ -179,7 +179,7 @@ class Utils{ } $machine = php_uname("a"); - $machine .= file_exists("/proc/cpuinfo") ? implode(preg_grep("/(model name|Processor|Serial)/", file("/proc/cpuinfo"))) : ""; + $machine .= ($cpuinfo = @file("/proc/cpuinfo")) !== false ? implode(preg_grep("/(model name|Processor|Serial)/", $cpuinfo)) : ""; $machine .= sys_get_temp_dir(); $machine .= $extra; $os = Utils::getOS(); @@ -321,14 +321,14 @@ class Utils{ switch(Utils::getOS()){ case "linux": case "android": - if(file_exists("/proc/cpuinfo")){ - foreach(file("/proc/cpuinfo") as $l){ + if(($cpuinfo = @file('/proc/cpuinfo')) !== false){ + foreach($cpuinfo as $l){ if(preg_match('/^processor[ \t]*:[ \t]*[0-9]+$/m', $l) > 0){ ++$processors; } } - }elseif(is_readable("/sys/devices/system/cpu/present")){ - if(preg_match("/^([0-9]+)\\-([0-9]+)$/", trim(file_get_contents("/sys/devices/system/cpu/present")), $matches) > 0){ + }elseif(($cpuPresent = @file_get_contents("/sys/devices/system/cpu/present")) !== false){ + if(preg_match("/^([0-9]+)\\-([0-9]+)$/", trim($cpuPresent), $matches) > 0){ $processors = (int) ($matches[2] - $matches[1]); } } From 83c40f45023cf22127474136c4e2a29f1f0bc661 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Wed, 15 Apr 2020 10:23:07 +0100 Subject: [PATCH 45/90] Timezone: properly account for failure to read timezone file --- src/pocketmine/utils/Timezone.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/pocketmine/utils/Timezone.php b/src/pocketmine/utils/Timezone.php index dd82ba6f3..10599ab3e 100644 --- a/src/pocketmine/utils/Timezone.php +++ b/src/pocketmine/utils/Timezone.php @@ -152,7 +152,7 @@ abstract class Timezone{ // Ubuntu / Debian. if(file_exists('/etc/timezone')){ $data = file_get_contents('/etc/timezone'); - if($data){ + if($data !== false){ return trim($data); } } @@ -160,7 +160,7 @@ abstract class Timezone{ // RHEL / CentOS if(file_exists('/etc/sysconfig/clock')){ $data = parse_ini_file('/etc/sysconfig/clock'); - if(isset($data['ZONE']) and is_string($data['ZONE'])){ + if($data !== false and isset($data['ZONE']) and is_string($data['ZONE'])){ return trim($data['ZONE']); } } From 5c9419b55ce6cb18626daca9a6560af02ce8fe15 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Wed, 15 Apr 2020 10:55:26 +0100 Subject: [PATCH 46/90] Timezone: use false checks instead of file existing for static analysis --- src/pocketmine/utils/Timezone.php | 27 ++++++++++--------------- tests/phpstan/configs/phpstan-bugs.neon | 6 ++++++ 2 files changed, 17 insertions(+), 16 deletions(-) diff --git a/src/pocketmine/utils/Timezone.php b/src/pocketmine/utils/Timezone.php index 10599ab3e..3745110c7 100644 --- a/src/pocketmine/utils/Timezone.php +++ b/src/pocketmine/utils/Timezone.php @@ -150,19 +150,16 @@ abstract class Timezone{ return self::parseOffset($offset); case 'linux': // Ubuntu / Debian. - if(file_exists('/etc/timezone')){ - $data = file_get_contents('/etc/timezone'); - if($data !== false){ - return trim($data); - } + $data = @file_get_contents('/etc/timezone'); + if($data !== false){ + return trim($data); } + // RHEL / CentOS - if(file_exists('/etc/sysconfig/clock')){ - $data = parse_ini_file('/etc/sysconfig/clock'); - if($data !== false and isset($data['ZONE']) and is_string($data['ZONE'])){ - return trim($data['ZONE']); - } + $data = @parse_ini_file('/etc/sysconfig/clock'); + if($data !== false and isset($data['ZONE']) and is_string($data['ZONE'])){ + return trim($data['ZONE']); } //Portable method for incompatible linux distributions. @@ -175,12 +172,10 @@ abstract class Timezone{ return self::parseOffset($offset); case 'mac': - if(is_link('/etc/localtime')){ - $filename = readlink('/etc/localtime'); - if(strpos($filename, '/usr/share/zoneinfo/') === 0){ - $timezone = substr($filename, 20); - return trim($timezone); - } + $filename = @readlink('/etc/localtime'); + if($filename !== false and strpos($filename, '/usr/share/zoneinfo/') === 0){ + $timezone = substr($filename, 20); + return trim($timezone); } return false; diff --git a/tests/phpstan/configs/phpstan-bugs.neon b/tests/phpstan/configs/phpstan-bugs.neon index 998fde5ad..23ffbd719 100644 --- a/tests/phpstan/configs/phpstan-bugs.neon +++ b/tests/phpstan/configs/phpstan-bugs.neon @@ -48,6 +48,12 @@ parameters: count: 1 path: ../../../src/pocketmine/network/mcpe/protocol/DataPacket.php + - + #readlink() can return false but phpstan doesn't know this + message: "#^Strict comparison using \\!\\=\\= between string and false will always evaluate to true\\.$#" + count: 1 + path: ../../../src/pocketmine/utils/Timezone.php + - #phpstan doesn't understand that SplFixedArray may contain null message: "#^Call to static method PHPUnit\\\\Framework\\\\Assert\\:\\:assertNotNull\\(\\) with int and string will always evaluate to true\\.$#" From 2622c34542253db8fdfd6740a41885b05794cfb4 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Wed, 15 Apr 2020 11:12:03 +0100 Subject: [PATCH 47/90] Terminal: explicitly assume that fopen(stdin) will not fail --- src/pocketmine/utils/Terminal.php | 1 + 1 file changed, 1 insertion(+) diff --git a/src/pocketmine/utils/Terminal.php b/src/pocketmine/utils/Terminal.php index c5117d286..e129cfae5 100644 --- a/src/pocketmine/utils/Terminal.php +++ b/src/pocketmine/utils/Terminal.php @@ -90,6 +90,7 @@ abstract class Terminal{ private static function detectFormattingCodesSupport() : bool{ $stdout = fopen("php://stdout", "w"); + if($stdout === false) throw new AssumptionFailedError("Opening php://stdout should never fail"); $result = ( stream_isatty($stdout) and //STDOUT isn't being piped ( From 41d7b8c0e40a979f8f0021fd988ba6dccbf77a54 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Wed, 15 Apr 2020 11:29:04 +0100 Subject: [PATCH 48/90] TextFormat: properly handle pcre errors in some cases these would previously just hit type errors. --- src/pocketmine/utils/TextFormat.php | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/pocketmine/utils/TextFormat.php b/src/pocketmine/utils/TextFormat.php index d02973c9b..08cd5aa6f 100644 --- a/src/pocketmine/utils/TextFormat.php +++ b/src/pocketmine/utils/TextFormat.php @@ -66,13 +66,19 @@ abstract class TextFormat{ public const ITALIC = TextFormat::ESCAPE . "o"; public const RESET = TextFormat::ESCAPE . "r"; + private static function makePcreError(string $info) : \InvalidArgumentException{ + throw new \InvalidArgumentException("$info: Encountered PCRE error " . preg_last_error() . " during regex operation"); + } + /** * Splits the string by Format tokens * * @return string[] */ public static function tokenize(string $string) : array{ - return preg_split("/(" . TextFormat::ESCAPE . "[0-9a-fk-or])/u", $string, -1, PREG_SPLIT_NO_EMPTY | PREG_SPLIT_DELIM_CAPTURE); + $result = preg_split("/(" . TextFormat::ESCAPE . "[0-9a-fk-or])/u", $string, -1, PREG_SPLIT_NO_EMPTY | PREG_SPLIT_DELIM_CAPTURE); + if($result === false) throw self::makePcreError("Failed to tokenize string"); + return $result; } /** @@ -83,6 +89,7 @@ abstract class TextFormat{ public static function clean(string $string, bool $removeFormat = true) : string{ $string = mb_scrub($string, 'UTF-8'); $string = preg_replace("/[\x{E000}-\x{F8FF}]/u", "", $string); //remove unicode private-use-area characters (they might break the console) + if($string === null) throw self::makePcreError("Failed to strip private-area characters"); if($removeFormat){ $string = str_replace(TextFormat::ESCAPE, "", preg_replace("/" . TextFormat::ESCAPE . "[0-9a-fk-or]/u", "", $string)); } From d246933e3e8cb478ced806d2419dc2404739cae1 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Wed, 15 Apr 2020 11:29:50 +0100 Subject: [PATCH 49/90] TextFormat: account for failure to encode JSON in toJSON() --- src/pocketmine/utils/TextFormat.php | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/pocketmine/utils/TextFormat.php b/src/pocketmine/utils/TextFormat.php index 08cd5aa6f..6d106db1c 100644 --- a/src/pocketmine/utils/TextFormat.php +++ b/src/pocketmine/utils/TextFormat.php @@ -288,7 +288,11 @@ abstract class TextFormat{ } } - return json_encode($newString, JSON_UNESCAPED_SLASHES); + $result = json_encode($newString, JSON_UNESCAPED_SLASHES); + if($result === false){ + throw new \InvalidArgumentException("Failed to encode result JSON: " . json_last_error_msg()); + } + return $result; } /** From 0c9d16f1efbd7ed5b7ddf21a1af0c2fde5ef2fe5 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Wed, 15 Apr 2020 12:02:38 +0100 Subject: [PATCH 50/90] Internet: explicitly assume return of curl_exec() is string after error checking this is documented as string|bool, but it's actually string|false if CURLOPT_RETURNTRANSFER is set, and bool if not. --- src/pocketmine/utils/Internet.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/pocketmine/utils/Internet.php b/src/pocketmine/utils/Internet.php index 84225eb50..729e57718 100644 --- a/src/pocketmine/utils/Internet.php +++ b/src/pocketmine/utils/Internet.php @@ -227,10 +227,10 @@ class Internet{ ]); try{ $raw = curl_exec($ch); - $error = curl_error($ch); - if($error !== ""){ - throw new InternetException($error); + if($raw === false){ + throw new InternetException(curl_error($ch)); } + if(!is_string($raw)) throw new AssumptionFailedError("curl_exec() should return string|false when CURLOPT_RETURNTRANSFER is set"); $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE); $headerSize = curl_getinfo($ch, CURLINFO_HEADER_SIZE); $rawHeaders = substr($raw, 0, $headerSize); From 24d64eedaba4603733fc4db942d157c2e1e441c1 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Wed, 15 Apr 2020 12:05:13 +0100 Subject: [PATCH 51/90] Process: make some assumptions about I/O explicit for type safety --- src/pocketmine/utils/Process.php | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/pocketmine/utils/Process.php b/src/pocketmine/utils/Process.php index ca3f13ac6..c588f82f4 100644 --- a/src/pocketmine/utils/Process.php +++ b/src/pocketmine/utils/Process.php @@ -55,7 +55,8 @@ final class Process{ $VmSize = null; $VmRSS = null; if(Utils::getOS() === "linux" or Utils::getOS() === "android"){ - $status = file_get_contents("/proc/self/status"); + $status = @file_get_contents("/proc/self/status"); + if($status === false) throw new AssumptionFailedError("/proc/self/status should always be accessible"); if(preg_match("/VmRSS:[ \t]+([0-9]+) kB/", $status, $matches) > 0){ $VmRSS = $matches[1] * 1024; } @@ -90,7 +91,8 @@ final class Process{ $heap = 0; if(Utils::getOS() === "linux" or Utils::getOS() === "android"){ - $mappings = file("/proc/self/maps"); + $mappings = @file("/proc/self/maps"); + if($mappings === false) throw new AssumptionFailedError("/proc/self/maps should always be accessible"); foreach($mappings as $line){ if(preg_match("#([a-z0-9]+)\\-([a-z0-9]+) [rwxp\\-]{4} [a-z0-9]+ [^\\[]*\\[([a-zA-z0-9]+)\\]#", trim($line), $matches) > 0){ if(strpos($matches[3], "heap") === 0){ @@ -107,7 +109,9 @@ final class Process{ public static function getThreadCount() : int{ if(Utils::getOS() === "linux" or Utils::getOS() === "android"){ - if(preg_match("/Threads:[ \t]+([0-9]+)/", file_get_contents("/proc/self/status"), $matches) > 0){ + $status = @file_get_contents("/proc/self/status"); + if($status === false) throw new AssumptionFailedError("/proc/self/status should always be accessible"); + if(preg_match("/Threads:[ \t]+([0-9]+)/", $status, $matches) > 0){ return (int) $matches[1]; } } From b193d9f9197353ab9c2352f416cf1a937c121cb1 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Wed, 15 Apr 2020 12:07:24 +0100 Subject: [PATCH 52/90] Process: shut up PHPStan about possible float returns on getMemoryUsage and friends this can never actually happen because the given data sources will never have such large numbers, but PHPStan doesn't know this. --- src/pocketmine/utils/Process.php | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/pocketmine/utils/Process.php b/src/pocketmine/utils/Process.php index c588f82f4..37fa63cbe 100644 --- a/src/pocketmine/utils/Process.php +++ b/src/pocketmine/utils/Process.php @@ -57,12 +57,14 @@ final class Process{ if(Utils::getOS() === "linux" or Utils::getOS() === "android"){ $status = @file_get_contents("/proc/self/status"); if($status === false) throw new AssumptionFailedError("/proc/self/status should always be accessible"); + + // the numbers found here should never be bigger than PHP_INT_MAX, so we expect them to always be castable to int if(preg_match("/VmRSS:[ \t]+([0-9]+) kB/", $status, $matches) > 0){ - $VmRSS = $matches[1] * 1024; + $VmRSS = ((int) $matches[1]) * 1024; } if(preg_match("/VmSize:[ \t]+([0-9]+) kB/", $status, $matches) > 0){ - $VmSize = $matches[1] * 1024; + $VmSize = ((int) $matches[1]) * 1024; } } @@ -96,9 +98,9 @@ final class Process{ foreach($mappings as $line){ if(preg_match("#([a-z0-9]+)\\-([a-z0-9]+) [rwxp\\-]{4} [a-z0-9]+ [^\\[]*\\[([a-zA-z0-9]+)\\]#", trim($line), $matches) > 0){ if(strpos($matches[3], "heap") === 0){ - $heap += hexdec($matches[2]) - hexdec($matches[1]); + $heap += (int) hexdec($matches[2]) - (int) hexdec($matches[1]); }elseif(strpos($matches[3], "stack") === 0){ - $stack += hexdec($matches[2]) - hexdec($matches[1]); + $stack += (int) hexdec($matches[2]) - (int) hexdec($matches[1]); } } } From 42a08e7e4ae5a55fd2b72fae95375e8426558176 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Wed, 15 Apr 2020 12:08:33 +0100 Subject: [PATCH 53/90] Utils: don't assume that callable is only array|string implicitly this should really support closures too, but since it's not used anywhere, I feel OK with this change. --- src/pocketmine/utils/Utils.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/pocketmine/utils/Utils.php b/src/pocketmine/utils/Utils.php index deac099b7..90f6f166e 100644 --- a/src/pocketmine/utils/Utils.php +++ b/src/pocketmine/utils/Utils.php @@ -111,8 +111,10 @@ class Utils{ public static function getCallableIdentifier(callable $variable){ if(is_array($variable)){ return sha1(strtolower(spl_object_hash($variable[0])) . "::" . strtolower($variable[1])); - }else{ + }elseif(is_string($variable)){ return sha1(strtolower($variable)); + }else{ + throw new AssumptionFailedError("Unhandled callable type"); } } From ae76e8f08fb20953bff44808a38d1dfa0a5a7f9c Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Wed, 15 Apr 2020 12:09:10 +0100 Subject: [PATCH 54/90] Utils: fix some implicit casts to boolean on result of preg_match_all() --- src/pocketmine/utils/Utils.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/pocketmine/utils/Utils.php b/src/pocketmine/utils/Utils.php index 90f6f166e..a2c2a611b 100644 --- a/src/pocketmine/utils/Utils.php +++ b/src/pocketmine/utils/Utils.php @@ -188,7 +188,7 @@ class Utils{ if($os === "win"){ @exec("ipconfig /ALL", $mac); $mac = implode("\n", $mac); - if(preg_match_all("#Physical Address[. ]{1,}: ([0-9A-F\\-]{17})#", $mac, $matches)){ + if(preg_match_all("#Physical Address[. ]{1,}: ([0-9A-F\\-]{17})#", $mac, $matches) > 0){ foreach($matches[1] as $i => $v){ if($v == "00-00-00-00-00-00"){ unset($matches[1][$i]); @@ -202,7 +202,7 @@ class Utils{ }else{ @exec("ifconfig 2>/dev/null", $mac); $mac = implode("\n", $mac); - if(preg_match_all("#HWaddr[ \t]{1,}([0-9a-f:]{17})#", $mac, $matches)){ + if(preg_match_all("#HWaddr[ \t]{1,}([0-9a-f:]{17})#", $mac, $matches) > 0){ foreach($matches[1] as $i => $v){ if($v == "00:00:00:00:00:00"){ unset($matches[1][$i]); From 099562d582e4bfae521b046dcbfed4b2d7741f3c Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Wed, 15 Apr 2020 12:10:21 +0100 Subject: [PATCH 55/90] Utils: assume explicitly that ob_get_contents() will not return false in getReferenceCount() based on context --- src/pocketmine/utils/Utils.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/pocketmine/utils/Utils.php b/src/pocketmine/utils/Utils.php index a2c2a611b..932711c11 100644 --- a/src/pocketmine/utils/Utils.php +++ b/src/pocketmine/utils/Utils.php @@ -514,7 +514,9 @@ class Utils{ public static function getReferenceCount($value, bool $includeCurrent = true){ ob_start(); debug_zval_dump($value); - $ret = explode("\n", ob_get_contents()); + $contents = ob_get_contents(); + if($contents === false) throw new AssumptionFailedError("ob_get_contents() should never return false here"); + $ret = explode("\n", $contents); ob_end_clean(); if(count($ret) >= 1 and preg_match('/^.* refcount\\(([0-9]+)\\)\\{$/', trim($ret[0]), $m) > 0){ From a51a16a55c83d2546f1dc0fe68c946698172bd93 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Wed, 15 Apr 2020 12:11:13 +0100 Subject: [PATCH 56/90] Utils: silence PHPStan warning about array_combine() result phpstan doesn't account for having 2 arrays of the same size, and even if it did, the size cannot be inferred easily here. --- src/pocketmine/utils/Utils.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/pocketmine/utils/Utils.php b/src/pocketmine/utils/Utils.php index 932711c11..28cb8b91c 100644 --- a/src/pocketmine/utils/Utils.php +++ b/src/pocketmine/utils/Utils.php @@ -616,7 +616,9 @@ class Utils{ public static function parseDocComment(string $docComment) : array{ preg_match_all('/(*ANYCRLF)^[\t ]*\* @([a-zA-Z]+)(?:[\t ]+(.+))?[\t ]*$/m', $docComment, $matches); - return array_combine($matches[1], $matches[2]); + $result = array_combine($matches[1], $matches[2]); + if($result === false) throw new AssumptionFailedError("array_combine() doesn't return false with two equal-sized arrays"); + return $result; } /** From a78133d0e3b10c9a63c87c98768262ab9d55a97d Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Wed, 15 Apr 2020 12:12:18 +0100 Subject: [PATCH 57/90] Utils: provide phpstan type information for testValidInstance() --- src/pocketmine/utils/Utils.php | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/pocketmine/utils/Utils.php b/src/pocketmine/utils/Utils.php index 28cb8b91c..6649ded34 100644 --- a/src/pocketmine/utils/Utils.php +++ b/src/pocketmine/utils/Utils.php @@ -632,6 +632,10 @@ class Utils{ return true; //stfu operator } + /** + * @phpstan-param class-string $className + * @phpstan-param class-string $baseName + */ public static function testValidInstance(string $className, string $baseName) : void{ try{ $base = new \ReflectionClass($baseName); From 1755b25808759daef5f93409b4c027d83912c6ef Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Wed, 15 Apr 2020 12:13:26 +0100 Subject: [PATCH 58/90] Utils: make explicit assumption about result of scandir() in recursiveUnlink() TODO: this assumption might be flawed in the case of threading... --- src/pocketmine/utils/Utils.php | 1 + 1 file changed, 1 insertion(+) diff --git a/src/pocketmine/utils/Utils.php b/src/pocketmine/utils/Utils.php index 6649ded34..fd99fba1c 100644 --- a/src/pocketmine/utils/Utils.php +++ b/src/pocketmine/utils/Utils.php @@ -676,6 +676,7 @@ class Utils{ public static function recursiveUnlink(string $dir) : void{ if(is_dir($dir)){ $objects = scandir($dir, SCANDIR_SORT_NONE); + if($objects === false) throw new AssumptionFailedError("scandir() shouldn't return false when is_dir() returns true"); foreach($objects as $object){ if($object !== "." and $object !== ".."){ if(is_dir($dir . "/" . $object)){ From 27b2710c56d88229e1b18ea4e194e26655aac6ce Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Wed, 15 Apr 2020 12:18:22 +0100 Subject: [PATCH 59/90] Config: make phpstan happy for load() currently this will never be reached if the regular exception handler has been set, but it might not be set if the class is used on its own. --- src/pocketmine/utils/Config.php | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/pocketmine/utils/Config.php b/src/pocketmine/utils/Config.php index c58acff71..33587a9df 100644 --- a/src/pocketmine/utils/Config.php +++ b/src/pocketmine/utils/Config.php @@ -172,6 +172,10 @@ class Config{ }else{ if($this->correct){ $content = file_get_contents($this->file); + if($content === false){ + $this->correct = false; + return false; + } $config = null; switch($this->type){ case Config::PROPERTIES: From bc985198a0f231d68341794e445a421c62752216 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Wed, 15 Apr 2020 12:20:23 +0100 Subject: [PATCH 60/90] Config: do not expect string keys on parseProperties(), because of key casting (PHP sucks) --- src/pocketmine/utils/Config.php | 1 - 1 file changed, 1 deletion(-) diff --git a/src/pocketmine/utils/Config.php b/src/pocketmine/utils/Config.php index 33587a9df..edcb635ae 100644 --- a/src/pocketmine/utils/Config.php +++ b/src/pocketmine/utils/Config.php @@ -573,7 +573,6 @@ class Config{ /** * @return mixed[] - * @phpstan-return array */ private function parseProperties(string $content) : array{ $result = []; From 5571ae05b5fe70e02866e575fc97a6974a3c1cab Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Wed, 15 Apr 2020 12:40:23 +0100 Subject: [PATCH 61/90] AsyncPool: silence a warning about wrong key type getTaskId() returns int|null, although it won't happen after the ID has been set. --- src/pocketmine/scheduler/AsyncPool.php | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/pocketmine/scheduler/AsyncPool.php b/src/pocketmine/scheduler/AsyncPool.php index fb3de9824..390fdeb71 100644 --- a/src/pocketmine/scheduler/AsyncPool.php +++ b/src/pocketmine/scheduler/AsyncPool.php @@ -162,13 +162,14 @@ class AsyncPool{ } $task->progressUpdates = new \Threaded; - $task->setTaskId($this->nextTaskId++); + $taskId = $this->nextTaskId++; + $task->setTaskId($taskId); - $this->tasks[$task->getTaskId()] = $task; + $this->tasks[$taskId] = $task; $this->getWorker($worker)->stack($task); $this->workerUsage[$worker]++; - $this->taskWorkers[$task->getTaskId()] = $worker; + $this->taskWorkers[$taskId] = $worker; $this->workerLastUsed[$worker] = time(); } From 8020912448aa37dab9b806543765694694521b2c Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Wed, 15 Apr 2020 12:40:54 +0100 Subject: [PATCH 62/90] AsyncPool: add phpstan array type information to all fields --- src/pocketmine/scheduler/AsyncPool.php | 25 ++++++++++++++++++++----- 1 file changed, 20 insertions(+), 5 deletions(-) diff --git a/src/pocketmine/scheduler/AsyncPool.php b/src/pocketmine/scheduler/AsyncPool.php index 390fdeb71..f5a0576f1 100644 --- a/src/pocketmine/scheduler/AsyncPool.php +++ b/src/pocketmine/scheduler/AsyncPool.php @@ -53,18 +53,33 @@ class AsyncPool{ /** @var int */ private $workerMemoryLimit; - /** @var AsyncTask[] */ + /** + * @var AsyncTask[] + * @phpstan-var array + */ private $tasks = []; - /** @var int[] */ + /** + * @var int[] + * @phpstan-var array + */ private $taskWorkers = []; /** @var int */ private $nextTaskId = 1; - /** @var AsyncWorker[] */ + /** + * @var AsyncWorker[] + * @phpstan-var array + */ private $workers = []; - /** @var int[] */ + /** + * @var int[] + * @phpstan-var array + */ private $workerUsage = []; - /** @var int[] */ + /** + * @var int[] + * @phpstan-var array + */ private $workerLastUsed = []; /** From 88b216a17bc1438a553f42f160a46e540b62bf2b Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Wed, 15 Apr 2020 12:42:18 +0100 Subject: [PATCH 63/90] AsyncTask: fix another phpstan level 7 error about wrong types this should really be a dedicated type, but everything done with pthreads sucks. --- src/pocketmine/scheduler/AsyncTask.php | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/pocketmine/scheduler/AsyncTask.php b/src/pocketmine/scheduler/AsyncTask.php index 0b36831ff..00b906526 100644 --- a/src/pocketmine/scheduler/AsyncTask.php +++ b/src/pocketmine/scheduler/AsyncTask.php @@ -25,6 +25,7 @@ namespace pocketmine\scheduler; use pocketmine\Collectable; use pocketmine\Server; +use pocketmine\utils\AssumptionFailedError; use function is_scalar; use function serialize; use function unserialize; @@ -97,7 +98,11 @@ abstract class AsyncTask extends Collectable{ * @return mixed */ public function getResult(){ - return $this->serialized ? unserialize($this->result) : $this->result; + if($this->serialized){ + if(!is_string($this->result)) throw new AssumptionFailedError("Result expected to be a serialized string"); + return unserialize($this->result); + } + return $this->result; } /** From 755919c496c80c96251fc8c556d85f13c21b1f4e Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Wed, 15 Apr 2020 12:43:05 +0100 Subject: [PATCH 64/90] SendUsageTask: explicitly assume that json_encode() will not return false --- src/pocketmine/scheduler/SendUsageTask.php | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/pocketmine/scheduler/SendUsageTask.php b/src/pocketmine/scheduler/SendUsageTask.php index 4e8bee608..7a722b6d0 100644 --- a/src/pocketmine/scheduler/SendUsageTask.php +++ b/src/pocketmine/scheduler/SendUsageTask.php @@ -25,6 +25,7 @@ namespace pocketmine\scheduler; use pocketmine\network\mcpe\protocol\ProtocolInfo; use pocketmine\Server; +use pocketmine\utils\AssumptionFailedError; use pocketmine\utils\Internet; use pocketmine\utils\Process; use pocketmine\utils\Utils; @@ -152,7 +153,9 @@ class SendUsageTask extends AsyncTask{ } $this->endpoint = $endpoint . "api/post"; - $this->data = json_encode($data/*, JSON_PRETTY_PRINT*/); + $data = json_encode($data/*, JSON_PRETTY_PRINT*/); + if($data === false) throw new AssumptionFailedError("Statistics JSON should never fail to encode: " . json_last_error_msg()); + $this->data = $data; } public function onRun(){ From bbe428a874476b4e3169c92aa7083223a356d9e7 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Wed, 15 Apr 2020 12:43:44 +0100 Subject: [PATCH 65/90] Spawnable: explicitly assume that NBTStream->write() will not return false it will never return false under these circumstances --- src/pocketmine/tile/Spawnable.php | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/pocketmine/tile/Spawnable.php b/src/pocketmine/tile/Spawnable.php index 6d416650a..41727905b 100644 --- a/src/pocketmine/tile/Spawnable.php +++ b/src/pocketmine/tile/Spawnable.php @@ -30,6 +30,7 @@ use pocketmine\nbt\tag\IntTag; use pocketmine\nbt\tag\StringTag; use pocketmine\network\mcpe\protocol\BlockActorDataPacket; use pocketmine\Player; +use pocketmine\utils\AssumptionFailedError; abstract class Spawnable extends Tile{ /** @var string|null */ @@ -96,7 +97,9 @@ abstract class Spawnable extends Tile{ self::$nbtWriter = new NetworkLittleEndianNBTStream(); } - $this->spawnCompoundCache = self::$nbtWriter->write($this->getSpawnCompound()); + $spawnCompoundCache = self::$nbtWriter->write($this->getSpawnCompound()); + if($spawnCompoundCache === false) throw new AssumptionFailedError("NBTStream->write() should not return false when given a CompoundTag"); + $this->spawnCompoundCache = $spawnCompoundCache; } return $this->spawnCompoundCache; From cdda74ef93f3a18b3653231b1cb89829d088fad7 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Wed, 15 Apr 2020 12:50:53 +0100 Subject: [PATCH 66/90] PluginDescription: use result of phpversion() to check if extension is loaded technically phpstan should account for this with the extension_loaded() check, but it currently doesn't and it's not worth fighting with it when the fix is so simple anyway. --- src/pocketmine/plugin/PluginDescription.php | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/pocketmine/plugin/PluginDescription.php b/src/pocketmine/plugin/PluginDescription.php index e604dfd06..10db86877 100644 --- a/src/pocketmine/plugin/PluginDescription.php +++ b/src/pocketmine/plugin/PluginDescription.php @@ -28,7 +28,6 @@ use function array_map; use function array_values; use function constant; use function defined; -use function extension_loaded; use function is_array; use function phpversion; use function preg_match; @@ -230,11 +229,11 @@ class PluginDescription{ */ public function checkRequiredExtensions(){ foreach($this->extensions as $name => $versionConstrs){ - if(!extension_loaded($name)){ + $gotVersion = phpversion($name); + if($gotVersion === false){ throw new PluginException("Required extension $name not loaded"); } - $gotVersion = phpversion($name); foreach($versionConstrs as $constr){ // versionConstrs_loop if($constr === "*"){ continue; From 0a3788f9ac92eac30b6b4268391e1a004a757587 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Wed, 15 Apr 2020 12:54:45 +0100 Subject: [PATCH 67/90] ScriptPluginLoader: properly handle the case where the script itself is somehow missing this won't ever happen during PocketMine runtime, but it might happen if something else tries to use it. --- src/pocketmine/plugin/ScriptPluginLoader.php | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/pocketmine/plugin/ScriptPluginLoader.php b/src/pocketmine/plugin/ScriptPluginLoader.php index 126f66de2..ea9d4c22d 100644 --- a/src/pocketmine/plugin/ScriptPluginLoader.php +++ b/src/pocketmine/plugin/ScriptPluginLoader.php @@ -55,7 +55,10 @@ class ScriptPluginLoader implements PluginLoader{ * Gets the PluginDescription from the file */ public function getPluginDescription(string $file) : ?PluginDescription{ - $content = file($file, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES); + $content = @file($file, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES); + if($content === false){ + return null; + } $data = []; From 959dd4cbf18c5db3cdc1e8ddd7bf3ac299267410 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Wed, 15 Apr 2020 12:59:15 +0100 Subject: [PATCH 68/90] PluginManager: explicitly assume the result of FilesystemIterator arrayification --- src/pocketmine/plugin/PluginManager.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/pocketmine/plugin/PluginManager.php b/src/pocketmine/plugin/PluginManager.php index 1b33e21fd..562657f36 100644 --- a/src/pocketmine/plugin/PluginManager.php +++ b/src/pocketmine/plugin/PluginManager.php @@ -37,6 +37,7 @@ use pocketmine\permission\Permission; use pocketmine\permission\PermissionManager; use pocketmine\Server; use pocketmine\timings\TimingsHandler; +use pocketmine\utils\AssumptionFailedError; use pocketmine\utils\Utils; use function array_intersect; use function array_map; @@ -229,6 +230,7 @@ class PluginManager{ shuffle($files); //this prevents plugins implicitly relying on the filesystem name order when they should be using dependency properties foreach($loaders as $loader){ foreach($files as $file){ + if(!is_string($file)) throw new AssumptionFailedError("FilesystemIterator current should be string when using CURRENT_AS_PATHNAME"); if(!$loader->canLoadPlugin($file)){ continue; } From 2da8ce7a20d20919fc2910c3b1bfc7dcbafa797d Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Wed, 15 Apr 2020 13:05:41 +0100 Subject: [PATCH 69/90] PluginBase: account for fopen() maybe returning false again, the error handler will normally take care of this, but we can't assume that the error handler is always set. --- src/pocketmine/plugin/PluginBase.php | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/pocketmine/plugin/PluginBase.php b/src/pocketmine/plugin/PluginBase.php index aac4a891e..aa98afd77 100644 --- a/src/pocketmine/plugin/PluginBase.php +++ b/src/pocketmine/plugin/PluginBase.php @@ -28,6 +28,7 @@ use pocketmine\command\CommandSender; use pocketmine\command\PluginIdentifiableCommand; use pocketmine\scheduler\TaskScheduler; use pocketmine\Server; +use pocketmine\utils\AssumptionFailedError; use pocketmine\utils\Config; use function dirname; use function fclose; @@ -171,7 +172,9 @@ abstract class PluginBase implements Plugin{ public function getResource(string $filename){ $filename = rtrim(str_replace("\\", "/", $filename), "/"); if(file_exists($this->file . "resources/" . $filename)){ - return fopen($this->file . "resources/" . $filename, "rb"); + $resource = fopen($this->file . "resources/" . $filename, "rb"); + if($resource === false) throw new AssumptionFailedError("fopen() should not fail on a file which exists"); + return $resource; } return null; @@ -195,7 +198,10 @@ abstract class PluginBase implements Plugin{ return false; } - $ret = stream_copy_to_stream($resource, $fp = fopen($out, "wb")) > 0; + $fp = fopen($out, "wb"); + if($fp === false) throw new AssumptionFailedError("fopen() should not fail with wb flags"); + + $ret = stream_copy_to_stream($resource, $fp) > 0; fclose($fp); fclose($resource); return $ret; From 63b109f23ec105105225cedc762f513855bdc56d Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Wed, 15 Apr 2020 21:16:47 +0100 Subject: [PATCH 70/90] RCONInstance: fixed incorrect doc comment for field --- src/pocketmine/network/rcon/RCONInstance.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pocketmine/network/rcon/RCONInstance.php b/src/pocketmine/network/rcon/RCONInstance.php index 73999cb0d..05aa0a5ac 100644 --- a/src/pocketmine/network/rcon/RCONInstance.php +++ b/src/pocketmine/network/rcon/RCONInstance.php @@ -167,7 +167,7 @@ class RCONInstance extends Thread{ /** @var resource[] $clients */ $clients = []; - /** @var int[] $authenticated */ + /** @var bool[] $authenticated */ $authenticated = []; /** @var float[] $timeouts */ $timeouts = []; From 619a9892e55a932a0430fa3fcda5cf8c341b124b Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Thu, 16 Apr 2020 01:29:28 +0100 Subject: [PATCH 71/90] RCON: properly handle potential errors during socket setup --- src/pocketmine/level/format/io/region/RegionLoader.php | 5 ++++- src/pocketmine/network/rcon/RCON.php | 8 ++++++-- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/src/pocketmine/level/format/io/region/RegionLoader.php b/src/pocketmine/level/format/io/region/RegionLoader.php index 87383a3a6..e86d3c56f 100644 --- a/src/pocketmine/level/format/io/region/RegionLoader.php +++ b/src/pocketmine/level/format/io/region/RegionLoader.php @@ -25,6 +25,7 @@ namespace pocketmine\level\format\io\region; use pocketmine\level\format\ChunkException; use pocketmine\level\format\io\exception\CorruptedChunkException; +use pocketmine\utils\AssumptionFailedError; use pocketmine\utils\Binary; use pocketmine\utils\MainLogger; use function ceil; @@ -98,7 +99,9 @@ class RegionLoader{ throw new CorruptedRegionException("Region file should be padded to a multiple of 4KiB"); } - $this->filePointer = fopen($this->filePath, "r+b"); + $filePointer = fopen($this->filePath, "r+b"); + if($filePointer === false) throw new AssumptionFailedError("fopen() should not fail here"); + $this->filePointer = $filePointer; stream_set_read_buffer($this->filePointer, 1024 * 16); //16KB stream_set_write_buffer($this->filePointer, 1024 * 16); //16KB if(!$exists){ diff --git a/src/pocketmine/network/rcon/RCON.php b/src/pocketmine/network/rcon/RCON.php index 61a123e37..e0522de45 100644 --- a/src/pocketmine/network/rcon/RCON.php +++ b/src/pocketmine/network/rcon/RCON.php @@ -75,13 +75,17 @@ class RCON{ throw new \InvalidArgumentException("Empty password"); } - $this->socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP); + $socket = @socket_create(AF_INET, SOCK_STREAM, SOL_TCP); + if($socket === false){ + throw new \RuntimeException("Failed to create socket:" . trim(socket_strerror(socket_last_error()))); + } + $this->socket = $socket; if(!socket_set_option($this->socket, SOL_SOCKET, SO_REUSEADDR, 1)){ throw new \RuntimeException("Unable to set option on socket: " . trim(socket_strerror(socket_last_error()))); } - if($this->socket === false or !@socket_bind($this->socket, $interface, $port) or !@socket_listen($this->socket, 5)){ + if(!@socket_bind($this->socket, $interface, $port) or !@socket_listen($this->socket, 5)){ throw new \RuntimeException(trim(socket_strerror(socket_last_error()))); } From 804a062c3ab517f17ea7c6d5ae42f9f6b2f0e5b9 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Sun, 19 Apr 2020 12:08:21 +0100 Subject: [PATCH 72/90] CrashDump: report the versions of all Composer libraries installed --- composer.json | 3 +- composer.lock | 56 ++++++++++++++++++++++++++++++++++-- src/pocketmine/CrashDump.php | 10 +++++-- 3 files changed, 63 insertions(+), 6 deletions(-) diff --git a/composer.json b/composer.json index d3d05d0c8..fc249ea02 100644 --- a/composer.json +++ b/composer.json @@ -34,7 +34,8 @@ "pocketmine/log": "^0.2.0", "pocketmine/log-pthreads": "^0.1.0", "pocketmine/callback-validator": "^1.0.1", - "adhocore/json-comment": "^0.1.0" + "adhocore/json-comment": "^0.1.0", + "ocramius/package-versions": "^1.5" }, "require-dev": { "phpstan/phpstan": "^0.12.14", diff --git a/composer.lock b/composer.lock index 78a37fed9..7bb68fa4f 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "6870d7b85559a32e2929692e0a0da169", + "content-hash": "3449adb803690a36539c03ecb3a8fb3d", "packages": [ { "name": "adhocore/json-comment", @@ -50,6 +50,57 @@ ], "time": "2020-01-03T13:51:23+00:00" }, + { + "name": "ocramius/package-versions", + "version": "1.5.1", + "source": { + "type": "git", + "url": "https://github.com/Ocramius/PackageVersions.git", + "reference": "1d32342b8c1eb27353c8887c366147b4c2da673c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/Ocramius/PackageVersions/zipball/1d32342b8c1eb27353c8887c366147b4c2da673c", + "reference": "1d32342b8c1eb27353c8887c366147b4c2da673c", + "shasum": "" + }, + "require": { + "composer-plugin-api": "^1.0.0", + "php": "^7.3.0" + }, + "require-dev": { + "composer/composer": "^1.8.6", + "doctrine/coding-standard": "^6.0.0", + "ext-zip": "*", + "infection/infection": "^0.13.4", + "phpunit/phpunit": "^8.2.5", + "vimeo/psalm": "^3.4.9" + }, + "type": "composer-plugin", + "extra": { + "class": "PackageVersions\\Installer", + "branch-alias": { + "dev-master": "1.6.x-dev" + } + }, + "autoload": { + "psr-4": { + "PackageVersions\\": "src/PackageVersions" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Marco Pivetta", + "email": "ocramius@gmail.com" + } + ], + "description": "Composer plugin that provides efficient querying for installed package versions (no runtime IO)", + "time": "2019-07-17T15:49:50+00:00" + }, { "name": "pocketmine/binaryutils", "version": "0.1.11", @@ -649,5 +700,6 @@ "ext-zip": "*", "ext-zlib": ">=1.2.11" }, - "platform-dev": [] + "platform-dev": [], + "plugin-api-version": "1.1.0" } diff --git a/src/pocketmine/CrashDump.php b/src/pocketmine/CrashDump.php index 49c0ff170..9837b501c 100644 --- a/src/pocketmine/CrashDump.php +++ b/src/pocketmine/CrashDump.php @@ -23,13 +23,13 @@ declare(strict_types=1); namespace pocketmine; +use PackageVersions\Versions; use pocketmine\network\mcpe\protocol\ProtocolInfo; use pocketmine\plugin\PluginBase; use pocketmine\plugin\PluginLoadOrder; use pocketmine\plugin\PluginManager; use pocketmine\utils\Utils; use pocketmine\utils\VersionString; -use raklib\RakLib; use function base64_encode; use function date; use function error_get_last; @@ -88,7 +88,7 @@ class CrashDump{ * having their content changed, version format changing, etc. * It is not necessary to increase this when adding new fields. */ - private const FORMAT_VERSION = 2; + private const FORMAT_VERSION = 3; private const PLUGIN_INVOLVEMENT_NONE = "none"; private const PLUGIN_INVOLVEMENT_DIRECT = "direct"; @@ -345,18 +345,22 @@ class CrashDump{ $this->data["general"]["is_dev"] = \pocketmine\IS_DEVELOPMENT_BUILD; $this->data["general"]["protocol"] = ProtocolInfo::CURRENT_PROTOCOL; $this->data["general"]["git"] = \pocketmine\GIT_COMMIT; - $this->data["general"]["raklib"] = RakLib::VERSION; $this->data["general"]["uname"] = php_uname("a"); $this->data["general"]["php"] = phpversion(); $this->data["general"]["zend"] = zend_version(); $this->data["general"]["php_os"] = PHP_OS; $this->data["general"]["os"] = Utils::getOS(); + $this->data["general"]["composer_libraries"] = Versions::VERSIONS; $this->addLine($this->server->getName() . " version: " . $version->getFullVersion(true) . " [Protocol " . ProtocolInfo::CURRENT_PROTOCOL . "]"); $this->addLine("Git commit: " . \pocketmine\GIT_COMMIT); $this->addLine("uname -a: " . php_uname("a")); $this->addLine("PHP Version: " . phpversion()); $this->addLine("Zend version: " . zend_version()); $this->addLine("OS : " . PHP_OS . ", " . Utils::getOS()); + $this->addLine("Composer libraries: "); + foreach(Versions::VERSIONS as $library => $libraryVersion){ + $this->addLine("- $library $libraryVersion"); + } } /** From 7d43dffac498c3bba7d8a343e7913bac3dbc90e5 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Sun, 19 Apr 2020 12:44:26 +0100 Subject: [PATCH 73/90] updated phpstan/phpstan-phpunit --- composer.lock | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/composer.lock b/composer.lock index 7bb68fa4f..e167dc5a2 100644 --- a/composer.lock +++ b/composer.lock @@ -568,21 +568,21 @@ }, { "name": "phpstan/phpstan-phpunit", - "version": "0.12.6", + "version": "0.12.8", "source": { "type": "git", "url": "https://github.com/phpstan/phpstan-phpunit.git", - "reference": "26394996368b6d033d012547d3197f4e07e23021" + "reference": "7232c17e2493dc598173da784477ce0afb2c4e0e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpstan/phpstan-phpunit/zipball/26394996368b6d033d012547d3197f4e07e23021", - "reference": "26394996368b6d033d012547d3197f4e07e23021", + "url": "https://api.github.com/repos/phpstan/phpstan-phpunit/zipball/7232c17e2493dc598173da784477ce0afb2c4e0e", + "reference": "7232c17e2493dc598173da784477ce0afb2c4e0e", "shasum": "" }, "require": { "php": "~7.1", - "phpstan/phpstan": "^0.12.4" + "phpstan/phpstan": "^0.12.6" }, "conflict": { "phpunit/phpunit": "<7.0" @@ -620,7 +620,7 @@ "MIT" ], "description": "PHPUnit extensions and rules for PHPStan", - "time": "2020-01-10T12:07:21+00:00" + "time": "2020-04-17T08:04:10+00:00" }, { "name": "phpstan/phpstan-strict-rules", From 70a4f73d73e0be6e0f99249f059a363a0a7670b1 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Sun, 19 Apr 2020 12:49:25 +0100 Subject: [PATCH 74/90] Drop PHP 7.2 support --- .travis.yml | 1 - BUILDING.md | 2 +- composer.json | 2 +- composer.lock | 4 ++-- src/pocketmine/PocketMine.php | 2 +- 5 files changed, 5 insertions(+), 6 deletions(-) diff --git a/.travis.yml b/.travis.yml index 2fc68b387..55ddfd2e2 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,7 +1,6 @@ language: php php: - - 7.2 - 7.3 before_script: diff --git a/BUILDING.md b/BUILDING.md index a4e0d8595..df02d6b20 100644 --- a/BUILDING.md +++ b/BUILDING.md @@ -2,7 +2,7 @@ ## Pre-requisites - A bash shell (git bash is sufficient for Windows) - [`git`](https://git-scm.com) available in your shell -- PHP 7.2 or newer available in your shell +- PHP 7.3 or newer available in your shell - [`composer`](https://getcomposer.org) available in your shell ## Custom PHP binaries diff --git a/composer.json b/composer.json index fc249ea02..3442e81e3 100644 --- a/composer.json +++ b/composer.json @@ -5,7 +5,7 @@ "homepage": "https://pmmp.io", "license": "LGPL-3.0", "require": { - "php": ">=7.2.0", + "php": ">=7.3.0", "php-64bit": "*", "ext-bcmath": "*", "ext-curl": "*", diff --git a/composer.lock b/composer.lock index e167dc5a2..4b764bdb5 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "3449adb803690a36539c03ecb3a8fb3d", + "content-hash": "86ad0aed5ce88fa096c73bced8c79348", "packages": [ { "name": "adhocore/json-comment", @@ -680,7 +680,7 @@ "prefer-stable": false, "prefer-lowest": false, "platform": { - "php": ">=7.2.0", + "php": ">=7.3.0", "php-64bit": "*", "ext-bcmath": "*", "ext-curl": "*", diff --git a/src/pocketmine/PocketMine.php b/src/pocketmine/PocketMine.php index 47fcc7e32..dcf4c5d97 100644 --- a/src/pocketmine/PocketMine.php +++ b/src/pocketmine/PocketMine.php @@ -35,7 +35,7 @@ namespace pocketmine { require_once __DIR__ . '/VersionInfo.php'; - const MIN_PHP_VERSION = "7.2.0"; + const MIN_PHP_VERSION = "7.3.0"; /** * @param string $message From 1579f41056925b3cca617075fcd07a7c361048b0 Mon Sep 17 00:00:00 2001 From: Twisted Date: Sun, 19 Apr 2020 15:42:27 +0100 Subject: [PATCH 75/90] Added missing Enchantment IDs (#3419) --- src/pocketmine/item/enchantment/Enchantment.php | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/pocketmine/item/enchantment/Enchantment.php b/src/pocketmine/item/enchantment/Enchantment.php index 4ba5e5d32..8586cdc3e 100644 --- a/src/pocketmine/item/enchantment/Enchantment.php +++ b/src/pocketmine/item/enchantment/Enchantment.php @@ -66,6 +66,9 @@ class Enchantment{ public const RIPTIDE = 30; public const LOYALTY = 31; public const CHANNELING = 32; + public const MULTISHOT = 33; + public const PIERCING = 34; + public const QUICK_CHARGE = 35; public const RARITY_COMMON = 10; public const RARITY_UNCOMMON = 5; From 3d2ca457f82f02536af3e87745a53b5e2d9231de Mon Sep 17 00:00:00 2001 From: Twisted Date: Sun, 19 Apr 2020 15:43:11 +0100 Subject: [PATCH 76/90] protocol: Added missing Window Types (#3420) --- src/pocketmine/network/mcpe/protocol/types/WindowTypes.php | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/pocketmine/network/mcpe/protocol/types/WindowTypes.php b/src/pocketmine/network/mcpe/protocol/types/WindowTypes.php index b29628ac9..afa36f5a9 100644 --- a/src/pocketmine/network/mcpe/protocol/types/WindowTypes.php +++ b/src/pocketmine/network/mcpe/protocol/types/WindowTypes.php @@ -51,9 +51,12 @@ interface WindowTypes{ public const ELEMENT_CONSTRUCTOR = 21; public const MATERIAL_REDUCER = 22; public const LAB_TABLE = 23; - + public const LOOM = 24; + public const LECTERN = 25; + public const GRINDSTONE = 26; public const BLAST_FURNACE = 27; public const SMOKER = 28; public const STONECUTTER = 29; + public const CARTOGRAPHY = 30; } From 7cdd26add5a13b2bb0afcf69b4bd3b8fd87c264c Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Sun, 10 May 2020 11:23:11 +0100 Subject: [PATCH 77/90] Player: make handleLogin() less unreadable --- src/pocketmine/Player.php | 29 +++++++++++++++++++++++++---- 1 file changed, 25 insertions(+), 4 deletions(-) diff --git a/src/pocketmine/Player.php b/src/pocketmine/Player.php index 4cf952e07..bf60adc5d 100644 --- a/src/pocketmine/Player.php +++ b/src/pocketmine/Player.php @@ -1858,12 +1858,25 @@ class Player extends Human implements CommandSender, ChunkLoader, IPlayer{ $animations = []; foreach($packet->clientData["AnimatedImageData"] as $animation){ - $animations[] = new SkinAnimation(new SkinImage($animation["ImageHeight"], $animation["ImageWidth"], base64_decode($animation["Image"], true)), $animation["Type"], $animation["Frames"]); + $animations[] = new SkinAnimation( + new SkinImage( + $animation["ImageHeight"], + $animation["ImageWidth"], + base64_decode($animation["Image"], true)), + $animation["Type"], + $animation["Frames"] + ); } $personaPieces = []; foreach($packet->clientData["PersonaPieces"] as $piece){ - $personaPieces[] = new PersonaSkinPiece($piece["PieceId"], $piece["PieceType"], $piece["PackId"], $piece["IsDefault"], $piece["ProductId"]); + $personaPieces[] = new PersonaSkinPiece( + $piece["PieceId"], + $piece["PieceType"], + $piece["PackId"], + $piece["IsDefault"], + $piece["ProductId"] + ); } $pieceTintColors = []; @@ -1874,9 +1887,17 @@ class Player extends Human implements CommandSender, ChunkLoader, IPlayer{ $skinData = new SkinData( $packet->clientData["SkinId"], base64_decode($packet->clientData["SkinResourcePatch"] ?? "", true), - new SkinImage($packet->clientData["SkinImageHeight"], $packet->clientData["SkinImageWidth"], base64_decode($packet->clientData["SkinData"], true)), + new SkinImage( + $packet->clientData["SkinImageHeight"], + $packet->clientData["SkinImageWidth"], + base64_decode($packet->clientData["SkinData"], true) + ), $animations, - new SkinImage($packet->clientData["CapeImageHeight"], $packet->clientData["CapeImageWidth"], base64_decode($packet->clientData["CapeData"] ?? "", true)), + new SkinImage( + $packet->clientData["CapeImageHeight"], + $packet->clientData["CapeImageWidth"], + base64_decode($packet->clientData["CapeData"] ?? "", true) + ), base64_decode($packet->clientData["SkinGeometryData"] ?? "", true), base64_decode($packet->clientData["SkinAnimationData"] ?? "", true), $packet->clientData["PremiumSkin"] ?? false, From 56883f9ff9d2a0934dd3585e565d109ea322f583 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Sun, 10 May 2020 11:35:53 +0100 Subject: [PATCH 78/90] MemoryManager: explicitly assume return type of ini_get() --- src/pocketmine/MemoryManager.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/pocketmine/MemoryManager.php b/src/pocketmine/MemoryManager.php index 344a1fe2f..91f46d291 100644 --- a/src/pocketmine/MemoryManager.php +++ b/src/pocketmine/MemoryManager.php @@ -27,6 +27,7 @@ use pocketmine\event\server\LowMemoryEvent; use pocketmine\scheduler\DumpWorkerMemoryTask; use pocketmine\scheduler\GarbageCollectionTask; use pocketmine\timings\Timings; +use pocketmine\utils\AssumptionFailedError; use pocketmine\utils\Process; use pocketmine\utils\Utils; use function arsort; @@ -305,6 +306,7 @@ class MemoryManager{ */ public static function dumpMemory($startingObject, string $outputFolder, int $maxNesting, int $maxStringSize, \Logger $logger){ $hardLimit = ini_get('memory_limit'); + if($hardLimit === false) throw new AssumptionFailedError("memory_limit INI directive should always exist"); ini_set('memory_limit', '-1'); gc_disable(); From 58e32086c04d6622c01f59d0cd7216bd8a50eddb Mon Sep 17 00:00:00 2001 From: XenialDan Date: Sun, 17 May 2020 11:10:35 +0200 Subject: [PATCH 79/90] Level: Updated TIME_* constants (#3385) - Added Level::TIME_NOON - Added Level::TIME_MIDNIGHT - Changed values of Level::TIME_DAY and Level::TIME_NIGHT --- src/pocketmine/level/Level.php | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/pocketmine/level/Level.php b/src/pocketmine/level/Level.php index d732c531b..61c2c7ffc 100644 --- a/src/pocketmine/level/Level.php +++ b/src/pocketmine/level/Level.php @@ -128,9 +128,11 @@ class Level implements ChunkManager, Metadatable{ public const Y_MASK = 0xFF; public const Y_MAX = 0x100; //256 - public const TIME_DAY = 0; + public const TIME_DAY = 1000; + public const TIME_NOON = 6000; public const TIME_SUNSET = 12000; - public const TIME_NIGHT = 14000; + public const TIME_NIGHT = 13000; + public const TIME_MIDNIGHT = 18000; public const TIME_SUNRISE = 23000; public const TIME_FULL = 24000; From 9ebd6d6b0fee486e1cb935cc7b5376d27ca99fd4 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Sun, 17 May 2020 14:03:22 +0100 Subject: [PATCH 80/90] Timezone: remove rogue newline --- src/pocketmine/utils/Timezone.php | 1 - 1 file changed, 1 deletion(-) diff --git a/src/pocketmine/utils/Timezone.php b/src/pocketmine/utils/Timezone.php index 3745110c7..8e12d66a2 100644 --- a/src/pocketmine/utils/Timezone.php +++ b/src/pocketmine/utils/Timezone.php @@ -155,7 +155,6 @@ abstract class Timezone{ return trim($data); } - // RHEL / CentOS $data = @parse_ini_file('/etc/sysconfig/clock'); if($data !== false and isset($data['ZONE']) and is_string($data['ZONE'])){ From 22b5de09b476a8c1638adfaba56b210c1eb1faf0 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Mon, 18 May 2020 20:00:51 +0100 Subject: [PATCH 81/90] added colours to EnchantParticle and InstantEnchantParticle, closes #3368 --- src/pocketmine/level/particle/EnchantParticle.php | 5 +++-- src/pocketmine/level/particle/InstantEnchantParticle.php | 5 +++-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/src/pocketmine/level/particle/EnchantParticle.php b/src/pocketmine/level/particle/EnchantParticle.php index ca2e599ce..c58541214 100644 --- a/src/pocketmine/level/particle/EnchantParticle.php +++ b/src/pocketmine/level/particle/EnchantParticle.php @@ -24,9 +24,10 @@ declare(strict_types=1); namespace pocketmine\level\particle; use pocketmine\math\Vector3; +use pocketmine\utils\Color; class EnchantParticle extends GenericParticle{ - public function __construct(Vector3 $pos){ - parent::__construct($pos, Particle::TYPE_MOB_SPELL); + public function __construct(Vector3 $pos, ?Color $color = null){ + parent::__construct($pos, Particle::TYPE_MOB_SPELL, $color !== null ? $color->toARGB() : 0); } } diff --git a/src/pocketmine/level/particle/InstantEnchantParticle.php b/src/pocketmine/level/particle/InstantEnchantParticle.php index 337a89ff3..30d0c87e5 100644 --- a/src/pocketmine/level/particle/InstantEnchantParticle.php +++ b/src/pocketmine/level/particle/InstantEnchantParticle.php @@ -24,9 +24,10 @@ declare(strict_types=1); namespace pocketmine\level\particle; use pocketmine\math\Vector3; +use pocketmine\utils\Color; class InstantEnchantParticle extends GenericParticle{ - public function __construct(Vector3 $pos){ - parent::__construct($pos, Particle::TYPE_MOB_SPELL_INSTANTANEOUS); + public function __construct(Vector3 $pos, ?Color $color = null){ + parent::__construct($pos, Particle::TYPE_MOB_SPELL_INSTANTANEOUS, $color !== null ? $color->toARGB() : 0); } } From 15baf093396febe6541aaac10e33a15683698ebb Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Mon, 18 May 2020 20:16:03 +0100 Subject: [PATCH 82/90] update l7 and l8 baselines for next-minor branch --- tests/phpstan/configs/l7-baseline.neon | 550 ----------------------- tests/phpstan/configs/l8-baseline.neon | 596 +------------------------ 2 files changed, 18 insertions(+), 1128 deletions(-) diff --git a/tests/phpstan/configs/l7-baseline.neon b/tests/phpstan/configs/l7-baseline.neon index 49c4d1b71..d09af1cf3 100644 --- a/tests/phpstan/configs/l7-baseline.neon +++ b/tests/phpstan/configs/l7-baseline.neon @@ -15,61 +15,6 @@ parameters: count: 1 path: ../../../build/server-phar.php - - - message: "#^Property pocketmine\\\\CrashDump\\:\\:\\$fp \\(resource\\) does not accept resource\\|false\\.$#" - count: 1 - path: ../../../src/pocketmine/CrashDump.php - - - - message: "#^Offset 'file' does not exist on array\\(\\?'type' \\=\\> int, \\?'message' \\=\\> string, \\?'file' \\=\\> string, \\?'line' \\=\\> int, 'trace' \\=\\> array\\\\>\\)\\.$#" - count: 1 - path: ../../../src/pocketmine/CrashDump.php - - - - message: "#^Offset 'file' does not exist on array\\(\\?'type' \\=\\> int, \\?'message' \\=\\> string, \\?'file' \\=\\> string, \\?'line' \\=\\> int, 'trace' \\=\\> array\\\\>, 'fullFile' \\=\\> string\\)\\.$#" - count: 1 - path: ../../../src/pocketmine/CrashDump.php - - - - message: "#^Offset 'type' does not exist on array\\(\\?'type' \\=\\> int, \\?'message' \\=\\> string, 'file' \\=\\> string, \\?'line' \\=\\> int, 'trace' \\=\\> array\\\\>, 'fullFile' \\=\\> string\\)\\.$#" - count: 2 - path: ../../../src/pocketmine/CrashDump.php - - - - message: "#^Offset 'message' does not exist on array\\('type' \\=\\> int\\|string, \\?'message' \\=\\> string, 'file' \\=\\> string, \\?'line' \\=\\> int, 'trace' \\=\\> array\\\\>, 'fullFile' \\=\\> string\\)\\.$#" - count: 2 - path: ../../../src/pocketmine/CrashDump.php - - - - message: "#^Cannot access offset float\\|int on array\\\\|false\\.$#" - count: 1 - path: ../../../src/pocketmine/CrashDump.php - - - - message: "#^Cannot access offset 0 on array\\\\|int\\.$#" - count: 1 - path: ../../../src/pocketmine/MemoryManager.php - - - - message: "#^Cannot access offset 1 on array\\\\|int\\.$#" - count: 1 - path: ../../../src/pocketmine/MemoryManager.php - - - - message: "#^Cannot access offset 0\\|1 on array\\\\|int\\.$#" - count: 2 - path: ../../../src/pocketmine/MemoryManager.php - - - - message: "#^Only booleans are allowed in an if condition, ReflectionClass\\|false given\\.$#" - count: 1 - path: ../../../src/pocketmine/MemoryManager.php - - - - message: "#^Cannot call method getName\\(\\) on ReflectionClass\\|false\\.$#" - count: 1 - path: ../../../src/pocketmine/MemoryManager.php - - message: "#^Parameter \\#1 \\$fp of function fwrite expects resource, resource\\|false given\\.$#" count: 1 @@ -80,11 +25,6 @@ parameters: count: 1 path: ../../../src/pocketmine/MemoryManager.php - - - message: "#^Parameter \\#2 \\$newvalue of function ini_set expects string, string\\|false given\\.$#" - count: 1 - path: ../../../src/pocketmine/MemoryManager.php - - message: "#^Parameter \\#3 \\$data of class pocketmine\\\\network\\\\mcpe\\\\protocol\\\\types\\\\SkinImage constructor expects string, string\\|false given\\.$#" count: 3 @@ -205,21 +145,6 @@ parameters: count: 1 path: ../../../src/pocketmine/Server.php - - - message: "#^Cannot access offset 0 on array\\\\|int\\.$#" - count: 1 - path: ../../../src/pocketmine/Server.php - - - - message: "#^Cannot access offset 1 on array\\\\|int\\.$#" - count: 1 - path: ../../../src/pocketmine/Server.php - - - - message: "#^Cannot access offset 2 on array\\\\|int\\.$#" - count: 1 - path: ../../../src/pocketmine/Server.php - - message: "#^Parameter \\#1 \\$x of method pocketmine\\\\level\\\\Level\\:\\:getBlockAt\\(\\) expects int, float\\|int given\\.$#" count: 1 @@ -455,71 +380,11 @@ parameters: count: 1 path: ../../../src/pocketmine/command/defaults/BanIpCommand.php - - - message: "#^Cannot call method getMaxStackSize\\(\\) on array\\\\|pocketmine\\\\item\\\\Item\\.$#" - count: 1 - path: ../../../src/pocketmine/command/defaults/GiveCommand.php - - - - message: "#^Cannot call method setCount\\(\\) on array\\\\|pocketmine\\\\item\\\\Item\\.$#" - count: 2 - path: ../../../src/pocketmine/command/defaults/GiveCommand.php - - - - message: "#^Cannot call method setNamedTag\\(\\) on array\\\\|pocketmine\\\\item\\\\Item\\.$#" - count: 1 - path: ../../../src/pocketmine/command/defaults/GiveCommand.php - - - - message: "#^Cannot clone non\\-object variable \\$item of type array\\\\|pocketmine\\\\item\\\\Item\\.$#" - count: 1 - path: ../../../src/pocketmine/command/defaults/GiveCommand.php - - - - message: "#^Parameter \\#1 \\.\\.\\.\\$slots of method pocketmine\\\\inventory\\\\BaseInventory\\:\\:addItem\\(\\) expects pocketmine\\\\item\\\\Item, array\\\\|pocketmine\\\\item\\\\Item given\\.$#" - count: 1 - path: ../../../src/pocketmine/command/defaults/GiveCommand.php - - - - message: "#^Cannot call method getDamage\\(\\) on array\\\\|pocketmine\\\\item\\\\Item\\.$#" - count: 1 - path: ../../../src/pocketmine/command/defaults/GiveCommand.php - - - - message: "#^Cannot call method getId\\(\\) on array\\\\|pocketmine\\\\item\\\\Item\\.$#" - count: 1 - path: ../../../src/pocketmine/command/defaults/GiveCommand.php - - - - message: "#^Cannot call method getName\\(\\) on array\\\\|pocketmine\\\\item\\\\Item\\.$#" - count: 1 - path: ../../../src/pocketmine/command/defaults/GiveCommand.php - - - - message: "#^Cannot call method getCount\\(\\) on array\\\\|pocketmine\\\\item\\\\Item\\.$#" - count: 1 - path: ../../../src/pocketmine/command/defaults/GiveCommand.php - - message: "#^Only booleans are allowed in an if condition, int\\|false given\\.$#" count: 1 path: ../../../src/pocketmine/command/defaults/PardonIpCommand.php - - - message: "#^Cannot access offset 0 on array\\\\|int\\.$#" - count: 1 - path: ../../../src/pocketmine/command/defaults/StatusCommand.php - - - - message: "#^Cannot access offset 1 on array\\\\|int\\.$#" - count: 1 - path: ../../../src/pocketmine/command/defaults/StatusCommand.php - - - - message: "#^Cannot access offset 2 on array\\\\|int\\.$#" - count: 2 - path: ../../../src/pocketmine/command/defaults/StatusCommand.php - - message: "#^Parameter \\#1 \\$fp of static method pocketmine\\\\timings\\\\TimingsHandler\\:\\:printTimings\\(\\) expects resource, resource\\|false given\\.$#" count: 1 @@ -605,16 +470,6 @@ parameters: count: 1 path: ../../../src/pocketmine/event/HandlerList.php - - - message: "#^Cannot access offset 0 on array\\\\|int\\.$#" - count: 1 - path: ../../../src/pocketmine/event/server/LowMemoryEvent.php - - - - message: "#^Cannot access offset 1 on array\\\\|int\\.$#" - count: 1 - path: ../../../src/pocketmine/event/server/LowMemoryEvent.php - - message: "#^Parameter \\#1 \\$json of function json_decode expects string, string\\|false given\\.$#" count: 1 @@ -635,31 +490,6 @@ parameters: count: 1 path: ../../../src/pocketmine/item/Item.php - - - message: "#^Cannot call method setDamage\\(\\) on array\\\\|pocketmine\\\\item\\\\Item\\.$#" - count: 1 - path: ../../../src/pocketmine/item/Item.php - - - - message: "#^Cannot call method setCount\\(\\) on array\\\\|pocketmine\\\\item\\\\Item\\.$#" - count: 1 - path: ../../../src/pocketmine/item/Item.php - - - - message: "#^Cannot call method setNamedTag\\(\\) on array\\\\|pocketmine\\\\item\\\\Item\\.$#" - count: 1 - path: ../../../src/pocketmine/item/Item.php - - - - message: "#^Method pocketmine\\\\item\\\\Item\\:\\:nbtDeserialize\\(\\) should return pocketmine\\\\item\\\\Item but returns array\\\\|pocketmine\\\\item\\\\Item\\.$#" - count: 1 - path: ../../../src/pocketmine/item/Item.php - - - - message: "#^Method pocketmine\\\\item\\\\ItemFactory\\:\\:fromString\\(\\) should return array\\\\|pocketmine\\\\item\\\\Item but returns array\\\\|pocketmine\\\\item\\\\Item\\>\\.$#" - count: 1 - path: ../../../src/pocketmine/item/ItemFactory.php - - message: "#^Parameter \\#2 \\$input1 of function array_map expects array, array\\|false given\\.$#" count: 1 @@ -890,16 +720,6 @@ parameters: count: 1 path: ../../../src/pocketmine/level/Level.php - - - message: "#^Cannot call method getBlock\\(\\) on array\\\\|pocketmine\\\\item\\\\Item\\.$#" - count: 2 - path: ../../../src/pocketmine/level/Level.php - - - - message: "#^Cannot call method getId\\(\\) on array\\\\|pocketmine\\\\item\\\\Item\\.$#" - count: 2 - path: ../../../src/pocketmine/level/Level.php - - message: "#^Parameter \\#2 \\$amount of method pocketmine\\\\level\\\\Level\\:\\:dropExperience\\(\\) expects int, float\\|int\\<1, max\\> given\\.$#" count: 1 @@ -950,21 +770,6 @@ parameters: count: 1 path: ../../../src/pocketmine/level/format/io/region/RegionLoader.php - - - message: "#^Property pocketmine\\\\level\\\\format\\\\io\\\\region\\\\RegionLoader\\:\\:\\$filePointer \\(resource\\) does not accept resource\\|false\\.$#" - count: 1 - path: ../../../src/pocketmine/level/format/io/region/RegionLoader.php - - - - message: "#^Parameter \\#1 \\$fp of function stream_set_read_buffer expects resource, resource\\|false given\\.$#" - count: 1 - path: ../../../src/pocketmine/level/format/io/region/RegionLoader.php - - - - message: "#^Parameter \\#1 \\$fp of function stream_set_write_buffer expects resource, resource\\|false given\\.$#" - count: 1 - path: ../../../src/pocketmine/level/format/io/region/RegionLoader.php - - message: "#^Parameter \\#1 \\$string of function strlen expects string, string\\|false given\\.$#" count: 1 @@ -975,11 +780,6 @@ parameters: count: 1 path: ../../../src/pocketmine/level/format/io/region/RegionLoader.php - - - message: "#^Cannot call method getBlock\\(\\) on array\\\\|pocketmine\\\\item\\\\Item\\.$#" - count: 1 - path: ../../../src/pocketmine/level/generator/Flat.php - - message: "#^Parameter \\#1 \\$start of method pocketmine\\\\utils\\\\Random\\:\\:nextRange\\(\\) expects int, float\\|int given\\.$#" count: 2 @@ -1060,11 +860,6 @@ parameters: count: 1 path: ../../../src/pocketmine/network/mcpe/VerifyLoginTask.php - - - message: "#^Property pocketmine\\\\network\\\\mcpe\\\\protocol\\\\AddActorPacket\\:\\:\\$type \\(int\\) does not accept int\\|false\\.$#" - count: 1 - path: ../../../src/pocketmine/network/mcpe/protocol/AddActorPacket.php - - message: "#^Parameter \\#1 \\$str of method pocketmine\\\\utils\\\\BinaryStream\\:\\:put\\(\\) expects string, string\\|false given\\.$#" count: 1 @@ -1130,26 +925,6 @@ parameters: count: 1 path: ../../../src/pocketmine/network/mcpe/protocol/types/RuntimeBlockMapping.php - - - message: "#^Property pocketmine\\\\network\\\\rcon\\\\RCON\\:\\:\\$socket \\(resource\\) does not accept resource\\|false\\.$#" - count: 1 - path: ../../../src/pocketmine/network/rcon/RCON.php - - - - message: "#^Parameter \\#1 \\$socket of function socket_set_option expects resource, resource\\|false given\\.$#" - count: 1 - path: ../../../src/pocketmine/network/rcon/RCON.php - - - - message: "#^Only booleans are allowed in an if condition, bool\\|int given\\.$#" - count: 1 - path: ../../../src/pocketmine/network/rcon/RCONInstance.php - - - - message: "#^Only booleans are allowed in a negated boolean, bool\\|int given\\.$#" - count: 2 - path: ../../../src/pocketmine/network/rcon/RCONInstance.php - - message: "#^Call to an undefined method object\\:\\:Add\\(\\)\\.$#" count: 1 @@ -1160,56 +935,11 @@ parameters: count: 1 path: ../../../src/pocketmine/network/upnp/UPnP.php - - - message: "#^Method pocketmine\\\\plugin\\\\PluginBase\\:\\:getResource\\(\\) should return resource\\|null but returns resource\\|false\\.$#" - count: 1 - path: ../../../src/pocketmine/plugin/PluginBase.php - - - - message: "#^Parameter \\#2 \\$dest of function stream_copy_to_stream expects resource, resource\\|false given\\.$#" - count: 1 - path: ../../../src/pocketmine/plugin/PluginBase.php - - - - message: "#^Parameter \\#1 \\$fp of function fclose expects resource, resource\\|false given\\.$#" - count: 1 - path: ../../../src/pocketmine/plugin/PluginBase.php - - - - message: "#^Parameter \\#1 \\$version1 of function version_compare expects string, string\\|false given\\.$#" - count: 1 - path: ../../../src/pocketmine/plugin/PluginDescription.php - - - - message: "#^Parameter \\#1 \\$path of method pocketmine\\\\plugin\\\\PluginLoader\\:\\:canLoadPlugin\\(\\) expects string, SplFileInfo\\|string given\\.$#" - count: 1 - path: ../../../src/pocketmine/plugin/PluginManager.php - - - - message: "#^Parameter \\#1 \\$file of method pocketmine\\\\plugin\\\\PluginLoader\\:\\:getPluginDescription\\(\\) expects string, SplFileInfo\\|string given\\.$#" - count: 1 - path: ../../../src/pocketmine/plugin/PluginManager.php - - - - message: "#^Parameter \\#2 \\$params of method pocketmine\\\\lang\\\\BaseLang\\:\\:translateString\\(\\) expects array\\, array\\ given\\.$#" - count: 1 - path: ../../../src/pocketmine/plugin/PluginManager.php - - - - message: "#^Parameter \\#1 \\$path of method pocketmine\\\\plugin\\\\PluginManager\\:\\:loadPlugin\\(\\) expects string, SplFileInfo\\|string given\\.$#" - count: 1 - path: ../../../src/pocketmine/plugin/PluginManager.php - - message: "#^Parameter \\#1 \\$event of method pocketmine\\\\plugin\\\\PluginManager\\:\\:registerEvent\\(\\) expects class\\-string\\, class\\-string\\ given\\.$#" count: 1 path: ../../../src/pocketmine/plugin/PluginManager.php - - - message: "#^Argument of an invalid type array\\\\|false supplied for foreach, only iterables are supported\\.$#" - count: 1 - path: ../../../src/pocketmine/plugin/ScriptPluginLoader.php - - message: "#^Parameter \\#1 \\$string of function strlen expects string, string\\|false given\\.$#" count: 2 @@ -1245,36 +975,6 @@ parameters: count: 1 path: ../../../src/pocketmine/resourcepacks/ZippedResourcePack.php - - - message: "#^Method pocketmine\\\\scheduler\\\\AsyncPool\\:\\:selectWorker\\(\\) should return int but returns int\\|string\\.$#" - count: 1 - path: ../../../src/pocketmine/scheduler/AsyncPool.php - - - - message: "#^Parameter \\#1 \\$variable_representation of function unserialize expects string, bool\\|float\\|int\\|string\\|null given\\.$#" - count: 1 - path: ../../../src/pocketmine/scheduler/AsyncTask.php - - - - message: "#^Cannot access offset 0 on array\\\\|int\\.$#" - count: 1 - path: ../../../src/pocketmine/scheduler/SendUsageTask.php - - - - message: "#^Cannot access offset 1 on array\\\\|int\\.$#" - count: 1 - path: ../../../src/pocketmine/scheduler/SendUsageTask.php - - - - message: "#^Cannot access offset 2 on array\\\\|int\\.$#" - count: 1 - path: ../../../src/pocketmine/scheduler/SendUsageTask.php - - - - message: "#^Property pocketmine\\\\scheduler\\\\SendUsageTask\\:\\:\\$data \\(string\\) does not accept string\\|false\\.$#" - count: 1 - path: ../../../src/pocketmine/scheduler/SendUsageTask.php - - message: "#^Parameter \\#2 \\$y of method pocketmine\\\\level\\\\Level\\:\\:getTileAt\\(\\) expects int, float\\|int given\\.$#" count: 1 @@ -1305,16 +1005,6 @@ parameters: count: 1 path: ../../../src/pocketmine/tile/Spawnable.php - - - message: "#^Property pocketmine\\\\tile\\\\Spawnable\\:\\:\\$spawnCompoundCache \\(string\\|null\\) does not accept string\\|false\\.$#" - count: 1 - path: ../../../src/pocketmine/tile/Spawnable.php - - - - message: "#^Method pocketmine\\\\tile\\\\Spawnable\\:\\:getSerializedSpawnCompound\\(\\) should return string but returns string\\|false\\.$#" - count: 1 - path: ../../../src/pocketmine/tile/Spawnable.php - - message: "#^Parameter \\#2 \\$value of class pocketmine\\\\nbt\\\\tag\\\\IntTag constructor expects int, float\\|int given\\.$#" count: 3 @@ -1340,243 +1030,3 @@ parameters: count: 1 path: ../../../src/pocketmine/tile/Tile.php - - - message: "#^Parameter \\#1 \\$content of method pocketmine\\\\utils\\\\Config\\:\\:parseProperties\\(\\) expects string, string\\|false given\\.$#" - count: 1 - path: ../../../src/pocketmine/utils/Config.php - - - - message: "#^Parameter \\#1 \\$json of function json_decode expects string, string\\|false given\\.$#" - count: 1 - path: ../../../src/pocketmine/utils/Config.php - - - - message: "#^Parameter \\#1 \\$str of static method pocketmine\\\\utils\\\\Config\\:\\:fixYAMLIndexes\\(\\) expects string, string\\|false given\\.$#" - count: 1 - path: ../../../src/pocketmine/utils/Config.php - - - - message: "#^Parameter \\#1 \\$variable_representation of function unserialize expects string, string\\|false given\\.$#" - count: 1 - path: ../../../src/pocketmine/utils/Config.php - - - - message: "#^Parameter \\#1 \\$content of static method pocketmine\\\\utils\\\\Config\\:\\:parseList\\(\\) expects string, string\\|false given\\.$#" - count: 1 - path: ../../../src/pocketmine/utils/Config.php - - - - message: "#^Method pocketmine\\\\utils\\\\Config\\:\\:parseProperties\\(\\) should return array\\ but returns array\\\\.$#" - count: 1 - path: ../../../src/pocketmine/utils/Config.php - - - - message: "#^Parameter \\#1 \\$socket of function socket_connect expects resource, resource\\|false given\\.$#" - count: 1 - path: ../../../src/pocketmine/utils/Internet.php - - - - message: "#^Parameter \\#1 \\$socket of function socket_last_error expects resource, resource\\|false given\\.$#" - count: 2 - path: ../../../src/pocketmine/utils/Internet.php - - - - message: "#^Parameter \\#1 \\$socket of function socket_getsockname expects resource, resource\\|false given\\.$#" - count: 1 - path: ../../../src/pocketmine/utils/Internet.php - - - - message: "#^Parameter \\#1 \\$socket of function socket_close expects resource, resource\\|false given\\.$#" - count: 1 - path: ../../../src/pocketmine/utils/Internet.php - - - - message: "#^Parameter \\#1 \\$ch of function curl_setopt_array expects resource, resource\\|false given\\.$#" - count: 1 - path: ../../../src/pocketmine/utils/Internet.php - - - - message: "#^Parameter \\#1 \\$ch of function curl_exec expects resource, resource\\|false given\\.$#" - count: 1 - path: ../../../src/pocketmine/utils/Internet.php - - - - message: "#^Parameter \\#1 \\$ch of function curl_error expects resource, resource\\|false given\\.$#" - count: 1 - path: ../../../src/pocketmine/utils/Internet.php - - - - message: "#^Parameter \\#1 \\$ch of function curl_getinfo expects resource, resource\\|false given\\.$#" - count: 2 - path: ../../../src/pocketmine/utils/Internet.php - - - - message: "#^Parameter \\#1 \\$str of function substr expects string, bool\\|string given\\.$#" - count: 2 - path: ../../../src/pocketmine/utils/Internet.php - - - - message: "#^Parameter \\#1 \\$ of callable callable\\(resource\\)\\: void expects resource, resource\\|false given\\.$#" - count: 1 - path: ../../../src/pocketmine/utils/Internet.php - - - - message: "#^Parameter \\#1 \\$ch of function curl_close expects resource, resource\\|false given\\.$#" - count: 1 - path: ../../../src/pocketmine/utils/Internet.php - - - - message: "#^Parameter \\#1 \\$stream of function stream_isatty expects resource, resource\\|false given\\.$#" - count: 1 - path: ../../../src/pocketmine/utils/Terminal.php - - - - message: "#^Parameter \\#1 \\$stream of function sapi_windows_vt100_support expects resource, resource\\|false given\\.$#" - count: 1 - path: ../../../src/pocketmine/utils/Terminal.php - - - - message: "#^Parameter \\#1 \\$fp of function fclose expects resource, resource\\|false given\\.$#" - count: 1 - path: ../../../src/pocketmine/utils/Terminal.php - - - - message: "#^Method pocketmine\\\\utils\\\\TextFormat\\:\\:tokenize\\(\\) should return array\\ but returns array\\\\|false\\.$#" - count: 1 - path: ../../../src/pocketmine/utils/TextFormat.php - - - - message: "#^Method pocketmine\\\\utils\\\\TextFormat\\:\\:toJSON\\(\\) should return string but returns string\\|false\\.$#" - count: 1 - path: ../../../src/pocketmine/utils/TextFormat.php - - - - message: "#^Method pocketmine\\\\utils\\\\Timezone\\:\\:get\\(\\) should return string but returns string\\|false\\.$#" - count: 1 - path: ../../../src/pocketmine/utils/Timezone.php - - - - message: "#^Parameter \\#1 \\$haystack of function strpos expects string, string\\|false given\\.$#" - count: 2 - path: ../../../src/pocketmine/utils/Timezone.php - - - - message: "#^Parameter \\#1 \\$abbr of function timezone_name_from_abbr expects string, string\\|false given\\.$#" - count: 1 - path: ../../../src/pocketmine/utils/Timezone.php - - - - message: "#^Parameter \\#1 \\$timezone_identifier of function date_default_timezone_set expects string, string\\|false given\\.$#" - count: 1 - path: ../../../src/pocketmine/utils/Timezone.php - - - - message: "#^Method pocketmine\\\\utils\\\\Timezone\\:\\:detectSystemTimezone\\(\\) should return string\\|false but returns bool\\|string\\.$#" - count: 2 - path: ../../../src/pocketmine/utils/Timezone.php - - - - message: "#^Only booleans are allowed in an if condition, string\\|false given\\.$#" - count: 1 - path: ../../../src/pocketmine/utils/Timezone.php - - - - message: "#^Cannot access offset 'ZONE' on array\\|false\\.$#" - count: 1 - path: ../../../src/pocketmine/utils/Timezone.php - - - - message: "#^Parameter \\#1 \\$str of function substr expects string, string\\|false given\\.$#" - count: 1 - path: ../../../src/pocketmine/utils/Timezone.php - - - - message: "#^Parameter \\#1 \\$uuid of static method pocketmine\\\\utils\\\\UUID\\:\\:fromBinary\\(\\) expects string, string\\|false given\\.$#" - count: 1 - path: ../../../src/pocketmine/utils/UUID.php - - - - message: "#^Parameter \\#1 \\$str of function strtolower expects string, callable given\\.$#" - count: 1 - path: ../../../src/pocketmine/utils/Utils.php - - - - message: "#^Parameter \\#1 \\$path of static method pocketmine\\\\utils\\\\Utils\\:\\:cleanPath\\(\\) expects string, string\\|false given\\.$#" - count: 2 - path: ../../../src/pocketmine/utils/Utils.php - - - - message: "#^Parameter \\#2 \\$input of function preg_grep expects array, array\\\\|false given\\.$#" - count: 1 - path: ../../../src/pocketmine/utils/Utils.php - - - - message: "#^Only booleans are allowed in an if condition, int\\|false given\\.$#" - count: 2 - path: ../../../src/pocketmine/utils/Utils.php - - - - message: "#^Argument of an invalid type array\\\\|false supplied for foreach, only iterables are supported\\.$#" - count: 2 - path: ../../../src/pocketmine/utils/Utils.php - - - - message: "#^Method pocketmine\\\\utils\\\\Utils\\:\\:getRealMemoryUsage\\(\\) should return array\\ but returns array\\\\.$#" - count: 1 - path: ../../../src/pocketmine/utils/Utils.php - - - - message: "#^Parameter \\#2 \\$subject of function preg_match expects string, string\\|false given\\.$#" - count: 3 - path: ../../../src/pocketmine/utils/Utils.php - - - - message: "#^Method pocketmine\\\\utils\\\\Utils\\:\\:getMemoryUsage\\(\\) should return array\\\\|int but returns float\\|int\\.$#" - count: 1 - path: ../../../src/pocketmine/utils/Utils.php - - - - message: "#^Method pocketmine\\\\utils\\\\Utils\\:\\:getMemoryUsage\\(\\) should return array\\\\|int but returns array\\\\.$#" - count: 1 - path: ../../../src/pocketmine/utils/Utils.php - - - - message: "#^Parameter \\#1 \\$str of function trim expects string, string\\|false given\\.$#" - count: 1 - path: ../../../src/pocketmine/utils/Utils.php - - - - message: "#^Parameter \\#1 \\$json of function json_decode expects string, string\\|false given\\.$#" - count: 1 - path: ../../../src/pocketmine/utils/Utils.php - - - - message: "#^Parameter \\#2 \\$str of function explode expects string, string\\|false given\\.$#" - count: 1 - path: ../../../src/pocketmine/utils/Utils.php - - - - message: "#^Method pocketmine\\\\utils\\\\Utils\\:\\:parseDocComment\\(\\) should return array\\ but returns array\\|false\\.$#" - count: 1 - path: ../../../src/pocketmine/utils/Utils.php - - - - message: "#^Parameter \\#1 \\$argument of class ReflectionClass constructor expects class\\-string\\\\|T of object, string given\\.$#" - count: 2 - path: ../../../src/pocketmine/utils/Utils.php - - - - message: "#^Parameter \\#2 \\$params of method pocketmine\\\\lang\\\\BaseLang\\:\\:translateString\\(\\) expects array\\, array\\ given\\.$#" - count: 1 - path: ../../../src/pocketmine/wizard/SetupWizard.php - - - - message: "#^Cannot call method getId\\(\\) on array\\\\|pocketmine\\\\item\\\\Item\\.$#" - count: 1 - path: ../../phpunit/item/ItemTest.php - - - - message: "#^Cannot call method getDamage\\(\\) on array\\\\|pocketmine\\\\item\\\\Item\\.$#" - count: 1 - path: ../../phpunit/item/ItemTest.php - diff --git a/tests/phpstan/configs/l8-baseline.neon b/tests/phpstan/configs/l8-baseline.neon index 210cd2a3f..ee06cb56c 100644 --- a/tests/phpstan/configs/l8-baseline.neon +++ b/tests/phpstan/configs/l8-baseline.neon @@ -107,7 +107,7 @@ parameters: - message: "#^Cannot call method getFolderName\\(\\) on pocketmine\\\\level\\\\Level\\|null\\.$#" - count: 3 + count: 2 path: ../../../src/pocketmine/Player.php - @@ -135,11 +135,6 @@ parameters: count: 1 path: ../../../src/pocketmine/Player.php - - - message: "#^Cannot call method broadcastPacketToViewers\\(\\) on pocketmine\\\\level\\\\Level\\|null\\.$#" - count: 1 - path: ../../../src/pocketmine/Player.php - - message: "#^Cannot call method useItemOn\\(\\) on pocketmine\\\\level\\\\Level\\|null\\.$#" count: 2 @@ -157,7 +152,7 @@ parameters: - message: "#^Cannot call method getTile\\(\\) on pocketmine\\\\level\\\\Level\\|null\\.$#" - count: 3 + count: 2 path: ../../../src/pocketmine/Player.php - @@ -196,7 +191,7 @@ parameters: path: ../../../src/pocketmine/Player.php - - message: "#^Cannot call method getLevel\\(\\) on pocketmine\\\\level\\\\Position\\|null\\.$#" + message: "#^Cannot call method getLevelNonNull\\(\\) on pocketmine\\\\level\\\\Position\\|null\\.$#" count: 1 path: ../../../src/pocketmine/Player.php @@ -280,61 +275,21 @@ parameters: count: 1 path: ../../../src/pocketmine/Worker.php - - - message: "#^Cannot call method setBlock\\(\\) on pocketmine\\\\level\\\\Level\\|null\\.$#" - count: 1 - path: ../../../src/pocketmine/block/Anvil.php - - - - message: "#^Cannot call method setBlock\\(\\) on pocketmine\\\\level\\\\Level\\|null\\.$#" - count: 2 - path: ../../../src/pocketmine/block/BaseRail.php - - message: "#^Parameter \\#1 \\$constraint of method pocketmine\\\\block\\\\BaseRail\\:\\:getPossibleConnectionDirectionsOneConstraint\\(\\) expects int, int\\|null given\\.$#" count: 1 path: ../../../src/pocketmine/block/BaseRail.php - - message: "#^Cannot call method useBreakOn\\(\\) on pocketmine\\\\level\\\\Level\\|null\\.$#" + message: "#^Cannot call method setBlock\\(\\) on pocketmine\\\\level\\\\Level\\|null\\.$#" count: 1 path: ../../../src/pocketmine/block/BaseRail.php - - - message: "#^Cannot call method setBlock\\(\\) on pocketmine\\\\level\\\\Level\\|null\\.$#" - count: 3 - path: ../../../src/pocketmine/block/Bed.php - - - - message: "#^Cannot call method getTime\\(\\) on pocketmine\\\\level\\\\Level\\|null\\.$#" - count: 1 - path: ../../../src/pocketmine/block/Bed.php - - message: "#^Only numeric types are allowed in \\-, int\\|null given on the left side\\.$#" count: 1 path: ../../../src/pocketmine/block/Bed.php - - - message: "#^Parameter \\#2 \\$level of static method pocketmine\\\\tile\\\\Tile\\:\\:createTile\\(\\) expects pocketmine\\\\level\\\\Level, pocketmine\\\\level\\\\Level\\|null given\\.$#" - count: 2 - path: ../../../src/pocketmine/block/Bed.php - - - - message: "#^Cannot call method getTile\\(\\) on pocketmine\\\\level\\\\Level\\|null\\.$#" - count: 1 - path: ../../../src/pocketmine/block/Bed.php - - - - message: "#^Cannot call method setBlock\\(\\) on pocketmine\\\\level\\\\Level\\|null\\.$#" - count: 2 - path: ../../../src/pocketmine/block/Block.php - - - - message: "#^Cannot call method getBlock\\(\\) on pocketmine\\\\level\\\\Level\\|null\\.$#" - count: 1 - path: ../../../src/pocketmine/block/Block.php - - message: "#^Cannot call method getBlockMetadata\\(\\) on pocketmine\\\\level\\\\Level\\|null\\.$#" count: 4 @@ -370,116 +325,21 @@ parameters: count: 1 path: ../../../src/pocketmine/block/BlockFactory.php - - - message: "#^Cannot call method setBlock\\(\\) on pocketmine\\\\level\\\\Level\\|null\\.$#" - count: 1 - path: ../../../src/pocketmine/block/BoneBlock.php - - - - message: "#^Cannot call method setBlock\\(\\) on pocketmine\\\\level\\\\Level\\|null\\.$#" - count: 1 - path: ../../../src/pocketmine/block/BurningFurnace.php - - - - message: "#^Parameter \\#2 \\$level of static method pocketmine\\\\tile\\\\Tile\\:\\:createTile\\(\\) expects pocketmine\\\\level\\\\Level, pocketmine\\\\level\\\\Level\\|null given\\.$#" - count: 2 - path: ../../../src/pocketmine/block/BurningFurnace.php - - - - message: "#^Cannot call method getTile\\(\\) on pocketmine\\\\level\\\\Level\\|null\\.$#" - count: 1 - path: ../../../src/pocketmine/block/BurningFurnace.php - - message: "#^Cannot call method setBlock\\(\\) on pocketmine\\\\level\\\\Level\\|null\\.$#" count: 1 path: ../../../src/pocketmine/block/Button.php - - message: "#^Cannot call method useBreakOn\\(\\) on pocketmine\\\\level\\\\Level\\|null\\.$#" - count: 2 - path: ../../../src/pocketmine/block/Cactus.php - - - - message: "#^Cannot call method getBlockAt\\(\\) on pocketmine\\\\level\\\\Level\\|null\\.$#" + message: "#^Cannot call method setBlock\\(\\) on pocketmine\\\\level\\\\Level\\|null\\.$#" count: 1 - path: ../../../src/pocketmine/block/Cactus.php - - - - message: "#^Cannot call method setBlock\\(\\) on pocketmine\\\\level\\\\Level\\|null\\.$#" - count: 4 - path: ../../../src/pocketmine/block/Cactus.php - - - - message: "#^Cannot call method setBlock\\(\\) on pocketmine\\\\level\\\\Level\\|null\\.$#" - count: 3 path: ../../../src/pocketmine/block/Cake.php - - - message: "#^Cannot call method setBlock\\(\\) on pocketmine\\\\level\\\\Level\\|null\\.$#" - count: 1 - path: ../../../src/pocketmine/block/Carpet.php - - - - message: "#^Cannot call method useBreakOn\\(\\) on pocketmine\\\\level\\\\Level\\|null\\.$#" - count: 1 - path: ../../../src/pocketmine/block/Carpet.php - - - - message: "#^Cannot call method getTile\\(\\) on pocketmine\\\\level\\\\Level\\|null\\.$#" - count: 2 - path: ../../../src/pocketmine/block/Chest.php - - - - message: "#^Cannot call method setBlock\\(\\) on pocketmine\\\\level\\\\Level\\|null\\.$#" - count: 1 - path: ../../../src/pocketmine/block/Chest.php - - - - message: "#^Parameter \\#2 \\$level of static method pocketmine\\\\tile\\\\Tile\\:\\:createTile\\(\\) expects pocketmine\\\\level\\\\Level, pocketmine\\\\level\\\\Level\\|null given\\.$#" - count: 2 - path: ../../../src/pocketmine/block/Chest.php - - message: "#^Cannot call method setBlock\\(\\) on pocketmine\\\\level\\\\Level\\|null\\.$#" count: 1 path: ../../../src/pocketmine/block/ConcretePowder.php - - - message: "#^Cannot call method setBlock\\(\\) on pocketmine\\\\level\\\\Level\\|null\\.$#" - count: 3 - path: ../../../src/pocketmine/block/Crops.php - - - - message: "#^Cannot call method useBreakOn\\(\\) on pocketmine\\\\level\\\\Level\\|null\\.$#" - count: 1 - path: ../../../src/pocketmine/block/Crops.php - - - - message: "#^Cannot call method setBlock\\(\\) on pocketmine\\\\level\\\\Level\\|null\\.$#" - count: 1 - path: ../../../src/pocketmine/block/Dandelion.php - - - - message: "#^Cannot call method useBreakOn\\(\\) on pocketmine\\\\level\\\\Level\\|null\\.$#" - count: 1 - path: ../../../src/pocketmine/block/Dandelion.php - - - - message: "#^Cannot call method useBreakOn\\(\\) on pocketmine\\\\level\\\\Level\\|null\\.$#" - count: 1 - path: ../../../src/pocketmine/block/DeadBush.php - - - - message: "#^Cannot call method setBlock\\(\\) on pocketmine\\\\level\\\\Level\\|null\\.$#" - count: 2 - path: ../../../src/pocketmine/block/Dirt.php - - - - message: "#^Cannot call method setBlock\\(\\) on pocketmine\\\\level\\\\Level\\|null\\.$#" - count: 6 - path: ../../../src/pocketmine/block/Door.php - - message: "#^Only numeric types are allowed in \\+, int\\|null given on the left side\\.$#" count: 1 @@ -491,29 +351,14 @@ parameters: path: ../../../src/pocketmine/block/Door.php - - message: "#^Cannot call method addSound\\(\\) on pocketmine\\\\level\\\\Level\\|null\\.$#" + message: "#^Cannot call method setBlock\\(\\) on pocketmine\\\\level\\\\Level\\|null\\.$#" count: 2 path: ../../../src/pocketmine/block/Door.php - - message: "#^Cannot call method setBlock\\(\\) on pocketmine\\\\level\\\\Level\\|null\\.$#" + message: "#^Cannot call method addSound\\(\\) on pocketmine\\\\level\\\\Level\\|null\\.$#" count: 2 - path: ../../../src/pocketmine/block/DoublePlant.php - - - - message: "#^Cannot call method useBreakOn\\(\\) on pocketmine\\\\level\\\\Level\\|null\\.$#" - count: 1 - path: ../../../src/pocketmine/block/DoublePlant.php - - - - message: "#^Cannot call method setBlock\\(\\) on pocketmine\\\\level\\\\Level\\|null\\.$#" - count: 1 - path: ../../../src/pocketmine/block/EnchantingTable.php - - - - message: "#^Parameter \\#2 \\$level of static method pocketmine\\\\tile\\\\Tile\\:\\:createTile\\(\\) expects pocketmine\\\\level\\\\Level, pocketmine\\\\level\\\\Level\\|null given\\.$#" - count: 1 - path: ../../../src/pocketmine/block/EnchantingTable.php + path: ../../../src/pocketmine/block/Door.php - message: "#^Cannot call method setBlock\\(\\) on pocketmine\\\\level\\\\Level\\|null\\.$#" @@ -523,26 +368,6 @@ parameters: - message: "#^Cannot call method setBlock\\(\\) on pocketmine\\\\level\\\\Level\\|null\\.$#" count: 1 - path: ../../../src/pocketmine/block/EnderChest.php - - - - message: "#^Parameter \\#2 \\$level of static method pocketmine\\\\tile\\\\Tile\\:\\:createTile\\(\\) expects pocketmine\\\\level\\\\Level, pocketmine\\\\level\\\\Level\\|null given\\.$#" - count: 2 - path: ../../../src/pocketmine/block/EnderChest.php - - - - message: "#^Cannot call method getTile\\(\\) on pocketmine\\\\level\\\\Level\\|null\\.$#" - count: 1 - path: ../../../src/pocketmine/block/EnderChest.php - - - - message: "#^Cannot call method setBlock\\(\\) on pocketmine\\\\level\\\\Level\\|null\\.$#" - count: 1 - path: ../../../src/pocketmine/block/Fallable.php - - - - message: "#^Parameter \\#2 \\$level of static method pocketmine\\\\entity\\\\Entity\\:\\:createEntity\\(\\) expects pocketmine\\\\level\\\\Level, pocketmine\\\\level\\\\Level\\|null given\\.$#" - count: 1 path: ../../../src/pocketmine/block/Fallable.php - @@ -560,21 +385,11 @@ parameters: count: 2 path: ../../../src/pocketmine/block/FenceGate.php - - - message: "#^Cannot call method setBlock\\(\\) on pocketmine\\\\level\\\\Level\\|null\\.$#" - count: 2 - path: ../../../src/pocketmine/block/FenceGate.php - - message: "#^Cannot call method addSound\\(\\) on pocketmine\\\\level\\\\Level\\|null\\.$#" count: 1 path: ../../../src/pocketmine/block/FenceGate.php - - - message: "#^Cannot call method setBlock\\(\\) on pocketmine\\\\level\\\\Level\\|null\\.$#" - count: 4 - path: ../../../src/pocketmine/block/Fire.php - - message: "#^Cannot call method scheduleDelayedBlockUpdate\\(\\) on pocketmine\\\\level\\\\Level\\|null\\.$#" count: 2 @@ -582,49 +397,14 @@ parameters: - message: "#^Cannot call method setBlock\\(\\) on pocketmine\\\\level\\\\Level\\|null\\.$#" - count: 1 - path: ../../../src/pocketmine/block/Flower.php - - - - message: "#^Cannot call method useBreakOn\\(\\) on pocketmine\\\\level\\\\Level\\|null\\.$#" - count: 1 - path: ../../../src/pocketmine/block/Flower.php - - - - message: "#^Cannot call method setBlock\\(\\) on pocketmine\\\\level\\\\Level\\|null\\.$#" - count: 2 - path: ../../../src/pocketmine/block/FlowerPot.php - - - - message: "#^Parameter \\#2 \\$level of static method pocketmine\\\\tile\\\\Tile\\:\\:createTile\\(\\) expects pocketmine\\\\level\\\\Level, pocketmine\\\\level\\\\Level\\|null given\\.$#" - count: 1 - path: ../../../src/pocketmine/block/FlowerPot.php - - - - message: "#^Cannot call method useBreakOn\\(\\) on pocketmine\\\\level\\\\Level\\|null\\.$#" - count: 1 - path: ../../../src/pocketmine/block/FlowerPot.php - - - - message: "#^Cannot call method getTile\\(\\) on pocketmine\\\\level\\\\Level\\|null\\.$#" - count: 2 - path: ../../../src/pocketmine/block/FlowerPot.php + count: 3 + path: ../../../src/pocketmine/block/Fire.php - message: "#^Only numeric types are allowed in \\-, int\\|null given on the left side\\.$#" count: 1 path: ../../../src/pocketmine/block/GlazedTerracotta.php - - - message: "#^Cannot call method setBlock\\(\\) on pocketmine\\\\level\\\\Level\\|null\\.$#" - count: 1 - path: ../../../src/pocketmine/block/GlazedTerracotta.php - - - - message: "#^Cannot call method setBlock\\(\\) on pocketmine\\\\level\\\\Level\\|null\\.$#" - count: 1 - path: ../../../src/pocketmine/block/GlowingRedstoneOre.php - - message: "#^Cannot call method getFullLightAt\\(\\) on pocketmine\\\\level\\\\Level\\|null\\.$#" count: 2 @@ -637,7 +417,7 @@ parameters: - message: "#^Cannot call method setBlock\\(\\) on pocketmine\\\\level\\\\Level\\|null\\.$#" - count: 4 + count: 2 path: ../../../src/pocketmine/block/Grass.php - @@ -650,26 +430,11 @@ parameters: count: 1 path: ../../../src/pocketmine/block/Grass.php - - - message: "#^Parameter \\#1 \\$level of static method pocketmine\\\\level\\\\generator\\\\object\\\\TallGrass\\:\\:growGrass\\(\\) expects pocketmine\\\\level\\\\ChunkManager, pocketmine\\\\level\\\\Level\\|null given\\.$#" - count: 1 - path: ../../../src/pocketmine/block/Grass.php - - message: "#^Cannot call method setBlock\\(\\) on pocketmine\\\\level\\\\Level\\|null\\.$#" count: 1 path: ../../../src/pocketmine/block/GrassPath.php - - - message: "#^Cannot call method setBlock\\(\\) on pocketmine\\\\level\\\\Level\\|null\\.$#" - count: 1 - path: ../../../src/pocketmine/block/HayBale.php - - - - message: "#^Cannot call method setBlock\\(\\) on pocketmine\\\\level\\\\Level\\|null\\.$#" - count: 1 - path: ../../../src/pocketmine/block/Ice.php - - message: "#^Cannot call method getHighestAdjacentBlockLight\\(\\) on pocketmine\\\\level\\\\Level\\|null\\.$#" count: 1 @@ -685,11 +450,6 @@ parameters: count: 2 path: ../../../src/pocketmine/block/ItemFrame.php - - - message: "#^Parameter \\#2 \\$level of static method pocketmine\\\\tile\\\\Tile\\:\\:createTile\\(\\) expects pocketmine\\\\level\\\\Level, pocketmine\\\\level\\\\Level\\|null given\\.$#" - count: 2 - path: ../../../src/pocketmine/block/ItemFrame.php - - message: "#^Cannot call method useBreakOn\\(\\) on pocketmine\\\\level\\\\Level\\|null\\.$#" count: 1 @@ -700,36 +460,11 @@ parameters: count: 1 path: ../../../src/pocketmine/block/ItemFrame.php - - - message: "#^Cannot call method setBlock\\(\\) on pocketmine\\\\level\\\\Level\\|null\\.$#" - count: 1 - path: ../../../src/pocketmine/block/Ladder.php - - message: "#^Cannot call method useBreakOn\\(\\) on pocketmine\\\\level\\\\Level\\|null\\.$#" count: 1 path: ../../../src/pocketmine/block/Ladder.php - - - message: "#^Cannot call method setBlock\\(\\) on pocketmine\\\\level\\\\Level\\|null\\.$#" - count: 1 - path: ../../../src/pocketmine/block/Lava.php - - - - message: "#^Cannot call method scheduleDelayedBlockUpdate\\(\\) on pocketmine\\\\level\\\\Level\\|null\\.$#" - count: 1 - path: ../../../src/pocketmine/block/Lava.php - - - - message: "#^Cannot call method setBlock\\(\\) on pocketmine\\\\level\\\\Level\\|null\\.$#" - count: 3 - path: ../../../src/pocketmine/block/Leaves.php - - - - message: "#^Cannot call method useBreakOn\\(\\) on pocketmine\\\\level\\\\Level\\|null\\.$#" - count: 1 - path: ../../../src/pocketmine/block/Leaves.php - - message: "#^Cannot call method setBlock\\(\\) on pocketmine\\\\level\\\\Level\\|null\\.$#" count: 1 @@ -765,245 +500,40 @@ parameters: count: 1 path: ../../../src/pocketmine/block/Liquid.php - - - message: "#^Cannot call method setBlock\\(\\) on pocketmine\\\\level\\\\Level\\|null\\.$#" - count: 2 - path: ../../../src/pocketmine/block/MelonStem.php - - - - message: "#^Cannot call method getBlockAt\\(\\) on pocketmine\\\\level\\\\Level\\|null\\.$#" - count: 1 - path: ../../../src/pocketmine/block/Mycelium.php - - - - message: "#^Cannot call method setBlock\\(\\) on pocketmine\\\\level\\\\Level\\|null\\.$#" - count: 1 - path: ../../../src/pocketmine/block/Mycelium.php - - - - message: "#^Cannot call method setBlock\\(\\) on pocketmine\\\\level\\\\Level\\|null\\.$#" - count: 2 - path: ../../../src/pocketmine/block/NetherWartPlant.php - - - - message: "#^Cannot call method useBreakOn\\(\\) on pocketmine\\\\level\\\\Level\\|null\\.$#" - count: 1 - path: ../../../src/pocketmine/block/NetherWartPlant.php - - - - message: "#^Cannot call method setBlock\\(\\) on pocketmine\\\\level\\\\Level\\|null\\.$#" - count: 1 - path: ../../../src/pocketmine/block/Pumpkin.php - - - - message: "#^Cannot call method setBlock\\(\\) on pocketmine\\\\level\\\\Level\\|null\\.$#" - count: 2 - path: ../../../src/pocketmine/block/PumpkinStem.php - - - - message: "#^Cannot call method setBlock\\(\\) on pocketmine\\\\level\\\\Level\\|null\\.$#" - count: 1 - path: ../../../src/pocketmine/block/Quartz.php - - - - message: "#^Cannot call method useBreakOn\\(\\) on pocketmine\\\\level\\\\Level\\|null\\.$#" - count: 1 - path: ../../../src/pocketmine/block/RedMushroom.php - - - - message: "#^Cannot call method setBlock\\(\\) on pocketmine\\\\level\\\\Level\\|null\\.$#" - count: 1 - path: ../../../src/pocketmine/block/RedMushroom.php - - - - message: "#^Cannot call method setBlock\\(\\) on pocketmine\\\\level\\\\Level\\|null\\.$#" - count: 3 - path: ../../../src/pocketmine/block/RedstoneOre.php - - - - message: "#^Cannot call method setBlock\\(\\) on pocketmine\\\\level\\\\Level\\|null\\.$#" - count: 2 - path: ../../../src/pocketmine/block/Sapling.php - - - - message: "#^Parameter \\#1 \\$level of static method pocketmine\\\\level\\\\generator\\\\object\\\\Tree\\:\\:growTree\\(\\) expects pocketmine\\\\level\\\\ChunkManager, pocketmine\\\\level\\\\Level\\|null given\\.$#" - count: 2 - path: ../../../src/pocketmine/block/Sapling.php - - - - message: "#^Cannot call method useBreakOn\\(\\) on pocketmine\\\\level\\\\Level\\|null\\.$#" - count: 1 - path: ../../../src/pocketmine/block/Sapling.php - - message: "#^Cannot call method getFullLightAt\\(\\) on pocketmine\\\\level\\\\Level\\|null\\.$#" count: 1 path: ../../../src/pocketmine/block/Sapling.php - - - message: "#^Cannot call method setBlock\\(\\) on pocketmine\\\\level\\\\Level\\|null\\.$#" - count: 2 - path: ../../../src/pocketmine/block/SignPost.php - - - - message: "#^Parameter \\#2 \\$level of static method pocketmine\\\\tile\\\\Tile\\:\\:createTile\\(\\) expects pocketmine\\\\level\\\\Level, pocketmine\\\\level\\\\Level\\|null given\\.$#" - count: 1 - path: ../../../src/pocketmine/block/SignPost.php - - - - message: "#^Cannot call method useBreakOn\\(\\) on pocketmine\\\\level\\\\Level\\|null\\.$#" - count: 1 - path: ../../../src/pocketmine/block/SignPost.php - - - - message: "#^Cannot call method setBlock\\(\\) on pocketmine\\\\level\\\\Level\\|null\\.$#" - count: 1 - path: ../../../src/pocketmine/block/Skull.php - - - - message: "#^Parameter \\#2 \\$level of static method pocketmine\\\\tile\\\\Tile\\:\\:createTile\\(\\) expects pocketmine\\\\level\\\\Level, pocketmine\\\\level\\\\Level\\|null given\\.$#" - count: 1 - path: ../../../src/pocketmine/block/Skull.php - - message: "#^Cannot call method getTile\\(\\) on pocketmine\\\\level\\\\Level\\|null\\.$#" count: 1 path: ../../../src/pocketmine/block/Skull.php - - - message: "#^Cannot call method setBlock\\(\\) on pocketmine\\\\level\\\\Level\\|null\\.$#" - count: 6 - path: ../../../src/pocketmine/block/Slab.php - - - - message: "#^Cannot call method setBlock\\(\\) on pocketmine\\\\level\\\\Level\\|null\\.$#" - count: 3 - path: ../../../src/pocketmine/block/SnowLayer.php - - message: "#^Cannot call method getBlockLightAt\\(\\) on pocketmine\\\\level\\\\Level\\|null\\.$#" count: 1 path: ../../../src/pocketmine/block/SnowLayer.php - - - message: "#^Cannot call method setBlock\\(\\) on pocketmine\\\\level\\\\Level\\|null\\.$#" - count: 1 - path: ../../../src/pocketmine/block/Stair.php - - - - message: "#^Cannot call method setBlock\\(\\) on pocketmine\\\\level\\\\Level\\|null\\.$#" - count: 2 - path: ../../../src/pocketmine/block/StandingBanner.php - - - - message: "#^Parameter \\#2 \\$level of static method pocketmine\\\\tile\\\\Tile\\:\\:createTile\\(\\) expects pocketmine\\\\level\\\\Level, pocketmine\\\\level\\\\Level\\|null given\\.$#" - count: 1 - path: ../../../src/pocketmine/block/StandingBanner.php - - - - message: "#^Cannot call method useBreakOn\\(\\) on pocketmine\\\\level\\\\Level\\|null\\.$#" - count: 1 - path: ../../../src/pocketmine/block/StandingBanner.php - - message: "#^Cannot call method getTile\\(\\) on pocketmine\\\\level\\\\Level\\|null\\.$#" count: 1 path: ../../../src/pocketmine/block/StandingBanner.php - - - message: "#^Cannot call method getBlockAt\\(\\) on pocketmine\\\\level\\\\Level\\|null\\.$#" - count: 2 - path: ../../../src/pocketmine/block/Sugarcane.php - - - - message: "#^Cannot call method setBlock\\(\\) on pocketmine\\\\level\\\\Level\\|null\\.$#" - count: 7 - path: ../../../src/pocketmine/block/Sugarcane.php - - - - message: "#^Cannot call method useBreakOn\\(\\) on pocketmine\\\\level\\\\Level\\|null\\.$#" - count: 1 - path: ../../../src/pocketmine/block/Sugarcane.php - - - - message: "#^Cannot call method setBlock\\(\\) on pocketmine\\\\level\\\\Level\\|null\\.$#" - count: 1 - path: ../../../src/pocketmine/block/TNT.php - - - - message: "#^Parameter \\#2 \\$level of static method pocketmine\\\\entity\\\\Entity\\:\\:createEntity\\(\\) expects pocketmine\\\\level\\\\Level, pocketmine\\\\level\\\\Level\\|null given\\.$#" - count: 1 - path: ../../../src/pocketmine/block/TNT.php - - - - message: "#^Cannot call method setBlock\\(\\) on pocketmine\\\\level\\\\Level\\|null\\.$#" - count: 2 - path: ../../../src/pocketmine/block/TallGrass.php - - - - message: "#^Cannot call method useBreakOn\\(\\) on pocketmine\\\\level\\\\Level\\|null\\.$#" - count: 1 - path: ../../../src/pocketmine/block/Torch.php - - - - message: "#^Cannot call method setBlock\\(\\) on pocketmine\\\\level\\\\Level\\|null\\.$#" - count: 2 - path: ../../../src/pocketmine/block/Torch.php - - - - message: "#^Cannot call method setBlock\\(\\) on pocketmine\\\\level\\\\Level\\|null\\.$#" - count: 2 - path: ../../../src/pocketmine/block/Trapdoor.php - - message: "#^Cannot call method addSound\\(\\) on pocketmine\\\\level\\\\Level\\|null\\.$#" count: 1 path: ../../../src/pocketmine/block/Trapdoor.php - - - message: "#^Cannot call method setBlock\\(\\) on pocketmine\\\\level\\\\Level\\|null\\.$#" - count: 2 - path: ../../../src/pocketmine/block/Vine.php - - message: "#^Cannot call method useBreakOn\\(\\) on pocketmine\\\\level\\\\Level\\|null\\.$#" count: 1 path: ../../../src/pocketmine/block/Vine.php - - - message: "#^Cannot call method useBreakOn\\(\\) on pocketmine\\\\level\\\\Level\\|null\\.$#" - count: 1 - path: ../../../src/pocketmine/block/WallBanner.php - - - - message: "#^Cannot call method useBreakOn\\(\\) on pocketmine\\\\level\\\\Level\\|null\\.$#" - count: 1 - path: ../../../src/pocketmine/block/WallSign.php - - message: "#^Cannot call method setBlock\\(\\) on pocketmine\\\\level\\\\Level\\|null\\.$#" count: 1 - path: ../../../src/pocketmine/block/Water.php - - - - message: "#^Cannot call method scheduleDelayedBlockUpdate\\(\\) on pocketmine\\\\level\\\\Level\\|null\\.$#" - count: 1 - path: ../../../src/pocketmine/block/Water.php - - - - message: "#^Cannot call method setBlock\\(\\) on pocketmine\\\\level\\\\Level\\|null\\.$#" - count: 1 - path: ../../../src/pocketmine/block/WaterLily.php - - - - message: "#^Cannot call method useBreakOn\\(\\) on pocketmine\\\\level\\\\Level\\|null\\.$#" - count: 1 - path: ../../../src/pocketmine/block/WaterLily.php - - - - message: "#^Cannot call method setBlock\\(\\) on pocketmine\\\\level\\\\Level\\|null\\.$#" - count: 1 - path: ../../../src/pocketmine/block/Wood.php + path: ../../../src/pocketmine/block/Vine.php - message: "#^Parameter \\#2 \\$replace of function str_replace expects array\\|string, string\\|null given\\.$#" @@ -1190,11 +720,6 @@ parameters: count: 1 path: ../../../src/pocketmine/entity/Entity.php - - - message: "#^Parameter \\#1 \\$targetLevel of method pocketmine\\\\entity\\\\Entity\\:\\:switchLevel\\(\\) expects pocketmine\\\\level\\\\Level, pocketmine\\\\level\\\\Level\\|null given\\.$#" - count: 1 - path: ../../../src/pocketmine/entity/Entity.php - - message: "#^Cannot call method getChunk\\(\\) on pocketmine\\\\level\\\\Level\\|null\\.$#" count: 1 @@ -1325,11 +850,6 @@ parameters: count: 1 path: ../../../src/pocketmine/entity/Living.php - - - message: "#^Cannot call method dropItem\\(\\) on pocketmine\\\\level\\\\Level\\|null\\.$#" - count: 1 - path: ../../../src/pocketmine/entity/Living.php - - message: "#^Cannot call method dropExperience\\(\\) on pocketmine\\\\level\\\\Level\\|null\\.$#" count: 1 @@ -1370,16 +890,6 @@ parameters: count: 1 path: ../../../src/pocketmine/entity/object/FallingBlock.php - - - message: "#^Cannot call method dropItem\\(\\) on pocketmine\\\\level\\\\Level\\|null\\.$#" - count: 1 - path: ../../../src/pocketmine/entity/object/FallingBlock.php - - - - message: "#^Cannot call method setBlock\\(\\) on pocketmine\\\\level\\\\Level\\|null\\.$#" - count: 1 - path: ../../../src/pocketmine/entity/object/FallingBlock.php - - message: "#^Cannot call method dropItem\\(\\) on pocketmine\\\\level\\\\Level\\|null\\.$#" count: 1 @@ -1485,46 +995,21 @@ parameters: count: 2 path: ../../../src/pocketmine/entity/projectile/SplashPotion.php - - - message: "#^Cannot call method getServer\\(\\) on pocketmine\\\\level\\\\Level\\|null\\.$#" - count: 1 - path: ../../../src/pocketmine/event/entity/EntityDamageByChildEntityEvent.php - - message: "#^Cannot call method getEffectLevel\\(\\) on pocketmine\\\\entity\\\\EffectInstance\\|null\\.$#" count: 2 path: ../../../src/pocketmine/event/entity/EntityDamageByEntityEvent.php - - - message: "#^Cannot call method getServer\\(\\) on pocketmine\\\\level\\\\Level\\|null\\.$#" - count: 1 - path: ../../../src/pocketmine/event/entity/EntityDamageByEntityEvent.php - - message: "#^Property pocketmine\\\\inventory\\\\BaseInventory\\:\\:\\$eventProcessor \\(pocketmine\\\\inventory\\\\InventoryEventProcessor\\) does not accept pocketmine\\\\inventory\\\\InventoryEventProcessor\\|null\\.$#" count: 1 path: ../../../src/pocketmine/inventory/BaseInventory.php - - - message: "#^Cannot call method broadcastLevelSoundEvent\\(\\) on pocketmine\\\\level\\\\Level\\|null\\.$#" - count: 2 - path: ../../../src/pocketmine/inventory/ChestInventory.php - - - - message: "#^Cannot call method broadcastPacketToViewers\\(\\) on pocketmine\\\\level\\\\Level\\|null\\.$#" - count: 1 - path: ../../../src/pocketmine/inventory/ChestInventory.php - - message: "#^Method pocketmine\\\\inventory\\\\CraftingManager\\:\\:getCraftingDataPacket\\(\\) should return pocketmine\\\\network\\\\mcpe\\\\protocol\\\\BatchPacket but returns pocketmine\\\\network\\\\mcpe\\\\protocol\\\\BatchPacket\\|null\\.$#" count: 1 path: ../../../src/pocketmine/inventory/CraftingManager.php - - - message: "#^Cannot call method getServer\\(\\) on pocketmine\\\\level\\\\Level\\|null\\.$#" - count: 1 - path: ../../../src/pocketmine/inventory/PlayerInventory.php - - message: "#^Parameter \\#2 \\$recipe of class pocketmine\\\\event\\\\inventory\\\\CraftItemEvent constructor expects pocketmine\\\\inventory\\\\CraftingRecipe, pocketmine\\\\inventory\\\\CraftingRecipe\\|null given\\.$#" count: 1 @@ -1570,11 +1055,6 @@ parameters: count: 2 path: ../../../src/pocketmine/item/Bucket.php - - - message: "#^Cannot call method getWorldHeight\\(\\) on pocketmine\\\\level\\\\Level\\|null\\.$#" - count: 1 - path: ../../../src/pocketmine/item/ChorusFruit.php - - message: "#^Parameter \\#1 \\$effectType of class pocketmine\\\\entity\\\\EffectInstance constructor expects pocketmine\\\\entity\\\\Effect, pocketmine\\\\entity\\\\Effect\\|null given\\.$#" count: 2 @@ -1595,11 +1075,6 @@ parameters: count: 1 path: ../../../src/pocketmine/item/PaintingItem.php - - - message: "#^Parameter \\#2 \\$level of static method pocketmine\\\\entity\\\\Entity\\:\\:createEntity\\(\\) expects pocketmine\\\\level\\\\Level, pocketmine\\\\level\\\\Level\\|null given\\.$#" - count: 1 - path: ../../../src/pocketmine/item/PaintingItem.php - - message: "#^Cannot call method broadcastLevelEvent\\(\\) on pocketmine\\\\level\\\\Level\\|null\\.$#" count: 1 @@ -1660,16 +1135,6 @@ parameters: count: 1 path: ../../../src/pocketmine/item/enchantment/EnchantmentList.php - - - message: "#^Property pocketmine\\\\level\\\\Explosion\\:\\:\\$level \\(pocketmine\\\\level\\\\Level\\) does not accept pocketmine\\\\level\\\\Level\\|null\\.$#" - count: 1 - path: ../../../src/pocketmine/level/Explosion.php - - - - message: "#^Parameter \\#1 \\$level of class pocketmine\\\\level\\\\utils\\\\SubChunkIteratorManager constructor expects pocketmine\\\\level\\\\ChunkManager, pocketmine\\\\level\\\\Level\\|null given\\.$#" - count: 1 - path: ../../../src/pocketmine/level/Explosion.php - - message: "#^Cannot call method getBlockId\\(\\) on pocketmine\\\\level\\\\format\\\\SubChunkInterface\\|null\\.$#" count: 1 @@ -1820,16 +1285,6 @@ parameters: count: 1 path: ../../../src/pocketmine/level/Level.php - - - message: "#^Cannot call method getName\\(\\) on pocketmine\\\\level\\\\Level\\|null\\.$#" - count: 1 - path: ../../../src/pocketmine/level/Location.php - - - - message: "#^Cannot call method getName\\(\\) on pocketmine\\\\level\\\\Level\\|null\\.$#" - count: 1 - path: ../../../src/pocketmine/level/Position.php - - message: "#^Method pocketmine\\\\level\\\\biome\\\\Biome\\:\\:getBiome\\(\\) should return pocketmine\\\\level\\\\biome\\\\Biome but returns pocketmine\\\\level\\\\biome\\\\Biome\\|null\\.$#" count: 1 @@ -2260,11 +1715,6 @@ parameters: count: 1 path: ../../../src/pocketmine/tile/Chest.php - - - message: "#^Cannot call method isInLoadedTerrain\\(\\) on pocketmine\\\\level\\\\Level\\|null\\.$#" - count: 1 - path: ../../../src/pocketmine/tile/Chest.php - - message: "#^Parameter \\#1 \\$x of class pocketmine\\\\math\\\\Vector3 constructor expects float\\|int, int\\|null given\\.$#" count: 1 @@ -2276,7 +1726,12 @@ parameters: path: ../../../src/pocketmine/tile/Chest.php - - message: "#^Cannot call method getTileAt\\(\\) on pocketmine\\\\level\\\\Level\\|null\\.$#" + message: "#^Parameter \\#1 \\$x of method pocketmine\\\\level\\\\Level\\:\\:getTileAt\\(\\) expects int, int\\|null given\\.$#" + count: 1 + path: ../../../src/pocketmine/tile/Chest.php + + - + message: "#^Parameter \\#3 \\$z of method pocketmine\\\\level\\\\Level\\:\\:getTileAt\\(\\) expects int, int\\|null given\\.$#" count: 1 path: ../../../src/pocketmine/tile/Chest.php @@ -2290,11 +1745,6 @@ parameters: count: 1 path: ../../../src/pocketmine/tile/Furnace.php - - - message: "#^Cannot call method setBlock\\(\\) on pocketmine\\\\level\\\\Level\\|null\\.$#" - count: 2 - path: ../../../src/pocketmine/tile/Furnace.php - - message: "#^Cannot call method broadcastPacketToViewers\\(\\) on pocketmine\\\\level\\\\Level\\|null\\.$#" count: 1 @@ -2305,11 +1755,6 @@ parameters: count: 1 path: ../../../src/pocketmine/tile/Spawnable.php - - - message: "#^Cannot call method addTile\\(\\) on pocketmine\\\\level\\\\Level\\|null\\.$#" - count: 1 - path: ../../../src/pocketmine/tile/Tile.php - - message: "#^Cannot clone non\\-object variable \\$customBlockDataTag of type pocketmine\\\\nbt\\\\tag\\\\NamedTag\\|null\\.$#" count: 1 @@ -2370,11 +1815,6 @@ parameters: count: 1 path: ../../../src/pocketmine/utils/MainLogger.php - - - message: "#^Parameter \\#3 \\$subject of function preg_replace expects array\\|string, string\\|null given\\.$#" - count: 2 - path: ../../../src/pocketmine/utils/TextFormat.php - - message: "#^Parameter \\#3 \\$subject of function str_replace expects array\\|string, string\\|null given\\.$#" count: 2 From da4a2d8552d6287b487971eec00f731c6416babf Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Tue, 19 May 2020 21:01:18 +0100 Subject: [PATCH 83/90] Fixed a bunch of missed Position->getLevel() usages these were not in the usage search because PhpStorm decided to refer to ChunkLoader->getLevel() for any Player references, which caused them to only show when that was searched. There's also an undetected LSP violation with ChunkLoader because it requires returning Level and Position->getLevel() returns Level|null. I don't know why PHPStan doesn't complain about that. --- src/pocketmine/Player.php | 2 +- .../command/defaults/ParticleCommand.php | 2 +- .../command/defaults/SeedCommand.php | 2 +- .../command/defaults/SetWorldSpawnCommand.php | 2 +- .../command/defaults/SpawnpointCommand.php | 4 +- .../command/defaults/TimeCommand.php | 2 +- src/pocketmine/item/Bow.php | 4 +- src/pocketmine/item/Bucket.php | 8 +-- src/pocketmine/item/FlintSteel.php | 4 +- src/pocketmine/item/PaintingItem.php | 2 +- src/pocketmine/item/ProjectileItem.php | 4 +- src/pocketmine/item/SpawnEgg.php | 2 +- tests/phpstan/configs/l8-baseline.neon | 52 +------------------ 13 files changed, 19 insertions(+), 71 deletions(-) diff --git a/src/pocketmine/Player.php b/src/pocketmine/Player.php index 240e6d3c2..218ba9f0b 100644 --- a/src/pocketmine/Player.php +++ b/src/pocketmine/Player.php @@ -521,7 +521,7 @@ class Player extends Human implements CommandSender, ChunkLoader, IPlayer{ } public function spawnTo(Player $player) : void{ - if($this->spawned and $player->spawned and $this->isAlive() and $player->isAlive() and $player->getLevel() === $this->level and $player->canSee($this) and !$this->isSpectator()){ + if($this->spawned and $player->spawned and $this->isAlive() and $player->isAlive() and $player->getLevelNonNull() === $this->level and $player->canSee($this) and !$this->isSpectator()){ parent::spawnTo($player); } } diff --git a/src/pocketmine/command/defaults/ParticleCommand.php b/src/pocketmine/command/defaults/ParticleCommand.php index 7b89b5372..5633ad89f 100644 --- a/src/pocketmine/command/defaults/ParticleCommand.php +++ b/src/pocketmine/command/defaults/ParticleCommand.php @@ -91,7 +91,7 @@ class ParticleCommand extends VanillaCommand{ } if($sender instanceof Player){ - $level = $sender->getLevel(); + $level = $sender->getLevelNonNull(); $pos = new Vector3( $this->getRelativeDouble($sender->getX(), $sender, $args[1]), $this->getRelativeDouble($sender->getY(), $sender, $args[2], 0, Level::Y_MAX), diff --git a/src/pocketmine/command/defaults/SeedCommand.php b/src/pocketmine/command/defaults/SeedCommand.php index 431c04d48..74cf328fa 100644 --- a/src/pocketmine/command/defaults/SeedCommand.php +++ b/src/pocketmine/command/defaults/SeedCommand.php @@ -44,7 +44,7 @@ class SeedCommand extends VanillaCommand{ } if($sender instanceof Player){ - $seed = $sender->getLevel()->getSeed(); + $seed = $sender->getLevelNonNull()->getSeed(); }else{ $seed = $sender->getServer()->getDefaultLevel()->getSeed(); } diff --git a/src/pocketmine/command/defaults/SetWorldSpawnCommand.php b/src/pocketmine/command/defaults/SetWorldSpawnCommand.php index 054adc059..6493ec296 100644 --- a/src/pocketmine/command/defaults/SetWorldSpawnCommand.php +++ b/src/pocketmine/command/defaults/SetWorldSpawnCommand.php @@ -51,7 +51,7 @@ class SetWorldSpawnCommand extends VanillaCommand{ if(count($args) === 0){ if($sender instanceof Player){ - $level = $sender->getLevel(); + $level = $sender->getLevelNonNull(); $pos = (new Vector3($sender->x, $sender->y, $sender->z))->round(); }else{ $sender->sendMessage(TextFormat::RED . "You can only perform this command as a player"); diff --git a/src/pocketmine/command/defaults/SpawnpointCommand.php b/src/pocketmine/command/defaults/SpawnpointCommand.php index 775e896f5..13c7e6d33 100644 --- a/src/pocketmine/command/defaults/SpawnpointCommand.php +++ b/src/pocketmine/command/defaults/SpawnpointCommand.php @@ -71,7 +71,7 @@ class SpawnpointCommand extends VanillaCommand{ if(count($args) === 4){ if($target->isValid()){ - $level = $target->getLevel(); + $level = $target->getLevelNonNull(); $pos = $sender instanceof Player ? $sender->getPosition() : $level->getSpawnLocation(); $x = $this->getRelativeDouble($pos->x, $sender, $args[1]); $y = $this->getRelativeDouble($pos->y, $sender, $args[2], 0, Level::Y_MAX); @@ -84,7 +84,7 @@ class SpawnpointCommand extends VanillaCommand{ } }elseif(count($args) <= 1){ if($sender instanceof Player){ - $pos = new Position($sender->getFloorX(), $sender->getFloorY(), $sender->getFloorZ(), $sender->getLevel()); + $pos = new Position($sender->getFloorX(), $sender->getFloorY(), $sender->getFloorZ(), $sender->getLevelNonNull()); $target->setSpawn($pos); Command::broadcastCommandMessage($sender, new TranslationContainer("commands.spawnpoint.success", [$target->getName(), round($pos->x, 2), round($pos->y, 2), round($pos->z, 2)])); diff --git a/src/pocketmine/command/defaults/TimeCommand.php b/src/pocketmine/command/defaults/TimeCommand.php index bd94e2ae5..eedfa1ed1 100644 --- a/src/pocketmine/command/defaults/TimeCommand.php +++ b/src/pocketmine/command/defaults/TimeCommand.php @@ -77,7 +77,7 @@ class TimeCommand extends VanillaCommand{ return true; } if($sender instanceof Player){ - $level = $sender->getLevel(); + $level = $sender->getLevelNonNull(); }else{ $level = $sender->getServer()->getDefaultLevel(); } diff --git a/src/pocketmine/item/Bow.php b/src/pocketmine/item/Bow.php index a8074f893..9856535f8 100644 --- a/src/pocketmine/item/Bow.php +++ b/src/pocketmine/item/Bow.php @@ -64,7 +64,7 @@ class Bow extends Tool{ $p = $diff / 20; $baseForce = min((($p ** 2) + $p * 2) / 3, 1); - $entity = Entity::createEntity("Arrow", $player->getLevel(), $nbt, $player, $baseForce >= 1); + $entity = Entity::createEntity("Arrow", $player->getLevelNonNull(), $nbt, $player, $baseForce >= 1); if($entity instanceof Projectile){ $infinity = $this->hasEnchantment(Enchantment::INFINITY); if($entity instanceof ArrowEntity){ @@ -110,7 +110,7 @@ class Bow extends Tool{ $ev->getProjectile()->flagForDespawn(); }else{ $ev->getProjectile()->spawnToAll(); - $player->getLevel()->broadcastLevelSoundEvent($player, LevelSoundEventPacket::SOUND_BOW); + $player->getLevelNonNull()->broadcastLevelSoundEvent($player, LevelSoundEventPacket::SOUND_BOW); } }else{ $entity->spawnToAll(); diff --git a/src/pocketmine/item/Bucket.php b/src/pocketmine/item/Bucket.php index 717a4b5c6..0cd99f5a8 100644 --- a/src/pocketmine/item/Bucket.php +++ b/src/pocketmine/item/Bucket.php @@ -62,8 +62,8 @@ class Bucket extends Item implements MaybeConsumable{ $ev = new PlayerBucketFillEvent($player, $blockReplace, $face, $this, $resultItem); $ev->call(); if(!$ev->isCancelled()){ - $player->getLevel()->setBlock($blockClicked, BlockFactory::get(Block::AIR), true, true); - $player->getLevel()->broadcastLevelSoundEvent($blockClicked->add(0.5, 0.5, 0.5), $blockClicked->getBucketFillSound()); + $player->getLevelNonNull()->setBlock($blockClicked, BlockFactory::get(Block::AIR), true, true); + $player->getLevelNonNull()->broadcastLevelSoundEvent($blockClicked->add(0.5, 0.5, 0.5), $blockClicked->getBucketFillSound()); if($player->isSurvival()){ if($stack->getCount() === 0){ $player->getInventory()->setItemInHand($ev->getItem()); @@ -84,8 +84,8 @@ class Bucket extends Item implements MaybeConsumable{ $ev = new PlayerBucketEmptyEvent($player, $blockReplace, $face, $this, ItemFactory::get(Item::BUCKET)); $ev->call(); if(!$ev->isCancelled()){ - $player->getLevel()->setBlock($blockReplace, $resultBlock->getFlowingForm(), true, true); - $player->getLevel()->broadcastLevelSoundEvent($blockReplace->add(0.5, 0.5, 0.5), $resultBlock->getBucketEmptySound()); + $player->getLevelNonNull()->setBlock($blockReplace, $resultBlock->getFlowingForm(), true, true); + $player->getLevelNonNull()->broadcastLevelSoundEvent($blockReplace->add(0.5, 0.5, 0.5), $resultBlock->getBucketEmptySound()); if($player->isSurvival()){ $player->getInventory()->setItemInHand($ev->getItem()); diff --git a/src/pocketmine/item/FlintSteel.php b/src/pocketmine/item/FlintSteel.php index 4afd59263..49aa84e54 100644 --- a/src/pocketmine/item/FlintSteel.php +++ b/src/pocketmine/item/FlintSteel.php @@ -28,7 +28,6 @@ use pocketmine\block\BlockFactory; use pocketmine\math\Vector3; use pocketmine\network\mcpe\protocol\LevelSoundEventPacket; use pocketmine\Player; -use function assert; class FlintSteel extends Tool{ public function __construct(int $meta = 0){ @@ -37,8 +36,7 @@ class FlintSteel extends Tool{ public function onActivate(Player $player, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector) : bool{ if($blockReplace->getId() === self::AIR){ - $level = $player->getLevel(); - assert($level !== null); + $level = $player->getLevelNonNull(); $level->setBlock($blockReplace, BlockFactory::get(Block::FIRE), true); $level->broadcastLevelSoundEvent($blockReplace->add(0.5, 0.5, 0.5), LevelSoundEventPacket::SOUND_IGNITE); diff --git a/src/pocketmine/item/PaintingItem.php b/src/pocketmine/item/PaintingItem.php index 208e0d7d2..90709223a 100644 --- a/src/pocketmine/item/PaintingItem.php +++ b/src/pocketmine/item/PaintingItem.php @@ -99,7 +99,7 @@ class PaintingItem extends Item{ $this->pop(); $entity->spawnToAll(); - $player->getLevel()->broadcastLevelEvent($blockReplace->add(0.5, 0.5, 0.5), LevelEventPacket::EVENT_SOUND_ITEMFRAME_PLACE); //item frame and painting have the same sound + $player->getLevelNonNull()->broadcastLevelEvent($blockReplace->add(0.5, 0.5, 0.5), LevelEventPacket::EVENT_SOUND_ITEMFRAME_PLACE); //item frame and painting have the same sound return true; } diff --git a/src/pocketmine/item/ProjectileItem.php b/src/pocketmine/item/ProjectileItem.php index f0f0860cc..fccc4c3bf 100644 --- a/src/pocketmine/item/ProjectileItem.php +++ b/src/pocketmine/item/ProjectileItem.php @@ -49,7 +49,7 @@ abstract class ProjectileItem extends Item{ $nbt = Entity::createBaseNBT($player->add(0, $player->getEyeHeight(), 0), $directionVector, $player->yaw, $player->pitch); $this->addExtraTags($nbt); - $projectile = Entity::createEntity($this->getProjectileEntityType(), $player->getLevel(), $nbt, $player); + $projectile = Entity::createEntity($this->getProjectileEntityType(), $player->getLevelNonNull(), $nbt, $player); if($projectile !== null){ $projectile->setMotion($projectile->getMotion()->multiply($this->getThrowForce())); } @@ -64,7 +64,7 @@ abstract class ProjectileItem extends Item{ }else{ $projectile->spawnToAll(); - $player->getLevel()->broadcastLevelSoundEvent($player, LevelSoundEventPacket::SOUND_THROW, 0, EntityIds::PLAYER); + $player->getLevelNonNull()->broadcastLevelSoundEvent($player, LevelSoundEventPacket::SOUND_THROW, 0, EntityIds::PLAYER); } }elseif($projectile !== null){ $projectile->spawnToAll(); diff --git a/src/pocketmine/item/SpawnEgg.php b/src/pocketmine/item/SpawnEgg.php index 92ac5d4a1..42400b0cd 100644 --- a/src/pocketmine/item/SpawnEgg.php +++ b/src/pocketmine/item/SpawnEgg.php @@ -41,7 +41,7 @@ class SpawnEgg extends Item{ $nbt->setString("CustomName", $this->getCustomName()); } - $entity = Entity::createEntity($this->meta, $player->getLevel(), $nbt); + $entity = Entity::createEntity($this->meta, $player->getLevelNonNull(), $nbt); if($entity instanceof Entity){ $this->pop(); diff --git a/tests/phpstan/configs/l8-baseline.neon b/tests/phpstan/configs/l8-baseline.neon index ee06cb56c..d7c045156 100644 --- a/tests/phpstan/configs/l8-baseline.neon +++ b/tests/phpstan/configs/l8-baseline.neon @@ -597,7 +597,7 @@ parameters: - message: "#^Cannot call method getSeed\\(\\) on pocketmine\\\\level\\\\Level\\|null\\.$#" - count: 2 + count: 1 path: ../../../src/pocketmine/command/defaults/SeedCommand.php - @@ -605,11 +605,6 @@ parameters: count: 1 path: ../../../src/pocketmine/command/defaults/SetWorldSpawnCommand.php - - - message: "#^Cannot call method getSpawnLocation\\(\\) on pocketmine\\\\level\\\\Level\\|null\\.$#" - count: 1 - path: ../../../src/pocketmine/command/defaults/SpawnpointCommand.php - - message: "#^Parameter \\#1 \\$name of method pocketmine\\\\Server\\:\\:getPlayer\\(\\) expects string, string\\|null given\\.$#" count: 1 @@ -845,11 +840,6 @@ parameters: count: 1 path: ../../../src/pocketmine/entity/Living.php - - - message: "#^Cannot call method getDifficulty\\(\\) on pocketmine\\\\level\\\\Level\\|null\\.$#" - count: 1 - path: ../../../src/pocketmine/entity/Living.php - - message: "#^Cannot call method dropExperience\\(\\) on pocketmine\\\\level\\\\Level\\|null\\.$#" count: 1 @@ -1030,31 +1020,11 @@ parameters: count: 1 path: ../../../src/pocketmine/item/Banner.php - - - message: "#^Parameter \\#2 \\$level of static method pocketmine\\\\entity\\\\Entity\\:\\:createEntity\\(\\) expects pocketmine\\\\level\\\\Level, pocketmine\\\\level\\\\Level\\|null given\\.$#" - count: 1 - path: ../../../src/pocketmine/item/Bow.php - - - - message: "#^Cannot call method broadcastLevelSoundEvent\\(\\) on pocketmine\\\\level\\\\Level\\|null\\.$#" - count: 1 - path: ../../../src/pocketmine/item/Bow.php - - message: "#^Cannot call method spawnToAll\\(\\) on pocketmine\\\\entity\\\\Entity\\|null\\.$#" count: 1 path: ../../../src/pocketmine/item/Bow.php - - - message: "#^Cannot call method setBlock\\(\\) on pocketmine\\\\level\\\\Level\\|null\\.$#" - count: 2 - path: ../../../src/pocketmine/item/Bucket.php - - - - message: "#^Cannot call method broadcastLevelSoundEvent\\(\\) on pocketmine\\\\level\\\\Level\\|null\\.$#" - count: 2 - path: ../../../src/pocketmine/item/Bucket.php - - message: "#^Parameter \\#1 \\$effectType of class pocketmine\\\\entity\\\\EffectInstance constructor expects pocketmine\\\\entity\\\\Effect, pocketmine\\\\entity\\\\Effect\\|null given\\.$#" count: 2 @@ -1075,11 +1045,6 @@ parameters: count: 1 path: ../../../src/pocketmine/item/PaintingItem.php - - - message: "#^Cannot call method broadcastLevelEvent\\(\\) on pocketmine\\\\level\\\\Level\\|null\\.$#" - count: 1 - path: ../../../src/pocketmine/item/PaintingItem.php - - message: "#^Parameter \\#1 \\$effectType of class pocketmine\\\\entity\\\\EffectInstance constructor expects pocketmine\\\\entity\\\\Effect, pocketmine\\\\entity\\\\Effect\\|null given\\.$#" count: 1 @@ -1090,16 +1055,6 @@ parameters: count: 32 path: ../../../src/pocketmine/item/Potion.php - - - message: "#^Parameter \\#2 \\$level of static method pocketmine\\\\entity\\\\Entity\\:\\:createEntity\\(\\) expects pocketmine\\\\level\\\\Level, pocketmine\\\\level\\\\Level\\|null given\\.$#" - count: 1 - path: ../../../src/pocketmine/item/ProjectileItem.php - - - - message: "#^Cannot call method broadcastLevelSoundEvent\\(\\) on pocketmine\\\\level\\\\Level\\|null\\.$#" - count: 1 - path: ../../../src/pocketmine/item/ProjectileItem.php - - message: "#^Parameter \\#1 \\$effectType of class pocketmine\\\\entity\\\\EffectInstance constructor expects pocketmine\\\\entity\\\\Effect, pocketmine\\\\entity\\\\Effect\\|null given\\.$#" count: 3 @@ -1115,11 +1070,6 @@ parameters: count: 1 path: ../../../src/pocketmine/item/RottenFlesh.php - - - message: "#^Parameter \\#2 \\$level of static method pocketmine\\\\entity\\\\Entity\\:\\:createEntity\\(\\) expects pocketmine\\\\level\\\\Level, pocketmine\\\\level\\\\Level\\|null given\\.$#" - count: 1 - path: ../../../src/pocketmine/item/SpawnEgg.php - - message: "#^Parameter \\#1 \\$effectType of class pocketmine\\\\entity\\\\EffectInstance constructor expects pocketmine\\\\entity\\\\Effect, pocketmine\\\\entity\\\\Effect\\|null given\\.$#" count: 1 From 45c89d084cad6976941205fba45c54d41100a7f8 Mon Sep 17 00:00:00 2001 From: XenialDan Date: Wed, 20 May 2020 20:40:03 +0100 Subject: [PATCH 84/90] TimeCommand: add time aliases "noon", "sunset", "midnight", "sunrise" closes #3508 --- .../command/defaults/TimeCommand.php | 28 +++++++++++++++---- 1 file changed, 22 insertions(+), 6 deletions(-) diff --git a/src/pocketmine/command/defaults/TimeCommand.php b/src/pocketmine/command/defaults/TimeCommand.php index eedfa1ed1..41c2903bc 100644 --- a/src/pocketmine/command/defaults/TimeCommand.php +++ b/src/pocketmine/command/defaults/TimeCommand.php @@ -96,12 +96,28 @@ class TimeCommand extends VanillaCommand{ return true; } - if($args[1] === "day"){ - $value = Level::TIME_DAY; - }elseif($args[1] === "night"){ - $value = Level::TIME_NIGHT; - }else{ - $value = $this->getInteger($sender, $args[1], 0); + switch($args[1]){ + case "day": + $value = Level::TIME_DAY; + break; + case "noon": + $value = Level::TIME_NOON; + break; + case "sunset": + $value = Level::TIME_SUNSET; + break; + case "night": + $value = Level::TIME_NIGHT; + break; + case "midnight": + $value = Level::TIME_MIDNIGHT; + break; + case "sunrise": + $value = Level::TIME_SUNRISE; + break; + default: + $value = $this->getInteger($sender, $args[1], 0); + break; } foreach($sender->getServer()->getLevels() as $level){ From ecbf21aceaf508b37ae6315784b2915a84f22ee8 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Sat, 23 May 2020 11:05:58 +0100 Subject: [PATCH 85/90] Utils: added OS constants, remove hardcoded OS strings everywhere --- src/pocketmine/command/CommandReader.php | 2 +- src/pocketmine/network/upnp/UPnP.php | 4 +-- src/pocketmine/utils/Process.php | 12 +++---- src/pocketmine/utils/Terminal.php | 10 +++--- src/pocketmine/utils/Timezone.php | 6 ++-- src/pocketmine/utils/Utils.php | 40 ++++++++++++++---------- 6 files changed, 41 insertions(+), 33 deletions(-) diff --git a/src/pocketmine/command/CommandReader.php b/src/pocketmine/command/CommandReader.php index 656d82464..5a779b48c 100644 --- a/src/pocketmine/command/CommandReader.php +++ b/src/pocketmine/command/CommandReader.php @@ -68,7 +68,7 @@ class CommandReader extends Thread{ $opts = getopt("", ["disable-readline", "enable-readline"]); - if(extension_loaded("readline") and (Utils::getOS() === "win" ? isset($opts["enable-readline"]) : !isset($opts["disable-readline"])) and !$this->isPipe(STDIN)){ + if(extension_loaded("readline") and (Utils::getOS() === Utils::OS_WINDOWS ? isset($opts["enable-readline"]) : !isset($opts["disable-readline"])) and !$this->isPipe(STDIN)){ $this->type = self::TYPE_READLINE; } } diff --git a/src/pocketmine/network/upnp/UPnP.php b/src/pocketmine/network/upnp/UPnP.php index 243300879..6fe5a6951 100644 --- a/src/pocketmine/network/upnp/UPnP.php +++ b/src/pocketmine/network/upnp/UPnP.php @@ -37,7 +37,7 @@ abstract class UPnP{ if(!Internet::$online){ throw new \RuntimeException("Server is offline"); } - if(Utils::getOS() !== "win"){ + if(Utils::getOS() !== Utils::OS_WINDOWS){ throw new \RuntimeException("UPnP is only supported on Windows"); } if(!class_exists("COM")){ @@ -62,7 +62,7 @@ abstract class UPnP{ if(!Internet::$online){ return false; } - if(Utils::getOS() != "win" or !class_exists("COM")){ + if(Utils::getOS() !== Utils::OS_WINDOWS or !class_exists("COM")){ return false; } diff --git a/src/pocketmine/utils/Process.php b/src/pocketmine/utils/Process.php index 37fa63cbe..aacdd4c33 100644 --- a/src/pocketmine/utils/Process.php +++ b/src/pocketmine/utils/Process.php @@ -54,7 +54,7 @@ final class Process{ $reserved = memory_get_usage(); $VmSize = null; $VmRSS = null; - if(Utils::getOS() === "linux" or Utils::getOS() === "android"){ + if(Utils::getOS() === Utils::OS_LINUX or Utils::getOS() === Utils::OS_ANDROID){ $status = @file_get_contents("/proc/self/status"); if($status === false) throw new AssumptionFailedError("/proc/self/status should always be accessible"); @@ -92,7 +92,7 @@ final class Process{ $stack = 0; $heap = 0; - if(Utils::getOS() === "linux" or Utils::getOS() === "android"){ + if(Utils::getOS() === Utils::OS_LINUX or Utils::getOS() === Utils::OS_ANDROID){ $mappings = @file("/proc/self/maps"); if($mappings === false) throw new AssumptionFailedError("/proc/self/maps should always be accessible"); foreach($mappings as $line){ @@ -110,7 +110,7 @@ final class Process{ } public static function getThreadCount() : int{ - if(Utils::getOS() === "linux" or Utils::getOS() === "android"){ + if(Utils::getOS() === Utils::OS_LINUX or Utils::getOS() === Utils::OS_ANDROID){ $status = @file_get_contents("/proc/self/status"); if($status === false) throw new AssumptionFailedError("/proc/self/status should always be accessible"); if(preg_match("/Threads:[ \t]+([0-9]+)/", $status, $matches) > 0){ @@ -131,11 +131,11 @@ final class Process{ MainLogger::getLogger()->syncFlushBuffer(); } switch(Utils::getOS()){ - case "win": + case Utils::OS_WINDOWS: exec("taskkill.exe /F /PID $pid > NUL"); break; - case "mac": - case "linux": + case Utils::OS_MACOS: + case Utils::OS_LINUX: default: if(function_exists("posix_kill")){ posix_kill($pid, 9); //SIGKILL diff --git a/src/pocketmine/utils/Terminal.php b/src/pocketmine/utils/Terminal.php index 22071cf23..9485acc9b 100644 --- a/src/pocketmine/utils/Terminal.php +++ b/src/pocketmine/utils/Terminal.php @@ -182,14 +182,14 @@ abstract class Terminal{ } switch(Utils::getOS()){ - case "linux": - case "mac": - case "bsd": + case Utils::OS_LINUX: + case Utils::OS_MACOS: + case Utils::OS_BSD: self::getEscapeCodes(); return; - case "win": - case "android": + case Utils::OS_WINDOWS: + case Utils::OS_ANDROID: self::getFallbackEscapeCodes(); return; } diff --git a/src/pocketmine/utils/Timezone.php b/src/pocketmine/utils/Timezone.php index 8e12d66a2..4c7e29c1d 100644 --- a/src/pocketmine/utils/Timezone.php +++ b/src/pocketmine/utils/Timezone.php @@ -113,7 +113,7 @@ abstract class Timezone{ */ public static function detectSystemTimezone(){ switch(Utils::getOS()){ - case 'win': + case Utils::OS_WINDOWS: $regex = '/(UTC)(\+*\-*\d*\d*\:*\d*\d*)/'; /* @@ -148,7 +148,7 @@ abstract class Timezone{ } return self::parseOffset($offset); - case 'linux': + case Utils::OS_LINUX: // Ubuntu / Debian. $data = @file_get_contents('/etc/timezone'); if($data !== false){ @@ -170,7 +170,7 @@ abstract class Timezone{ } return self::parseOffset($offset); - case 'mac': + case Utils::OS_MACOS: $filename = @readlink('/etc/localtime'); if($filename !== false and strpos($filename, '/usr/share/zoneinfo/') === 0){ $timezone = substr($filename, 20); diff --git a/src/pocketmine/utils/Utils.php b/src/pocketmine/utils/Utils.php index 6312d56ce..0a37267c5 100644 --- a/src/pocketmine/utils/Utils.php +++ b/src/pocketmine/utils/Utils.php @@ -99,6 +99,14 @@ use const STR_PAD_RIGHT; * Big collection of functions */ class Utils{ + public const OS_WINDOWS = "win"; + public const OS_IOS = "ios"; + public const OS_MACOS = "mac"; + public const OS_ANDROID = "android"; + public const OS_LINUX = "linux"; + public const OS_BSD = "bsd"; + public const OS_UNKNOWN = "other"; + /** @var string|null */ public static $os; /** @var UUID|null */ @@ -186,7 +194,7 @@ class Utils{ $machine .= sys_get_temp_dir(); $machine .= $extra; $os = Utils::getOS(); - if($os === "win"){ + if($os === Utils::OS_WINDOWS){ @exec("ipconfig /ALL", $mac); $mac = implode("\n", $mac); if(preg_match_all("#Physical Address[. ]{1,}: ([0-9A-F\\-]{17})#", $mac, $matches) > 0){ @@ -197,7 +205,7 @@ class Utils{ } $machine .= implode(" ", $matches[1]); //Mac Addresses } - }elseif($os === "linux"){ + }elseif($os === Utils::OS_LINUX){ if(file_exists("/etc/machine-id")){ $machine .= file_get_contents("/etc/machine-id"); }else{ @@ -212,9 +220,9 @@ class Utils{ $machine .= implode(" ", $matches[1]); //Mac Addresses } } - }elseif($os === "android"){ + }elseif($os === Utils::OS_ANDROID){ $machine .= @file_get_contents("/system/build.prop"); - }elseif($os === "mac"){ + }elseif($os === Utils::OS_MACOS){ $machine .= `system_profiler SPHardwareDataType | grep UUID`; } $data = $machine . PHP_MAXPATHLEN; @@ -261,22 +269,22 @@ class Utils{ $uname = php_uname("s"); if(stripos($uname, "Darwin") !== false){ if(strpos(php_uname("m"), "iP") === 0){ - self::$os = "ios"; + self::$os = self::OS_IOS; }else{ - self::$os = "mac"; + self::$os = self::OS_MACOS; } }elseif(stripos($uname, "Win") !== false or $uname === "Msys"){ - self::$os = "win"; + self::$os = self::OS_WINDOWS; }elseif(stripos($uname, "Linux") !== false){ if(@file_exists("/system/build.prop")){ - self::$os = "android"; + self::$os = self::OS_ANDROID; }else{ - self::$os = "linux"; + self::$os = self::OS_LINUX; } }elseif(stripos($uname, "BSD") !== false or $uname === "DragonFly"){ - self::$os = "bsd"; + self::$os = self::OS_BSD; }else{ - self::$os = "other"; + self::$os = self::OS_UNKNOWN; } } @@ -322,8 +330,8 @@ class Utils{ } switch(Utils::getOS()){ - case "linux": - case "android": + case Utils::OS_LINUX: + case Utils::OS_ANDROID: if(($cpuinfo = @file('/proc/cpuinfo')) !== false){ foreach($cpuinfo as $l){ if(preg_match('/^processor[ \t]*:[ \t]*[0-9]+$/m', $l) > 0){ @@ -336,11 +344,11 @@ class Utils{ } } break; - case "bsd": - case "mac": + case Utils::OS_BSD: + case Utils::OS_MACOS: $processors = (int) `sysctl -n hw.ncpu`; break; - case "win": + case Utils::OS_WINDOWS: $processors = (int) getenv("NUMBER_OF_PROCESSORS"); break; } From 485f573955fdfda52395e15fc497066d6ef77040 Mon Sep 17 00:00:00 2001 From: Dylan T Date: Sun, 31 May 2020 15:51:30 +0100 Subject: [PATCH 86/90] =?UTF-8?q?Player:=20remove=20move=20buffering,=20im?= =?UTF-8?q?plement=20simple=20rate=20limited=20movement=E2=80=A6=20(#3167)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Introduction This PR is a second attempt at improving movement processing to fix #1215 , #2730 and more. This is significantly less complex than the previous attempt #2646 -- it gets rid of the movement buffering system entirely and instead relies on a simple rate limit counter to restrict on-the-fly movement processing. Movement is rate limited to a max average of 2 per tick. It allows up to 5 seconds' backlog to accommodate network lag. The rate limit counter is increased by 2 per tick and decreased once for every movement processed. This prevents movement processing being abused for denial of service attacks. Changes API changes This PR, while obviously highly beneficial for most current users, poses some BC-breaking issues because of changes to the internal Player API. Player->processMovement() (protected) has been removed. This is a BC concern for custom player classes which overrode it and called it as a parent. In addition, child implementations won't be called every tick any more, which could break some custom movement processing systems. Player->newPosition (protected) has been removed. This internal field may have been accessed by custom movement implementations. Player->isTeleporting (protected) has been removed. BC concern is same as previous point. Player->getNextPosition() (public) has been @deprecated. Added the following protected Player class members: int $moveRateLimit ?Vector3 $forceMoveSync handleMovement() processMostRecentMovements() revertMovement() Behavioural changes Player movement is now subject to less rubberbanding and has more reliable behaviour. --- src/pocketmine/Player.php | 131 +++++++++++++++++++++----------------- 1 file changed, 74 insertions(+), 57 deletions(-) diff --git a/src/pocketmine/Player.php b/src/pocketmine/Player.php index 002d3fe4f..ad3f14399 100644 --- a/src/pocketmine/Player.php +++ b/src/pocketmine/Player.php @@ -217,6 +217,9 @@ class Player extends Human implements CommandSender, ChunkLoader, IPlayer{ public const SPECTATOR = 3; public const VIEW = Player::SPECTATOR; + private const MOVES_PER_TICK = 2; + private const MOVE_BACKLOG_SIZE = 100 * self::MOVES_PER_TICK; //100 ticks backlog (5 seconds) + /** * Validates the given username. */ @@ -329,10 +332,11 @@ class Player extends Human implements CommandSender, ChunkLoader, IPlayer{ /** @var bool[] map: raw UUID (string) => bool */ protected $hiddenPlayers = []; + /** @var int */ + protected $moveRateLimit = 10 * self::MOVES_PER_TICK; /** @var Vector3|null */ - protected $newPosition; - /** @var bool */ - protected $isTeleporting = false; + protected $forceMoveSync = null; + /** @var int */ protected $inAirTicks = 0; /** @var float */ @@ -865,8 +869,11 @@ class Player extends Human implements CommandSender, ChunkLoader, IPlayer{ $this->lastPingMeasure = $pingMS; } + /** + * @deprecated + */ public function getNextPosition() : Position{ - return $this->newPosition !== null ? Position::fromObject($this->newPosition, $this->level) : $this->getPosition(); + return $this->getPosition(); } public function getInAirTicks() : int{ @@ -1517,23 +1524,19 @@ class Player extends Human implements CommandSender, ChunkLoader, IPlayer{ } } - /** - * @return void - */ - protected function processMovement(int $tickDiff){ - if(!$this->isAlive() or !$this->spawned or $this->newPosition === null or $this->isSleeping()){ + protected function handleMovement(Vector3 $newPos) : void{ + $this->moveRateLimit--; + if($this->moveRateLimit < 0){ return; } - assert($this->x !== null and $this->y !== null and $this->z !== null); - assert($this->newPosition->x !== null and $this->newPosition->y !== null and $this->newPosition->z !== null); - - $newPos = $this->newPosition; - $distanceSquared = $newPos->distanceSquared($this); + $oldPos = $this->asLocation(); + $distanceSquared = $newPos->distanceSquared($oldPos); $revert = false; - if(($distanceSquared / ($tickDiff ** 2)) > 100){ + if($distanceSquared > 100){ + //TODO: this is probably too big if we process every movement /* !!! BEWARE YE WHO ENTER HERE !!! * * This is NOT an anti-cheat check. It is a safety check. @@ -1545,7 +1548,7 @@ class Player extends Human implements CommandSender, ChunkLoader, IPlayer{ * asking for help if you suffer the consequences of messing with this. */ $this->server->getLogger()->debug($this->getName() . " moved too fast, reverting movement"); - $this->server->getLogger()->debug("Old position: " . $this->asVector3() . ", new position: " . $this->newPosition); + $this->server->getLogger()->debug("Old position: " . $this->asVector3() . ", new position: " . $newPos); $revert = true; }elseif(!$this->level->isInLoadedTerrain($newPos) or !$this->level->isChunkGenerated($newPos->getFloorX() >> 4, $newPos->getFloorZ() >> 4)){ $revert = true; @@ -1559,7 +1562,7 @@ class Player extends Human implements CommandSender, ChunkLoader, IPlayer{ $this->move($dx, $dy, $dz); - $diff = $this->distanceSquared($newPos) / $tickDiff ** 2; + $diff = $this->distanceSquared($newPos); if($this->isSurvival() and $diff > 0.0625){ $ev = new PlayerIllegalMoveEvent($this, $newPos, new Vector3($this->lastX, $this->lastY, $this->lastZ)); @@ -1570,7 +1573,7 @@ class Player extends Human implements CommandSender, ChunkLoader, IPlayer{ if(!$ev->isCancelled()){ $revert = true; $this->server->getLogger()->debug($this->getServer()->getLanguage()->translateString("pocketmine.player.invalidMove", [$this->getName()])); - $this->server->getLogger()->debug("Old position: " . $this->asVector3() . ", new position: " . $this->newPosition); + $this->server->getLogger()->debug("Old position: " . $this->asVector3() . ", new position: " . $newPos); } } @@ -1579,13 +1582,25 @@ class Player extends Human implements CommandSender, ChunkLoader, IPlayer{ } } + if($revert){ + $this->revertMovement($oldPos); + } + } + + /** + * Fires movement events and synchronizes player movement, every tick. + */ + protected function processMostRecentMovements() : void{ + $exceededRateLimit = $this->moveRateLimit < 0; + $this->moveRateLimit = min(self::MOVE_BACKLOG_SIZE, max(0, $this->moveRateLimit) + self::MOVES_PER_TICK); + $from = new Location($this->lastX, $this->lastY, $this->lastZ, $this->lastYaw, $this->lastPitch, $this->level); $to = $this->getLocation(); $delta = (($this->lastX - $to->x) ** 2) + (($this->lastY - $to->y) ** 2) + (($this->lastZ - $to->z) ** 2); $deltaAngle = abs($this->lastYaw - $to->yaw) + abs($this->lastPitch - $to->pitch); - if(!$revert and ($delta > 0.0001 or $deltaAngle > 1.0)){ + if($delta > 0.0001 or $deltaAngle > 1.0){ $this->lastX = $to->x; $this->lastY = $to->y; $this->lastZ = $to->z; @@ -1597,41 +1612,47 @@ class Player extends Human implements CommandSender, ChunkLoader, IPlayer{ $ev->call(); - if(!($revert = $ev->isCancelled())){ //Yes, this is intended - if($to->distanceSquared($ev->getTo()) > 0.01){ //If plugins modify the destination - $this->teleport($ev->getTo()); - }else{ - $this->broadcastMovement(); - - $distance = sqrt((($from->x - $to->x) ** 2) + (($from->z - $to->z) ** 2)); - //TODO: check swimming (adds 0.015 exhaustion in MCPE) - if($this->isSprinting()){ - $this->exhaust(0.1 * $distance, PlayerExhaustEvent::CAUSE_SPRINTING); - }else{ - $this->exhaust(0.01 * $distance, PlayerExhaustEvent::CAUSE_WALKING); - } - } + if($ev->isCancelled()){ + $this->revertMovement($from); + return; } - } - if($revert){ + if($to->distanceSquared($ev->getTo()) > 0.01){ //If plugins modify the destination + $this->teleport($ev->getTo()); + return; + } - $this->lastX = $from->x; - $this->lastY = $from->y; - $this->lastZ = $from->z; + $this->broadcastMovement(); - $this->lastYaw = $from->yaw; - $this->lastPitch = $from->pitch; + $distance = sqrt((($from->x - $to->x) ** 2) + (($from->z - $to->z) ** 2)); + //TODO: check swimming (adds 0.015 exhaustion in MCPE) + if($this->isSprinting()){ + $this->exhaust(0.1 * $distance, PlayerExhaustEvent::CAUSE_SPRINTING); + }else{ + $this->exhaust(0.01 * $distance, PlayerExhaustEvent::CAUSE_WALKING); + } - $this->setPosition($from); - $this->sendPosition($from, $from->yaw, $from->pitch, MovePlayerPacket::MODE_RESET); - }else{ - if($distanceSquared != 0 and $this->nextChunkOrderRun > 20){ + if($this->nextChunkOrderRun > 20){ $this->nextChunkOrderRun = 20; } } - $this->newPosition = null; + if($exceededRateLimit){ //client and server positions will be out of sync if this happens + $this->server->getLogger()->debug("Player " . $this->getName() . " exceeded movement rate limit, forcing to last accepted position"); + $this->sendPosition($this, $this->yaw, $this->pitch, MovePlayerPacket::MODE_RESET); + } + } + + protected function revertMovement(Location $from) : void{ + $this->lastX = $from->x; + $this->lastY = $from->y; + $this->lastZ = $from->z; + + $this->lastYaw = $from->yaw; + $this->lastPitch = $from->pitch; + + $this->setPosition($from); + $this->sendPosition($from, $from->yaw, $from->pitch, MovePlayerPacket::MODE_RESET); } public function fall(float $fallDistance) : void{ @@ -1703,7 +1724,7 @@ class Player extends Human implements CommandSender, ChunkLoader, IPlayer{ $this->timings->startTiming(); if($this->spawned){ - $this->processMovement($tickDiff); + $this->processMostRecentMovements(); $this->motion->x = $this->motion->y = $this->motion->z = 0; //TODO: HACK! (Fixes player knockback being messed up) if($this->onGround){ $this->inAirTicks = 0; @@ -2259,8 +2280,7 @@ class Player extends Human implements CommandSender, ChunkLoader, IPlayer{ public function handleMovePlayer(MovePlayerPacket $packet) : bool{ $newPos = $packet->position->subtract(0, $this->baseOffset, 0); - if($this->isTeleporting and $newPos->distanceSquared($this) > 1){ //Tolerate up to 1 block to avoid problems with client-sided physics when spawning in blocks - $this->sendPosition($this, null, null, MovePlayerPacket::MODE_RESET); + if($this->forceMoveSync !== null and $newPos->distanceSquared($this->forceMoveSync) > 1){ //Tolerate up to 1 block to avoid problems with client-sided physics when spawning in blocks $this->server->getLogger()->debug("Got outdated pre-teleport movement from " . $this->getName() . ", received " . $newPos . ", expected " . $this->asVector3()); //Still getting movements from before teleport, ignore them }elseif((!$this->isAlive() or !$this->spawned) and $newPos->distanceSquared($this) > 0.01){ @@ -2268,9 +2288,7 @@ class Player extends Human implements CommandSender, ChunkLoader, IPlayer{ $this->server->getLogger()->debug("Reverted movement of " . $this->getName() . " due to not alive or not spawned, received " . $newPos . ", locked at " . $this->asVector3()); }else{ // Once we get a movement within a reasonable distance, treat it as a teleport ACK and remove position lock - if($this->isTeleporting){ - $this->isTeleporting = false; - } + $this->forceMoveSync = null; $packet->yaw = fmod($packet->yaw, 360); $packet->pitch = fmod($packet->pitch, 360); @@ -2280,7 +2298,7 @@ class Player extends Human implements CommandSender, ChunkLoader, IPlayer{ } $this->setRotation($packet->yaw, $packet->pitch); - $this->newPosition = $newPos; + $this->handleMovement($newPos); } return true; @@ -3794,12 +3812,14 @@ class Player extends Human implements CommandSender, ChunkLoader, IPlayer{ $pk->onGround = $this->onGround; if($targets !== null){ + if(in_array($this, $targets, true)){ + $this->forceMoveSync = $pos->asVector3(); + } $this->server->broadcastPacket($targets, $pk); }else{ + $this->forceMoveSync = $pos->asVector3(); $this->dataPacket($pk); } - - $this->newPosition = null; } /** @@ -3817,11 +3837,8 @@ class Player extends Human implements CommandSender, ChunkLoader, IPlayer{ $this->resetFallDistance(); $this->nextChunkOrderRun = 0; - $this->newPosition = null; $this->stopSleep(); - $this->isTeleporting = true; - //TODO: workaround for player last pos not getting updated //Entity::updateMovement() normally handles this, but it's overridden with an empty function in Player $this->resetLastMovements(); From 484557935e8fd72e6ca5d8332193d644ef185cbc Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Sun, 31 May 2020 16:06:48 +0100 Subject: [PATCH 87/90] Level: remove dead block placement code (player movements are now always processed immediately, just not immediately broadcasted) --- src/pocketmine/level/Level.php | 9 --------- 1 file changed, 9 deletions(-) diff --git a/src/pocketmine/level/Level.php b/src/pocketmine/level/Level.php index 61c2c7ffc..03b5b29b7 100644 --- a/src/pocketmine/level/Level.php +++ b/src/pocketmine/level/Level.php @@ -1897,15 +1897,6 @@ class Level implements ChunkManager, Metadatable{ if(count($this->getCollidingEntities($collisionBox)) > 0){ return false; //Entity in block } - - if($player !== null){ - if(($diff = $player->getNextPosition()->subtract($player->getPosition())) and $diff->lengthSquared() > 0.00001){ - $bb = $player->getBoundingBox()->offsetCopy($diff->x, $diff->y, $diff->z); - if($collisionBox->intersectsWith($bb)){ - return false; //Inside player BB - } - } - } } } From 3be83e09f2f4928297be3c85ded0ac1263c0dace Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Mon, 1 Jun 2020 13:51:36 +0100 Subject: [PATCH 88/90] Revert BC-breaking backport from b38c81c96 this can't be applied to a minor version because it places additional requirements on the Inventory contract. --- src/pocketmine/inventory/BaseInventory.php | 7 ------- src/pocketmine/inventory/Inventory.php | 5 ----- 2 files changed, 12 deletions(-) diff --git a/src/pocketmine/inventory/BaseInventory.php b/src/pocketmine/inventory/BaseInventory.php index 94933099d..434495cfc 100644 --- a/src/pocketmine/inventory/BaseInventory.php +++ b/src/pocketmine/inventory/BaseInventory.php @@ -372,13 +372,6 @@ abstract class BaseInventory implements Inventory{ } } - public function swap(int $slot1, int $slot2) : void{ - $i1 = $this->getItem($slot1); - $i2 = $this->getItem($slot2); - $this->setItem($slot1, $i2); - $this->setItem($slot2, $i1); - } - /** * @return Player[] */ diff --git a/src/pocketmine/inventory/Inventory.php b/src/pocketmine/inventory/Inventory.php index dd81b272a..f950b73af 100644 --- a/src/pocketmine/inventory/Inventory.php +++ b/src/pocketmine/inventory/Inventory.php @@ -152,11 +152,6 @@ interface Inventory{ */ public function clearAll(bool $send = true) : void; - /** - * Swaps the specified slots. - */ - public function swap(int $slot1, int $slot2) : void; - /** * Gets all the Players viewing the inventory * Players will view their inventory at all times, even when not open. From 5c63e06b0f5267a6e45e7f912f8acf8621175892 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Mon, 1 Jun 2020 14:57:27 +0100 Subject: [PATCH 89/90] piece together a changelog for release --- changelogs/3.13.md | 111 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 111 insertions(+) create mode 100644 changelogs/3.13.md diff --git a/changelogs/3.13.md b/changelogs/3.13.md new file mode 100644 index 000000000..470fdb4fc --- /dev/null +++ b/changelogs/3.13.md @@ -0,0 +1,111 @@ +**For Minecraft: Bedrock Edition 1.14.60** + +This is a feature release, containing various minor API additions, deprecations and a few minor features. + +### Note about API versions +Plugins which don't touch the protocol and compatible with any previous 3.x.y version will also run on these releases and do not need API bumps. +Plugin developers should **only** update their required API to this version if you need the changes in this build. + +**WARNING: If your plugin uses the protocol, you're not shielded by API change constraints.** You should consider using the `mcpe-protocol` directive in `plugin.yml` as a constraint if you do. + +# 3.13.0 +## Core +- PHP 7.3.0 or newer is now required. +- Player movement processing has been revamped. It's now more tolerant of network lag and doesn't have as many problems with falling. + +## User Interface +- `/time` now supports additional aliases `noon`, `sunset`, `midnight` and `sunrise`. +- Removed warnings when a plugin registers a handler for a deprecated event. Since this warning is developer-focused, and too specific to be useful, it just caused annoyance and confusion to users who didn't know what it meant. + +## API +### General +- It's now possible to require a specific operating system using the `os` directive in `plugin.yml`. More information about this directive can be found in the [developer documentation](https://github.com/pmmp/DeveloperDocs). + +### Player +- `Player->resetItemCooldown()` now accepts a second parameter, allowing plugins to provide a custom duration. +- The following methods have been deprecated and have recommended replacements: + - `Player->addTitle()` -> `Player->sendTitle()` + - `Player->addSubTitle()` -> `Player->sendSubTitle()` + - `Player->addActionBarMessage()` -> `Player->sendActionBarMessage()` + +### Event +- The following methods have been deprecated: + - `EntityDespawnEvent->getType()` + - `EntityDespawnEvent->getPosition()` + - `EntityDespawnEvent->isCreature()` + - `EntityDespawnEvent->isHuman()` + - `EntityDespawnEvent->isProjectile()` + - `EntityDespawnEvent->isVehicle()` + - `EntityDespawnEvent->isItem()` + - `EntitySpawnEvent->getType()` + - `EntitySpawnEvent->getPosition()` + - `EntitySpawnEvent->isCreature()` + - `EntitySpawnEvent->isHuman()` + - `EntitySpawnEvent->isProjectile()` + - `EntitySpawnEvent->isVehicle()` + - `EntitySpawnEvent->isItem()` +- Added the following API methods: + - `EntityDeathEvent->getXpDropAmount()` + - `EntityDeathEvent->setXpDropAmount()` +- `PlayerDeathEvent::__construct()` now accepts a fourth (optional) parameter `int $xp`. +- `EntityDeathEvent::__construct()` now accepts a third (optional) parameter `int $xp`. + +### Inventory +- The following classes have been deprecated: + - `Recipe` +- The following methods have been deprecated: + - `CraftingManager->registerRecipe()` + - `Recipe->registerToCraftingManager()` (and all its implementations) + +### Item +- New `Enchantment` type ID constants have been added. +- `ItemFactory::fromStringSingle()` has been added. This works exactly the same as `ItemFactory::fromString()`, but it has a return type of `Item` instead of `Item|Item[]` (more static analysis friendly). + +### Level +- Added the following API methods: + - `Position->getLevelNonNull()`: this is the same as `Position->getLevel()`, but throws an `AssumptionFailedError` if the level is null or invalid (more static analysis friendly). + - `Level->getTimeOfDay()` +- The following constants have been changed: + - `Level::TIME_DAY` now has a value of `1000` + - `Level::TIME_NIGHT` now has a value of `13000` +- Added the following constants: + - `Level::TIME_MIDNIGHT` + - `Level::TIME_NOON` +- The following types of particles now accept optional `Color` parameters in the constructor: + - `EnchantParticle` + - `InstantEnchantParticle` + +### Network +- Added the following API methods: + - `RakLibInterface->setPacketLimit()` + +### Scheduler +AsyncTask thread-local storage has been improved, making it simpler and easier to use. +- `AsyncTask->fetchLocal()` no longer deletes stored thread-local data. Instead, the storage behaves more like properties, and gets deleted when the AsyncTask object goes out of scope. +- `AsyncTask->peekLocal()` has been `@deprecated` (use `fetchLocal()` instead). +- Notices are no longer emitted if an async task doesn't fetch its locally stored data. +- The following methods have been deprecated: + - `AsyncTask->getFromThreadStore()` (use its worker's corresponding method) + - `AsyncTask->saveToThreadStore()` (use its worker's corresponding method) + - `AsyncTask->removeFromThreadStore()` (use its worker's corresponding method) + +### Utils +- The following functions have been deprecated and have recommended replacements: + - `Utils::getMemoryUsage()` -> split into `Process::getMemoryUsage()` and `Process::getAdvancedMemoryUsage()` (not 1:1 replacement!!) + - `Utils::getRealMemoryUsage()` -> `Process::getRealMemoryUsage()` + - `Utils::getThreadCount()` -> `Process::getThreadCount()` + - `Utils::kill()` -> `Process::kill()` + - `Utils::execute()` -> `Process::execute()` +- Added the following constants: + - `Utils::OS_WINDOWS` + - `Utils::OS_IOS` + - `Utils::OS_MACOS` + - `Utils::OS_ANDROID` + - `Utils::OS_LINUX` + - `Utils::OS_BSD` + - `Utils::OS_UNKNOWN` +- Added the following API methods: + - `Config->getPath()` + - `Utils::recursiveUnlink()` + - `Terminal::write()` + - `Terminal::writeLine()` From a0de9b0d46baf9fe72e3347ed80b35b66dc1022b Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Thu, 4 Jun 2020 13:39:26 +0100 Subject: [PATCH 90/90] Player: use real time to update rate limit, fixes #3554 (except in very extreme cases) --- src/pocketmine/Player.php | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/pocketmine/Player.php b/src/pocketmine/Player.php index f8e8ba503..42f5c97a0 100644 --- a/src/pocketmine/Player.php +++ b/src/pocketmine/Player.php @@ -334,8 +334,10 @@ class Player extends Human implements CommandSender, ChunkLoader, IPlayer{ /** @var bool[] map: raw UUID (string) => bool */ protected $hiddenPlayers = []; - /** @var int */ + /** @var float */ protected $moveRateLimit = 10 * self::MOVES_PER_TICK; + /** @var float|null */ + protected $lastMovementProcess = null; /** @var Vector3|null */ protected $forceMoveSync = null; @@ -1593,8 +1595,11 @@ class Player extends Human implements CommandSender, ChunkLoader, IPlayer{ * Fires movement events and synchronizes player movement, every tick. */ protected function processMostRecentMovements() : void{ + $now = microtime(true); + $multiplier = $this->lastMovementProcess !== null ? ($now - $this->lastMovementProcess) * 20 : 1; $exceededRateLimit = $this->moveRateLimit < 0; - $this->moveRateLimit = min(self::MOVE_BACKLOG_SIZE, max(0, $this->moveRateLimit) + self::MOVES_PER_TICK); + $this->moveRateLimit = min(self::MOVE_BACKLOG_SIZE, max(0, $this->moveRateLimit) + self::MOVES_PER_TICK * $multiplier); + $this->lastMovementProcess = $now; $from = new Location($this->lastX, $this->lastY, $this->lastZ, $this->lastYaw, $this->lastPitch, $this->level); $to = $this->getLocation();