Merge branch 'stable'

This commit is contained in:
Dylan K. Taylor 2020-02-07 18:13:55 +00:00
commit fb1126797a
88 changed files with 543 additions and 283 deletions

View File

@ -38,14 +38,16 @@ before_script:
- echo "extension=leveldb.so" >> ~/.phpenv/versions/$(phpenv version-name)/etc/php.ini
script:
- composer install
- composer install --prefer-dist
- ./vendor/bin/phpstan analyze --no-progress --memory-limit=2G
- ./vendor/bin/phpunit --bootstrap vendor/autoload.php --fail-on-warning tests/phpunit
- composer install --no-dev
- composer install --no-dev --prefer-dist
- ./tests/travis.sh -t4
cache:
- leveldb-mcpe
- leveldb-mcpe
- $HOME/.composer/cache/files
- $HOME/.composer/cache/vcs
notifications:
email: false

View File

@ -21,7 +21,7 @@
declare(strict_types=1);
namespace pocketmine\build_script;
namespace pocketmine\build\make_release;
use pocketmine\utils\VersionString;
use function dirname;
@ -37,17 +37,6 @@ use const STDIN;
require_once dirname(__DIR__) . '/vendor/autoload.php';
if(isset($argv[1])){
$currentVer = new VersionString($argv[1]);
}else{
$currentVer = new VersionString(BASE_VERSION);
}
$nextVer = new VersionString(sprintf(
"%u.%u.%u",
$currentVer->getMajor(),
$currentVer->getMinor(),
$currentVer->getPatch() + 1
));
function replaceVersion(string $versionInfoPath, string $newVersion, bool $isDev) : void{
$versionInfo = file_get_contents($versionInfoPath);
@ -63,17 +52,40 @@ function replaceVersion(string $versionInfoPath, string $newVersion, bool $isDev
);
file_put_contents($versionInfoPath, $versionInfo);
}
$versionInfoPath = dirname(__DIR__) . '/src/pocketmine/VersionInfo.php';
replaceVersion($versionInfoPath, $currentVer->getBaseVersion(), false);
echo "please add appropriate notes to the changelog and press enter...";
fgets(STDIN);
system('git add "' . dirname(__DIR__) . '/changelogs"');
system('git commit -m "Release ' . $currentVer->getBaseVersion() . '" --include "' . $versionInfoPath . '"');
system('git tag ' . $currentVer->getBaseVersion());
replaceVersion($versionInfoPath, $nextVer->getBaseVersion(), true);
system('git add "' . $versionInfoPath . '"');
system('git commit -m "' . $nextVer->getBaseVersion() . ' is next" --include "' . $versionInfoPath . '"');
echo "pushing changes in 5 seconds\n";
sleep(5);
system('git push origin HEAD ' . $currentVer->getBaseVersion());
/**
* @param string[] $argv
* @phpstan-param list<string> $argv
*/
function main(array $argv) : void{
if(isset($argv[1])){
$currentVer = new VersionString($argv[1]);
}else{
$currentVer = new VersionString(BASE_VERSION);
}
$nextVer = new VersionString(sprintf(
"%u.%u.%u",
$currentVer->getMajor(),
$currentVer->getMinor(),
$currentVer->getPatch() + 1
));
$versionInfoPath = dirname(__DIR__) . '/src/pocketmine/VersionInfo.php';
replaceVersion($versionInfoPath, $currentVer->getBaseVersion(), false);
echo "please add appropriate notes to the changelog and press enter...";
fgets(STDIN);
system('git add "' . dirname(__DIR__) . '/changelogs"');
system('git commit -m "Release ' . $currentVer->getBaseVersion() . '" --include "' . $versionInfoPath . '"');
system('git tag ' . $currentVer->getBaseVersion());
replaceVersion($versionInfoPath, $nextVer->getBaseVersion(), true);
system('git add "' . $versionInfoPath . '"');
system('git commit -m "' . $nextVer->getBaseVersion() . ' is next" --include "' . $versionInfoPath . '"');
echo "pushing changes in 5 seconds\n";
sleep(5);
system('git push origin HEAD ' . $currentVer->getBaseVersion());
}
if(!defined('pocketmine\_PHPSTAN_ANALYSIS')){
main($argv);
}

View File

@ -62,7 +62,7 @@ function preg_quote_array(array $strings, string $delim = null) : array{
*/
function buildPhar(string $pharPath, string $basePath, array $includedPaths, array $metadata, string $stub, int $signatureAlgo = \Phar::SHA1, ?int $compression = null){
$basePath = rtrim(str_replace("/", DIRECTORY_SEPARATOR, $basePath), DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR;
$includedPaths = array_map(function($path){
$includedPaths = array_map(function(string $path) : string{
return rtrim(str_replace("/", DIRECTORY_SEPARATOR, $path), DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR;
}, $includedPaths);
yield "Creating output file $pharPath";

View File

@ -40,12 +40,14 @@
"pocketmine/snooze": "^0.1.0",
"pocketmine/classloader": "dev-master",
"daverandom/callback-validator": "dev-master",
"adhocore/json-comment": "^0.0.7",
"adhocore/json-comment": "^0.1.0",
"particle/validator": "^2.3"
},
"require-dev": {
"phpstan/phpstan": "^0.12.8",
"irstea/phpunit-shim": "^7.5"
"phpstan/phpstan": "^0.12.9",
"irstea/phpunit-shim": "^8.5",
"phpstan/phpstan-phpunit": "^0.12.6",
"phpstan/phpstan-strict-rules": "^0.12.2"
},
"autoload": {
"psr-4": {

140
composer.lock generated
View File

@ -4,27 +4,27 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
"content-hash": "77f8107fac0660c32e4d30124c8cce3f",
"content-hash": "bb9233cea6e62cc28ea22863681e066e",
"packages": [
{
"name": "adhocore/json-comment",
"version": "v0.0.7",
"version": "0.1.0",
"source": {
"type": "git",
"url": "https://github.com/adhocore/php-json-comment.git",
"reference": "135356c7e7336ef59924f1d921c770045f937a76"
"reference": "8448076039389f558f39ad0553aab87db3f81614"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/adhocore/php-json-comment/zipball/135356c7e7336ef59924f1d921c770045f937a76",
"reference": "135356c7e7336ef59924f1d921c770045f937a76",
"url": "https://api.github.com/repos/adhocore/php-json-comment/zipball/8448076039389f558f39ad0553aab87db3f81614",
"reference": "8448076039389f558f39ad0553aab87db3f81614",
"shasum": ""
},
"require": {
"php": ">=5.4"
},
"require-dev": {
"phpunit/phpunit": "^4.8 || ^5.7 || ^6.5"
"phpunit/phpunit": "^6.5 || ^7.5"
},
"type": "library",
"autoload": {
@ -48,7 +48,7 @@
"json",
"strip-comment"
],
"time": "2018-08-01T12:27:26+00:00"
"time": "2020-01-03T13:51:23+00:00"
},
{
"name": "daverandom/callback-validator",
@ -587,11 +587,11 @@
"packages-dev": [
{
"name": "irstea/phpunit-shim",
"version": "7.5.20",
"version": "8.5.2",
"source": {
"type": "git",
"url": "https://gitlab.irstea.fr/pole-is/tools/phpunit-shim.git",
"reference": "81cd2d11e12165fddd2731033187dce4fbe8e013"
"reference": "39b6155954d6caec1110a9e78582c4816ab247bc"
},
"require": {
"ext-dom": "*",
@ -599,7 +599,8 @@
"ext-libxml": "*",
"ext-mbstring": "*",
"ext-xml": "*",
"php": "^7.1"
"ext-xmlwriter": "*",
"php": "^7.2"
},
"replace": {
"phpunit/phpunit": "self.version"
@ -631,20 +632,20 @@
"testing",
"xunit"
],
"time": "2020-01-09T03:20:19+00:00"
"time": "2020-01-09T03:20:20+00:00"
},
{
"name": "phpstan/phpstan",
"version": "0.12.8",
"version": "0.12.9",
"source": {
"type": "git",
"url": "https://github.com/phpstan/phpstan.git",
"reference": "62a552602b7586d82826231f2fd4cbfe39fe0b1d"
"reference": "297cb2458a96ea96d5e9d6ef38f1b7305c071f32"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/phpstan/phpstan/zipball/62a552602b7586d82826231f2fd4cbfe39fe0b1d",
"reference": "62a552602b7586d82826231f2fd4cbfe39fe0b1d",
"url": "https://api.github.com/repos/phpstan/phpstan/zipball/297cb2458a96ea96d5e9d6ef38f1b7305c071f32",
"reference": "297cb2458a96ea96d5e9d6ef38f1b7305c071f32",
"shasum": ""
},
"require": {
@ -670,7 +671,114 @@
"MIT"
],
"description": "PHPStan - PHP Static Analysis Tool",
"time": "2020-01-26T23:36:48+00:00"
"time": "2020-02-04T22:30:27+00:00"
},
{
"name": "phpstan/phpstan-phpunit",
"version": "0.12.6",
"source": {
"type": "git",
"url": "https://github.com/phpstan/phpstan-phpunit.git",
"reference": "26394996368b6d033d012547d3197f4e07e23021"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/phpstan/phpstan-phpunit/zipball/26394996368b6d033d012547d3197f4e07e23021",
"reference": "26394996368b6d033d012547d3197f4e07e23021",
"shasum": ""
},
"require": {
"php": "~7.1",
"phpstan/phpstan": "^0.12.4"
},
"conflict": {
"phpunit/phpunit": "<7.0"
},
"require-dev": {
"consistence/coding-standard": "^3.5",
"dealerdirect/phpcodesniffer-composer-installer": "^0.4.4",
"ergebnis/composer-normalize": "^2.0.2",
"jakub-onderka/php-parallel-lint": "^1.0",
"phing/phing": "^2.16.0",
"phpstan/phpstan-strict-rules": "^0.12",
"phpunit/phpunit": "^7.0",
"satooshi/php-coveralls": "^1.0",
"slevomat/coding-standard": "^4.7.2"
},
"type": "phpstan-extension",
"extra": {
"branch-alias": {
"dev-master": "0.12-dev"
},
"phpstan": {
"includes": [
"extension.neon",
"rules.neon"
]
}
},
"autoload": {
"psr-4": {
"PHPStan\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"description": "PHPUnit extensions and rules for PHPStan",
"time": "2020-01-10T12:07:21+00:00"
},
{
"name": "phpstan/phpstan-strict-rules",
"version": "0.12.2",
"source": {
"type": "git",
"url": "https://github.com/phpstan/phpstan-strict-rules.git",
"reference": "a670a59aff7cf96f75d21b974860ada10e25b2ee"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/phpstan/phpstan-strict-rules/zipball/a670a59aff7cf96f75d21b974860ada10e25b2ee",
"reference": "a670a59aff7cf96f75d21b974860ada10e25b2ee",
"shasum": ""
},
"require": {
"php": "~7.1",
"phpstan/phpstan": "^0.12.6"
},
"require-dev": {
"consistence/coding-standard": "^3.0.1",
"dealerdirect/phpcodesniffer-composer-installer": "^0.4.4",
"ergebnis/composer-normalize": "^2.0.2",
"jakub-onderka/php-parallel-lint": "^1.0",
"phing/phing": "^2.16.0",
"phpstan/phpstan-phpunit": "^0.12",
"phpunit/phpunit": "^7.0",
"slevomat/coding-standard": "^4.5.2"
},
"type": "phpstan-extension",
"extra": {
"branch-alias": {
"dev-master": "0.12-dev"
},
"phpstan": {
"includes": [
"rules.neon"
]
}
},
"autoload": {
"psr-4": {
"PHPStan\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"description": "Extra strict and opinionated rules for PHPStan",
"time": "2020-01-20T13:08:52+00:00"
}
],
"aliases": [],

View File

@ -3,9 +3,14 @@ includes:
- tests/phpstan/configs/custom-leveldb.neon
- tests/phpstan/configs/ds-bugs.neon
- tests/phpstan/configs/gc-hacks.neon
- tests/phpstan/configs/php-bugs.neon
- tests/phpstan/configs/phpstan-bugs.neon
- tests/phpstan/configs/phpunit-wiring-tests.neon
- tests/phpstan/configs/pthreads-bugs.neon
- tests/phpstan/configs/runtime-type-checks.neon
- vendor/phpstan/phpstan-phpunit/extension.neon
- vendor/phpstan/phpstan-phpunit/rules.neon
- vendor/phpstan/phpstan-strict-rules/rules.neon
rules:
- pocketmine\phpstan\rules\DisallowEnumComparisonRule
@ -15,11 +20,15 @@ parameters:
autoload_files:
- tests/phpstan/bootstrap.php
- src/PocketMine.php
- build/make-release.php
- build/server-phar.php
- vendor/irstea/phpunit-shim/phpunit
paths:
- src
- tests/phpstan/rules
- build/make-release.php
- build/server-phar.php
- tests/phpunit
dynamicConstantNames:
- pocketmine\IS_DEVELOPMENT_BUILD
- pocketmine\DEBUG
@ -27,11 +36,36 @@ parameters:
- tests/phpstan/stubs/pthreads.stub
reportUnmatchedIgnoredErrors: false #no other way to silence platform-specific non-warnings
ignoreErrors:
-
message: "#^Instanceof between pocketmine\\\\plugin\\\\PluginManager and pocketmine\\\\plugin\\\\PluginManager will always evaluate to true\\.$#"
count: 1
path: src/CrashDump.php
-
message: "#^Function parallel\\\\bootstrap not found\\.$#"
count: 1
path: src/PocketMine.php
-
message: "#^Instanceof between pocketmine\\\\plugin\\\\PluginManager and pocketmine\\\\plugin\\\\PluginManager will always evaluate to true\\.$#"
count: 1
path: src/Server.php
-
message: "#^Instanceof between pocketmine\\\\scheduler\\\\AsyncPool and pocketmine\\\\scheduler\\\\AsyncPool will always evaluate to true\\.$#"
count: 1
path: src/Server.php
-
message: "#^Instanceof between pocketmine\\\\command\\\\CommandReader and pocketmine\\\\command\\\\CommandReader will always evaluate to true\\.$#"
count: 1
path: src/Server.php
-
message: "#^Instanceof between pocketmine\\\\network\\\\Network and pocketmine\\\\network\\\\Network will always evaluate to true\\.$#"
count: 2
path: src/Server.php
-
message: "#^Call to an undefined method pocketmine\\\\command\\\\CommandSender\\:\\:teleport\\(\\)\\.$#"
count: 1
@ -73,6 +107,11 @@ parameters:
count: 1
path: src/event/entity/ProjectileLaunchEvent.php
-
message: "#^pocketmine\\\\inventory\\\\DoubleChestInventory\\:\\:__construct\\(\\) does not call parent constructor from pocketmine\\\\inventory\\\\ChestInventory\\.$#"
count: 1
path: src/inventory/DoubleChestInventory.php
-
message: "#^Cannot instantiate interface pocketmine\\\\world\\\\format\\\\io\\\\WorldProvider\\.$#"
count: 1
@ -83,6 +122,11 @@ parameters:
count: 1
path: src/world/WorldManager.php
-
message: "#^Variable property access on \\$this\\(pocketmine\\\\world\\\\generator\\\\PopulationTask\\)\\.$#"
count: 4
path: src/world/generator/PopulationTask.php
-
message: "#^Cannot instantiate interface pocketmine\\\\world\\\\format\\\\io\\\\WritableWorldProvider\\.$#"
count: 2

View File

@ -190,7 +190,7 @@ class MemoryManager{
* Returns the allowed chunk radius based on the current memory usage.
*/
public function getViewDistance(int $distance) : int{
return ($this->lowMemory and $this->lowMemChunkRadiusOverride > 0) ? (int) min($this->lowMemChunkRadiusOverride, $distance) : $distance;
return ($this->lowMemory and $this->lowMemChunkRadiusOverride > 0) ? min($this->lowMemChunkRadiusOverride, $distance) : $distance;
}
/**
@ -340,7 +340,7 @@ class MemoryManager{
}
$staticCount++;
self::continueDump($property->getValue(), $staticProperties[$className][$property->getName()], $objects, $refCounts, 0, $maxNesting, $maxStringSize);
$staticProperties[$className][$property->getName()] = self::continueDump($property->getValue(), $objects, $refCounts, 0, $maxNesting, $maxStringSize);
}
if(count($staticProperties[$className]) === 0){
@ -373,14 +373,14 @@ class MemoryManager{
}
$globalCount++;
self::continueDump($value, $globalVariables[$varName], $objects, $refCounts, 0, $maxNesting, $maxStringSize);
$globalVariables[$varName] = self::continueDump($value, $objects, $refCounts, 0, $maxNesting, $maxStringSize);
}
file_put_contents($outputFolder . "/globalVariables.js", json_encode($globalVariables, JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT));
$logger->info("Wrote $globalCount global variables");
}
self::continueDump($startingObject, $data, $objects, $refCounts, 0, $maxNesting, $maxStringSize);
$data = self::continueDump($startingObject, $objects, $refCounts, 0, $maxNesting, $maxStringSize);
do{
$continue = false;
@ -428,7 +428,7 @@ class MemoryManager{
$property->setAccessible(true);
}
self::continueDump($property->getValue($object), $info["properties"][$name], $objects, $refCounts, 0, $maxNesting, $maxStringSize);
$info["properties"][$name] = self::continueDump($property->getValue($object), $objects, $refCounts, 0, $maxNesting, $maxStringSize);
}
}
@ -455,14 +455,14 @@ class MemoryManager{
/**
* @param mixed $from
* @param mixed $data reference parameter
* @param object[] $objects reference parameter
* @param int[] $refCounts reference parameter
*
* @return mixed
*/
private static function continueDump($from, &$data, array &$objects, array &$refCounts, int $recursion, int $maxNesting, int $maxStringSize) : void{
private static function continueDump($from, array &$objects, array &$refCounts, int $recursion, int $maxNesting, int $maxStringSize){
if($maxNesting <= 0){
$data = "(error) NESTING LIMIT REACHED";
return;
return "(error) NESTING LIMIT REACHED";
}
--$maxNesting;
@ -478,12 +478,11 @@ class MemoryManager{
$data = "(object) $hash@" . get_class($from);
}elseif(is_array($from)){
if($recursion >= 5){
$data = "(error) ARRAY RECURSION LIMIT REACHED";
return;
return "(error) ARRAY RECURSION LIMIT REACHED";
}
$data = [];
foreach($from as $key => $value){
self::continueDump($value, $data[$key], $objects, $refCounts, $recursion + 1, $maxNesting, $maxStringSize);
$data[$key] = self::continueDump($value, $objects, $refCounts, $recursion + 1, $maxNesting, $maxStringSize);
}
}elseif(is_string($from)){
$data = "(string) len(" . strlen($from) . ") " . substr(Utils::printable($from), 0, $maxStringSize);
@ -492,5 +491,7 @@ class MemoryManager{
}else{
$data = $from;
}
return $data;
}
}

View File

@ -178,7 +178,7 @@ namespace pocketmine {
$opts = getopt("", ["bootstrap:"]);
if(isset($opts["bootstrap"])){
$bootstrap = realpath($opts["bootstrap"]) ?: $opts["bootstrap"];
$bootstrap = ($real = realpath($opts["bootstrap"])) !== false ? $real : $opts["bootstrap"];
}else{
$bootstrap = dirname(__FILE__, 2) . '/vendor/autoload.php';
}
@ -256,7 +256,6 @@ namespace pocketmine {
}
}
ThreadManager::init();
/*
* We now use the Composer autoloader, but this autoloader is still for loading plugins.
*/

View File

@ -159,23 +159,23 @@ class Server{
public const BROADCAST_CHANNEL_ADMINISTRATIVE = "pocketmine.broadcast.admin";
public const BROADCAST_CHANNEL_USERS = "pocketmine.broadcast.user";
/** @var Server */
/** @var Server|null */
private static $instance = null;
/** @var SleeperHandler */
private $tickSleeper;
/** @var BanList */
private $banByName = null;
private $banByName;
/** @var BanList */
private $banByIP = null;
private $banByIP;
/** @var Config */
private $operators = null;
private $operators;
/** @var Config */
private $whitelist = null;
private $whitelist;
/** @var bool */
private $isRunning = true;
@ -184,13 +184,13 @@ class Server{
private $hasStopped = false;
/** @var PluginManager */
private $pluginManager = null;
private $pluginManager;
/** @var float */
private $profilingTickRate = 20;
/** @var AutoUpdater */
private $updater = null;
private $updater;
/** @var AsyncPool */
private $asyncPool;
@ -227,10 +227,10 @@ class Server{
private $memoryManager;
/** @var CommandReader */
private $console = null;
private $console;
/** @var SimpleCommandMap */
private $commandMap = null;
private $commandMap;
/** @var CraftingManager */
private $craftingManager;
@ -274,7 +274,7 @@ class Server{
private $uniquePlayers = [];
/** @var QueryRegenerateEvent */
private $queryRegenerateTask = null;
private $queryRegenerateTask;
/** @var Config */
private $properties;
@ -914,7 +914,7 @@ class Server{
$poolSize = max(1, (int) $poolSize);
}
$this->asyncPool = new AsyncPool($poolSize, (int) max(-1, (int) $this->getProperty("memory.async-worker-hard-limit", 256)), $this->autoloader, $this->logger);
$this->asyncPool = new AsyncPool($poolSize, max(-1, (int) $this->getProperty("memory.async-worker-hard-limit", 256)), $this->autoloader, $this->logger);
if($this->getProperty("network.batch-threshold", 256) >= 0){
ZlibNetworkCompression::$THRESHOLD = (int) $this->getProperty("network.batch-threshold", 256);
@ -1093,7 +1093,7 @@ class Server{
$this->network->blockAddress($entry->getName(), -1);
}
if($this->getProperty("network.upnp-forwarding", false)){
if((bool) $this->getProperty("network.upnp-forwarding", false)){
try{
$this->network->registerInterface(new UPnP($this->logger, Internet::getInternalIP(), $this->getPort()));
}catch(\RuntimeException $e){
@ -1101,7 +1101,7 @@ class Server{
}
}
if($this->getProperty("settings.send-usage", true)){
if((bool) $this->getProperty("settings.send-usage", true)){
$this->sendUsageTicker = 6000;
$this->sendUsage(SendUsageTask::TYPE_OPEN);
}
@ -1504,7 +1504,7 @@ class Server{
}
if($report){
$url = ($this->getProperty("auto-report.use-https", true) ? "https" : "http") . "://" . $this->getProperty("auto-report.host", "crash.pmmp.io") . "/submit/api";
$url = ((bool) $this->getProperty("auto-report.use-https", true) ? "https" : "http") . "://" . $this->getProperty("auto-report.host", "crash.pmmp.io") . "/submit/api";
$reply = Internet::postURL($url, [
"report" => "yes",
"name" => $this->getName() . " " . $this->getPocketMineVersion(),

View File

@ -61,14 +61,14 @@ use function min;
*/
class BlockFactory{
/** @var \SplFixedArray|Block[] */
private static $fullList = null;
private static $fullList;
/** @var \SplFixedArray|int[] */
public static $lightFilter = null;
public static $lightFilter;
/** @var \SplFixedArray|bool[] */
public static $diffusesSkyLight = null;
public static $diffusesSkyLight;
/** @var \SplFixedArray|float[] */
public static $blastResistance = null;
public static $blastResistance;
/**
* Initializes the block factory. By default this is called only once on server start, however you may wish to use

View File

@ -124,7 +124,7 @@ class Leaves extends Transparent{
}
public function getDrops(Item $item) : array{
if($item->getBlockToolType() & BlockToolType::SHEARS){
if(($item->getBlockToolType() & BlockToolType::SHEARS) !== 0){
return $this->getDropsForCompatibleTool($item);
}

View File

@ -155,7 +155,7 @@ class Sign extends Transparent{
throw new \UnexpectedValueException($author->getName() . " tried to write $size bytes of text onto a sign (bigger than max 1000)");
}
$removeFormat = $author->getRemoveFormat();
$ev = new SignChangeEvent($this, $author, new SignText(array_map(function(string $line) use ($removeFormat){
$ev = new SignChangeEvent($this, $author, new SignText(array_map(function(string $line) use ($removeFormat) : string{
return TextFormat::clean($line, $removeFormat);
}, $text->getLines())));
$ev->call();

View File

@ -130,7 +130,7 @@ class Vine extends Flowable{
}
public function getDrops(Item $item) : array{
if($item->getBlockToolType() & BlockToolType::SHEARS){
if(($item->getBlockToolType() & BlockToolType::SHEARS) !== 0){
return $this->getDropsForCompatibleTool($item);
}

View File

@ -65,11 +65,11 @@ abstract class Command{
/** @var string|null */
private $permission = null;
/** @var string */
/** @var string|null */
private $permissionMessage = null;
/** @var TimingsHandler */
public $timings;
/** @var TimingsHandler|null */
public $timings = null;
/**
* @param string[] $aliases

View File

@ -152,7 +152,7 @@ class CommandReader extends Thread{
case self::TYPE_PIPED:
if(($raw = fgets(self::$stdin)) === false){ //broken pipe or EOF
$this->initStdin();
$this->synchronized(function(){
$this->synchronized(function() : void{
$this->wait(200000);
}); //prevent CPU waste if it's end of pipe
return true; //loop back round

View File

@ -184,7 +184,7 @@ class SimpleCommandMap implements CommandMap{
return false;
}
if(isset($this->knownCommands[$label]) and $this->knownCommands[$label]->getLabel() !== null and $this->knownCommands[$label]->getLabel() === $label){
if(isset($this->knownCommands[$label]) and $this->knownCommands[$label]->getLabel() === $label){
return false;
}

View File

@ -63,7 +63,7 @@ class BanListCommand extends VanillaCommand{
}
$list = $list->getEntries();
$message = implode(", ", array_map(function(BanEntry $entry){
$message = implode(", ", array_map(function(BanEntry $entry) : string{
return $entry->getName();
}, $list));

View File

@ -71,7 +71,7 @@ class EffectCommand extends VanillaCommand{
try{
$effect = VanillaEffects::fromString($args[1]);
}catch(\InvalidArgumentException $e){
$sender->sendMessage(new TranslationContainer(TextFormat::RED . "%commands.effect.notFound", [(string) $args[1]]));
$sender->sendMessage(new TranslationContainer(TextFormat::RED . "%commands.effect.notFound", [$args[1]]));
return true;
}

View File

@ -57,22 +57,22 @@ class HelpCommand extends VanillaCommand{
}
if(count($args) === 0){
$command = "";
$commandName = "";
$pageNumber = 1;
}elseif(is_numeric($args[count($args) - 1])){
$pageNumber = (int) array_pop($args);
if($pageNumber <= 0){
$pageNumber = 1;
}
$command = implode(" ", $args);
$commandName = implode(" ", $args);
}else{
$command = implode(" ", $args);
$commandName = implode(" ", $args);
$pageNumber = 1;
}
$pageHeight = $sender->getScreenLineHeight();
if($command === ""){
if($commandName === ""){
/** @var Command[][] $commands */
$commands = [];
foreach($sender->getServer()->getCommandMap()->getCommands() as $command){
@ -82,7 +82,7 @@ class HelpCommand extends VanillaCommand{
}
ksort($commands, SORT_NATURAL | SORT_FLAG_CASE);
$commands = array_chunk($commands, $pageHeight);
$pageNumber = (int) min(count($commands), $pageNumber);
$pageNumber = min(count($commands), $pageNumber);
if($pageNumber < 1){
$pageNumber = 1;
}
@ -95,7 +95,7 @@ class HelpCommand extends VanillaCommand{
return true;
}else{
if(($cmd = $sender->getServer()->getCommandMap()->getCommand(strtolower($command))) instanceof Command){
if(($cmd = $sender->getServer()->getCommandMap()->getCommand(strtolower($commandName))) instanceof Command){
if($cmd->testPermissionSilent($sender)){
$message = TextFormat::YELLOW . "--------- " . TextFormat::WHITE . " Help: /" . $cmd->getName() . TextFormat::YELLOW . " ---------\n";
$message .= TextFormat::GOLD . "Description: " . TextFormat::WHITE . $cmd->getDescription() . "\n";
@ -105,7 +105,7 @@ class HelpCommand extends VanillaCommand{
return true;
}
}
$sender->sendMessage(TextFormat::RED . "No help for " . strtolower($command));
$sender->sendMessage(TextFormat::RED . "No help for " . strtolower($commandName));
return true;
}

View File

@ -47,9 +47,9 @@ class ListCommand extends VanillaCommand{
return true;
}
$playerNames = array_map(function(Player $player){
$playerNames = array_map(function(Player $player) : string{
return $player->getName();
}, array_filter($sender->getServer()->getOnlinePlayers(), function(Player $player) use ($sender){
}, array_filter($sender->getServer()->getOnlinePlayers(), function(Player $player) use ($sender) : bool{
return !($sender instanceof Player) or $sender->canSee($player);
}));

View File

@ -52,7 +52,7 @@ class TeleportCommand extends VanillaCommand{
return true;
}
$args = array_values(array_filter($args, function($arg){
$args = array_values(array_filter($args, function(string $arg) : bool{
return $arg !== "";
}));
if(count($args) < 1 or count($args) > 6){

View File

@ -138,7 +138,7 @@ class CraftingManager{
*/
public static function sort(Item $i1, Item $i2) : int{
//Use spaceship operator to compare each property, then try the next one if they are equivalent.
($retval = $i1->getId() <=> $i2->getId()) === 0 && ($retval = $i1->getMeta() <=> $i2->getMeta()) === 0 && ($retval = $i1->getCount() <=> $i2->getCount());
($retval = $i1->getId() <=> $i2->getId()) === 0 && ($retval = $i1->getMeta() <=> $i2->getMeta()) === 0 && ($retval = $i1->getCount() <=> $i2->getCount()) === 0;
return $retval;
}

View File

@ -48,7 +48,7 @@ class AttributeMap{
* @return Attribute[]
*/
public function needSend() : array{
return array_filter($this->attributes, function(Attribute $attribute){
return array_filter($this->attributes, function(Attribute $attribute) : bool{
return $attribute->isSyncable() and $attribute->isDesynchronized();
});
}

View File

@ -265,9 +265,9 @@ final class EntityFactory{
new DoubleTag($pos->z)
]))
->setTag("Motion", new ListTag([
new DoubleTag($motion ? $motion->x : 0.0),
new DoubleTag($motion ? $motion->y : 0.0),
new DoubleTag($motion ? $motion->z : 0.0)
new DoubleTag($motion !== null ? $motion->x : 0.0),
new DoubleTag($motion !== null ? $motion->y : 0.0),
new DoubleTag($motion !== null ? $motion->z : 0.0)
]))
->setTag("Rotation", new ListTag([
new FloatTag($yaw),

View File

@ -245,9 +245,9 @@ class ExperienceManager{
$equipment[$mainHandIndex] = $item;
}
//TODO: check offhand
foreach($this->entity->getArmorInventory()->getContents() as $k => $item){
if($item instanceof Durable and $item->hasEnchantment(Enchantment::MENDING())){
$equipment[$k] = $item;
foreach($this->entity->getArmorInventory()->getContents() as $k => $armorItem){
if($armorItem instanceof Durable and $armorItem->hasEnchantment(Enchantment::MENDING())){
$equipment[$k] = $armorItem;
}
}

View File

@ -182,7 +182,7 @@ class Human extends Living implements ProjectileSource, InventoryHolder{
public function getXpDropAmount() : int{
//this causes some XP to be lost on death when above level 1 (by design), dropping at most enough points for
//about 7.5 levels of XP.
return (int) min(100, 7 * $this->xpManager->getXpLevel());
return min(100, 7 * $this->xpManager->getXpLevel());
}
/**

View File

@ -126,7 +126,7 @@ abstract class Living extends Entity{
$this->setAirSupplyTicks($nbt->getShort("Air", self::DEFAULT_BREATH_TICKS));
/** @var CompoundTag[]|ListTag $activeEffectsTag */
/** @var CompoundTag[]|ListTag|null $activeEffectsTag */
$activeEffectsTag = $nbt->getListTag("ActiveEffects");
if($activeEffectsTag !== null){
foreach($activeEffectsTag as $e){

View File

@ -75,6 +75,6 @@ abstract class ExperienceUtils{
$x = Math::solveQuadratic($a, $b, $c - $xp);
return (float) max($x); //we're only interested in the positive solution
return max($x); //we're only interested in the positive solution
}
}

View File

@ -36,7 +36,10 @@ abstract class BaseInventory implements Inventory{
/** @var int */
protected $maxStackSize = Inventory::MAX_STACK;
/** @var \SplFixedArray|(Item|null)[] */
/**
* @var \SplFixedArray|(Item|null)[]
* @phpstan-var \SplFixedArray<Item|null>
*/
protected $slots;
/** @var Player[] */
protected $viewers = [];

View File

@ -25,7 +25,10 @@ namespace pocketmine\item\enchantment;
class EnchantmentList{
/** @var \SplFixedArray|EnchantmentEntry[] */
/**
* @var \SplFixedArray|EnchantmentEntry[]
* @phpstan-var \SplFixedArray<EnchantmentEntry>
*/
private $enchantments;
public function __construct(int $size){

View File

@ -58,7 +58,7 @@ class Language{
$allFiles = scandir($path, SCANDIR_SORT_NONE);
if($allFiles !== false){
$files = array_filter($allFiles, function($filename){
$files = array_filter($allFiles, function(string $filename) : bool{
return substr($filename, -4) === ".ini";
});
@ -133,7 +133,7 @@ class Language{
*/
public function translateString(string $str, array $params = [], ?string $onlyPrefix = null) : string{
$baseText = $this->get($str);
$baseText = $this->parseTranslation(($baseText !== null and ($onlyPrefix === null or strpos($str, $onlyPrefix) === 0)) ? $baseText : $str, $onlyPrefix);
$baseText = $this->parseTranslation(($onlyPrefix === null or strpos($str, $onlyPrefix) === 0) ? $baseText : $str, $onlyPrefix);
foreach($params as $i => $p){
$baseText = str_replace("{%$i}", $this->parseTranslation((string) $p), $baseText, $onlyPrefix);

View File

@ -695,9 +695,9 @@ class InGamePacketHandler extends PacketHandler{
$raw = $matches[1];
$lastComma = -1;
$newParts = [];
$quoteType = null;
$inQuotes = false;
for($i = 0, $len = strlen($raw); $i <= $len; ++$i){
if($i === $len or ($raw[$i] === "," and $quoteType === null)){
if($i === $len or ($raw[$i] === "," and !$inQuotes)){
$part = substr($raw, $lastComma + 1, $i - ($lastComma + 1));
if(trim($part) === ""){ //regular parts will have quotes or something else that makes them non-empty
$part = '""';
@ -705,12 +705,13 @@ class InGamePacketHandler extends PacketHandler{
$newParts[] = $part;
$lastComma = $i;
}elseif($raw[$i] === '"'){
if($quoteType === null){
$quoteType = $raw[$i];
}elseif($raw[$i] === $quoteType){
for($backslashes = 0; $backslashes < $i && $raw[$i - $backslashes - 1] === "\\"; ++$backslashes){}
if(!$inQuotes){
$inQuotes = true;
}else{
$backslashes = 0;
for(; $backslashes < $i && $raw[$i - $backslashes - 1] === "\\"; ++$backslashes){}
if(($backslashes % 2) === 0){ //unescaped quote
$quoteType = null;
$inQuotes = false;
}
}
}

View File

@ -82,7 +82,7 @@ class LoginPacketHandler extends PacketHandler{
new SkinImage(
$animation[LoginPacket::I_ANIMATION_IMAGE_HEIGHT],
$animation[LoginPacket::I_ANIMATION_IMAGE_WIDTH],
base64_decode($animation[LoginPacket::I_ANIMATION_IMAGE_DATA])
base64_decode($animation[LoginPacket::I_ANIMATION_IMAGE_DATA], true)
),
$animation[LoginPacket::I_ANIMATION_IMAGE_TYPE],
$animation[LoginPacket::I_ANIMATION_IMAGE_FRAMES]
@ -90,12 +90,12 @@ class LoginPacketHandler extends PacketHandler{
}
$skinData = new SkinData(
$packet->clientData[LoginPacket::I_SKIN_ID],
base64_decode($packet->clientData[LoginPacket::I_SKIN_RESOURCE_PATCH]),
new SkinImage($packet->clientData[LoginPacket::I_SKIN_HEIGHT], $packet->clientData[LoginPacket::I_SKIN_WIDTH], base64_decode($packet->clientData[LoginPacket::I_SKIN_DATA])),
base64_decode($packet->clientData[LoginPacket::I_SKIN_RESOURCE_PATCH], true),
new SkinImage($packet->clientData[LoginPacket::I_SKIN_HEIGHT], $packet->clientData[LoginPacket::I_SKIN_WIDTH], base64_decode($packet->clientData[LoginPacket::I_SKIN_DATA], true)),
$animations,
new SkinImage($packet->clientData[LoginPacket::I_CAPE_HEIGHT], $packet->clientData[LoginPacket::I_CAPE_WIDTH], base64_decode($packet->clientData[LoginPacket::I_CAPE_DATA])),
base64_decode($packet->clientData[LoginPacket::I_GEOMETRY_DATA]),
base64_decode($packet->clientData[LoginPacket::I_ANIMATION_DATA]),
new SkinImage($packet->clientData[LoginPacket::I_CAPE_HEIGHT], $packet->clientData[LoginPacket::I_CAPE_WIDTH], base64_decode($packet->clientData[LoginPacket::I_CAPE_DATA], true)),
base64_decode($packet->clientData[LoginPacket::I_GEOMETRY_DATA], true),
base64_decode($packet->clientData[LoginPacket::I_ANIMATION_DATA], true),
$packet->clientData[LoginPacket::I_PREMIUM_SKIN],
$packet->clientData[LoginPacket::I_PERSONA_SKIN],
$packet->clientData[LoginPacket::I_PERSONA_CAPE_ON_CLASSIC_SKIN],

View File

@ -94,7 +94,7 @@ class AdventureSettingsPacket extends DataPacket implements ClientboundPacket, S
}
public function getFlag(int $flag) : bool{
if($flag & self::BITFLAG_SECOND_SET){
if(($flag & self::BITFLAG_SECOND_SET) !== 0){
return ($this->flags2 & $flag) !== 0;
}
@ -102,7 +102,7 @@ class AdventureSettingsPacket extends DataPacket implements ClientboundPacket, S
}
public function setFlag(int $flag, bool $value) : void{
if($flag & self::BITFLAG_SECOND_SET){
if(($flag & self::BITFLAG_SECOND_SET) !== 0){
$flagSet =& $this->flags2;
}else{
$flagSet =& $this->flags;

View File

@ -60,7 +60,7 @@ class AnimatePacket extends DataPacket implements ClientboundPacket, Serverbound
protected function decodePayload() : void{
$this->action = $this->getVarInt();
$this->entityRuntimeId = $this->getEntityRuntimeId();
if($this->action & 0x80){
if(($this->action & 0x80) !== 0){
$this->float = $this->getLFloat();
}
}
@ -68,7 +68,7 @@ class AnimatePacket extends DataPacket implements ClientboundPacket, Serverbound
protected function encodePayload() : void{
$this->putVarInt($this->action);
$this->putEntityRuntimeId($this->entityRuntimeId);
if($this->action & 0x80){
if(($this->action & 0x80) !== 0){
$this->putLFloat($this->float);
}
}

View File

@ -304,13 +304,13 @@ class AvailableCommandsPacket extends DataPacket implements ClientboundPacket{
$parameter->isOptional = $this->getBool();
$parameter->flags = $this->getByte();
if($parameter->paramType & self::ARG_FLAG_ENUM){
if(($parameter->paramType & self::ARG_FLAG_ENUM) !== 0){
$index = ($parameter->paramType & 0xffff);
$parameter->enum = $enums[$index] ?? null;
if($parameter->enum === null){
throw new BadPacketException("deserializing $name parameter $parameter->paramName: expected enum at $index, but got none");
}
}elseif($parameter->paramType & self::ARG_FLAG_POSTFIX){
}elseif(($parameter->paramType & self::ARG_FLAG_POSTFIX) !== 0){
$index = ($parameter->paramType & 0xffff);
$parameter->postfix = $postfixes[$index] ?? null;
if($parameter->postfix === null){
@ -374,8 +374,8 @@ class AvailableCommandsPacket extends DataPacket implements ClientboundPacket{
* @phpstan-param array<int, string> $postfixes
*/
private function argTypeToString(int $argtype, array $postfixes) : string{
if($argtype & self::ARG_FLAG_VALID){
if($argtype & self::ARG_FLAG_ENUM){
if(($argtype & self::ARG_FLAG_VALID) !== 0){
if(($argtype & self::ARG_FLAG_ENUM) !== 0){
return "stringenum (" . ($argtype & 0xffff) . ")";
}
@ -401,7 +401,7 @@ class AvailableCommandsPacket extends DataPacket implements ClientboundPacket{
case self::ARG_TYPE_COMMAND:
return "command";
}
}elseif($argtype & self::ARG_FLAG_POSTFIX){
}elseif(($argtype & self::ARG_FLAG_POSTFIX) !== 0){
$postfix = $postfixes[$argtype & 0xffff];
return "int (postfix $postfix)";
@ -422,7 +422,7 @@ class AvailableCommandsPacket extends DataPacket implements ClientboundPacket{
/** @var CommandEnum[] $enums */
$enums = [];
$addEnumFn = static function(CommandEnum $enum) use (&$enums, &$enumIndexes, &$enumValueIndexes){
$addEnumFn = static function(CommandEnum $enum) use (&$enums, &$enumIndexes, &$enumValueIndexes) : void{
if(!isset($enumIndexes[$enum->getName()])){
$enums[$enumIndexes[$enum->getName()] = count($enumIndexes)] = $enum;
}

View File

@ -42,8 +42,8 @@ class ClientCacheBlobStatusPacket extends DataPacket implements ServerboundPacke
*/
public static function create(array $hitHashes, array $missHashes) : self{
//type checks
(static function(int ...$hashes){})(...$hitHashes);
(static function(int ...$hashes){})(...$missHashes);
(static function(int ...$hashes) : void{})(...$hitHashes);
(static function(int ...$hashes) : void{})(...$missHashes);
$result = new self;
$result->hitHashes = $hitHashes;

View File

@ -40,7 +40,7 @@ class ClientCacheMissResponsePacket extends DataPacket implements ClientboundPac
*/
public static function create(array $blobs) : self{
//type check
(static function(ChunkCacheBlob ...$blobs){})(...$blobs);
(static function(ChunkCacheBlob ...$blobs) : void{})(...$blobs);
$result = new self;
$result->blobs = $blobs;

View File

@ -60,7 +60,7 @@ class LevelChunkPacket extends DataPacket implements ClientboundPacket{
* @param int[] $usedBlobHashes
*/
public static function withCache(int $chunkX, int $chunkZ, int $subChunkCount, array $usedBlobHashes, string $extraPayload) : self{
(static function(int ...$hashes){})(...$usedBlobHashes);
(static function(int ...$hashes) : void{})(...$usedBlobHashes);
$result = new self;
$result->chunkX = $chunkX;
$result->chunkZ = $chunkZ;

View File

@ -59,7 +59,7 @@ class MoveActorDeltaPacket extends DataPacket implements ClientboundPacket{
* @throws BinaryDataException
*/
private function maybeReadCoord(int $flag) : int{
if($this->flags & $flag){
if(($this->flags & $flag) !== 0){
return $this->getVarInt();
}
return 0;
@ -69,7 +69,7 @@ class MoveActorDeltaPacket extends DataPacket implements ClientboundPacket{
* @throws BinaryDataException
*/
private function maybeReadRotation(int $flag) : float{
if($this->flags & $flag){
if(($this->flags & $flag) !== 0){
return $this->getByteRotation();
}
return 0.0;
@ -87,13 +87,13 @@ class MoveActorDeltaPacket extends DataPacket implements ClientboundPacket{
}
private function maybeWriteCoord(int $flag, int $val) : void{
if($this->flags & $flag){
if(($this->flags & $flag) !== 0){
$this->putVarInt($val);
}
}
private function maybeWriteRotation(int $flag, float $val) : void{
if($this->flags & $flag){
if(($this->flags & $flag) !== 0){
$this->putByteRotation($val);
}
}

View File

@ -28,7 +28,7 @@ use pocketmine\utils\BinaryDataException;
class PacketPool{
/** @var \SplFixedArray<Packet> */
protected static $pool = null;
protected static $pool;
public static function init() : void{
static::$pool = new \SplFixedArray(256);

View File

@ -122,7 +122,7 @@ final class RuntimeBlockMapping{
*/
private static function randomizeTable(array $table) : array{
$postSeed = mt_rand(); //save a seed to set afterwards, to avoid poor quality randoms
mt_srand(getmypid() ?: 0); //Use a seed which is the same on all threads. This isn't a secure seed, but we don't care.
mt_srand(getmypid()); //Use a seed which is the same on all threads. This isn't a secure seed, but we don't care.
shuffle($table);
mt_srand($postSeed); //restore a good quality seed that isn't dependent on PID
return $table;

View File

@ -35,7 +35,7 @@ class CommandEnumConstraint{
* @param int[] $constraints
*/
public function __construct(CommandEnum $enum, int $valueOffset, array $constraints){
(static function(int ...$_){})(...$constraints);
(static function(int ...$_) : void{})(...$constraints);
if(!isset($enum->getValues()[$valueOffset])){
throw new \InvalidArgumentException("Invalid enum value offset $valueOffset");
}

View File

@ -498,7 +498,7 @@ class NetworkBinaryStream extends BinaryStream{
* @see NetworkBinaryStream::putVector3()
*/
public function putVector3Nullable(?Vector3 $vector) : void{
if($vector){
if($vector !== null){
$this->putVector3($vector);
}else{
$this->putLFloat(0.0);
@ -520,7 +520,7 @@ class NetworkBinaryStream extends BinaryStream{
* @throws BinaryDataException
*/
public function getByteRotation() : float{
return (float) ($this->getByte() * (360 / 256));
return ($this->getByte() * (360 / 256));
}
public function putByteRotation(float $rotation) : void{

View File

@ -38,7 +38,7 @@ class BanEntry{
/** @var string */
private $name;
/** @var \DateTime */
private $creationDate = null;
private $creationDate;
/** @var string */
private $source = "(Unknown)";
/** @var \DateTime|null */

View File

@ -32,7 +32,7 @@ class PermissibleBase implements Permissible{
/** @var ServerOperator */
private $opable;
/** @var Permissible */
/** @var Permissible|null */
private $parent = null;
/** @var PermissionAttachment[] */

View File

@ -28,7 +28,7 @@ use pocketmine\plugin\Plugin;
trait PermissibleDelegateTrait{
/** @var PermissibleBase */
private $perm = null;
private $perm;
/**
* @param Permission|string $name

View File

@ -27,7 +27,7 @@ use pocketmine\plugin\Plugin;
use pocketmine\plugin\PluginException;
class PermissionAttachment{
/** @var PermissionRemovedExecutor */
/** @var PermissionRemovedExecutor|null */
private $removed = null;
/** @var bool[] */
@ -84,7 +84,7 @@ class PermissionAttachment{
*/
public function setPermissions(array $permissions) : void{
foreach($permissions as $key => $value){
$this->permissions[$key] = (bool) $value;
$this->permissions[$key] = $value;
}
$this->permissible->recalculatePermissions();
}

View File

@ -102,9 +102,7 @@ class PermissionParser{
if(is_array($data["children"])){
foreach($data["children"] as $k => $v){
if(is_array($v)){
if(($perm = self::loadPermission($k, $v, $default, $output)) !== null){
$output[] = $perm;
}
$output[] = self::loadPermission($k, $v, $default, $output);
}
$children[$k] = true;
}

View File

@ -170,7 +170,7 @@ class Player extends Human implements CommandSender, ChunkLoader, ChunkListener,
/** @var PlayerCursorInventory */
protected $cursorInventory;
/** @var CraftingGrid */
protected $craftingGrid = null;
protected $craftingGrid;
/** @var int */
protected $messageCounter = 2;

View File

@ -328,7 +328,7 @@ class PluginManager{
if(!isset($dependencies[$name]) and !isset($softDependencies[$name])){
unset($plugins[$name]);
$loadedThisLoop++;
if($plugin = $this->loadPlugin($file, $loaders) and $plugin instanceof Plugin){
if(($plugin = $this->loadPlugin($file, $loaders)) instanceof Plugin){
$loadedPlugins[$name] = $plugin;
}else{
$this->server->getLogger()->critical($this->server->getLanguage()->translateString("pocketmine.plugin.genericLoadError", [$name]));

View File

@ -62,7 +62,7 @@ class ZippedResourcePack implements ResourcePack{
/** @var \stdClass */
protected $manifest;
/** @var string */
/** @var string|null */
protected $sha256 = null;
/** @var resource */

View File

@ -54,7 +54,7 @@ abstract class AsyncTask extends \Threaded{
*/
private static $threadLocalStorage = null;
/** @var AsyncWorker $worker */
/** @var AsyncWorker|null $worker */
public $worker = null;
/** @var \Threaded */

View File

@ -27,7 +27,7 @@ use function spl_object_id;
class ThreadManager extends \Volatile{
/** @var ThreadManager */
/** @var ThreadManager|null */
private static $instance = null;
public static function init() : void{
@ -35,6 +35,9 @@ class ThreadManager extends \Volatile{
}
public static function getInstance() : ThreadManager{
if(self::$instance === null){
self::$instance = new ThreadManager();
}
return self::$instance;
}
@ -43,7 +46,7 @@ class ThreadManager extends \Volatile{
*/
public function add($thread) : void{
if($thread instanceof Thread or $thread instanceof Worker){
$this->{spl_object_id($thread)} = $thread;
$this[spl_object_id($thread)] = $thread;
}
}
@ -52,7 +55,7 @@ class ThreadManager extends \Volatile{
*/
public function remove($thread) : void{
if($thread instanceof Thread or $thread instanceof Worker){
unset($this->{spl_object_id($thread)});
unset($this[spl_object_id($thread)]);
}
}

View File

@ -128,7 +128,7 @@ class TimingsHandler{
/** @var string */
private $name;
/** @var TimingsHandler */
/** @var TimingsHandler|null */
private $parent = null;
/** @var int */

View File

@ -57,7 +57,7 @@ class AutoUpdater{
$this->logger = new \PrefixedLogger($server->getLogger(), "Auto Updater");
$this->endpoint = "http://$endpoint/api/";
if($server->getProperty("auto-updater.enabled", true)){
if((bool) $server->getProperty("auto-updater.enabled", true)){
$this->doCheck();
}
}
@ -77,10 +77,10 @@ class AutoUpdater{
$this->checkUpdate();
if($this->hasUpdate()){
(new UpdateNotifyEvent($this))->call();
if($this->server->getProperty("auto-updater.on-update.warn-console", true)){
if((bool) $this->server->getProperty("auto-updater.on-update.warn-console", true)){
$this->showConsoleUpdate();
}
}elseif($this->server->getProperty("auto-updater.preferred-channel", true)){
}else{
if(!\pocketmine\IS_DEVELOPMENT_BUILD and $this->getChannel() !== "stable"){
$this->showChannelSuggestionStable();
}elseif(\pocketmine\IS_DEVELOPMENT_BUILD and $this->getChannel() === "stable"){

View File

@ -166,29 +166,28 @@ class Config{
$this->save();
}else{
$content = file_get_contents($this->file);
$config = null;
switch($this->type){
case Config::PROPERTIES:
$this->parseProperties($content);
$config = $this->parseProperties($content);
break;
case Config::JSON:
$this->config = json_decode($content, true);
$config = json_decode($content, true);
break;
case Config::YAML:
$content = self::fixYAMLIndexes($content);
$this->config = yaml_parse($content);
$config = yaml_parse($content);
break;
case Config::SERIALIZED:
$this->config = unserialize($content);
$config = unserialize($content);
break;
case Config::ENUM:
$this->parseList($content);
$config = self::parseList($content);
break;
default:
throw new \InvalidStateException("Config type is unknown");
}
if(!is_array($this->config)){
$this->config = $default;
}
$this->config = is_array($config) ? $config : $default;
if($this->fillDefaults($default, $this->config) > 0){
$this->save();
}
@ -508,14 +507,20 @@ class Config{
return $changed;
}
private function parseList(string $content) : void{
/**
* @return true[]
* @phpstan-return array<string, true>
*/
private static function parseList(string $content) : array{
$result = [];
foreach(explode("\n", trim(str_replace("\r\n", "\n", $content))) as $v){
$v = trim($v);
if($v == ""){
continue;
}
$this->config[$v] = true;
$result[$v] = true;
}
return $result;
}
private function writeProperties() : string{
@ -532,7 +537,12 @@ class Config{
return $content;
}
private function parseProperties(string $content) : void{
/**
* @return mixed[]
* @phpstan-return array<string, mixed>
*/
private function parseProperties(string $content) : array{
$result = [];
if(preg_match_all('/^\s*([a-zA-Z0-9\-_\.]+)[ \t]*=([^\r\n]*)/um', $content, $matches) > 0){ //false or 0 matches
foreach($matches[1] as $i => $k){
$v = trim($matches[2][$i]);
@ -548,11 +558,13 @@ class Config{
$v = false;
break;
}
if(isset($this->config[$k])){
if(isset($result[$k])){
\GlobalLogger::get()->debug("[Config] Repeated property " . $k . " on file " . $this->file);
}
$this->config[$k] = $v;
$result[$k] = $v;
}
}
return $result;
}
}

View File

@ -252,7 +252,7 @@ class MainLogger extends \AttachableThreadedLogger{
public function syncFlushBuffer() : void{
$this->syncFlush = true;
$this->synchronized(function(){
$this->synchronized(function() : void{
$this->notify(); //write immediately
while($this->syncFlush){
@ -284,7 +284,7 @@ class MainLogger extends \AttachableThreadedLogger{
while(!$this->shutdown){
$this->writeLogStream($logResource);
$this->synchronized(function(){
$this->synchronized(function() : void{
$this->wait(25000);
});
}

View File

@ -126,7 +126,7 @@ final class Process{
}
switch(Utils::getOS()){
case "win":
exec("taskkill.exe /F /PID " . ((int) $pid) . " > NUL");
exec("taskkill.exe /F /PID $pid > NUL");
break;
case "mac":
case "linux":
@ -134,7 +134,7 @@ final class Process{
if(function_exists("posix_kill")){
posix_kill($pid, 9); //SIGKILL
}else{
exec("kill -9 " . ((int) $pid) . " > /dev/null 2>&1");
exec("kill -9 $pid > /dev/null 2>&1");
}
}
}

View File

@ -44,7 +44,7 @@ class ServerKiller extends Thread{
protected function onRun() : void{
$start = time();
$this->synchronized(function(){
$this->synchronized(function() : void{
if(!$this->stopped){
$this->wait($this->time * 1000000);
}

View File

@ -337,7 +337,7 @@ class Utils{
$hash = 0;
for($i = 0, $len = strlen($string); $i < $len; $i++){
$ord = ord($string[$i]);
if($ord & 0x80){
if(($ord & 0x80) !== 0){
$ord -= 0x100;
}
$hash = 31 * $hash + $ord;
@ -408,7 +408,7 @@ class Utils{
$args = $trace[$i]["params"];
}
$params = implode(", ", array_map(function($value) use($maxStringLength){
$params = implode(", ", array_map(function($value) use($maxStringLength) : string{
if(is_object($value)){
return "object " . self::getNiceClassName($value);
}

View File

@ -58,14 +58,14 @@ class Explosion{
public $affectedBlocks = [];
/** @var float */
public $stepLen = 0.3;
/** @var Entity|Block */
/** @var Entity|Block|null */
private $what;
/** @var SubChunkIteratorManager */
private $subChunkHandler;
/**
* @param Entity|Block $what
* @param Entity|Block|null $what
*/
public function __construct(Position $center, float $size, $what = null){
if(!$center->isValid()){
@ -97,7 +97,7 @@ class Explosion{
$currentChunk = null;
$currentSubChunk = null;
$mRays = (int) ($this->rays - 1);
$mRays = $this->rays - 1;
for($i = 0; $i < $this->rays; ++$i){
for($j = 0; $j < $this->rays; ++$j){
for($k = 0; $k < $this->rays; ++$k){

View File

@ -1718,8 +1718,11 @@ class World implements ChunkManager{
*
* @param string $entityType Class of entity to use for instanceof
* @param bool $includeDead Whether to include entitites which are dead
* @phpstan-template TEntity of Entity
* @phpstan-param class-string<TEntity> $entityType
*
* @return Entity|null an entity of type $entityType, or null if not found
* @phpstan-return TEntity
*/
public function getNearestEntity(Vector3 $pos, float $maxDistance, string $entityType = Entity::class, bool $includeDead = false) : ?Entity{
assert(is_a($entityType, Entity::class, true));
@ -1731,7 +1734,10 @@ class World implements ChunkManager{
$currentTargetDistSq = $maxDistance ** 2;
/** @var Entity|null $currentTarget */
/**
* @var Entity|null $currentTarget
* @phpstan-var TEntity|null $currentTarget
*/
$currentTarget = null;
for($x = $minX; $x <= $maxX; ++$x){

View File

@ -145,7 +145,7 @@ class WorldManager{
foreach($world->getPlayers() as $player){
if($world === $this->defaultWorld or $this->defaultWorld === null){
$player->disconnect("Forced default world unload");
}elseif($this->defaultWorld instanceof World){
}else{
$player->teleport($this->defaultWorld->getSafeSpawn());
}
}

View File

@ -50,7 +50,10 @@ abstract class Biome{
public const MAX_BIOMES = 256;
/** @var Biome[]|\SplFixedArray */
/**
* @var Biome[]|\SplFixedArray
* @phpstan-var \SplFixedArray<Biome>
*/
private static $biomes;
/** @var int */

View File

@ -68,7 +68,10 @@ class Chunk{
/** @var bool */
protected $terrainPopulated = false;
/** @var \SplFixedArray|SubChunk[] */
/**
* @var \SplFixedArray|SubChunk[]
* @phpstan-var \SplFixedArray<SubChunk>
*/
protected $subChunks;
/** @var Tile[] */
@ -77,7 +80,10 @@ class Chunk{
/** @var Entity[] */
protected $entities = [];
/** @var \SplFixedArray|int[] */
/**
* @var \SplFixedArray|int[]
* @phpstan-var \SplFixedArray<int>
*/
protected $heightMap;
/** @var string */
@ -289,8 +295,8 @@ class Chunk{
* @return int New calculated heightmap value (0-256 inclusive)
*/
public function recalculateHeightMapColumn(int $x, int $z) : int{
$max = $this->getHighestBlockAt($x, $z);
for($y = $max; $y >= 0; --$y){
$y = $this->getHighestBlockAt($x, $z);
for(; $y >= 0; --$y){
if(BlockFactory::$lightFilter[$state = $this->getFullBlock($x, $y, $z)] > 1 or BlockFactory::$diffusesSkyLight[$state]){
break;
}
@ -312,9 +318,10 @@ class Chunk{
for($x = 0; $x < 16; ++$x){
for($z = 0; $z < 16; ++$z){
$y = ($this->subChunks->count() * 16) - 1;
$heightMap = $this->getHeightMap($x, $z);
for($y = ($this->subChunks->count() * 16) - 1; $y >= $heightMap; --$y){
for(; $y >= $heightMap; --$y){
$this->setBlockSkyLight($x, $y, $z, 15);
}
@ -486,17 +493,15 @@ class Chunk{
$this->dirtyFlags |= self::DIRTY_FLAG_ENTITIES;
$world->timings->syncChunkLoadEntitiesTimer->startTiming();
foreach($this->NBTentities as $nbt){
if($nbt instanceof CompoundTag){
try{
$entity = EntityFactory::createFromData($world, $nbt);
if(!($entity instanceof Entity)){
$world->getLogger()->warning("Chunk $this->x $this->z: Deleted unknown entity type " . $nbt->getString("id", $nbt->getString("identifier", "<unknown>", true), true));
continue;
}
}catch(\Exception $t){ //TODO: this shouldn't be here
$world->getLogger()->logException($t);
try{
$entity = EntityFactory::createFromData($world, $nbt);
if(!($entity instanceof Entity)){
$world->getLogger()->warning("Chunk $this->x $this->z: Deleted unknown entity type " . $nbt->getString("id", $nbt->getString("identifier", "<unknown>", true), true));
continue;
}
}catch(\Exception $t){ //TODO: this shouldn't be here
$world->getLogger()->logException($t);
continue;
}
}
@ -507,13 +512,11 @@ class Chunk{
$this->dirtyFlags |= self::DIRTY_FLAG_TILES;
$world->timings->syncChunkLoadTileEntitiesTimer->startTiming();
foreach($this->NBTtiles as $nbt){
if($nbt instanceof CompoundTag){
if(($tile = TileFactory::createFromData($world, $nbt)) !== null){
$world->addTile($tile);
}else{
$world->getLogger()->warning("Chunk $this->x $this->z: Deleted unknown tile entity type " . $nbt->getString("id", "<unknown>", true));
continue;
}
if(($tile = TileFactory::createFromData($world, $nbt)) !== null){
$world->addTile($tile);
}else{
$world->getLogger()->warning("Chunk $this->x $this->z: Deleted unknown tile entity type " . $nbt->getString("id", "<unknown>", true));
continue;
}
}
@ -597,6 +600,7 @@ class Chunk{
/**
* @return \SplFixedArray|SubChunk[]
* @phpstan-return \SplFixedArray<SubChunk>
*/
public function getSubChunks() : \SplFixedArray{
return $this->subChunks;

View File

@ -121,9 +121,9 @@ class Flat extends Generator{
protected function parsePreset() : void{
$preset = explode(";", $this->preset);
$blocks = (string) ($preset[1] ?? "");
$blocks = $preset[1] ?? "";
$this->biome = (int) ($preset[2] ?? 1);
$options = (string) ($preset[3] ?? "");
$options = $preset[3] ?? "";
$this->structure = self::parseLayers($blocks);
$this->floorLevel = count($this->structure);

View File

@ -105,48 +105,26 @@ class PopulationTask extends AsyncTask{
}
foreach($chunks as $c){
if($c !== null){
$manager->setChunk($c->getX(), $c->getZ(), $c);
if(!$c->isGenerated()){
$generator->generateChunk($c->getX(), $c->getZ());
$c = $manager->getChunk($c->getX(), $c->getZ());
$c->setGenerated();
}
$manager->setChunk($c->getX(), $c->getZ(), $c);
if(!$c->isGenerated()){
$generator->generateChunk($c->getX(), $c->getZ());
$c->setGenerated();
}
}
$generator->populateChunk($chunk->getX(), $chunk->getZ());
$chunk = $manager->getChunk($chunk->getX(), $chunk->getZ());
$chunk->recalculateHeightMap();
$chunk->populateSkyLight();
$chunk->setLightPopulated();
$chunk->setPopulated();
$this->chunk = FastChunkSerializer::serialize($chunk);
$manager->setChunk($chunk->getX(), $chunk->getZ(), null);
foreach($chunks as $i => $c){
if($c !== null){
$c = $chunks[$i] = $manager->getChunk($c->getX(), $c->getZ());
if(!$c->isDirty()){
$chunks[$i] = null;
}
}else{
//This way non-changed chunks are not set
$chunks[$i] = null;
}
$this->{"chunk$i"} = $c->isDirty() ? FastChunkSerializer::serialize($c) : null;
}
$manager->cleanChunks();
for($i = 0; $i < 9; ++$i){
if($i === 4){
continue;
}
$this->{"chunk$i"} = $chunks[$i] !== null ? FastChunkSerializer::serialize($chunks[$i]) : null;
}
}
public function onCompletion() : void{

View File

@ -34,7 +34,10 @@ abstract class BiomeSelector{
/** @var Simplex */
private $rainfall;
/** @var Biome[]|\SplFixedArray */
/**
* @var Biome[]|\SplFixedArray
* @phpstan-var \SplFixedArray<Biome>
*/
private $map = null;
public function __construct(Random $random){

View File

@ -203,6 +203,10 @@ abstract class Noise{
return $result;
}
/**
* @return \SplFixedArray|float[]
* @phpstan-return \SplFixedArray<float>
*/
public function getFastNoise1D(int $xSize, int $samplingRate, int $x, int $y, int $z) : \SplFixedArray{
if($samplingRate === 0){
throw new \InvalidArgumentException("samplingRate cannot be 0");
@ -227,6 +231,10 @@ abstract class Noise{
return $noiseArray;
}
/**
* @return \SplFixedArray|float[][]
* @phpstan-return \SplFixedArray<\SplFixedArray<float>>
*/
public function getFastNoise2D(int $xSize, int $zSize, int $samplingRate, int $x, int $y, int $z) : \SplFixedArray{
assert($samplingRate !== 0, new \InvalidArgumentException("samplingRate cannot be 0"));

View File

@ -72,22 +72,22 @@ class Ore{
$endY = (int) ($seedY + $size);
$endZ = (int) ($seedZ + $size);
for($x = $startX; $x <= $endX; ++$x){
$sizeX = ($x + 0.5 - $seedX) / $size;
for($xx = $startX; $xx <= $endX; ++$xx){
$sizeX = ($xx + 0.5 - $seedX) / $size;
$sizeX *= $sizeX;
if($sizeX < 1){
for($y = $startY; $y <= $endY; ++$y){
$sizeY = ($y + 0.5 - $seedY) / $size;
for($yy = $startY; $yy <= $endY; ++$yy){
$sizeY = ($yy + 0.5 - $seedY) / $size;
$sizeY *= $sizeY;
if($y > 0 and ($sizeX + $sizeY) < 1){
for($z = $startZ; $z <= $endZ; ++$z){
$sizeZ = ($z + 0.5 - $seedZ) / $size;
if($yy > 0 and ($sizeX + $sizeY) < 1){
for($zz = $startZ; $zz <= $endZ; ++$zz){
$sizeZ = ($zz + 0.5 - $seedZ) / $size;
$sizeZ *= $sizeZ;
if(($sizeX + $sizeY + $sizeZ) < 1 and $world->getBlockAt($x, $y, $z)->getId() === BlockLegacyIds::STONE){
$world->setBlockAt($x, $y, $z, $this->type->material);
if(($sizeX + $sizeY + $sizeZ) < 1 and $world->getBlockAt($xx, $yy, $zz)->getId() === BlockLegacyIds::STONE){
$world->setBlockAt($xx, $yy, $zz, $this->type->material);
}
}
}

View File

@ -46,12 +46,13 @@ class GroundCover extends Populator{
$diffY = 1;
}
for($y = 127; $y > 0; --$y){
if(!BlockFactory::fromFullBlock($chunk->getFullBlock($x, $y, $z))->isTransparent()){
$startY = 127;
for(; $startY > 0; --$startY){
if(!BlockFactory::fromFullBlock($chunk->getFullBlock($x, $startY, $z))->isTransparent()){
break;
}
}
$startY = min(127, $y + $diffY);
$startY = min(127, $startY + $diffY);
$endY = $startY - count($cover);
for($y = $startY; $y > $endY and $y >= 0; --$y){
$b = $cover[$startY - $y];

View File

@ -69,10 +69,10 @@ class TallGrass extends Populator{
for($y = 127; $y >= 0; --$y){
$b = $this->world->getBlockAt($x, $y, $z)->getId();
if($b !== BlockLegacyIds::AIR and $b !== BlockLegacyIds::LEAVES and $b !== BlockLegacyIds::LEAVES2 and $b !== BlockLegacyIds::SNOW_LAYER){
break;
return $y + 1;
}
}
return $y === 0 ? -1 : ++$y;
return -1;
}
}

View File

@ -70,15 +70,15 @@ class Tree extends Populator{
}
private function getHighestWorkableBlock(int $x, int $z) : int{
for($y = 127; $y > 0; --$y){
for($y = 127; $y >= 0; --$y){
$b = $this->world->getBlockAt($x, $y, $z)->getId();
if($b === BlockLegacyIds::DIRT or $b === BlockLegacyIds::GRASS){
break;
return $y + 1;
}elseif($b !== BlockLegacyIds::AIR and $b !== BlockLegacyIds::SNOW_LAYER){
return -1;
}
}
return ++$y;
return -1;
}
}

View File

@ -0,0 +1,3 @@
parameters:
ignoreErrors:
- "#^Method ReflectionMethod\\:\\:getClosure\\(\\) invoked with 0 parameters, 1 required\\.$#"

View File

@ -1,17 +1,10 @@
parameters:
ignoreErrors:
- "#^Call to function is_resource\\(\\) with resource will always evaluate to true\\.$#"
-
message: "#^Default value of the parameter \\#\\d+ \\$[A-Za-z\\d_]+ \\(\\-?\\d+\\) of method .+\\(\\) is incompatible with type float\\.$#"
path: ../../../src
-
message: "#^Cannot access an offset on Threaded\\.$#"
path: ../../../src
-
message: "#^Cannot assign new offset to Threaded\\.$#"
path: ../../../src
-
message: "#^Offset string does not exist on array\\(\\)\\.$#"
count: 3
@ -39,6 +32,12 @@ parameters:
count: 1
path: ../../../src/block/Liquid.php
-
#readline() may return false
message: "#^Strict comparison using \\!\\=\\= between string and false will always evaluate to true\\.$#"
count: 1
path: ../../../src/command/CommandReader.php
-
message: "#^Call to function assert\\(\\) with false and 'unknown hit type' will always evaluate to false\\.$#"
count: 1
@ -65,3 +64,9 @@ parameters:
message: "#^If condition is always false\\.$#"
count: 1
path: ../../../src/network/mcpe/protocol/types/entity/EntityMetadataCollection.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\\.$#"
count: 1
path: ../../../tests/phpunit/block/BlockTest.php

View File

@ -0,0 +1,6 @@
parameters:
ignoreErrors:
-
message: "#^Parameter \\#1 \\$class of static method pocketmine\\\\world\\\\format\\\\io\\\\WorldProviderManager\\:\\:addProvider\\(\\) expects class\\-string\\<pocketmine\\\\world\\\\format\\\\io\\\\WorldProvider\\>, string given\\.$#"
count: 2
path: ../../phpunit/world/format/io/LevelProviderManagerTest.php

View File

@ -1,13 +1,50 @@
parameters:
ignoreErrors:
-
message: "#^Instanceof between pocketmine\\\\event\\\\RegisteredListener and pocketmine\\\\event\\\\RegisteredListener will always evaluate to true\\.$#"
count: 1
path: ../../../src/event/HandlerList.php
-
#jsonDeserialize(), not currently validated
message: "#^Casting to int something that's already int\\.$#"
count: 3
path: ../../../src/item/Item.php
-
#commands plugin.yml not currently validated, can't be sure
message: "#^Call to function is_array\\(\\) with array\\<string, mixed\\> will always evaluate to true\\.$#"
count: 1
path: ../../../src/plugin/PluginBase.php
-
#::add() / ::remove() thread parameter
message: "#^If condition is always true\\.$#"
count: 2
path: ../../../src/thread/ThreadManager.php
-
message: "#^Instanceof between pocketmine\\\\thread\\\\Worker and pocketmine\\\\thread\\\\Worker will always evaluate to true\\.$#"
count: 2
path: ../../../src/thread/ThreadManager.php
-
#->sendBlocks() blocks parameter
message: "#^Else branch is unreachable because ternary operator condition is always true\\.$#"
count: 1
path: ../../../src/world/World.php
-
message: "#^Instanceof between pocketmine\\\\math\\\\Vector3 and pocketmine\\\\math\\\\Vector3 will always evaluate to true\\.$#"
count: 1
path: ../../../src/world/World.php
-
message: "#^Call to function is_object\\(\\) with \\*NEVER\\* will always evaluate to true\\.$#"
count: 1
path: ../../../src/world/World.php
-
message: "#^Call to function assert\\(\\) with bool will always evaluate to true\\.$#"
count: 1
path: ../../../src/world/World.php

View File

@ -64,7 +64,7 @@ class BlockTest extends TestCase{
}
}
self::assertTrue(false, "Can't test registering new blocks because no unused spaces left");
throw new \RuntimeException("Can't test registering new blocks because no unused spaces left");
}
/**
@ -97,7 +97,8 @@ class BlockTest extends TestCase{
}
/**
* @return array
* @return int[][]
* @phpstan-return list<array{int,int}>
*/
public function blockGetProvider() : array{
return [

View File

@ -29,7 +29,7 @@ use pocketmine\item\ItemIds;
class BaseInventoryTest extends TestCase{
public static function setUpBeforeClass(){
public static function setUpBeforeClass() : void{
ItemFactory::init();
}

View File

@ -42,6 +42,10 @@ class ItemFactoryTest extends TestCase{
}
}
/**
* @return mixed[][]
* @phpstan-return list<array{string,int,int}>
*/
public function itemFromStringProvider() : array{
return [
["dye:4", ItemIds::DYE, 4],

View File

@ -33,6 +33,10 @@ class StupidJsonDecodeTest extends TestCase{
$this->stupidJsonDecodeFunc = (new \ReflectionMethod(InGamePacketHandler::class, 'stupid_json_decode'))->getClosure();
}
/**
* @return mixed[][]
* @phpstan-return list<array{string,mixed}>
*/
public function stupidJsonDecodeProvider() : array{
return [
["[\n \"a\",\"b,c,d,e\\\" \",,0,1,2, false, 0.001]", ['a', 'b,c,d,e" ', '', 0, 1, 2, false, 0.001]],
@ -55,7 +59,7 @@ class StupidJsonDecodeTest extends TestCase{
*
* @throws \ReflectionException
*/
public function testStupidJsonDecode(string $brokenJson, $expect){
public function testStupidJsonDecode(string $brokenJson, $expect) : void{
$decoded = ($this->stupidJsonDecodeFunc)($brokenJson, true);
self::assertEquals($expect, $decoded);
}

View File

@ -28,7 +28,8 @@ use PHPUnit\Framework\TestCase;
class ConfigTest extends TestCase{
/**
* @return \Generator
* @return \Generator|mixed[][]
* @phpstan-return \Generator<int, array{string, mixed[]}, void, void>
*/
public function fixYamlIndexesProvider() : \Generator{
yield ["x: 1\ny: 2\nz: 3\n", [
@ -60,8 +61,8 @@ class ConfigTest extends TestCase{
/**
* @dataProvider fixYamlIndexesProvider
*
* @param string $test
* @param array $expected
* @param string $test
* @param mixed[] $expected
*/
public function testFixYamlIndexes(string $test, array $expected) : void{
$fixed = Config::fixYAMLIndexes($test);

View File

@ -29,7 +29,7 @@ use function defined;
class UtilsTest extends TestCase{
public function setUp(){
public function setUp() : void{
if(!defined('pocketmine\PATH')){
define('pocketmine\PATH', 'dummy');
}
@ -38,6 +38,10 @@ class UtilsTest extends TestCase{
}
}
/**
* @return string[][]
* @phpstan-return list<array{string}>
*/
public function parseDocCommentNewlineProvider() : array{
return [
["\t/**\r\n\t * @param PlayerJoinEvent \$event\r\n\t * @priority HIGHEST\r\n\t * @notHandler\r\n\t */"],
@ -61,6 +65,6 @@ class UtilsTest extends TestCase{
public function testNamespacedNiceClosureName() : void{
//be careful with this test. The closure has to be declared on the same line as the assertion.
self::assertSame('closure@' . Filesystem::cleanPath(__FILE__) . '#L' . __LINE__, Utils::getNiceClosureName(function(){}));
self::assertSame('closure@' . Filesystem::cleanPath(__FILE__) . '#L' . __LINE__, Utils::getNiceClosureName(function() : void{}));
}
}

View File

@ -38,7 +38,7 @@ class RegionLoaderTest extends TestCase{
/** @var RegionLoader */
private $region;
public function setUp(){
public function setUp() : void{
$this->regionPath = sys_get_temp_dir() . '/test.testregion';
if(file_exists($this->regionPath)){
unlink($this->regionPath);
@ -47,7 +47,7 @@ class RegionLoaderTest extends TestCase{
$this->region->open();
}
public function tearDown(){
public function tearDown() : void{
$this->region->close();
if(file_exists($this->regionPath)){
unlink($this->regionPath);
@ -69,6 +69,10 @@ class RegionLoaderTest extends TestCase{
self::assertSame($data, $r->readChunk(0, 0));
}
/**
* @return \Generator|int[][]
* @phpstan-return \Generator<int, array{int,int}, void, void>
*/
public function outOfBoundsCoordsProvider() : \Generator{
yield [-1, -1];
yield [32, 32];