mirror of
https://github.com/pmmp/PocketMine-MP.git
synced 2025-09-14 13:25:11 +00:00
Compare commits
69 Commits
Author | SHA1 | Date | |
---|---|---|---|
0d5704b156 | |||
f355044626 | |||
4794ba236a | |||
6490a49c70 | |||
5cd7e11b29 | |||
08e3b8ffdc | |||
9232f4509c | |||
cef77907c6 | |||
06ec8b8397 | |||
ee08286eca | |||
a83211f96a | |||
0b3c4ee496 | |||
54de518634 | |||
a908197907 | |||
3e23a568ca | |||
dadc5c1b87 | |||
a37d740111 | |||
2de0ec02ba | |||
d83820477f | |||
8726604899 | |||
9cbe378e8c | |||
494660102e | |||
216138a37e | |||
b08c38f8f9 | |||
911b6feaf9 | |||
2cb6990698 | |||
f7d66613df | |||
95c32d26df | |||
9e1f6a2486 | |||
76994f15ac | |||
cf73d74bd0 | |||
37a8d95464 | |||
9a4b72add5 | |||
919534d978 | |||
cb598155a4 | |||
00888fdc55 | |||
77795ae3bc | |||
f39fc7e525 | |||
77f7595e0e | |||
e8d3a25028 | |||
1370930ea9 | |||
70c3008b7b | |||
46930b98b7 | |||
92be8c8ec0 | |||
62069bc7af | |||
26230c1f9b | |||
a9fafbc5eb | |||
b8778cb791 | |||
73c5fe5cf9 | |||
b3cfa5a3a0 | |||
6127a02a8b | |||
dbca36e5e2 | |||
1171bae691 | |||
494f8e8251 | |||
3c9af56e06 | |||
40a2211a5a | |||
0196aa21d7 | |||
833f3e574b | |||
a386ff8ce7 | |||
e6c3b0fc0d | |||
9568364277 | |||
73d4ff6b52 | |||
7e98aa1497 | |||
f00c69c513 | |||
50a4c42f3f | |||
6b61efcfc8 | |||
1a99938e4b | |||
a4d68fb32b | |||
5682cc8d53 |
@ -36,7 +36,6 @@ use function system;
|
||||
use const pocketmine\BASE_VERSION;
|
||||
use const STDIN;
|
||||
|
||||
require_once dirname(__DIR__) . '/src/pocketmine/VersionInfo.php';
|
||||
require_once dirname(__DIR__) . '/vendor/autoload.php';
|
||||
|
||||
if(isset($argv[1])){
|
||||
|
147
build/server-phar.php
Normal file
147
build/server-phar.php
Normal file
@ -0,0 +1,147 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
*
|
||||
* ____ _ _ __ __ _ __ __ ____
|
||||
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
|
||||
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
|
||||
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
|
||||
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* @author PocketMine Team
|
||||
* @link http://www.pocketmine.net/
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace pocketmine\build\server_phar;
|
||||
|
||||
use pocketmine\utils\Git;
|
||||
|
||||
require dirname(__DIR__) . '/vendor/autoload.php';
|
||||
|
||||
/**
|
||||
* @param string[] $strings
|
||||
* @param string|null $delim
|
||||
*
|
||||
* @return string[]
|
||||
*/
|
||||
function preg_quote_array(array $strings, string $delim = null) : array{
|
||||
return array_map(function(string $str) use ($delim) : string{ return preg_quote($str, $delim); }, $strings);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $pharPath
|
||||
* @param string $basePath
|
||||
* @param string[] $includedPaths
|
||||
* @param array $metadata
|
||||
* @param string $stub
|
||||
* @param int $signatureAlgo
|
||||
* @param int|null $compression
|
||||
*
|
||||
* @return \Generator|string[]
|
||||
*/
|
||||
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){
|
||||
return rtrim(str_replace("/", DIRECTORY_SEPARATOR, $path), DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR;
|
||||
}, $includedPaths);
|
||||
yield "Creating output file $pharPath";
|
||||
if(file_exists($pharPath)){
|
||||
yield "Phar file already exists, overwriting...";
|
||||
try{
|
||||
\Phar::unlinkArchive($pharPath);
|
||||
}catch(\PharException $e){
|
||||
//unlinkArchive() doesn't like dodgy phars
|
||||
unlink($pharPath);
|
||||
}
|
||||
}
|
||||
|
||||
yield "Adding files...";
|
||||
|
||||
$start = microtime(true);
|
||||
$phar = new \Phar($pharPath);
|
||||
$phar->setMetadata($metadata);
|
||||
$phar->setStub($stub);
|
||||
$phar->setSignatureAlgorithm($signatureAlgo);
|
||||
$phar->startBuffering();
|
||||
|
||||
//If paths contain any of these, they will be excluded
|
||||
$excludedSubstrings = preg_quote_array([
|
||||
realpath($pharPath), //don't add the phar to itself
|
||||
], '/');
|
||||
|
||||
$folderPatterns = preg_quote_array([
|
||||
DIRECTORY_SEPARATOR . 'tests' . DIRECTORY_SEPARATOR,
|
||||
DIRECTORY_SEPARATOR . '.' //"Hidden" files, git dirs etc
|
||||
], '/');
|
||||
|
||||
//Only exclude these within the basedir, otherwise the project won't get built if it itself is in a directory that matches these patterns
|
||||
$basePattern = preg_quote(rtrim($basePath, DIRECTORY_SEPARATOR), '/');
|
||||
foreach($folderPatterns as $p){
|
||||
$excludedSubstrings[] = $basePattern . '.*' . $p;
|
||||
}
|
||||
|
||||
$regex = sprintf('/^(?!.*(%s))^%s(%s).*/i',
|
||||
implode('|', $excludedSubstrings), //String may not contain any of these substrings
|
||||
preg_quote($basePath, '/'), //String must start with this path...
|
||||
implode('|', preg_quote_array($includedPaths, '/')) //... and must be followed by one of these relative paths, if any were specified. If none, this will produce a null capturing group which will allow anything.
|
||||
);
|
||||
|
||||
$directory = new \RecursiveDirectoryIterator($basePath, \FilesystemIterator::SKIP_DOTS | \FilesystemIterator::FOLLOW_SYMLINKS | \FilesystemIterator::CURRENT_AS_PATHNAME); //can't use fileinfo because of symlinks
|
||||
$iterator = new \RecursiveIteratorIterator($directory);
|
||||
$regexIterator = new \RegexIterator($iterator, $regex);
|
||||
|
||||
$count = count($phar->buildFromIterator($regexIterator, $basePath));
|
||||
yield "Added $count files";
|
||||
|
||||
if($compression !== null){
|
||||
yield "Checking for compressible files...";
|
||||
foreach($phar as $file => $finfo){
|
||||
/** @var \PharFileInfo $finfo */
|
||||
if($finfo->getSize() > (1024 * 512)){
|
||||
yield "Compressing " . $finfo->getFilename();
|
||||
$finfo->compress($compression);
|
||||
}
|
||||
}
|
||||
}
|
||||
$phar->stopBuffering();
|
||||
|
||||
yield "Done in " . round(microtime(true) - $start, 3) . "s";
|
||||
}
|
||||
|
||||
function main() : void{
|
||||
if(ini_get("phar.readonly") == 1){
|
||||
echo "Set phar.readonly to 0 with -dphar.readonly=0" . PHP_EOL;
|
||||
exit(1);
|
||||
}
|
||||
|
||||
$opts = getopt("", ["out:"]);
|
||||
$gitHash = Git::getRepositoryStatePretty(dirname(__DIR__));
|
||||
echo "Git hash detected as $gitHash" . PHP_EOL;
|
||||
foreach(buildPhar(
|
||||
$opts["out"] ?? getcwd() . DIRECTORY_SEPARATOR . "PocketMine-MP.phar",
|
||||
dirname(__DIR__) . DIRECTORY_SEPARATOR,
|
||||
[
|
||||
'src',
|
||||
'vendor'
|
||||
],
|
||||
[
|
||||
'git' => $gitHash
|
||||
],
|
||||
'<?php require("phar://" . __FILE__ . "/src/pocketmine/PocketMine.php"); __HALT_COMPILER();'
|
||||
) as $line){
|
||||
echo $line . PHP_EOL;
|
||||
}
|
||||
}
|
||||
|
||||
if(!defined('pocketmine\_PHPSTAN_ANALYSIS')){
|
||||
main();
|
||||
}
|
45
changelogs/3.11.md
Normal file
45
changelogs/3.11.md
Normal file
@ -0,0 +1,45 @@
|
||||
**For Minecraft: Bedrock Edition 1.14.0**
|
||||
|
||||
### Note about API versions
|
||||
Plugins which don't touch the protocol and compatible with any previous 3.x.y version will also run on these releases and do not need API bumps.
|
||||
Plugin developers should **only** update their required API to this version if you need the changes in this build.
|
||||
|
||||
**WARNING: If your plugin uses the protocol, you're not shielded by API change constraints.** You should consider using the `mcpe-protocol` directive in `plugin.yml` as a constraint if you do.
|
||||
|
||||
# 3.11.0
|
||||
- Added support for Minecraft: Bedrock Edition 1.14.0
|
||||
- Removed compatibility with 1.13.0
|
||||
|
||||
# 3.11.1
|
||||
- Fixed blocks with incorrect properties when placed or interacted with.
|
||||
|
||||
# 3.11.2
|
||||
## Core
|
||||
- PHPStan 0.12.3 with level 5 is now used for automated static analysis.
|
||||
- Fixed a possible crash when plugins override the `EnderChest` tile class with something incompatible.
|
||||
- Fixed disconnected players being considered as never played.
|
||||
- Fixed enchantments with IDs outside the range 0-255 in item NBT crashing the server.
|
||||
- Fixed particles rendering incorrectly.
|
||||
- Timings handlers are no longer able to underflow; they now throw exceptions when attempting to be stopped more times than they were started.
|
||||
- Fixed explosion rays getting stuck in empty subchunks (possible incorrect behaviour in large caves).
|
||||
- Fixed bad tile/entity NBT data being propagated from world providers in some cases.
|
||||
- Fixed a possible crash when detecting timezone on CentOS.
|
||||
- Fixed many cases of incorrectly documented types in the API found by PHPStan.
|
||||
- Generation tasks no longer assume that generator instances stored in TLS are always valid, fixing a possible crash.
|
||||
|
||||
## Protocol
|
||||
- Fixed skin animation image corruption in LoginPacket handling caused by incorrect data handling.
|
||||
- Fixed skin animation extra data not being decoded from LoginPacket.
|
||||
- `SkinImage` now throws `InvalidArgumentException` if it receives an unexpected amount of bytes for the given image heigh/width.
|
||||
- Fixed broken code in `PlayerAuthInputPacket::create()`.
|
||||
- Removed some dead constants from `NetworkInventoryAction`.
|
||||
|
||||
# 3.11.3
|
||||
- Fixed some PHPStan false-positives in release builds.
|
||||
- Git hash is now correctly detected for source builds when the working directory is not the repository root.
|
||||
- Added a specialized build script `build/server-phar.php` for creating server phars.
|
||||
- Fixed timings crashing the server.
|
||||
- Timings chains now work correctly.
|
||||
- Fixed some minor timing errors in chained timings.
|
||||
- Forcing resource packs no longer causes removal of client-sided resource packs. If this behaviour is desired, use a vanilla resource pack at the bottom of your resource stack (as was necessary for non-forced packs).
|
||||
- Added documentation to the API to clarify that effect durations are in ticks.
|
@ -4,14 +4,20 @@ includes:
|
||||
- tests/phpstan/configs/optional-leveldb.neon
|
||||
- tests/phpstan/configs/phpstan-bugs.neon
|
||||
- tests/phpstan/configs/pthreads-bugs.neon
|
||||
- tests/phpstan/configs/runtime-type-checks.neon
|
||||
|
||||
parameters:
|
||||
level: 3
|
||||
level: 5
|
||||
autoload_files:
|
||||
- tests/phpstan/bootstrap.php
|
||||
- src/pocketmine/PocketMine.php
|
||||
- build/server-phar.php
|
||||
paths:
|
||||
- src
|
||||
- build/server-phar.php
|
||||
dynamicConstantNames:
|
||||
- pocketmine\IS_DEVELOPMENT_BUILD
|
||||
- pocketmine\DEBUG
|
||||
reportUnmatchedIgnoredErrors: false #no other way to silence platform-specific non-warnings
|
||||
ignoreErrors:
|
||||
-
|
||||
|
@ -464,11 +464,11 @@ class Player extends Human implements CommandSender, ChunkLoader, IPlayer{
|
||||
}
|
||||
|
||||
public function getFirstPlayed(){
|
||||
return $this->namedtag instanceof CompoundTag ? $this->namedtag->getLong("firstPlayed", 0, true) : null;
|
||||
return $this->namedtag->getLong("firstPlayed", 0, true);
|
||||
}
|
||||
|
||||
public function getLastPlayed(){
|
||||
return $this->namedtag instanceof CompoundTag ? $this->namedtag->getLong("lastPlayed", 0, true) : null;
|
||||
return $this->namedtag->getLong("lastPlayed", 0, true);
|
||||
}
|
||||
|
||||
public function hasPlayedBefore() : bool{
|
||||
@ -741,7 +741,7 @@ class Player extends Human implements CommandSender, ChunkLoader, IPlayer{
|
||||
$data->overloads[0][0] = $parameter;
|
||||
|
||||
$aliases = $command->getAliases();
|
||||
if(!empty($aliases)){
|
||||
if(count($aliases) > 0){
|
||||
if(!in_array($data->commandName, $aliases, true)){
|
||||
//work around a client bug which makes the original name not show when aliases are used
|
||||
$aliases[] = $data->commandName;
|
||||
@ -1208,7 +1208,7 @@ class Player extends Human implements CommandSender, ChunkLoader, IPlayer{
|
||||
}
|
||||
|
||||
$this->loadQueue = $newOrder;
|
||||
if(!empty($this->loadQueue) or !empty($unloadChunks)){
|
||||
if(count($this->loadQueue) > 0 or count($unloadChunks) > 0){
|
||||
$pk = new NetworkChunkPublisherUpdatePacket();
|
||||
$pk->x = $this->getFloorX();
|
||||
$pk->y = $this->getFloorY();
|
||||
@ -1921,7 +1921,7 @@ class Player extends Human implements CommandSender, ChunkLoader, IPlayer{
|
||||
|
||||
$animations = [];
|
||||
foreach($packet->clientData["AnimatedImageData"] as $animation){
|
||||
$animations[] = new SkinAnimation(new SkinImage($animation["ImageHeight"], $animation["ImageWidth"], $animation["Image"]), $animation["Type"], $animation["Frames"]);
|
||||
$animations[] = new SkinAnimation(new SkinImage($animation["ImageHeight"], $animation["ImageWidth"], base64_decode($animation["Image"], true)), $animation["Type"], $animation["Frames"]);
|
||||
}
|
||||
|
||||
$skinData = new SkinData(
|
||||
@ -1931,7 +1931,7 @@ class Player extends Human implements CommandSender, ChunkLoader, IPlayer{
|
||||
$animations,
|
||||
new SkinImage($packet->clientData["CapeImageHeight"], $packet->clientData["CapeImageWidth"], base64_decode($packet->clientData["CapeData"] ?? "")),
|
||||
base64_decode($packet->clientData["SkinGeometryData"] ?? ""),
|
||||
base64_decode($packet->clientData["AnimationData"] ?? ""),
|
||||
base64_decode($packet->clientData["SkinAnimationData"] ?? ""),
|
||||
$packet->clientData["PremiumSkin"] ?? false,
|
||||
$packet->clientData["PersonaSkin"] ?? false,
|
||||
$packet->clientData["CapeOnClassicSkin"] ?? false,
|
||||
@ -2118,7 +2118,10 @@ class Player extends Human implements CommandSender, ChunkLoader, IPlayer{
|
||||
$pk = new ResourcePackStackPacket();
|
||||
$manager = $this->server->getResourcePackManager();
|
||||
$pk->resourcePackStack = $manager->getResourceStack();
|
||||
$pk->mustAccept = $manager->resourcePacksRequired();
|
||||
//we don't force here, because it doesn't have user-facing effects
|
||||
//but it does have an annoying side-effect when true: it makes
|
||||
//the client remove its own non-server-supplied resource packs.
|
||||
$pk->mustAccept = false;
|
||||
$this->dataPacket($pk);
|
||||
break;
|
||||
case ResourcePackClientResponsePacket::STATUS_COMPLETED:
|
||||
|
@ -23,6 +23,7 @@ declare(strict_types=1);
|
||||
|
||||
namespace pocketmine {
|
||||
|
||||
use pocketmine\utils\Git;
|
||||
use pocketmine\utils\MainLogger;
|
||||
use pocketmine\utils\ServerKiller;
|
||||
use pocketmine\utils\Terminal;
|
||||
@ -140,7 +141,7 @@ namespace pocketmine {
|
||||
}
|
||||
|
||||
function server(){
|
||||
if(!empty($messages = check_platform_dependencies())){
|
||||
if(count($messages = check_platform_dependencies()) > 0){
|
||||
echo PHP_EOL;
|
||||
$binary = version_compare(PHP_VERSION, "5.4") >= 0 ? PHP_BINARY : "unknown";
|
||||
critical_error("Selected PHP binary ($binary) does not satisfy some requirements.");
|
||||
@ -186,12 +187,7 @@ namespace pocketmine {
|
||||
$gitHash = str_repeat("00", 20);
|
||||
|
||||
if(\Phar::running(true) === ""){
|
||||
if(Utils::execute("git rev-parse HEAD", $out) === 0 and $out !== false and strlen($out = trim($out)) === 40){
|
||||
$gitHash = trim($out);
|
||||
if(Utils::execute("git diff --quiet") === 1 or Utils::execute("git diff --cached --quiet") === 1){ //Locally-modified
|
||||
$gitHash .= "-dirty";
|
||||
}
|
||||
}
|
||||
$gitHash = Git::getRepositoryStatePretty(\pocketmine\PATH);
|
||||
}else{
|
||||
$phar = new \Phar(\Phar::running(false));
|
||||
$meta = $phar->getMetadata();
|
||||
|
@ -114,6 +114,7 @@ use function asort;
|
||||
use function assert;
|
||||
use function base64_encode;
|
||||
use function class_exists;
|
||||
use function cli_set_process_title;
|
||||
use function count;
|
||||
use function define;
|
||||
use function explode;
|
||||
@ -128,7 +129,6 @@ use function getmypid;
|
||||
use function getopt;
|
||||
use function gettype;
|
||||
use function implode;
|
||||
use function ini_get;
|
||||
use function ini_set;
|
||||
use function is_array;
|
||||
use function is_bool;
|
||||
@ -1212,9 +1212,9 @@ class Server{
|
||||
}
|
||||
$path = $this->getDataPath() . "worlds/" . $name . "/";
|
||||
if(!($this->getLevelByName($name) instanceof Level)){
|
||||
return is_dir($path) and !empty(array_filter(scandir($path, SCANDIR_SORT_NONE), function($v){
|
||||
return is_dir($path) and count(array_filter(scandir($path, SCANDIR_SORT_NONE), function($v){
|
||||
return $v !== ".." and $v !== ".";
|
||||
}));
|
||||
})) > 0;
|
||||
}
|
||||
|
||||
return true;
|
||||
@ -1928,14 +1928,14 @@ class Server{
|
||||
* @param bool $immediate
|
||||
*/
|
||||
public function batchPackets(array $players, array $packets, bool $forceSync = false, bool $immediate = false){
|
||||
if(empty($packets)){
|
||||
if(count($packets) === 0){
|
||||
throw new \InvalidArgumentException("Cannot send empty batch");
|
||||
}
|
||||
Timings::$playerNetworkTimer->startTiming();
|
||||
|
||||
$targets = array_filter($players, function(Player $player) : bool{ return $player->isConnected(); });
|
||||
|
||||
if(!empty($targets)){
|
||||
if(count($targets) > 0){
|
||||
$pk = new BatchPacket();
|
||||
|
||||
foreach($packets as $p){
|
||||
@ -2246,6 +2246,9 @@ class Server{
|
||||
$this->crashDump();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return void
|
||||
*/
|
||||
public function crashDump(){
|
||||
while(@ob_end_flush()){}
|
||||
if(!$this->isRunning){
|
||||
|
@ -19,6 +19,8 @@
|
||||
*
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace pocketmine;
|
||||
|
||||
// composer autoload doesn't use require_once and also pthreads can inherit things
|
||||
@ -30,6 +32,6 @@ const _VERSION_INFO_INCLUDED = true;
|
||||
|
||||
|
||||
const NAME = "PocketMine-MP";
|
||||
const BASE_VERSION = "3.10.1";
|
||||
const BASE_VERSION = "3.11.3";
|
||||
const IS_DEVELOPMENT_BUILD = false;
|
||||
const BUILD_NUMBER = 0;
|
||||
|
@ -40,6 +40,7 @@ use pocketmine\network\mcpe\protocol\types\RuntimeBlockMapping;
|
||||
use pocketmine\Player;
|
||||
use pocketmine\plugin\Plugin;
|
||||
use function array_merge;
|
||||
use function count;
|
||||
use function get_class;
|
||||
use const PHP_INT_MAX;
|
||||
|
||||
@ -727,7 +728,7 @@ class Block extends Position implements BlockIds, Metadatable{
|
||||
*/
|
||||
public function calculateIntercept(Vector3 $pos1, Vector3 $pos2) : ?RayTraceResult{
|
||||
$bbs = $this->getCollisionBoxes();
|
||||
if(empty($bbs)){
|
||||
if(count($bbs) === 0){
|
||||
return null;
|
||||
}
|
||||
|
||||
|
@ -84,6 +84,9 @@ class EnderChest extends Chest{
|
||||
$enderChest = $t;
|
||||
}else{
|
||||
$enderChest = Tile::createTile(Tile::ENDER_CHEST, $this->getLevel(), TileEnderChest::createNBT($this));
|
||||
if(!($enderChest instanceof TileEnderChest)){
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if(!$this->getSide(Vector3::SIDE_UP)->isTransparent()){
|
||||
|
@ -25,6 +25,7 @@ namespace pocketmine\block;
|
||||
|
||||
use pocketmine\math\AxisAlignedBB;
|
||||
use pocketmine\math\Vector3;
|
||||
use function count;
|
||||
|
||||
abstract class Fence extends Transparent{
|
||||
|
||||
@ -85,7 +86,7 @@ abstract class Fence extends Transparent{
|
||||
);
|
||||
}
|
||||
|
||||
if(empty($bbs)){
|
||||
if(count($bbs) === 0){
|
||||
//centre post AABB (only needed if not connected on any axis - other BBs overlapping will do this if any connections are made)
|
||||
return [
|
||||
new AxisAlignedBB(
|
||||
|
@ -25,6 +25,7 @@ namespace pocketmine\block;
|
||||
|
||||
use pocketmine\math\AxisAlignedBB;
|
||||
use pocketmine\math\Vector3;
|
||||
use function count;
|
||||
|
||||
abstract class Thin extends Transparent{
|
||||
|
||||
@ -77,7 +78,7 @@ abstract class Thin extends Transparent{
|
||||
);
|
||||
}
|
||||
|
||||
if(empty($bbs)){
|
||||
if(count($bbs) === 0){
|
||||
//centre post AABB (only needed if not connected on any axis - other BBs overlapping will do this if any connections are made)
|
||||
return [
|
||||
new AxisAlignedBB(
|
||||
|
@ -328,12 +328,12 @@ class SimpleCommandMap implements CommandMap{
|
||||
}
|
||||
}
|
||||
|
||||
if(!empty($recursive)){
|
||||
if(count($recursive) > 0){
|
||||
$this->server->getLogger()->warning($this->server->getLanguage()->translateString("pocketmine.command.alias.recursive", [$alias, implode(", ", $recursive)]));
|
||||
continue;
|
||||
}
|
||||
|
||||
if(!empty($bad)){
|
||||
if(count($bad) > 0){
|
||||
$this->server->getLogger()->warning($this->server->getLanguage()->translateString("pocketmine.command.alias.notFound", [$alias, implode(", ", $bad)]));
|
||||
continue;
|
||||
}
|
||||
|
@ -195,7 +195,8 @@ class Effect{
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the default duration this effect will apply for if a duration is not specified.
|
||||
* Returns the default duration (in ticks) this effect will apply for if a duration is not specified.
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function getDefaultDuration() : int{
|
||||
|
@ -75,6 +75,8 @@ class EffectInstance{
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the number of ticks remaining until the effect expires.
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function getDuration() : int{
|
||||
@ -82,6 +84,8 @@ class EffectInstance{
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the number of ticks remaining until the effect expires.
|
||||
*
|
||||
* @param int $duration
|
||||
*
|
||||
* @throws \InvalidArgumentException
|
||||
|
@ -463,12 +463,12 @@ abstract class Entity extends Location implements Metadatable, EntityIds{
|
||||
/** @var Block[]|null */
|
||||
protected $blocksAround = null;
|
||||
|
||||
/** @var float|null */
|
||||
public $lastX = null;
|
||||
/** @var float|null */
|
||||
public $lastY = null;
|
||||
/** @var float|null */
|
||||
public $lastZ = null;
|
||||
/** @var float */
|
||||
public $lastX;
|
||||
/** @var float */
|
||||
public $lastY;
|
||||
/** @var float */
|
||||
public $lastZ;
|
||||
|
||||
/** @var Vector3 */
|
||||
protected $motion;
|
||||
@ -1102,7 +1102,7 @@ abstract class Entity extends Location implements Metadatable, EntityIds{
|
||||
$this->justCreated = false;
|
||||
|
||||
$changedProperties = $this->propertyManager->getDirty();
|
||||
if(!empty($changedProperties)){
|
||||
if(count($changedProperties) > 0){
|
||||
$this->sendData($this->hasSpawned, $changedProperties);
|
||||
$this->propertyManager->clearDirtyProperties();
|
||||
}
|
||||
|
@ -61,6 +61,7 @@ use function array_merge;
|
||||
use function array_rand;
|
||||
use function array_values;
|
||||
use function ceil;
|
||||
use function count;
|
||||
use function in_array;
|
||||
use function max;
|
||||
use function min;
|
||||
@ -554,7 +555,7 @@ class Human extends Creature implements ProjectileSource, InventoryHolder{
|
||||
}
|
||||
}
|
||||
|
||||
if(!empty($equipment)){
|
||||
if(count($equipment) > 0){
|
||||
$repairItem = $equipment[$k = array_rand($equipment)];
|
||||
if($repairItem->getDamage() > 0){
|
||||
$repairAmount = min($repairItem->getDamage(), $xpValue * 2);
|
||||
|
@ -263,7 +263,7 @@ abstract class Living extends Entity implements Damageable{
|
||||
* @return bool
|
||||
*/
|
||||
public function hasEffects() : bool{
|
||||
return !empty($this->effects);
|
||||
return count($this->effects) > 0;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -332,7 +332,7 @@ abstract class Living extends Entity implements Damageable{
|
||||
}
|
||||
}
|
||||
|
||||
if(!empty($colors)){
|
||||
if(count($colors) > 0){
|
||||
$this->propertyManager->setInt(Entity::DATA_POTION_COLOR, Color::mix(...$colors)->toARGB());
|
||||
$this->propertyManager->setByte(Entity::DATA_POTION_AMBIENT, $ambient ? 1 : 0);
|
||||
}else{
|
||||
@ -713,7 +713,7 @@ abstract class Living extends Entity implements Damageable{
|
||||
}
|
||||
}
|
||||
|
||||
return !empty($this->effects);
|
||||
return count($this->effects) > 0;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -893,7 +893,7 @@ abstract class Living extends Entity implements Damageable{
|
||||
*/
|
||||
public function getTargetBlock(int $maxDistance, array $transparent = []) : ?Block{
|
||||
$line = $this->getLineOfSight($maxDistance, 1, $transparent);
|
||||
if(!empty($line)){
|
||||
if(count($line) > 0){
|
||||
return array_shift($line);
|
||||
}
|
||||
|
||||
|
@ -34,7 +34,6 @@ use pocketmine\level\Position;
|
||||
use pocketmine\nbt\tag\ByteTag;
|
||||
use pocketmine\nbt\tag\IntTag;
|
||||
use function abs;
|
||||
use function floor;
|
||||
use function get_class;
|
||||
|
||||
class FallingBlock extends Entity{
|
||||
|
@ -34,6 +34,7 @@ use pocketmine\item\Potion;
|
||||
use pocketmine\network\mcpe\protocol\LevelEventPacket;
|
||||
use pocketmine\network\mcpe\protocol\LevelSoundEventPacket;
|
||||
use pocketmine\utils\Color;
|
||||
use function count;
|
||||
use function round;
|
||||
use function sqrt;
|
||||
|
||||
@ -63,7 +64,7 @@ class SplashPotion extends Throwable{
|
||||
$effects = $this->getPotionEffects();
|
||||
$hasEffects = true;
|
||||
|
||||
if(empty($effects)){
|
||||
if(count($effects) === 0){
|
||||
$colors = [
|
||||
new Color(0x38, 0x5d, 0xc6) //Default colour for splash water bottle and similar with no effects.
|
||||
];
|
||||
|
@ -46,7 +46,7 @@ abstract class BaseInventory implements Inventory{
|
||||
protected $name;
|
||||
/** @var string */
|
||||
protected $title;
|
||||
/** @var \SplFixedArray|Item[] */
|
||||
/** @var \SplFixedArray|(Item|null)[] */
|
||||
protected $slots;
|
||||
/** @var Player[] */
|
||||
protected $viewers = [];
|
||||
|
@ -66,19 +66,23 @@ class PlayerInventory extends BaseInventory{
|
||||
* @return bool if the equipment change was successful, false if not.
|
||||
*/
|
||||
public function equipItem(int $hotbarSlot) : bool{
|
||||
$holder = $this->getHolder();
|
||||
if(!$this->isHotbarSlot($hotbarSlot)){
|
||||
$this->sendContents($this->getHolder());
|
||||
if($holder instanceof Player){
|
||||
$this->sendContents($holder);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
$ev = new PlayerItemHeldEvent($this->getHolder(), $this->getItem($hotbarSlot), $hotbarSlot);
|
||||
$ev->call();
|
||||
if($holder instanceof Player){
|
||||
$ev = new PlayerItemHeldEvent($holder, $this->getItem($hotbarSlot), $hotbarSlot);
|
||||
$ev->call();
|
||||
|
||||
if($ev->isCancelled()){
|
||||
$this->sendHeldItem($this->getHolder());
|
||||
return false;
|
||||
if($ev->isCancelled()){
|
||||
$this->sendHeldItem($holder);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
$this->setHeldItemIndex($hotbarSlot, false);
|
||||
|
||||
return true;
|
||||
|
@ -135,6 +135,6 @@ class ShapelessRecipe implements CraftingRecipe{
|
||||
return false; //failed to match the needed item to a given item
|
||||
}
|
||||
|
||||
return empty($input); //crafting grid should be empty apart from the given ingredient stacks
|
||||
return count($input) === 0; //crafting grid should be empty apart from the given ingredient stacks
|
||||
}
|
||||
}
|
||||
|
@ -68,14 +68,14 @@ class CraftingTransaction extends InventoryTransaction{
|
||||
* @throws TransactionValidationException
|
||||
*/
|
||||
protected function matchRecipeItems(array $txItems, array $recipeItems, bool $wildcards, int $iterations = 0) : int{
|
||||
if(empty($recipeItems)){
|
||||
if(count($recipeItems) === 0){
|
||||
throw new TransactionValidationException("No recipe items given");
|
||||
}
|
||||
if(empty($txItems)){
|
||||
if(count($txItems) === 0){
|
||||
throw new TransactionValidationException("No transaction items given");
|
||||
}
|
||||
|
||||
while(!empty($recipeItems)){
|
||||
while(count($recipeItems) > 0){
|
||||
/** @var Item $recipeItem */
|
||||
$recipeItem = array_pop($recipeItems);
|
||||
$needCount = $recipeItem->getCount();
|
||||
@ -114,7 +114,7 @@ class CraftingTransaction extends InventoryTransaction{
|
||||
if($iterations < 1){
|
||||
throw new TransactionValidationException("Tried to craft zero times");
|
||||
}
|
||||
if(!empty($txItems)){
|
||||
if(count($txItems) > 0){
|
||||
//all items should be destroyed in this process
|
||||
throw new TransactionValidationException("Expected 0 ingredients left over, have " . count($txItems));
|
||||
}
|
||||
|
@ -237,13 +237,13 @@ class InventoryTransaction{
|
||||
* @return null|Item
|
||||
*/
|
||||
protected function findResultItem(Item $needOrigin, array $possibleActions) : ?Item{
|
||||
assert(!empty($possibleActions));
|
||||
assert(count($possibleActions) > 0);
|
||||
|
||||
foreach($possibleActions as $i => $action){
|
||||
if($action->getSourceItem()->equalsExact($needOrigin)){
|
||||
$newList = $possibleActions;
|
||||
unset($newList[$i]);
|
||||
if(empty($newList)){
|
||||
if(count($newList) === 0){
|
||||
return $action->getTargetItem();
|
||||
}
|
||||
$result = $this->findResultItem($action->getTargetItem(), $newList);
|
||||
|
@ -31,6 +31,7 @@ use pocketmine\math\Vector3;
|
||||
use pocketmine\network\mcpe\protocol\LevelEventPacket;
|
||||
use pocketmine\Player;
|
||||
use function array_rand;
|
||||
use function count;
|
||||
|
||||
class PaintingItem extends Item{
|
||||
public function __construct(int $meta = 0){
|
||||
@ -66,7 +67,7 @@ class PaintingItem extends Item{
|
||||
}
|
||||
}
|
||||
|
||||
if(empty($motives)){ //No space available
|
||||
if(count($motives) === 0){ //No space available
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -155,6 +155,9 @@ class Enchantment{
|
||||
* @return Enchantment|null
|
||||
*/
|
||||
public static function getEnchantment(int $id) : ?Enchantment{
|
||||
if($id < 0 or $id >= self::$enchantments->getSize()){
|
||||
return null;
|
||||
}
|
||||
return self::$enchantments[$id] ?? null;
|
||||
}
|
||||
|
||||
|
@ -115,9 +115,9 @@ class BaseLang{
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $str
|
||||
* @param string[] $params
|
||||
* @param string|null $onlyPrefix
|
||||
* @param string $str
|
||||
* @param (float|int|string)[] $params
|
||||
* @param string|null $onlyPrefix
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
|
@ -31,8 +31,8 @@ class TranslationContainer extends TextContainer{
|
||||
protected $params = [];
|
||||
|
||||
/**
|
||||
* @param string $text
|
||||
* @param string[] $params
|
||||
* @param string $text
|
||||
* @param (float|int|string)[] $params
|
||||
*/
|
||||
public function __construct(string $text, array $params = []){
|
||||
parent::__construct($text);
|
||||
|
@ -123,6 +123,10 @@ class Explosion{
|
||||
$vBlock->y = $pointerY >= $y ? $y : $y - 1;
|
||||
$vBlock->z = $pointerZ >= $z ? $z : $z - 1;
|
||||
|
||||
$pointerX += $vector->x;
|
||||
$pointerY += $vector->y;
|
||||
$pointerZ += $vector->z;
|
||||
|
||||
if(!$this->subChunkHandler->moveTo($vBlock->x, $vBlock->y, $vBlock->z)){
|
||||
continue;
|
||||
}
|
||||
@ -137,10 +141,6 @@ class Explosion{
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$pointerX += $vector->x;
|
||||
$pointerY += $vector->y;
|
||||
$pointerZ += $vector->z;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -503,7 +503,7 @@ class Level implements ChunkManager, Metadatable{
|
||||
if(!is_array($pk)){
|
||||
$pk = [$pk];
|
||||
}
|
||||
if(!empty($pk)){
|
||||
if(count($pk) > 0){
|
||||
if($players === null){
|
||||
foreach($pk as $e){
|
||||
$this->broadcastPacketToViewers($sound, $e);
|
||||
@ -519,7 +519,7 @@ class Level implements ChunkManager, Metadatable{
|
||||
if(!is_array($pk)){
|
||||
$pk = [$pk];
|
||||
}
|
||||
if(!empty($pk)){
|
||||
if(count($pk) > 0){
|
||||
if($players === null){
|
||||
foreach($pk as $e){
|
||||
$this->broadcastPacketToViewers($particle, $e);
|
||||
@ -881,7 +881,7 @@ class Level implements ChunkManager, Metadatable{
|
||||
if(count($this->changedBlocks) > 0){
|
||||
if(count($this->players) > 0){
|
||||
foreach($this->changedBlocks as $index => $blocks){
|
||||
if(empty($blocks)){ //blocks can be set normally and then later re-set with direct send
|
||||
if(count($blocks) === 0){ //blocks can be set normally and then later re-set with direct send
|
||||
continue;
|
||||
}
|
||||
unset($this->chunkCache[$index]);
|
||||
@ -909,8 +909,8 @@ class Level implements ChunkManager, Metadatable{
|
||||
$this->checkSleep();
|
||||
}
|
||||
|
||||
if(!empty($this->globalPackets)){
|
||||
if(!empty($this->players)){
|
||||
if(count($this->globalPackets) > 0){
|
||||
if(count($this->players) > 0){
|
||||
$this->server->batchPackets($this->players, $this->globalPackets);
|
||||
}
|
||||
$this->globalPackets = [];
|
||||
@ -1845,7 +1845,7 @@ class Level implements ChunkManager, Metadatable{
|
||||
|
||||
$item->onDestroyBlock($target);
|
||||
|
||||
if(!empty($drops)){
|
||||
if(count($drops) > 0){
|
||||
$dropPos = $target->add(0.5, 0.5, 0.5);
|
||||
foreach($drops as $drop){
|
||||
if(!$drop->isNull()){
|
||||
@ -1949,7 +1949,7 @@ class Level implements ChunkManager, Metadatable{
|
||||
|
||||
if($hand->isSolid()){
|
||||
foreach($hand->getCollisionBoxes() as $collisionBox){
|
||||
if(!empty($this->getCollidingEntities($collisionBox))){
|
||||
if(count($this->getCollidingEntities($collisionBox)) > 0){
|
||||
return false; //Entity in block
|
||||
}
|
||||
|
||||
@ -2442,7 +2442,7 @@ class Level implements ChunkManager, Metadatable{
|
||||
* @param int $x
|
||||
* @param int $z
|
||||
*
|
||||
* @return Chunk[]
|
||||
* @return (Chunk|null)[]
|
||||
*/
|
||||
public function getAdjacentChunks(int $x, int $z) : array{
|
||||
$result = [];
|
||||
|
@ -33,12 +33,12 @@ class Location extends Position{
|
||||
public $pitch;
|
||||
|
||||
/**
|
||||
* @param int $x
|
||||
* @param int $y
|
||||
* @param int $z
|
||||
* @param float $yaw
|
||||
* @param float $pitch
|
||||
* @param Level $level
|
||||
* @param float|int $x
|
||||
* @param float|int $y
|
||||
* @param float|int $z
|
||||
* @param float $yaw
|
||||
* @param float $pitch
|
||||
* @param Level $level
|
||||
*/
|
||||
public function __construct($x = 0, $y = 0, $z = 0, $yaw = 0.0, $pitch = 0.0, Level $level = null){
|
||||
$this->yaw = $yaw;
|
||||
|
@ -33,10 +33,10 @@ class Position extends Vector3{
|
||||
public $level = null;
|
||||
|
||||
/**
|
||||
* @param int $x
|
||||
* @param int $y
|
||||
* @param int $z
|
||||
* @param Level $level
|
||||
* @param float|int $x
|
||||
* @param float|int $y
|
||||
* @param float|int $z
|
||||
* @param Level $level
|
||||
*/
|
||||
public function __construct($x = 0, $y = 0, $z = 0, Level $level = null){
|
||||
parent::__construct($x, $y, $z);
|
||||
|
@ -71,7 +71,7 @@ interface LevelProvider{
|
||||
* @param string $name
|
||||
* @param int $seed
|
||||
* @param string $generator
|
||||
* @param array[] $options
|
||||
* @param array $options
|
||||
*/
|
||||
public static function generate(string $path, string $name, int $seed, string $generator, array $options = []);
|
||||
|
||||
|
@ -26,6 +26,7 @@ namespace pocketmine\level\format\io\leveldb;
|
||||
use pocketmine\level\format\Chunk;
|
||||
use pocketmine\level\format\io\BaseLevelProvider;
|
||||
use pocketmine\level\format\io\ChunkUtils;
|
||||
use pocketmine\level\format\io\exception\CorruptedChunkException;
|
||||
use pocketmine\level\format\io\exception\UnsupportedChunkFormatException;
|
||||
use pocketmine\level\format\SubChunk;
|
||||
use pocketmine\level\generator\Flat;
|
||||
@ -33,12 +34,18 @@ use pocketmine\level\generator\GeneratorManager;
|
||||
use pocketmine\level\Level;
|
||||
use pocketmine\level\LevelException;
|
||||
use pocketmine\nbt\LittleEndianNBTStream;
|
||||
use pocketmine\nbt\tag\{ByteTag, CompoundTag, FloatTag, IntTag, LongTag, StringTag};
|
||||
use pocketmine\nbt\tag\ByteTag;
|
||||
use pocketmine\nbt\tag\CompoundTag;
|
||||
use pocketmine\nbt\tag\FloatTag;
|
||||
use pocketmine\nbt\tag\IntTag;
|
||||
use pocketmine\nbt\tag\LongTag;
|
||||
use pocketmine\nbt\tag\StringTag;
|
||||
use pocketmine\network\mcpe\protocol\ProtocolInfo;
|
||||
use pocketmine\utils\Binary;
|
||||
use pocketmine\utils\BinaryStream;
|
||||
use function array_values;
|
||||
use function chr;
|
||||
use function count;
|
||||
use function defined;
|
||||
use function explode;
|
||||
use function extension_loaded;
|
||||
@ -409,24 +416,27 @@ class LevelDB extends BaseLevelProvider{
|
||||
/** @var CompoundTag[] $entities */
|
||||
$entities = [];
|
||||
if(($entityData = $this->db->get($index . self::TAG_ENTITY)) !== false and $entityData !== ""){
|
||||
$entities = $nbt->read($entityData, true);
|
||||
if(!is_array($entities)){
|
||||
$entities = [$entities];
|
||||
}
|
||||
}
|
||||
|
||||
/** @var CompoundTag $entityNBT */
|
||||
foreach($entities as $entityNBT){
|
||||
if($entityNBT->hasTag("id", IntTag::class)){
|
||||
$entityNBT->setInt("id", $entityNBT->getInt("id") & 0xff); //remove type flags - TODO: use these instead of removing them)
|
||||
$entityTags = $nbt->read($entityData, true);
|
||||
foreach((is_array($entityTags) ? $entityTags : [$entityTags]) as $entityTag){
|
||||
if(!($entityTag instanceof CompoundTag)){
|
||||
throw new CorruptedChunkException("Entity root tag should be TAG_Compound");
|
||||
}
|
||||
if($entityTag->hasTag("id", IntTag::class)){
|
||||
$entityTag->setInt("id", $entityTag->getInt("id") & 0xff); //remove type flags - TODO: use these instead of removing them)
|
||||
}
|
||||
$entities[] = $entityTag;
|
||||
}
|
||||
}
|
||||
|
||||
/** @var CompoundTag[] $tiles */
|
||||
$tiles = [];
|
||||
if(($tileData = $this->db->get($index . self::TAG_BLOCK_ENTITY)) !== false and $tileData !== ""){
|
||||
$tiles = $nbt->read($tileData, true);
|
||||
if(!is_array($tiles)){
|
||||
$tiles = [$tiles];
|
||||
$tileTags = $nbt->read($tileData, true);
|
||||
foreach((is_array($tileTags) ? $tileTags : [$tileTags]) as $tileTag){
|
||||
if(!($tileTag instanceof CompoundTag)){
|
||||
throw new CorruptedChunkException("Tile root tag should be TAG_Compound");
|
||||
}
|
||||
$tiles[] = $tileTag;
|
||||
}
|
||||
}
|
||||
|
||||
@ -510,7 +520,7 @@ class LevelDB extends BaseLevelProvider{
|
||||
* @param string $index
|
||||
*/
|
||||
private function writeTags(array $targets, string $index){
|
||||
if(!empty($targets)){
|
||||
if(count($targets) > 0){
|
||||
$nbt = new LittleEndianNBTStream();
|
||||
$this->db->put($index, $nbt->write($targets));
|
||||
}else{
|
||||
|
@ -51,7 +51,7 @@ class Anvil extends McRegion{
|
||||
|
||||
$subChunks = [];
|
||||
foreach($chunk->getSubChunks() as $y => $subChunk){
|
||||
if($subChunk->isEmpty()){
|
||||
if(!($subChunk instanceof SubChunk) or $subChunk->isEmpty()){
|
||||
continue;
|
||||
}
|
||||
|
||||
@ -122,8 +122,8 @@ class Anvil extends McRegion{
|
||||
$chunk->getInt("xPos"),
|
||||
$chunk->getInt("zPos"),
|
||||
$subChunks,
|
||||
$chunk->hasTag("Entities", ListTag::class) ? $chunk->getListTag("Entities")->getValue() : [],
|
||||
$chunk->hasTag("TileEntities", ListTag::class) ? $chunk->getListTag("TileEntities")->getValue() : [],
|
||||
$chunk->hasTag("Entities", ListTag::class) ? self::getCompoundList("Entities", $chunk->getListTag("Entities")) : [],
|
||||
$chunk->hasTag("TileEntities", ListTag::class) ? self::getCompoundList("TileEntities", $chunk->getListTag("TileEntities")) : [],
|
||||
$biomeIds,
|
||||
$chunk->getIntArray("HeightMap", [])
|
||||
);
|
||||
|
@ -194,8 +194,8 @@ class McRegion extends BaseLevelProvider{
|
||||
$chunk->getInt("xPos"),
|
||||
$chunk->getInt("zPos"),
|
||||
$subChunks,
|
||||
$chunk->hasTag("Entities", ListTag::class) ? $chunk->getListTag("Entities")->getValue() : [],
|
||||
$chunk->hasTag("TileEntities", ListTag::class) ? $chunk->getListTag("TileEntities")->getValue() : [],
|
||||
$chunk->hasTag("Entities", ListTag::class) ? self::getCompoundList("Entities", $chunk->getListTag("Entities")) : [],
|
||||
$chunk->hasTag("TileEntities", ListTag::class) ? self::getCompoundList("TileEntities", $chunk->getListTag("TileEntities")) : [],
|
||||
$biomeIds,
|
||||
$heightMap
|
||||
);
|
||||
@ -205,6 +205,31 @@ class McRegion extends BaseLevelProvider{
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $context
|
||||
* @param ListTag $list
|
||||
*
|
||||
* @return CompoundTag[]
|
||||
* @throws CorruptedChunkException
|
||||
*/
|
||||
protected static function getCompoundList(string $context, ListTag $list) : array{
|
||||
if($list->count() === 0){ //empty lists might have wrong types, we don't care
|
||||
return [];
|
||||
}
|
||||
if($list->getTagType() !== NBT::TAG_Compound){
|
||||
throw new CorruptedChunkException("Expected TAG_List<TAG_Compound> for '$context'");
|
||||
}
|
||||
$result = [];
|
||||
foreach($list as $tag){
|
||||
if(!($tag instanceof CompoundTag)){
|
||||
//this should never happen, but it's still possible due to lack of native type safety
|
||||
throw new CorruptedChunkException("Expected TAG_List<TAG_Compound> for '$context'");
|
||||
}
|
||||
$result[] = $tag;
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
|
||||
public static function getProviderName() : string{
|
||||
return "mcregion";
|
||||
}
|
||||
|
@ -56,11 +56,9 @@ class PopulationTask extends AsyncTask{
|
||||
}
|
||||
|
||||
public function onRun(){
|
||||
/** @var SimpleChunkManager $manager */
|
||||
$manager = $this->getFromThreadStore("generation.level{$this->levelId}.manager");
|
||||
/** @var Generator $generator */
|
||||
$generator = $this->getFromThreadStore("generation.level{$this->levelId}.generator");
|
||||
if($manager === null or $generator === null){
|
||||
if(!($manager instanceof SimpleChunkManager) or !($generator instanceof Generator)){
|
||||
$this->state = false;
|
||||
return;
|
||||
}
|
||||
|
@ -29,7 +29,7 @@ use pocketmine\network\mcpe\protocol\DataPacket;
|
||||
abstract class Particle extends Vector3{
|
||||
|
||||
public const TYPE_BUBBLE = 1;
|
||||
//2 same as 1
|
||||
public const TYPE_BUBBLE_MANUAL = 2;
|
||||
public const TYPE_CRITICAL = 3;
|
||||
public const TYPE_BLOCK_FORCE_FIELD = 4;
|
||||
public const TYPE_SMOKE = 5;
|
||||
@ -40,56 +40,61 @@ abstract class Particle extends Vector3{
|
||||
public const TYPE_LARGE_SMOKE = 10;
|
||||
public const TYPE_REDSTONE = 11;
|
||||
public const TYPE_RISING_RED_DUST = 12;
|
||||
//62 same as 12
|
||||
public const TYPE_ITEM_BREAK = 13;
|
||||
public const TYPE_SNOWBALL_POOF = 14;
|
||||
public const TYPE_HUGE_EXPLODE = 15;
|
||||
//60 same as 15
|
||||
public const TYPE_HUGE_EXPLODE_SEED = 16;
|
||||
public const TYPE_MOB_FLAME = 17;
|
||||
public const TYPE_HEART = 18;
|
||||
public const TYPE_TERRAIN = 19;
|
||||
public const TYPE_SUSPENDED_TOWN = 20, TYPE_TOWN_AURA = 20;
|
||||
//61 same as 20
|
||||
public const TYPE_PORTAL = 21;
|
||||
//22 same as 21
|
||||
public const TYPE_SPLASH = 23, TYPE_WATER_SPLASH = 23;
|
||||
//24 same as 23
|
||||
public const TYPE_WATER_SPLASH_MANUAL = 24;
|
||||
public const TYPE_WATER_WAKE = 25;
|
||||
public const TYPE_DRIP_WATER = 26;
|
||||
public const TYPE_DRIP_LAVA = 27;
|
||||
public const TYPE_FALLING_DUST = 28, TYPE_DUST = 28;
|
||||
public const TYPE_MOB_SPELL = 29;
|
||||
public const TYPE_MOB_SPELL_AMBIENT = 30;
|
||||
public const TYPE_MOB_SPELL_INSTANTANEOUS = 31;
|
||||
public const TYPE_INK = 32;
|
||||
public const TYPE_SLIME = 33;
|
||||
public const TYPE_RAIN_SPLASH = 34;
|
||||
public const TYPE_VILLAGER_ANGRY = 35;
|
||||
//59 same as 35
|
||||
public const TYPE_VILLAGER_HAPPY = 36;
|
||||
public const TYPE_ENCHANTMENT_TABLE = 37;
|
||||
public const TYPE_TRACKING_EMITTER = 38;
|
||||
public const TYPE_NOTE = 39;
|
||||
public const TYPE_WITCH_SPELL = 40;
|
||||
public const TYPE_CARROT = 41;
|
||||
//42 unknown
|
||||
public const TYPE_END_ROD = 43;
|
||||
//58 same as 43
|
||||
public const TYPE_DRAGONS_BREATH = 44;
|
||||
public const TYPE_SPIT = 45;
|
||||
public const TYPE_TOTEM = 46;
|
||||
public const TYPE_FOOD = 47;
|
||||
public const TYPE_FIREWORKS_STARTER = 48;
|
||||
public const TYPE_FIREWORKS_SPARK = 49;
|
||||
public const TYPE_FIREWORKS_OVERLAY = 50;
|
||||
public const TYPE_BALLOON_GAS = 51;
|
||||
public const TYPE_COLORED_FLAME = 52;
|
||||
public const TYPE_SPARKLER = 53;
|
||||
public const TYPE_CONDUIT = 54;
|
||||
public const TYPE_BUBBLE_COLUMN_UP = 55;
|
||||
public const TYPE_BUBBLE_COLUMN_DOWN = 56;
|
||||
public const TYPE_SNEEZE = 57;
|
||||
public const TYPE_DRIP_HONEY = 28;
|
||||
public const TYPE_FALLING_DUST = 29, TYPE_DUST = 29;
|
||||
public const TYPE_MOB_SPELL = 30;
|
||||
public const TYPE_MOB_SPELL_AMBIENT = 31;
|
||||
public const TYPE_MOB_SPELL_INSTANTANEOUS = 32;
|
||||
public const TYPE_INK = 33;
|
||||
public const TYPE_SLIME = 34;
|
||||
public const TYPE_RAIN_SPLASH = 35;
|
||||
public const TYPE_VILLAGER_ANGRY = 36;
|
||||
public const TYPE_VILLAGER_HAPPY = 37;
|
||||
public const TYPE_ENCHANTMENT_TABLE = 38;
|
||||
public const TYPE_TRACKING_EMITTER = 39;
|
||||
public const TYPE_NOTE = 40;
|
||||
public const TYPE_WITCH_SPELL = 41;
|
||||
public const TYPE_CARROT = 42;
|
||||
public const TYPE_MOB_APPEARANCE = 43;
|
||||
public const TYPE_END_ROD = 44;
|
||||
public const TYPE_DRAGONS_BREATH = 45;
|
||||
public const TYPE_SPIT = 46;
|
||||
public const TYPE_TOTEM = 47;
|
||||
public const TYPE_FOOD = 48;
|
||||
public const TYPE_FIREWORKS_STARTER = 49;
|
||||
public const TYPE_FIREWORKS_SPARK = 50;
|
||||
public const TYPE_FIREWORKS_OVERLAY = 51;
|
||||
public const TYPE_BALLOON_GAS = 52;
|
||||
public const TYPE_COLORED_FLAME = 53;
|
||||
public const TYPE_SPARKLER = 54;
|
||||
public const TYPE_CONDUIT = 55;
|
||||
public const TYPE_BUBBLE_COLUMN_UP = 56;
|
||||
public const TYPE_BUBBLE_COLUMN_DOWN = 57;
|
||||
public const TYPE_SNEEZE = 58;
|
||||
public const TYPE_SHULKER_BULLET = 59;
|
||||
public const TYPE_BLEACH = 60;
|
||||
public const TYPE_DRAGON_DESTROY_BLOCK = 61;
|
||||
public const TYPE_MYCELIUM_DUST = 62;
|
||||
public const TYPE_FALLING_RED_DUST = 63;
|
||||
public const TYPE_CAMPFIRE_SMOKE = 64;
|
||||
public const TYPE_TALL_CAMPFIRE_SMOKE = 65;
|
||||
public const TYPE_DRAGON_BREATH_FIRE = 66;
|
||||
public const TYPE_DRAGON_BREATH_TRAIL = 67;
|
||||
|
||||
/**
|
||||
* @return DataPacket|DataPacket[]
|
||||
|
@ -35,7 +35,7 @@ class CompressBatchedTask extends AsyncTask{
|
||||
|
||||
/**
|
||||
* @param BatchPacket $batch
|
||||
* @param string[] $targets
|
||||
* @param Player[] $targets
|
||||
*/
|
||||
public function __construct(BatchPacket $batch, array $targets){
|
||||
$this->data = $batch->payload;
|
||||
|
@ -38,9 +38,9 @@ use pocketmine\nbt\tag\CompoundTag;
|
||||
use pocketmine\nbt\tag\IntTag;
|
||||
use pocketmine\network\mcpe\protocol\types\CommandOriginData;
|
||||
use pocketmine\network\mcpe\protocol\types\EntityLink;
|
||||
use pocketmine\network\mcpe\protocol\types\SkinAnimation;
|
||||
use pocketmine\network\mcpe\protocol\types\SkinData;
|
||||
use pocketmine\network\mcpe\protocol\types\SkinImage;
|
||||
use pocketmine\network\mcpe\protocol\types\SkinAnimation;
|
||||
use pocketmine\network\mcpe\protocol\types\StructureSettings;
|
||||
use pocketmine\utils\BinaryStream;
|
||||
use pocketmine\utils\UUID;
|
||||
|
@ -67,7 +67,6 @@ use pocketmine\network\mcpe\protocol\ShowCreditsPacket;
|
||||
use pocketmine\network\mcpe\protocol\SpawnExperienceOrbPacket;
|
||||
use pocketmine\network\mcpe\protocol\TextPacket;
|
||||
use pocketmine\network\mcpe\protocol\types\SkinAdapterSingleton;
|
||||
use pocketmine\network\mcpe\protocol\types\SkinData;
|
||||
use pocketmine\Player;
|
||||
use pocketmine\Server;
|
||||
use pocketmine\timings\Timings;
|
||||
|
@ -37,6 +37,7 @@ use function openssl_verify;
|
||||
use function ord;
|
||||
use function str_split;
|
||||
use function strlen;
|
||||
use function strtr;
|
||||
use function time;
|
||||
use function wordwrap;
|
||||
use const OPENSSL_ALGO_SHA384;
|
||||
|
@ -26,7 +26,6 @@ namespace pocketmine\network\mcpe\protocol;
|
||||
#include <rules/DataPacket.h>
|
||||
|
||||
use pocketmine\network\mcpe\NetworkSession;
|
||||
use function base64_decode;
|
||||
use function file_get_contents;
|
||||
|
||||
class AvailableActorIdentifiersPacket extends DataPacket{
|
||||
|
@ -31,6 +31,7 @@ use pocketmine\network\mcpe\protocol\types\CommandEnum;
|
||||
use pocketmine\network\mcpe\protocol\types\CommandEnumConstraint;
|
||||
use pocketmine\network\mcpe\protocol\types\CommandParameter;
|
||||
use pocketmine\utils\BinaryDataException;
|
||||
use function array_search;
|
||||
use function count;
|
||||
use function dechex;
|
||||
|
||||
|
@ -23,6 +23,8 @@ declare(strict_types=1);
|
||||
|
||||
namespace pocketmine\network\mcpe\protocol;
|
||||
|
||||
#include <rules/DataPacket.h>
|
||||
|
||||
use pocketmine\network\mcpe\NetworkSession;
|
||||
|
||||
class CompletedUsingItemPacket extends DataPacket{
|
||||
|
@ -85,7 +85,7 @@ class PlayerAuthInputPacket extends DataPacket/* implements ServerboundPacket*/{
|
||||
$result->inputMode = $inputMode;
|
||||
$result->playMode = $playMode;
|
||||
if($vrGazeDirection !== null){
|
||||
$this->vrGazeDirection = $vrGazeDirection->asVector3();
|
||||
$result->vrGazeDirection = $vrGazeDirection->asVector3();
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
|
@ -27,7 +27,6 @@ namespace pocketmine\network\mcpe\protocol;
|
||||
|
||||
|
||||
use pocketmine\network\mcpe\NetworkSession;
|
||||
use pocketmine\network\mcpe\protocol\types\SkinData;
|
||||
use pocketmine\network\mcpe\protocol\types\PlayerListEntry;
|
||||
use function count;
|
||||
|
||||
|
@ -39,15 +39,15 @@ interface ProtocolInfo{
|
||||
/**
|
||||
* Actual Minecraft: PE protocol version
|
||||
*/
|
||||
public const CURRENT_PROTOCOL = 388;
|
||||
public const CURRENT_PROTOCOL = 389;
|
||||
/**
|
||||
* Current Minecraft PE version reported by the server. This is usually the earliest currently supported version.
|
||||
*/
|
||||
public const MINECRAFT_VERSION = 'v1.13.0';
|
||||
public const MINECRAFT_VERSION = 'v1.14.0';
|
||||
/**
|
||||
* Version number sent to clients in ping responses.
|
||||
*/
|
||||
public const MINECRAFT_VERSION_NETWORK = '1.13.0';
|
||||
public const MINECRAFT_VERSION_NETWORK = '1.14.0';
|
||||
|
||||
public const LOGIN_PACKET = 0x01;
|
||||
public const PLAY_STATUS_PACKET = 0x02;
|
||||
|
@ -28,7 +28,6 @@ namespace pocketmine\network\mcpe\protocol;
|
||||
|
||||
|
||||
use pocketmine\network\mcpe\NetworkSession;
|
||||
use function strlen;
|
||||
|
||||
class ResourcePackChunkDataPacket extends DataPacket{
|
||||
public const NETWORK_ID = ProtocolInfo::RESOURCE_PACK_CHUNK_DATA_PACKET;
|
||||
|
@ -28,9 +28,7 @@ namespace pocketmine\network\mcpe\protocol;
|
||||
|
||||
use pocketmine\math\Vector3;
|
||||
use pocketmine\nbt\NetworkLittleEndianNBTStream;
|
||||
use pocketmine\nbt\tag\CompoundTag;
|
||||
use pocketmine\nbt\tag\ListTag;
|
||||
use pocketmine\nbt\tag\StringTag;
|
||||
use pocketmine\network\mcpe\NetworkBinaryStream;
|
||||
use pocketmine\network\mcpe\NetworkSession;
|
||||
use pocketmine\network\mcpe\protocol\types\PlayerPermissions;
|
||||
|
@ -27,14 +27,16 @@ use pocketmine\entity\Skin;
|
||||
|
||||
use function is_array;
|
||||
use function is_string;
|
||||
use function json_decode;
|
||||
use function json_encode;
|
||||
use function random_bytes;
|
||||
use function str_repeat;
|
||||
|
||||
class LegacySkinAdapter implements SkinAdapter{
|
||||
|
||||
public function toSkinData(Skin $skin) : SkinData{
|
||||
$capeData = new SkinImage(32, 64, $skin->getCapeData());
|
||||
if($skin->getCapeData() === ""){
|
||||
$capeData = new SkinImage(0, 0, $skin->getCapeData());
|
||||
}
|
||||
$capeData = $skin->getCapeData();
|
||||
$capeImage = $capeData === "" ? new SkinImage(0, 0, "") : new SkinImage(32, 64, $capeData);
|
||||
$geometryName = $skin->getGeometryName();
|
||||
if($geometryName === ""){
|
||||
$geometryName = "geometry.humanoid.custom";
|
||||
@ -43,13 +45,18 @@ class LegacySkinAdapter implements SkinAdapter{
|
||||
$skin->getSkinId(),
|
||||
json_encode(["geometry" => ["default" => $geometryName]]),
|
||||
SkinImage::fromLegacy($skin->getSkinData()), [],
|
||||
$capeData,
|
||||
$capeImage,
|
||||
$skin->getGeometryData()
|
||||
);
|
||||
}
|
||||
|
||||
public function fromSkinData(SkinData $data) : Skin{
|
||||
$capeData = $data->getCapeImage()->getData();
|
||||
if($data->isPersona()){
|
||||
return new Skin("Standard_Custom", str_repeat(random_bytes(3) . "\xff", 2048));
|
||||
}
|
||||
|
||||
$capeData = $data->isPersonaCapeOnClassic() ? "" : $data->getCapeImage()->getData();
|
||||
|
||||
$geometryName = "";
|
||||
$resourcePatch = json_decode($data->getResourcePatch(), true);
|
||||
if(is_array($resourcePatch["geometry"]) && is_string($resourcePatch["geometry"]["default"])){
|
||||
@ -57,11 +64,7 @@ class LegacySkinAdapter implements SkinAdapter{
|
||||
}else{
|
||||
//TODO: Kick for invalid skin
|
||||
}
|
||||
if($data->isPersona()){
|
||||
return new Skin("Standard_Custom", str_repeat(random_bytes(3) . "\xff", 2048));
|
||||
}elseif($data->isPersonaCapeOnClassic()){
|
||||
$capeData = "";
|
||||
}
|
||||
|
||||
return new Skin($data->getSkinId(), $data->getSkinImage()->getData(), $capeData, $geometryName, $data->getGeometryData());
|
||||
}
|
||||
}
|
||||
|
@ -48,18 +48,12 @@ class NetworkInventoryAction{
|
||||
*
|
||||
* Expect these to change in the future.
|
||||
*/
|
||||
public const SOURCE_TYPE_CRAFTING_ADD_INGREDIENT = -2;
|
||||
public const SOURCE_TYPE_CRAFTING_REMOVE_INGREDIENT = -3;
|
||||
public const SOURCE_TYPE_CRAFTING_RESULT = -4;
|
||||
public const SOURCE_TYPE_CRAFTING_USE_INGREDIENT = -5;
|
||||
|
||||
public const SOURCE_TYPE_ANVIL_INPUT = -10;
|
||||
public const SOURCE_TYPE_ANVIL_MATERIAL = -11;
|
||||
public const SOURCE_TYPE_ANVIL_RESULT = -12;
|
||||
public const SOURCE_TYPE_ANVIL_OUTPUT = -13;
|
||||
|
||||
public const SOURCE_TYPE_ENCHANT_INPUT = -15;
|
||||
public const SOURCE_TYPE_ENCHANT_MATERIAL = -16;
|
||||
public const SOURCE_TYPE_ENCHANT_OUTPUT = -17;
|
||||
|
||||
public const SOURCE_TYPE_TRADING_INPUT_1 = -20;
|
||||
@ -69,9 +63,6 @@ class NetworkInventoryAction{
|
||||
|
||||
public const SOURCE_TYPE_BEACON = -24;
|
||||
|
||||
/** Any client-side window dropping its contents when the player closes it */
|
||||
public const SOURCE_TYPE_CONTAINER_DROP_CONTENTS = -100;
|
||||
|
||||
public const ACTION_MAGIC_SLOT_CREATIVE_DELETE_ITEM = 0;
|
||||
public const ACTION_MAGIC_SLOT_CREATIVE_CREATE_ITEM = 1;
|
||||
|
||||
@ -214,10 +205,6 @@ class NetworkInventoryAction{
|
||||
case self::SOURCE_TODO:
|
||||
//These types need special handling.
|
||||
switch($this->windowId){
|
||||
case self::SOURCE_TYPE_CRAFTING_ADD_INGREDIENT:
|
||||
case self::SOURCE_TYPE_CRAFTING_REMOVE_INGREDIENT:
|
||||
case self::SOURCE_TYPE_CONTAINER_DROP_CONTENTS: //TODO: this type applies to all fake windows, not just crafting
|
||||
return new SlotChangeAction($player->getCraftingGrid(), $this->inventorySlot, $this->oldItem, $this->newItem);
|
||||
case self::SOURCE_TYPE_CRAFTING_RESULT:
|
||||
case self::SOURCE_TYPE_CRAFTING_USE_INGREDIENT:
|
||||
return null;
|
||||
|
@ -23,7 +23,6 @@ declare(strict_types=1);
|
||||
|
||||
namespace pocketmine\network\mcpe\protocol\types;
|
||||
|
||||
use pocketmine\entity\Skin;
|
||||
use pocketmine\utils\UUID;
|
||||
|
||||
class PlayerListEntry{
|
||||
|
@ -28,8 +28,6 @@ use pocketmine\nbt\NBT;
|
||||
use pocketmine\nbt\NetworkLittleEndianNBTStream;
|
||||
use pocketmine\nbt\tag\CompoundTag;
|
||||
use pocketmine\nbt\tag\ListTag;
|
||||
use pocketmine\nbt\tag\StringTag;
|
||||
use pocketmine\utils\BinaryDataException;
|
||||
use function file_get_contents;
|
||||
use function getmypid;
|
||||
use function json_decode;
|
||||
|
@ -25,7 +25,7 @@ namespace pocketmine\network\mcpe\protocol\types;
|
||||
|
||||
/**
|
||||
* Accessor for SkinAdapter
|
||||
*/
|
||||
*/
|
||||
class SkinAdapterSingleton{
|
||||
/** @var SkinAdapter|null */
|
||||
private static $skinAdapter = null;
|
||||
|
@ -22,6 +22,7 @@
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace pocketmine\network\mcpe\protocol\types;
|
||||
use function strlen;
|
||||
|
||||
class SkinImage{
|
||||
|
||||
@ -33,6 +34,9 @@ class SkinImage{
|
||||
private $data;
|
||||
|
||||
public function __construct(int $height, int $width, string $data){
|
||||
if(($expected = $height * $width * 4) !== ($actual = strlen($data))){
|
||||
throw new \InvalidArgumentException("Data should be exactly $expected bytes, got $actual bytes");
|
||||
}
|
||||
$this->height = $height;
|
||||
$this->width = $width;
|
||||
$this->data = $data;
|
||||
|
@ -24,6 +24,7 @@ declare(strict_types=1);
|
||||
namespace pocketmine\permission;
|
||||
|
||||
use function array_shift;
|
||||
use function count;
|
||||
use function explode;
|
||||
use function implode;
|
||||
use function strlen;
|
||||
@ -136,10 +137,10 @@ class BanEntry{
|
||||
/**
|
||||
* @param string $date
|
||||
*
|
||||
* @return \DateTime|null
|
||||
* @return \DateTime
|
||||
* @throws \RuntimeException
|
||||
*/
|
||||
private static function parseDate(string $date) : ?\DateTime{
|
||||
private static function parseDate(string $date) : \DateTime{
|
||||
$datetime = \DateTime::createFromFormat(self::$format, $date);
|
||||
if(!($datetime instanceof \DateTime)){
|
||||
throw new \RuntimeException("Error parsing date for BanEntry: " . implode(", ", \DateTime::getLastErrors()["errors"]));
|
||||
@ -161,17 +162,17 @@ class BanEntry{
|
||||
$str = explode("|", trim($str));
|
||||
$entry = new BanEntry(trim(array_shift($str)));
|
||||
do{
|
||||
if(empty($str)){
|
||||
if(count($str) === 0){
|
||||
break;
|
||||
}
|
||||
|
||||
$entry->setCreated(self::parseDate(array_shift($str)));
|
||||
if(empty($str)){
|
||||
if(count($str) === 0){
|
||||
break;
|
||||
}
|
||||
|
||||
$entry->setSource(trim(array_shift($str)));
|
||||
if(empty($str)){
|
||||
if(count($str) === 0){
|
||||
break;
|
||||
}
|
||||
|
||||
@ -179,7 +180,7 @@ class BanEntry{
|
||||
if($expire !== "" and strtolower($expire) !== "forever"){
|
||||
$entry->setExpires(self::parseDate($expire));
|
||||
}
|
||||
if(empty($str)){
|
||||
if(count($str) === 0){
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -168,7 +168,7 @@ class PermissionManager{
|
||||
public function unsubscribeFromAllPermissions(Permissible $permissible) : void{
|
||||
foreach($this->permSubs as $permission => &$subs){
|
||||
unset($subs[spl_object_hash($permissible)]);
|
||||
if(empty($subs)){
|
||||
if(count($subs) === 0){
|
||||
unset($this->permSubs[$permission]);
|
||||
}
|
||||
}
|
||||
|
@ -38,6 +38,7 @@ use function strlen;
|
||||
use function strtoupper;
|
||||
use function substr;
|
||||
use function version_compare;
|
||||
use function yaml_parse;
|
||||
|
||||
class PluginDescription{
|
||||
private $map;
|
||||
|
@ -40,6 +40,7 @@ use pocketmine\timings\TimingsHandler;
|
||||
use pocketmine\utils\Utils;
|
||||
use function array_intersect;
|
||||
use function array_map;
|
||||
use function array_merge;
|
||||
use function array_pad;
|
||||
use function class_exists;
|
||||
use function count;
|
||||
|
@ -34,6 +34,7 @@ use function filesize;
|
||||
use function fopen;
|
||||
use function fread;
|
||||
use function fseek;
|
||||
use function gettype;
|
||||
use function hash_file;
|
||||
use function implode;
|
||||
|
||||
|
Submodule src/pocketmine/resources/vanilla updated: a38b427888...cc132c80dd
@ -38,6 +38,7 @@ use pocketmine\level\Level;
|
||||
use pocketmine\nbt\tag\CompoundTag;
|
||||
use pocketmine\network\mcpe\protocol\ContainerSetDataPacket;
|
||||
use function ceil;
|
||||
use function count;
|
||||
use function max;
|
||||
|
||||
class Furnace extends Spawnable implements InventoryHolder, Container, Nameable{
|
||||
@ -232,7 +233,7 @@ class Furnace extends Spawnable implements InventoryHolder, Container, Nameable{
|
||||
$packets[] = $pk;
|
||||
}
|
||||
|
||||
if(!empty($packets)){
|
||||
if(count($packets) > 0){
|
||||
foreach($this->getInventory()->getViewers() as $player){
|
||||
$windowId = $player->getWindowId($this->getInventory());
|
||||
if($windowId > 0){
|
||||
|
@ -31,6 +31,8 @@ use pocketmine\tile\Tile;
|
||||
use function dechex;
|
||||
|
||||
abstract class Timings{
|
||||
/** @var bool */
|
||||
private static $initialized = false;
|
||||
|
||||
/** @var TimingsHandler */
|
||||
public static $fullTickTimer;
|
||||
@ -104,9 +106,10 @@ abstract class Timings{
|
||||
public static $pluginTaskTimingMap = [];
|
||||
|
||||
public static function init(){
|
||||
if(self::$serverTickTimer instanceof TimingsHandler){
|
||||
if(self::$initialized){
|
||||
return;
|
||||
}
|
||||
self::$initialized = true;
|
||||
|
||||
self::$fullTickTimer = new TimingsHandler("Full Server Tick");
|
||||
self::$serverTickTimer = new TimingsHandler("** Full Server Tick", self::$fullTickTimer);
|
||||
|
@ -158,29 +158,45 @@ class TimingsHandler{
|
||||
}
|
||||
|
||||
public function startTiming(){
|
||||
if(self::$enabled and ++$this->timingDepth === 1){
|
||||
$this->start = microtime(true);
|
||||
if($this->parent !== null and ++$this->parent->timingDepth === 1){
|
||||
$this->parent->start = $this->start;
|
||||
if(self::$enabled){
|
||||
$this->internalStartTiming(microtime(true));
|
||||
}
|
||||
}
|
||||
|
||||
private function internalStartTiming(float $now) : void{
|
||||
if(++$this->timingDepth === 1){
|
||||
$this->start = $now;
|
||||
if($this->parent !== null){
|
||||
$this->parent->internalStartTiming($now);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function stopTiming(){
|
||||
if(self::$enabled){
|
||||
if(--$this->timingDepth !== 0 or $this->start === 0){
|
||||
return;
|
||||
}
|
||||
$this->internalStopTiming(microtime(true));
|
||||
}
|
||||
}
|
||||
|
||||
$diff = microtime(true) - $this->start;
|
||||
$this->totalTime += $diff;
|
||||
$this->curTickTotal += $diff;
|
||||
++$this->curCount;
|
||||
++$this->count;
|
||||
$this->start = 0;
|
||||
if($this->parent !== null){
|
||||
$this->parent->stopTiming();
|
||||
}
|
||||
private function internalStopTiming(float $now) : void{
|
||||
if($this->timingDepth === 0){
|
||||
//TODO: it would be nice to bail here, but since we'd have to track timing depth across resets
|
||||
//and enable/disable, it would have a performance impact. Therefore, considering the limited
|
||||
//usefulness of bailing here anyway, we don't currently bother.
|
||||
return;
|
||||
}
|
||||
if(--$this->timingDepth !== 0 or $this->start == 0){
|
||||
return;
|
||||
}
|
||||
|
||||
$diff = $now - $this->start;
|
||||
$this->totalTime += $diff;
|
||||
$this->curTickTotal += $diff;
|
||||
++$this->curCount;
|
||||
++$this->count;
|
||||
$this->start = 0;
|
||||
if($this->parent !== null){
|
||||
$this->parent->internalStopTiming($now);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -420,7 +420,7 @@ class Config{
|
||||
while(count($vars) > 0){
|
||||
$nodeName = array_shift($vars);
|
||||
if(isset($currentNode[$nodeName])){
|
||||
if(empty($vars)){ //final node
|
||||
if(count($vars) === 0){ //final node
|
||||
unset($currentNode[$nodeName]);
|
||||
}elseif(is_array($currentNode[$nodeName])){
|
||||
$currentNode =& $currentNode[$nodeName];
|
||||
|
70
src/pocketmine/utils/Git.php
Normal file
70
src/pocketmine/utils/Git.php
Normal file
@ -0,0 +1,70 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
*
|
||||
* ____ _ _ __ __ _ __ __ ____
|
||||
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
|
||||
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
|
||||
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
|
||||
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* @author PocketMine Team
|
||||
* @link http://www.pocketmine.net/
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace pocketmine\utils;
|
||||
|
||||
use function str_repeat;
|
||||
use function strlen;
|
||||
use function trim;
|
||||
|
||||
final class Git{
|
||||
|
||||
private function __construct(){
|
||||
//NOOP
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the git hash of the currently checked out head of the given repository, or null on failure.
|
||||
*
|
||||
* @param string $dir
|
||||
* @param bool &$dirty Output, set to whether the repo has local changes
|
||||
*
|
||||
* @return string|null
|
||||
*/
|
||||
public static function getRepositoryState(string $dir, bool &$dirty) : ?string{
|
||||
if(Utils::execute("git -C \"$dir\" rev-parse HEAD", $out) === 0 and $out !== false and strlen($out = trim($out)) === 40){
|
||||
if(Utils::execute("git -C \"$dir\" diff --quiet") === 1 or Utils::execute("git -C \"$dir\" diff --cached --quiet") === 1){ //Locally-modified
|
||||
$dirty = true;
|
||||
}
|
||||
return $out;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Infallible, returns a string representing git state, or a string of zeros on failure.
|
||||
* If the repo is dirty, a "-dirty" suffix is added.
|
||||
*
|
||||
* @param string $dir
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function getRepositoryStatePretty(string $dir) : string{
|
||||
$dirty = false;
|
||||
$detectedHash = self::getRepositoryState($dir, $dirty);
|
||||
if($detectedHash !== null){
|
||||
return $detectedHash . ($dirty ? "-dirty" : "");
|
||||
}
|
||||
return str_repeat("00", 20);
|
||||
}
|
||||
}
|
@ -33,6 +33,7 @@ use function implode;
|
||||
use function ini_get;
|
||||
use function ini_set;
|
||||
use function is_link;
|
||||
use function is_string;
|
||||
use function json_decode;
|
||||
use function parse_ini_file;
|
||||
use function preg_match;
|
||||
@ -149,7 +150,7 @@ abstract class Timezone{
|
||||
// RHEL / CentOS
|
||||
if(file_exists('/etc/sysconfig/clock')){
|
||||
$data = parse_ini_file('/etc/sysconfig/clock');
|
||||
if(!empty($data['ZONE'])){
|
||||
if(isset($data['ZONE']) and is_string($data['ZONE'])){
|
||||
return trim($data['ZONE']);
|
||||
}
|
||||
}
|
||||
|
@ -58,6 +58,7 @@ use function is_object;
|
||||
use function is_readable;
|
||||
use function is_string;
|
||||
use function json_decode;
|
||||
use function ltrim;
|
||||
use function memory_get_usage;
|
||||
use function ob_end_clean;
|
||||
use function ob_get_contents;
|
||||
@ -72,6 +73,7 @@ use function preg_match_all;
|
||||
use function preg_replace;
|
||||
use function proc_close;
|
||||
use function proc_open;
|
||||
use function rtrim;
|
||||
use function sha1;
|
||||
use function spl_object_hash;
|
||||
use function str_pad;
|
||||
@ -82,6 +84,7 @@ use function stripos;
|
||||
use function strlen;
|
||||
use function strpos;
|
||||
use function strtolower;
|
||||
use function strtr;
|
||||
use function substr;
|
||||
use function sys_get_temp_dir;
|
||||
use function trim;
|
||||
|
@ -33,6 +33,7 @@ use pocketmine\utils\Config;
|
||||
use pocketmine\utils\Internet;
|
||||
use pocketmine\utils\InternetException;
|
||||
use function base64_encode;
|
||||
use function count;
|
||||
use function fgets;
|
||||
use function random_bytes;
|
||||
use function sleep;
|
||||
@ -59,7 +60,7 @@ class SetupWizard{
|
||||
$this->message(\pocketmine\NAME . " set-up wizard");
|
||||
|
||||
$langs = BaseLang::getLanguageList();
|
||||
if(empty($langs)){
|
||||
if(count($langs) === 0){
|
||||
$this->error("No language files found, please use provided builds or clone the repository recursively.");
|
||||
return false;
|
||||
}
|
||||
|
@ -1,35 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
PHP_BINARY="php"
|
||||
DIR=""
|
||||
FIND="find"
|
||||
|
||||
while getopts "p:d:f:" OPTION 2> /dev/null; do
|
||||
case ${OPTION} in
|
||||
p)
|
||||
PHP_BINARY="$OPTARG"
|
||||
;;
|
||||
d)
|
||||
DIR="$OPTARG"
|
||||
;;
|
||||
f)
|
||||
FIND="$OPTARG"
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
if [ "$DIR" == "" ]; then
|
||||
echo No directory specified
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo Running PHP lint scans on \"$DIR\"...
|
||||
|
||||
OUTPUT=`$FIND "$DIR" -name "*.php" -print0 | xargs -0 -n1 -P4 "$PHP_BINARY" -l`
|
||||
|
||||
if [ $? -ne 0 ]; then
|
||||
echo $OUTPUT | grep -v "No syntax errors"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo Lint scan completed successfully.
|
@ -27,7 +27,28 @@ parameters:
|
||||
path: ../../../src/pocketmine/MemoryManager.php
|
||||
|
||||
-
|
||||
message: "#^Array \\(array\\) does not accept key int\\.$#"
|
||||
message: "#^Comparison operation \"\\>\\=\" between 0 and 2 is always false\\.$#"
|
||||
count: 1
|
||||
path: ../../../src/pocketmine/plugin/PluginDescription.php
|
||||
path: ../../../src/pocketmine/block/Liquid.php
|
||||
|
||||
-
|
||||
#adjacentSources comparison FP
|
||||
message: "#^If condition is always false\\.$#"
|
||||
count: 1
|
||||
path: ../../../src/pocketmine/block/Liquid.php
|
||||
|
||||
-
|
||||
#$class::NETWORK_ID false positive
|
||||
message: "#^Strict comparison using \\!\\=\\= between \\-1 and \\-1 will always evaluate to false\\.$#"
|
||||
count: 1
|
||||
path: ../../../src/pocketmine/entity/Entity.php
|
||||
|
||||
-
|
||||
message: "#^Call to function assert\\(\\) with false and 'unknown hit type' will always evaluate to false\\.$#"
|
||||
count: 1
|
||||
path: ../../../src/pocketmine/entity/projectile/Projectile.php
|
||||
|
||||
-
|
||||
message: "#^Strict comparison using \\=\\=\\= between int\\<1, max\\> and 0 will always evaluate to false\\.$#"
|
||||
count: 1
|
||||
path: ../../../src/pocketmine/utils/Config.php
|
||||
|
31
tests/phpstan/configs/runtime-type-checks.neon
Normal file
31
tests/phpstan/configs/runtime-type-checks.neon
Normal file
@ -0,0 +1,31 @@
|
||||
parameters:
|
||||
ignoreErrors:
|
||||
-
|
||||
#::add() / ::remove() thread parameter
|
||||
message: "#^If condition is always true\\.$#"
|
||||
count: 2
|
||||
path: ../../../src/pocketmine/ThreadManager.php
|
||||
|
||||
-
|
||||
#::get() tags parameter
|
||||
message: "#^If condition is always false\\.$#"
|
||||
count: 1
|
||||
path: ../../../src/pocketmine/item/ItemFactory.php
|
||||
|
||||
-
|
||||
#::get() tags parameter
|
||||
message: "#^Strict comparison using \\!\\=\\= between null and null will always evaluate to false\\.$#"
|
||||
count: 1
|
||||
path: ../../../src/pocketmine/item/ItemFactory.php
|
||||
|
||||
-
|
||||
#::get() tags parameter
|
||||
message: "#^Else branch is unreachable because ternary operator condition is always true\\.$#"
|
||||
count: 1
|
||||
path: ../../../src/pocketmine/item/ItemFactory.php
|
||||
|
||||
-
|
||||
#->sendBlocks() blocks parameter
|
||||
message: "#^Else branch is unreachable because ternary operator condition is always true\\.$#"
|
||||
count: 2
|
||||
path: ../../../src/pocketmine/level/Level.php
|
@ -14,14 +14,7 @@ while getopts "p:t:" OPTION 2> /dev/null; do
|
||||
esac
|
||||
done
|
||||
|
||||
./tests/lint.sh -p "$PHP_BINARY" -d ./src/pocketmine
|
||||
|
||||
if [ $? -ne 0 ]; then
|
||||
echo Lint scan failed!
|
||||
exit 1
|
||||
fi
|
||||
|
||||
[ ! -f phpstan.phar ] && echo "Downloading PHPStan..." && curl -sSLO https://github.com/phpstan/phpstan/releases/download/0.12.0/phpstan.phar
|
||||
[ ! -f phpstan.phar ] && echo "Downloading PHPStan..." && curl -sSLO https://github.com/phpstan/phpstan/releases/download/0.12.3/phpstan.phar
|
||||
"$PHP_BINARY" phpstan.phar analyze --no-progress --memory-limit=2G || exit 1
|
||||
echo "PHPStan scan succeeded"
|
||||
|
||||
@ -39,7 +32,7 @@ cd tests/plugins/PocketMine-DevTools
|
||||
"$PHP_BINARY" -dphar.readonly=0 ./src/DevTools/ConsoleScript.php --make ./ --relative ./ --out ../../../DevTools.phar
|
||||
cd ../../..
|
||||
|
||||
"$PHP_BINARY" -dphar.readonly=0 DevTools.phar --make src,vendor --relative ./ --entry src/pocketmine/PocketMine.php --out PocketMine-MP.phar
|
||||
"$PHP_BINARY" -dphar.readonly=0 ./build/server-phar.php ./PocketMine-MP.phar
|
||||
if [ -f PocketMine-MP.phar ]; then
|
||||
echo Server phar created successfully.
|
||||
else
|
||||
|
Reference in New Issue
Block a user