Compare commits

..

45 Commits

Author SHA1 Message Date
e8b6b56330 Release 3.15.4 2020-11-10 16:48:18 +00:00
c368ebb5e7 InventoryTransaction: beware of conflicting slot change actions with the same origin/target
these types of chains would never normally occur, but they've been seen in the wild. Attempting to resolve such chains has exponentially increasing complexity.
2020-11-10 16:45:20 +00:00
fa920aa868 Misplaced the changelog AGAIN 2020-11-08 19:25:55 +00:00
a421d32273 3.15.4 is next 2020-11-08 14:48:31 +00:00
6c21c23444 Release 3.15.3 2020-11-08 14:48:31 +00:00
55e0d9c520 Properly time chunk loading and chunk sending on timings reports, closes #3895 2020-11-08 14:30:12 +00:00
37ee3f2775 Player: fixed orderChunks performance issue on newly-generated maps
every time a chunk passed through Level->generateChunkCallback(), it fired onChunkChanged() for chunk listeners, which in turn caused players to rerun chunk orders even though the target chunk had not been sent yet anyway.
2020-11-05 16:17:39 +00:00
bfdcc12e81 phpstan 0.12.54 2020-11-05 14:49:00 +00:00
b2299e08e0 phpstan 0.12.53 2020-11-03 15:00:56 +00:00
d7741050c5 Updated composer dependencies 2020-11-03 14:54:50 +00:00
6cff08cd65 Chunk: fixed hasChanged being set on fastDeserialize() chunks (caused by 2bb497b716)
this caused some performance issues and silent bugs with the generator, notably that the generator would always think all chunks had been changed, causing them to be re-set back into the world 9 times.
2020-11-01 15:50:21 +00:00
fec42f16ba Level: properly define type of generator field 2020-11-01 14:36:05 +00:00
deb0cee8a0 BaseInventory::canAddItem(): consider item max stack size (#3881)
this fixes addItem() failing when canAddItem() reported that an item can be added.
2020-11-01 13:49:13 +00:00
c0dafe7872 Explosion: remove dead code
this was needed for the old ExplodePacket, which was removed a few versions back.
2020-10-29 13:32:56 +00:00
340881d590 remove superfluous newline 2020-10-26 15:59:57 +00:00
e2e960e43d tests: add missing function imports 2020-10-26 15:59:42 +00:00
500fd2d842 tests: strip useless phpdoc 2020-10-26 15:59:17 +00:00
0b550b346b imports cleanup 2020-10-26 15:43:25 +00:00
1424114cf2 Clean phpstan baselines
some of these are dead, others are FPs fixed by newer PHPStan versions.
2020-10-24 17:22:49 +01:00
a8980a0f67 phpstan 0.12.51 2020-10-24 17:10:31 +01:00
69aa7c5ac1 Support for Composer v2 (#3880) 2020-10-24 16:42:38 +01:00
11b74868ee CraftingTransaction: remove impossible condition
this is never hit thanks to the logic flow above - recipeItems is never empty.
2020-10-24 11:22:02 +01:00
9a53de0903 Utils: explode() never returns an empty array 2020-10-24 11:19:37 +01:00
0f8101d4a6 McRegion: Ignore files which don't have a valid file extension
previously a file with a 4-letter name ending in 'mca' in the region folder of a PMAnvil world would cause the world format to be unrecognized. This happens because strrpos() returns false when the substring isn't found, which gets coerced to 0 when used in addition.
2020-10-24 11:15:07 +01:00
55ecac4c80 Fixed always-true condition in world loading
this has a couple of side effects which need to be explored.
- first of all, this bug prevented generateLevel() from filling in the preset from server.properties. With this fix, worlds which don't have any extra generator settings will start to be generated using server.properties settings, which is almost certainly not expected behaviour.
- preset can now be specified separately from generator in pocketmine.yml, which is nicer for users.
2020-10-24 11:10:35 +01:00
2a1d1e90a2 php-cs-fixer nits 2020-10-21 16:44:57 +01:00
4444a79468 Bump phpunit/phpunit from 9.4.1 to 9.4.2 (#3875) 2020-10-20 09:06:46 +00:00
4cbeee3ab8 Bump phpstan/phpstan from 0.12.49 to 0.12.50 (#3874) 2020-10-17 13:44:43 +00:00
a251960c1c AsyncPool: expose workerUsage to the API
this allows plugins (and maybe later on the core) to detect async worker overload and warn the user about potential performance issues.
I planned to implement such detection in the core directly, but it turned out to be a bit more complex than I anticipated. At the least, this API might be useful to someone else.
2020-10-16 21:20:49 +01:00
52f734799e Human: do not modify totalXp unless setting XP succeeds 2020-10-16 20:43:03 +01:00
42171f6e06 Human: beware negative values in addXp() 2020-10-16 20:42:13 +01:00
1fe4fdc67c PluginDescription: fixed some very old refactoring errors 2020-10-15 13:55:40 +01:00
af4f30d1c8 Bump phpstan/phpstan from 0.12.48 to 0.12.49 (#3873) 2020-10-13 16:31:25 +00:00
3e2926441d PluginDescription: make sure that extensions constraints are actually strings 2020-10-13 17:21:10 +01:00
0b33762be0 PluginDescription: fixed type of extensions (reported by phpstan 0.12.49) 2020-10-13 17:21:10 +01:00
e6f89213dc Entity: properly account for upwards motion when calculating fall distance (#3867)
Previously, upwards movement wouldn't be considered, but downwards would, so if an entity bobbed up and down in the air for a while (e.g. while being comboed in PvP), the downwards distance would accumulate and deal a large amount of fall damage on touchdown.
This commit changes fall distance measurement to correctly account for upwards movement.

A better way of measuring fall distance would simply be to record the highest Y coordinate reached while in the air, and then measure the distance between that and the point of contact when landing. This would also remove the need to constantly update the fallDistance field. However, this would involve a BC break and will therefore have to wait until PM4.
2020-10-13 14:16:09 +01:00
f8d249b240 Isolate and always show IP details on install (#3870)
* Isolate and always show IP details on install

* camelCase
2020-10-13 14:11:28 +01:00
b39afa20d1 Bump phpunit/phpunit from 9.4.0 to 9.4.1 (#3872) 2020-10-13 13:09:56 +00:00
7027a9b972 camelCase 2020-10-12 08:25:34 -04:00
b02f3f4090 Isolate and always show IP details on install 2020-10-11 18:57:30 -04:00
8564912149 phpstan: define LEVELDB_ZLIB_RAW_COMPRESSION if it doesn't exist (for phpstan)
this improves the analysis quality by informing phpstan of the type of whatever should be there.
2020-10-11 23:01:21 +01:00
873535f719 Timezone: explicitly check result of getURL()
phpstan-strict-rules should report this, but it doesn't ...
2020-10-09 17:23:22 +01:00
78f4fcf6ab StatusCommand: removed "Maximum memory (system)"
it's not clear what this was actually supposed to represent, but it actually reports VmSize, which is already reported by "Total virtual memory". This line confuses users and is misleading.
2020-10-08 22:58:37 +01:00
90b749c260 net: reduce default compression level to 6
On larger packets, this worsens compression ratio by 1-2%, but reduces CPU load due to compression by 15-20%. Higher levels than 6 are far more expensive for diminishing returns.
Level 5 produces a further 25-30% CPU reduction, but increases bandwidth usage by 20-25%, so 6 is the sweet spot.
2020-10-08 16:51:10 +01:00
d5398b2781 3.15.3 is next 2020-10-06 13:33:42 +01:00
47 changed files with 428 additions and 325 deletions

View File

@ -24,6 +24,7 @@ declare(strict_types=1);
namespace pocketmine\build\make_release;
use pocketmine\utils\VersionString;
use function defined;
use function dirname;
use function fgets;
use function file_get_contents;
@ -37,7 +38,6 @@ use const STDIN;
require_once dirname(__DIR__) . '/vendor/autoload.php';
function replaceVersion(string $versionInfoPath, string $newVersion, bool $isDev) : void{
$versionInfo = file_get_contents($versionInfoPath);
$versionInfo = preg_replace(

View File

@ -32,3 +32,23 @@ Plugin developers should **only** update their required API to this version if y
- Fixed issues with preloading `SubChunk`.
- `/gc` and automatic garbage collection will now release unused heap blocks back to the OS. Previously, the PHP process might hold onto these blocks indefinitely even when not used, causing elevated real memory usage.
- Added some documentation to `FurnaceBurnEvent`.
# 3.15.3
- Fixed fall damage accumulation over continuous knockbacks (e.g. combo attacks in PvP).
- Fixed a bug in `Human->addXp()` that would cause a crash when saving player data.
- `Human->addXp()` will no longer modify the target's total XP if `PlayerExperienceChangeEvent` was cancelled.
- `AsyncPool->getTaskQueueSizes()` has been added to allow external detection of async pool overload. This is planned to be implemented as a core feature in the future, but it hasn't been done yet.
- `BaseInventory->canAddItem()` behaviour now matches `addItem()` by considering the max stack size of the given item.
- Fixed a bug in generator options handling for worlds loaded via `pocketmine.yml`. This fix has the following side effects:
- It's now possible to provide generator options as an `options` key when loading a world via `pocketmine.yml`.
- If generator options are not provided, the options from `server.properties` will be used, instead of using an empty preset. (It's not clear whether this is desired behaviour, but it was clearly intended, since there is code to do this which was broken until this release. As such, this behaviour is subject to change in the future.)
- Fixed a bug in region-based world loading where some files without filename extensions and names containing a region filename extension (e.g a file named `amca` in a McRegion world) would cause the world not to load. These files are now ignored.
- Default network compression level has been lowered to 6, due to level 7 being 25% more expensive for only a marginal improvement in bandwidth.
- Fixed a performance issue with chunk requesting when players trigger chunk generation on first join.
- Setup wizard will now always show IP information, even if the user chose to skip the setup wizard when prompted. (This doesn't affect `--no-wizard` in any way.)
- `Maximum memory (system)` is no longer reported in `/status` due to having a misleading output (it was the same as the current memory usage).
- The `Player Chunk Send` timer on timings reports now actually reports measurements of chunk sending, not chunk loading.
- A new parent timer `World Load` has been added to timings reports, which aggregates timings from `syncChunkLoad` and subtimings from all worlds.
# 3.15.4
- Fixed a bug in the inventory transaction system that caused the server to freeze under some circumstances.

View File

@ -35,10 +35,10 @@
"pocketmine/log-pthreads": "^0.1.0",
"pocketmine/callback-validator": "^1.0.2",
"adhocore/json-comment": "^0.1.0",
"ocramius/package-versions": "^1.5"
"composer-runtime-api": "^2.0"
},
"require-dev": {
"phpstan/phpstan": "0.12.48",
"phpstan/phpstan": "0.12.54",
"phpstan/phpstan-phpunit": "^0.12.6",
"phpstan/phpstan-strict-rules": "^0.12.2",
"phpunit/phpunit": "^9.2"

443
composer.lock generated

File diff suppressed because it is too large Load Diff

View File

@ -2,7 +2,6 @@ includes:
- tests/phpstan/configs/actual-problems.neon
- tests/phpstan/configs/check-explicit-mixed-baseline.neon
- tests/phpstan/configs/com-dotnet-magic.neon
- tests/phpstan/configs/custom-leveldb.neon
- tests/phpstan/configs/gc-hacks.neon
- tests/phpstan/configs/l7-baseline.neon
- tests/phpstan/configs/l8-baseline.neon

View File

@ -23,7 +23,7 @@ declare(strict_types=1);
namespace pocketmine;
use PackageVersions\Versions;
use Composer\InstalledVersions;
use pocketmine\network\mcpe\protocol\ProtocolInfo;
use pocketmine\plugin\PluginBase;
use pocketmine\plugin\PluginLoadOrder;
@ -54,6 +54,7 @@ use function php_uname;
use function phpinfo;
use function phpversion;
use function preg_replace;
use function sprintf;
use function str_split;
use function strpos;
use function substr;
@ -338,6 +339,15 @@ class CrashDump{
private function generalData() : void{
$version = new VersionString(\pocketmine\BASE_VERSION, \pocketmine\IS_DEVELOPMENT_BUILD, \pocketmine\BUILD_NUMBER);
$composerLibraries = [];
foreach(InstalledVersions::getInstalledPackages() as $package){
$composerLibraries[$package] = sprintf(
"%s@%s",
InstalledVersions::getPrettyVersion($package) ?? "unknown",
InstalledVersions::getReference($package) ?? "unknown"
);
}
$this->data["general"] = [];
$this->data["general"]["name"] = $this->server->getName();
$this->data["general"]["base_version"] = \pocketmine\BASE_VERSION;
@ -350,7 +360,7 @@ class CrashDump{
$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->data["general"]["composer_libraries"] = $composerLibraries;
$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"));
@ -358,7 +368,7 @@ class CrashDump{
$this->addLine("Zend version: " . zend_version());
$this->addLine("OS : " . PHP_OS . ", " . Utils::getOS());
$this->addLine("Composer libraries: ");
foreach(Versions::VERSIONS as $library => $libraryVersion){
foreach($composerLibraries as $library => $libraryVersion){
$this->addLine("- $library $libraryVersion");
}
}

View File

@ -4122,7 +4122,8 @@ class Player extends Human implements CommandSender, ChunkLoader, IPlayer{
}
public function onChunkChanged(Chunk $chunk){
if(isset($this->usedChunks[$hash = Level::chunkHash($chunk->getX(), $chunk->getZ())])){
$hasSent = $this->usedChunks[$hash = Level::chunkHash($chunk->getX(), $chunk->getZ())] ?? false;
if($hasSent){
$this->usedChunks[$hash] = false;
$this->nextChunkOrderRun = 0;
}

View File

@ -1400,10 +1400,10 @@ class Server{
Network::$BATCH_THRESHOLD = -1;
}
$this->networkCompressionLevel = (int) $this->getProperty("network.compression-level", 7);
$this->networkCompressionLevel = (int) $this->getProperty("network.compression-level", 6);
if($this->networkCompressionLevel < 1 or $this->networkCompressionLevel > 9){
$this->logger->warning("Invalid network compression level $this->networkCompressionLevel set, setting to default 7");
$this->networkCompressionLevel = 7;
$this->logger->warning("Invalid network compression level $this->networkCompressionLevel set, setting to default 6");
$this->networkCompressionLevel = 6;
}
$this->networkCompressionAsync = (bool) $this->getProperty("network.async-compression", true);
@ -1543,7 +1543,7 @@ class Server{
if(isset($options["generator"])){
$generatorOptions = explode(":", $options["generator"]);
$generator = GeneratorManager::getGenerator(array_shift($generatorOptions));
if(count($options) > 0){
if(count($generatorOptions) > 0){
$options["preset"] = implode(":", $generatorOptions);
}
}else{

View File

@ -33,6 +33,6 @@ if(defined('pocketmine\_VERSION_INFO_INCLUDED')){
const _VERSION_INFO_INCLUDED = true;
const NAME = "PocketMine-MP";
const BASE_VERSION = "3.15.2";
const BASE_VERSION = "3.15.4";
const IS_DEVELOPMENT_BUILD = false;
const BUILD_NUMBER = 0;

View File

@ -100,7 +100,6 @@ class StatusCommand extends VanillaCommand{
$sender->sendMessage(TextFormat::GOLD . "Total memory: " . TextFormat::RED . number_format(round(($mUsage[1] / 1024) / 1024, 2), 2) . " MB.");
$sender->sendMessage(TextFormat::GOLD . "Total virtual memory: " . TextFormat::RED . number_format(round(($mUsage[2] / 1024) / 1024, 2), 2) . " MB.");
$sender->sendMessage(TextFormat::GOLD . "Heap memory: " . TextFormat::RED . number_format(round(($rUsage[0] / 1024) / 1024, 2), 2) . " MB.");
$sender->sendMessage(TextFormat::GOLD . "Maximum memory (system): " . TextFormat::RED . number_format(round(($mUsage[2] / 1024) / 1024, 2), 2) . " MB.");
if($server->getProperty("memory.global-limit") > 0){
$sender->sendMessage(TextFormat::GOLD . "Maximum memory (manager): " . TextFormat::RED . number_format(round($server->getProperty("memory.global-limit"), 2), 2) . " MB.");

View File

@ -1451,8 +1451,14 @@ abstract class Entity extends Location implements Metadatable, EntityIds{
$this->fall($this->fallDistance);
$this->resetFallDistance();
}
}elseif($distanceThisTick < 0){
}elseif($distanceThisTick < $this->fallDistance){
//we've fallen some distance (distanceThisTick is negative)
//or we ascended back towards where fall distance was measured from initially (distanceThisTick is positive but less than existing fallDistance)
$this->fallDistance -= $distanceThisTick;
}else{
//we ascended past the apex where fall distance was originally being measured from
//reset it so it will be measured starting from the new, higher position
$this->fallDistance = 0;
}
}

View File

@ -400,12 +400,14 @@ class Human extends Creature implements ProjectileSource, InventoryHolder{
* @param bool $playSound Whether to play level-up and XP gained sounds.
*/
public function addXp(int $amount, bool $playSound = true) : bool{
$this->totalXp += $amount;
$oldLevel = $this->getXpLevel();
$oldTotal = $this->getCurrentTotalXp();
if($this->setCurrentTotalXp($oldTotal + $amount)){
if($amount > 0){
$this->totalXp += $amount;
}
if($playSound){
$newLevel = $this->getXpLevel();
if((int) ($newLevel / 5) > (int) ($oldLevel / 5)){

View File

@ -25,6 +25,7 @@ namespace pocketmine\entity\utils;
use pocketmine\math\Math;
use pocketmine\utils\AssumptionFailedError;
use function count;
use function max;
abstract class ExperienceUtils{

View File

@ -252,11 +252,11 @@ abstract class BaseInventory implements Inventory{
for($i = 0, $size = $this->getSize(); $i < $size; ++$i){
$slot = $this->getItem($i);
if($item->equals($slot)){
if(($diff = $slot->getMaxStackSize() - $slot->getCount()) > 0){
if(($diff = min($slot->getMaxStackSize(), $item->getMaxStackSize()) - $slot->getCount()) > 0){
$count -= $diff;
}
}elseif($slot->isNull()){
$count -= $this->getMaxStackSize();
$count -= min($this->getMaxStackSize(), $item->getMaxStackSize());
}
if($count <= 0){

View File

@ -108,9 +108,6 @@ class CraftingTransaction extends InventoryTransaction{
}
}
if($iterations < 1){
throw new TransactionValidationException("Tried to craft zero times");
}
if(count($txItems) > 0){
//all items should be destroyed in this process
throw new TransactionValidationException("Expected 0 ingredients left over, have " . count($txItems));

View File

@ -230,21 +230,34 @@ class InventoryTransaction{
protected function findResultItem(Item $needOrigin, array $possibleActions) : ?Item{
assert(count($possibleActions) > 0);
$candidate = null;
$newList = $possibleActions;
foreach($possibleActions as $i => $action){
if($action->getSourceItem()->equalsExact($needOrigin)){
$newList = $possibleActions;
if($candidate !== null){
/*
* we found multiple possible actions that match the origin action
* this means that there are multiple ways that this chain could play out
* if we cared so much about this, we could build all the possible chains in parallel and see which
* variation managed to complete the chain, but this has an extremely high complexity which is not
* worth the trouble for this scenario (we don't usually expect to see chains longer than a couple
* of actions in here anyway), and might still result in multiple possible results.
*/
return null;
}
$candidate = $action;
unset($newList[$i]);
if(count($newList) === 0){
return $action->getTargetItem();
}
$result = $this->findResultItem($action->getTargetItem(), $newList);
if($result !== null){
return $result;
}
}
}
if($candidate === null){
//chaining is not possible with this origin, none of the actions are valid
return null;
}
return null;
if(count($newList) === 0){
return $candidate->getTargetItem();
}
return $this->findResultItem($candidate->getTargetItem(), $newList);
}
/**

View File

@ -154,7 +154,6 @@ class Explosion{
* and creating sounds and particles.
*/
public function explodeB() : bool{
$send = [];
$updateBlocks = [];
$source = (new Vector3($this->source->x, $this->source->y, $this->source->z))->floor();
@ -254,7 +253,6 @@ class Explosion{
$updateBlocks[$index] = true;
}
}
$send[] = new Vector3($block->x - $source->x, $block->y - $source->y, $block->z - $source->z);
}
$this->level->addParticle(new HugeExplodeSeedParticle($source));

View File

@ -53,7 +53,6 @@ use pocketmine\level\format\io\ChunkRequestTask;
use pocketmine\level\format\io\exception\CorruptedChunkException;
use pocketmine\level\format\io\exception\UnsupportedChunkFormatException;
use pocketmine\level\format\io\LevelProvider;
use pocketmine\level\generator\Generator;
use pocketmine\level\generator\GeneratorManager;
use pocketmine\level\generator\GeneratorRegisterTask;
use pocketmine\level\generator\GeneratorUnregisterTask;
@ -289,7 +288,10 @@ class Level implements ChunkManager, Metadatable{
/** @var bool */
private $doingTick = false;
/** @var string|Generator */
/**
* @var string
* @phpstan-var class-string<\pocketmine\level\generator\Generator>
*/
private $generator;
/** @var bool */

View File

@ -80,15 +80,14 @@ class LevelTimings{
$this->entityTick = new TimingsHandler("** " . $name . "entityTick");
$this->tileEntityTick = new TimingsHandler("** " . $name . "tileEntityTick");
$this->syncChunkSendTimer = new TimingsHandler("** " . $name . "syncChunkSend");
$this->syncChunkSendPrepareTimer = new TimingsHandler("** " . $name . "syncChunkSendPrepare");
Timings::init(); //make sure the timers we want are available
$this->syncChunkSendTimer = new TimingsHandler("** " . $name . "syncChunkSend", Timings::$playerChunkSendTimer);
$this->syncChunkSendPrepareTimer = new TimingsHandler("** " . $name . "syncChunkSendPrepare", Timings::$playerChunkSendTimer);
$this->syncChunkLoadTimer = new TimingsHandler("** " . $name . "syncChunkLoad");
$this->syncChunkLoadTimer = new TimingsHandler("** " . $name . "syncChunkLoad", Timings::$worldLoadTimer);
$this->syncChunkLoadDataTimer = new TimingsHandler("** " . $name . "syncChunkLoad - Data");
$this->syncChunkLoadEntitiesTimer = new TimingsHandler("** " . $name . "syncChunkLoad - Entities");
$this->syncChunkLoadTileEntitiesTimer = new TimingsHandler("** " . $name . "syncChunkLoad - TileEntities");
Timings::init(); //make sure the timer we want is available
$this->syncChunkSaveTimer = new TimingsHandler("** " . $name . "syncChunkSave", Timings::$worldSaveTimer);
$this->doTick = new TimingsHandler($name . "doTick");

View File

@ -929,6 +929,7 @@ class Chunk{
$chunk->setGenerated($terrainGenerated);
$chunk->setPopulated($terrainPopulated);
$chunk->setLightPopulated($lightPopulated);
$chunk->setChanged(false);
return $chunk;
}

View File

@ -245,11 +245,13 @@ class McRegion extends BaseLevelProvider{
if($isValid){
$files = array_filter(scandir($path . "/region/", SCANDIR_SORT_NONE), function(string $file) : bool{
return substr($file, strrpos($file, ".") + 1, 2) === "mc"; //region file
$extPos = strrpos($file, ".");
return $extPos !== false && substr($file, $extPos + 1, 2) === "mc"; //region file
});
foreach($files as $f){
if(substr($f, strrpos($f, ".") + 1) !== static::REGION_FILE_EXTENSION){
$extPos = strrpos($f, ".");
if($extPos !== false && substr($f, $extPos + 1) !== static::REGION_FILE_EXTENSION){
$isValid = false;
break;
}

View File

@ -35,7 +35,10 @@ use function unserialize;
class GeneratorRegisterTask extends AsyncTask{
/** @var string */
/**
* @var string
* @phpstan-var class-string<Generator>
*/
public $generatorClass;
/** @var string */
public $settings;
@ -48,6 +51,7 @@ class GeneratorRegisterTask extends AsyncTask{
/**
* @param mixed[] $generatorSettings
* @phpstan-param class-string<Generator> $generatorClass
* @phpstan-param array<string, mixed> $generatorSettings
*/
public function __construct(Level $level, string $generatorClass, array $generatorSettings = []){

View File

@ -58,7 +58,7 @@ class PluginDescription{
private $compatibleOperatingSystems = [];
/**
* @var string[][]
* @phpstan-var array<string, list<mixed>>
* @phpstan-var array<string, list<string>>
*/
private $extensions = [];
/** @var string[] */
@ -104,13 +104,13 @@ class PluginDescription{
$this->name = $plugin["name"];
if(preg_match('/^[A-Za-z0-9 _.-]+$/', $this->name) === 0){
throw new PluginException("Invalid PluginDescription name");
throw new PluginException("Invalid Plugin name");
}
$this->name = str_replace(" ", "_", $this->name);
$this->version = (string) $plugin["version"];
$this->main = $plugin["main"];
if(stripos($this->main, "pocketmine\\") === 0){
throw new PluginException("Invalid PluginDescription main, cannot start within the PocketMine namespace");
throw new PluginException("Invalid Plugin main, cannot start within the PocketMine namespace");
}
$this->api = array_map("\strval", (array) ($plugin["api"] ?? []));
@ -132,7 +132,7 @@ class PluginDescription{
$k = $v;
$v = "*";
}
$this->extensions[$k] = is_array($v) ? $v : [$v];
$this->extensions[$k] = array_map('strval', is_array($v) ? $v : [$v]);
}
}
@ -149,7 +149,7 @@ class PluginDescription{
if(isset($plugin["load"])){
$order = mb_strtoupper($plugin["load"]);
if(!defined(PluginLoadOrder::class . "::" . $order)){
throw new PluginException("Invalid PluginDescription load");
throw new PluginException("Invalid Plugin load");
}else{
$this->order = constant(PluginLoadOrder::class . "::" . $order);
}

View File

@ -84,7 +84,7 @@ network:
#Set to 0 to compress everything, -1 to disable.
batch-threshold: 256
#Compression level used when sending batched packets. Higher = more CPU, less bandwidth usage
compression-level: 7
compression-level: 6
#Use AsyncTasks for compression. Adds half/one tick delay, less CPU load on main thread
async-compression: false
#Experimental, only for Windows. Tries to use UPnP to automatically port forward

View File

@ -329,6 +329,16 @@ class AsyncPool{
$this->collectWorkers();
}
/**
* Returns an array of worker ID => task queue size
*
* @return int[]
* @phpstan-return array<int, int>
*/
public function getTaskQueueSizes() : array{
return $this->workerUsage;
}
public function shutdownUnusedWorkers() : int{
$ret = 0;
$time = time();

View File

@ -59,6 +59,8 @@ abstract class Timings{
/** @var TimingsHandler */
public static $serverCommandTimer;
/** @var TimingsHandler */
public static $worldLoadTimer;
/** @var TimingsHandler */
public static $worldSaveTimer;
/** @var TimingsHandler */
public static $populationTimer;
@ -126,6 +128,7 @@ abstract class Timings{
self::$connectionTimer = new TimingsHandler("Connection Handler");
self::$schedulerTimer = new TimingsHandler("Scheduler");
self::$serverCommandTimer = new TimingsHandler("Server Command");
self::$worldLoadTimer = new TimingsHandler("World Load");
self::$worldSaveTimer = new TimingsHandler("World Save");
self::$populationTimer = new TimingsHandler("World Population");
self::$generationCallbackTimer = new TimingsHandler("World Generation Callback");

View File

@ -88,7 +88,7 @@ abstract class Timezone{
break;
}
if($response = Internet::getURL("http://ip-api.com/json") //If system timezone detection fails or timezone is an invalid value.
if(($response = Internet::getURL("http://ip-api.com/json")) !== false //If system timezone detection fails or timezone is an invalid value.
and $ip_geolocation_data = json_decode($response, true)
and $ip_geolocation_data['status'] !== 'fail'
and date_default_timezone_set($ip_geolocation_data['timezone'])

View File

@ -527,7 +527,7 @@ class Utils{
$ret = explode("\n", $contents);
ob_end_clean();
if(count($ret) >= 1 and preg_match('/^.* refcount\\(([0-9]+)\\)\\{$/', trim($ret[0]), $m) > 0){
if(preg_match('/^.* refcount\\(([0-9]+)\\)\\{$/', trim($ret[0]), $m) > 0){
return ((int) $m[1]) - ($includeCurrent ? 3 : 4); //$value + zval call + extra call
}
return -1;

View File

@ -92,6 +92,7 @@ class SetupWizard{
$config->save();
if(strtolower($this->getInput($this->lang->get("skip_installer"), "n", "y/N")) === "y"){
$this->printIpDetails();
return true;
}
@ -101,6 +102,7 @@ class SetupWizard{
$this->generateUserFiles();
$this->networkFunctions();
$this->printIpDetails();
$this->endWizard();
@ -218,7 +220,9 @@ LICENSE;
}
$config->save();
}
private function printIpDetails() : void{
$this->message($this->lang->get("ip_get"));
$externalIP = Internet::getIP();

View File

@ -23,6 +23,11 @@ declare(strict_types=1);
define('pocketmine\_PHPSTAN_ANALYSIS', true);
if(!defined('LEVELDB_ZLIB_RAW_COMPRESSION')){
//leveldb might not be loaded
define('LEVELDB_ZLIB_RAW_COMPRESSION', 4);
}
//TODO: these need to be defined properly or removed
define('pocketmine\COMPOSER_AUTOLOADER_PATH', dirname(__DIR__, 2) . '/vendor/autoload.php');
define('pocketmine\DATA', '');

View File

@ -530,21 +530,6 @@ parameters:
count: 1
path: ../../../src/pocketmine/plugin/PluginDescription.php
-
message: "#^Method pocketmine\\\\plugin\\\\PluginDescription\\:\\:getRequiredExtensions\\(\\) should return array\\<string, array\\<int, string\\>\\> but returns array\\<string, array\\<int, mixed\\>\\>\\.$#"
count: 1
path: ../../../src/pocketmine/plugin/PluginDescription.php
-
message: "#^Parameter \\#1 \\$str of function substr expects string, mixed given\\.$#"
count: 2
path: ../../../src/pocketmine/plugin/PluginDescription.php
-
message: "#^Part \\$constr \\(mixed\\) of encapsed string cannot be cast to string\\.$#"
count: 2
path: ../../../src/pocketmine/plugin/PluginDescription.php
-
message: "#^Parameter \\#1 \\$description of method pocketmine\\\\command\\\\Command\\:\\:setDescription\\(\\) expects string, mixed given\\.$#"
count: 1

View File

@ -1,12 +0,0 @@
parameters:
ignoreErrors:
#TODO: use custom stubs
-
message: "#^Used constant LEVELDB_ZLIB_RAW_COMPRESSION not found\\.$#"
count: 1
path: ../../../src/pocketmine/level/format/io/leveldb/LevelDB.php
-
message: "#^Constant LEVELDB_ZLIB_RAW_COMPRESSION not found\\.$#"
count: 1
path: ../../../src/pocketmine/level/format/io/leveldb/LevelDB.php

View File

@ -355,21 +355,11 @@ parameters:
count: 1
path: ../../../src/pocketmine/command/CommandReader.php
-
message: "#^Parameter \\#2 \\$params of class pocketmine\\\\lang\\\\TranslationContainer constructor expects array\\<float\\|int\\|string\\>, array\\<int, string\\|null\\> given\\.$#"
count: 1
path: ../../../src/pocketmine/command/defaults/BanCommand.php
-
message: "#^Only booleans are allowed in an if condition, int\\|false given\\.$#"
count: 1
path: ../../../src/pocketmine/command/defaults/BanIpCommand.php
-
message: "#^Parameter \\#2 \\$params of class pocketmine\\\\lang\\\\TranslationContainer constructor expects array\\<float\\|int\\|string\\>, array\\<int, string\\|null\\> given\\.$#"
count: 1
path: ../../../src/pocketmine/command/defaults/BanIpCommand.php
-
message: "#^Only booleans are allowed in an if condition, int\\|false given\\.$#"
count: 1
@ -575,11 +565,6 @@ parameters:
count: 1
path: ../../../src/pocketmine/level/Explosion.php
-
message: "#^Parameter \\#2 \\$generatorClass of class pocketmine\\\\level\\\\generator\\\\GeneratorRegisterTask constructor expects string, pocketmine\\\\level\\\\generator\\\\Generator\\|string given\\.$#"
count: 1
path: ../../../src/pocketmine/level/Level.php
-
message: "#^Cannot access offset 'priority' on array\\('priority' \\=\\> int, 'data' \\=\\> pocketmine\\\\math\\\\Vector3\\)\\|int\\|pocketmine\\\\math\\\\Vector3\\.$#"
count: 1
@ -750,11 +735,6 @@ parameters:
count: 1
path: ../../../src/pocketmine/level/format/io/region/McRegion.php
-
message: "#^Only numeric types are allowed in \\+, int\\|false given on the left side\\.$#"
count: 2
path: ../../../src/pocketmine/level/format/io/region/McRegion.php
-
message: "#^Only numeric types are allowed in %%, int\\|false given on the left side\\.$#"
count: 1

View File

@ -240,11 +240,6 @@ parameters:
count: 1
path: ../../../src/pocketmine/Server.php
-
message: "#^Parameter \\#1 \\$name of static method pocketmine\\\\level\\\\generator\\\\GeneratorManager\\:\\:getGenerator\\(\\) expects string, string\\|null given\\.$#"
count: 1
path: ../../../src/pocketmine/Server.php
-
message: "#^Parameter \\#1 \\$uuid of method pocketmine\\\\Server\\:\\:updatePlayerListData\\(\\) expects pocketmine\\\\utils\\\\UUID, pocketmine\\\\utils\\\\UUID\\|null given\\.$#"
count: 1
@ -535,46 +530,6 @@ parameters:
count: 1
path: ../../../src/pocketmine/command/SimpleCommandMap.php
-
message: "#^Parameter \\#1 \\$target of method pocketmine\\\\permission\\\\BanList\\:\\:addBan\\(\\) expects string, string\\|null given\\.$#"
count: 1
path: ../../../src/pocketmine/command/defaults/BanCommand.php
-
message: "#^Parameter \\#1 \\$name of method pocketmine\\\\Server\\:\\:getPlayerExact\\(\\) expects string, string\\|null given\\.$#"
count: 1
path: ../../../src/pocketmine/command/defaults/BanCommand.php
-
message: "#^Parameter \\#2 \\$subject of function preg_match expects string, string\\|null given\\.$#"
count: 1
path: ../../../src/pocketmine/command/defaults/BanIpCommand.php
-
message: "#^Parameter \\#1 \\$ip of method pocketmine\\\\command\\\\defaults\\\\BanIpCommand\\:\\:processIPBan\\(\\) expects string, string\\|null given\\.$#"
count: 1
path: ../../../src/pocketmine/command/defaults/BanIpCommand.php
-
message: "#^Parameter \\#1 \\$name of method pocketmine\\\\Server\\:\\:getPlayer\\(\\) expects string, string\\|null given\\.$#"
count: 1
path: ../../../src/pocketmine/command/defaults/BanIpCommand.php
-
message: "#^Parameter \\#1 \\$name of method pocketmine\\\\Server\\:\\:getOfflinePlayer\\(\\) expects string, string\\|null given\\.$#"
count: 1
path: ../../../src/pocketmine/command/defaults/DeopCommand.php
-
message: "#^Parameter \\#1 \\$name of method pocketmine\\\\Server\\:\\:getPlayer\\(\\) expects string, string\\|null given\\.$#"
count: 1
path: ../../../src/pocketmine/command/defaults/KickCommand.php
-
message: "#^Parameter \\#1 \\$name of method pocketmine\\\\Server\\:\\:getOfflinePlayer\\(\\) expects string, string\\|null given\\.$#"
count: 1
path: ../../../src/pocketmine/command/defaults/OpCommand.php
-
message: "#^Cannot call method addParticle\\(\\) on pocketmine\\\\level\\\\Level\\|null\\.$#"
count: 1
@ -1535,11 +1490,6 @@ parameters:
count: 1
path: ../../../src/pocketmine/network/rcon/RCONInstance.php
-
message: "#^Parameter \\#1 \\$str of function trim expects string, string\\|null given\\.$#"
count: 1
path: ../../../src/pocketmine/permission/BanEntry.php
-
message: "#^Method pocketmine\\\\permission\\\\DefaultPermissions\\:\\:registerPermission\\(\\) should return pocketmine\\\\permission\\\\Permission but returns pocketmine\\\\permission\\\\Permission\\|null\\.$#"
count: 1
@ -1670,11 +1620,6 @@ parameters:
count: 1
path: ../../../src/pocketmine/utils/Config.php
-
message: "#^Parameter \\#1 \\$str of function trim expects string, string\\|null given\\.$#"
count: 1
path: ../../../src/pocketmine/utils/Config.php
-
message: "#^Method pocketmine\\\\utils\\\\MainLogger\\:\\:getLogger\\(\\) should return pocketmine\\\\utils\\\\MainLogger but returns pocketmine\\\\utils\\\\MainLogger\\|null\\.$#"
count: 1

View File

@ -60,11 +60,6 @@ parameters:
count: 2
path: ../../../src/pocketmine/level/Level.php
-
message: "#^Call to function assert\\(\\) with bool will always evaluate to true\\.$#"
count: 1
path: ../../../src/pocketmine/level/Level.php
-
message: "#^Call to function is_subclass_of\\(\\) with class\\-string\\<pocketmine\\\\level\\\\generator\\\\Generator\\> and 'pocketmine\\\\\\\\level\\\\\\\\generator\\\\\\\\Generator' will always evaluate to true\\.$#"
count: 1

View File

@ -110,8 +110,6 @@ class BlockTest extends TestCase{
/**
* @dataProvider blockGetProvider
* @param int $id
* @param int $meta
*/
public function testBlockGet(int $id, int $meta) : void{
$block = BlockFactory::get($id, $meta);

View File

@ -79,9 +79,6 @@ class ItemTest extends TestCase{
/**
* @dataProvider itemFromStringProvider
* @param string $string
* @param int $id
* @param int $meta
*/
public function testFromStringSingle(string $string, int $id, int $meta) : void{
$item = ItemFactory::fromStringSingle($string);

View File

@ -82,8 +82,6 @@ class RegionLoaderTest extends TestCase{
/**
* @dataProvider outOfBoundsCoordsProvider
* @param int $x
* @param int $z
*
* @throws ChunkException
* @throws \InvalidArgumentException
@ -109,8 +107,6 @@ class RegionLoaderTest extends TestCase{
/**
* @dataProvider outOfBoundsCoordsProvider
* @param int $x
* @param int $z
*
* @throws \InvalidArgumentException
* @throws \pocketmine\level\format\io\exception\CorruptedChunkException

View File

@ -24,6 +24,7 @@ declare(strict_types=1);
namespace pocketmine\level\format\io\region;
use PHPUnit\Framework\TestCase;
use function sprintf;
class RegionLocationTableEntryTest extends TestCase{

View File

@ -57,7 +57,6 @@ class StupidJsonDecodeTest extends TestCase{
/**
* @dataProvider stupidJsonDecodeProvider
*
* @param string $brokenJson
* @param mixed $expect
*
* @throws \ReflectionException

View File

@ -24,6 +24,7 @@ declare(strict_types=1);
namespace pocketmine\utils;
use PHPUnit\Framework\TestCase;
use function yaml_parse;
class ConfigTest extends TestCase{
@ -61,7 +62,6 @@ class ConfigTest extends TestCase{
/**
* @dataProvider fixYamlIndexesProvider
*
* @param string $test
* @param mixed[] $expected
*/
public function testFixYamlIndexes(string $test, array $expected) : void{

View File

@ -51,7 +51,6 @@ class UtilsTest extends TestCase{
}
/**
* @param string $docComment
* @dataProvider parseDocCommentNewlineProvider
*/
public function testParseDocCommentNewlines(string $docComment) : void{

View File

@ -26,6 +26,7 @@ namespace pmmp\TesterPlugin;
use pocketmine\event\Listener;
use pocketmine\event\server\CommandEvent;
use pocketmine\plugin\PluginBase;
use function array_shift;
class Main extends PluginBase implements Listener{

View File

@ -23,6 +23,8 @@ declare(strict_types=1);
namespace pmmp\TesterPlugin;
use function time;
abstract class Test{
const RESULT_WAITING = -1;
const RESULT_OK = 0;

View File

@ -28,7 +28,10 @@ use pocketmine\scheduler\AsyncTask;
use pocketmine\Server;
use pocketmine\utils\AssumptionFailedError;
use pocketmine\utils\MainLogger;
use function ob_end_flush;
use function ob_get_contents;
use function ob_start;
use function strpos;
class AsyncTaskMainLoggerTest extends Test{
@ -69,5 +72,4 @@ class AsyncTaskMainLoggerTest extends Test{
return "Verifies that the MainLogger is accessible by MainLogger::getLogger() in an AsyncTask";
}
}

View File

@ -25,6 +25,7 @@ namespace pmmp\TesterPlugin\tests;
use pmmp\TesterPlugin\Test;
use pocketmine\scheduler\AsyncTask;
use function usleep;
class AsyncTaskMemoryLeakTest extends Test{

View File

@ -15,3 +15,4 @@ before_script:
- make install
- cd ..
- echo "extension=pthreads.so" >> ~/.phpenv/versions/$(phpenv version-name)/etc/php.ini
- composer self-update --2