Compare commits

..

146 Commits

Author SHA1 Message Date
13f28d8454 Release 3.11.4 2020-01-20 18:06:46 +00:00
5a97c378fc phpstan: green on level 6, minus iterable types
iterable types are a big pain in the ass because of pthreads' awful architecture, and there's nothing I can do about that without BC-breaking changes to pthreads.
2020-01-20 17:54:55 +00:00
e5d62ec901 phpstan 0.12.6 2020-01-20 17:26:48 +00:00
cfd975009e Leaves: fix decay performance issue
this code was written with references in mind, but it looks like someone forgot the reference.
2020-01-20 11:52:11 +00:00
73257ffde7 updated pocketmine/spl dependency 2020-01-19 19:50:20 +00:00
8252bea699 phpstan: enable MissingMethodReturnTypehintRule
this was a bitch of a job, but it's one step closer to bypassing level 6.
2020-01-19 19:43:52 +00:00
ea935a1af5 pocketmine root: sweep missing return type information 2020-01-19 19:40:01 +00:00
e8a5fa8a37 updater: populate missing return type information 2020-01-19 19:38:41 +00:00
db734675d8 level: populate missing interface return types 2020-01-19 19:38:09 +00:00
6ede56015d level/biome: populate missing return type information 2020-01-19 19:37:08 +00:00
5334099fbf level/format: populate missing return type information 2020-01-19 19:36:34 +00:00
82e9072223 level/format/io: populate missing return type information 2020-01-19 19:35:45 +00:00
2c11742f9e Player: populate missing type information 2020-01-19 19:16:38 +00:00
bd4a63b668 Server: populate missing return type information 2020-01-19 19:09:08 +00:00
cd36af46bf Level: populate missing type information 2020-01-19 18:44:41 +00:00
aa7d55e21d level/generator: populate missing return type information 2020-01-19 18:07:54 +00:00
31e8efa6d1 level/light: populate missing return type information 2020-01-19 18:06:31 +00:00
facca13139 permission: populate missing return type information
PermissibleBase has some redundant phpdoc removed so that the Permissible interface can provide return types.
2020-01-19 17:23:52 +00:00
fffeeddca6 DataPacket: add magic method return types to keep phpstan happy
this really shouldn't be necessary, but it is what it is.
2020-01-19 17:14:34 +00:00
e6ba3ce8a6 item: populate missing return type information 2020-01-19 17:13:33 +00:00
11cae2f0c0 timings: populate missing return type information 2020-01-19 17:12:13 +00:00
f5a18df835 scheduler: populate missing return type information 2020-01-19 17:11:12 +00:00
1cc7027f92 plugin: populate missing return type information 2020-01-19 17:09:33 +00:00
8776b71d63 tile: populate missing return type information 2020-01-19 17:08:40 +00:00
0b9d0f3cdc utils: populate missing return type information 2020-01-19 17:07:48 +00:00
e419d76367 metadata: populate missing return type information 2020-01-19 17:06:48 +00:00
36cde9f352 inventory: populate missing return type information 2020-01-19 17:05:31 +00:00
05c602a044 event: populate missing return type information 2020-01-19 17:05:01 +00:00
0db7e57a15 lang: populate missing return type information 2020-01-19 17:04:25 +00:00
205e47c0c4 entity: populate missing return type information 2020-01-19 17:03:54 +00:00
e328d00cca command: populate missing return type info 2020-01-19 17:02:55 +00:00
ccbcc14600 Block: populate missing return type info 2020-01-19 17:02:03 +00:00
e544bc0d4b Item: added missing return type info for clearCustomBlockData() 2020-01-18 20:11:47 +00:00
fd27227cc7 Item: fix @return annotations for fluent methods (needed for correct auto complete) 2020-01-18 20:10:46 +00:00
b42966f61b network: explicitly specify @return void 2020-01-18 19:35:01 +00:00
ca86ec2ec2 Network: added missing return type information for getUpload() and getDownload() 2020-01-18 19:33:27 +00:00
97b6183404 PermissionManager: add native return types to private functions 2020-01-18 17:59:10 +00:00
0587d03c03 PluginDescription: add native return types to private functions 2020-01-18 17:57:24 +00:00
c7f1b605f2 PluginBase: remove useless duplicate doc comment from onLoad() stub 2020-01-18 17:56:44 +00:00
f069df65a8 PermissibleBase: added native returm types to private functions 2020-01-18 17:54:13 +00:00
1e624e7bb9 Attribute: add missing @return $this annotations 2020-01-18 17:50:58 +00:00
f16a530849 MainLogger: add native return types to private functions 2020-01-18 17:47:38 +00:00
7137b8a8a4 Config: added native void return types to private functions 2020-01-18 17:46:25 +00:00
ab57914322 CraftingDataPacket: added native return typehints to private methods 2020-01-18 17:45:15 +00:00
260869c0d5 Position: populate missing return type information for fromObject() 2020-01-18 17:44:14 +00:00
9135877da1 SetupWizard: add native void typehints to private methods 2020-01-18 17:39:06 +00:00
07cb603231 Liquid: add missing return type to getFluidHeightPercent() 2020-01-17 13:58:54 +00:00
f59094e6d6 Fence: add missing return type to canConnect() 2020-01-17 13:58:29 +00:00
d8acae5495 Door: add missing return type to getFullDamage() 2020-01-17 13:57:56 +00:00
239fe909be CobblestoneWall: add missing return type for canConnect() 2020-01-17 13:57:29 +00:00
c22576a266 CrashDump: add void native return types to private methods 2020-01-17 13:55:38 +00:00
bac788fd00 Timezone: add missing return type for detectSystemTimezone() 2020-01-15 20:18:35 +00:00
f6d96c5827 DataPacket: clean() returns $this, not void 2020-01-14 17:30:48 +00:00
b1458db47b Revert "CraftingDataPacket: fixed trying to return void result of parent function"
This reverts commit e12ecaf629.
2020-01-14 17:16:17 +00:00
2d2c9379cd DataPacket: apply @return void annotations to make phpstan happy
this eliminates 250+ errors on level 6.
2020-01-14 15:39:07 +00:00
3400771770 DataPacket: add missing return type info for pid() 2020-01-14 15:38:24 +00:00
e12ecaf629 CraftingDataPacket: fixed trying to return void result of parent function 2020-01-14 15:37:06 +00:00
1303cbfe02 UUID: add some missing return type annotations 2020-01-14 15:35:46 +00:00
ad4a211cba Color: add missing return type annotation for fromABGR() 2020-01-14 15:35:14 +00:00
d1e56c4611 Location: add missing return types for getYaw() and getPitch() 2020-01-14 15:34:40 +00:00
d9bbab54f4 Entity: fixing position and velocity sync on start/stop movement, closes #3133
the delta for velocity sync is WAYYYYYY too big, but that's a task for another commit.
2020-01-14 13:08:38 +00:00
07cf4eb7a9 Revert "Create .sonarcloud.properties"
This reverts commit 50a7663369.
2020-01-13 21:46:38 -06:00
50a7663369 Create .sonarcloud.properties 2020-01-13 21:31:36 -06:00
651ef500a3 Make pocketmine\PATH and pocketmine\RESOURCE_PATH always available
these are non-dependent on environment, so they can be determined with no external input.
    This fixes 2 PHPStan issues, fixes some code that couldn't run outside of PM, and makes it easier to write code that depends on PM.
2020-01-13 10:55:54 +00:00
30f2e75278 phpstan 0.12.5 2020-01-12 16:57:43 +00:00
2cfc25b4f8 phpstan: enable checkGenericClassInNonGenericObjectType 2020-01-11 23:04:16 +00:00
5bded9cff8 AttributeMap: add phpstan generic parameters for ArrayAccess 2020-01-11 23:03:21 +00:00
5816ff85ba don't depend on phpstan 0.12.4 phpdoc inheriting
this causes build failure because the parameter names are different to
the base class.
2020-01-11 22:08:16 +00:00
8f7d8347ee update pocketmine/spl dependency 2020-01-11 22:05:37 +00:00
3614d9a78d phpstan: enable MissingMethodParameterTypehintRule 2020-01-11 21:54:42 +00:00
818d0e19ab RCONInstance: remove always-false branch (readPacket() never returns null) 2020-01-11 21:54:03 +00:00
17720041a3 phpdoc: populate missing parameter typeinfo 2020-01-11 21:53:24 +00:00
c329ff7d4f SubChunk: remove nonsensical reference from internal function 2020-01-11 21:49:33 +00:00
8794292788 remove &$var reference notations in phpdoc
this isn't required by the spec and PHPStan chokes on it. I was previously having it ignore these errors, but it turns out that PHPStan is not making use of extended typeinfo provided if it can't parse the tag, which is problematic on level 6 and also a problem for array-of-type. Therefore, we are going to have to take the hit.
2020-01-11 21:20:55 +00:00
0a39e580e9 MainLogger: log exception chains in logException(), closes #2447
this method is simpler than #2447 and easier to apply to stable.
2020-01-09 21:01:12 +00:00
c4580dd56d MainLogger: extract a printErrorMessage() function from logException() 2020-01-09 20:51:13 +00:00
fab81d28bc MainLogger: always log exceptions with CRITICAL level
if we reached this point, it's almost always due to a general exception handler which doesn't know what else to do with the error.
2020-01-09 20:44:21 +00:00
039478223e phpstan: enable MissingFunctionReturnTypehintRule 2020-01-09 20:14:15 +00:00
64b5db4bf2 bootstrap: add some @return annotations for phpstan 2020-01-09 20:13:53 +00:00
c85f4256c7 phpstan: enable MissingFunctionParameterTypehintRule 2020-01-09 20:10:15 +00:00
1192b8bdf1 bootstrap: add PhpDoc to critical_error to make phpstan happy
it wants phpdoc or typehints, and we can't provide typehints because bootstrap needs to be compatible with old PHP versions.
2020-01-09 20:09:33 +00:00
6dcd2a4ece phpstan: start phasing in some level 6 checks 2020-01-09 19:56:04 +00:00
3fff0a0656 BigTree: evict unmaintained dead code
phpstan whines about all this stuff, and everything left is private, so we can get rid of it. Sadly we can't ditch the class without breaking BC, so that sticks with 4.0.
2020-01-09 14:26:46 +00:00
e1e1bfa5e3 CompressBatchedTask: remove useless code causing build failure
assuming that pthreads does not have leak issues, this code is pointless, and if pthreads does have leak issues, this may not prevent them anyway.
2020-01-09 14:19:35 +00:00
1eedac87b2 added missing @var property types (reported by phpstan) 2020-01-09 14:13:54 +00:00
cda3e6f4dc PluginDescription: clean up type information for extensions field 2020-01-09 11:20:01 +00:00
e6a58e2690 format/leveldb: fix crash on truncated level.dat file 2020-01-08 09:55:03 +00:00
27350c4673 3.11.4 is next 2020-01-04 16:46:55 +00:00
0d5704b156 Release 3.11.3 2020-01-04 16:46:55 +00:00
f355044626 resources: do not remove client-side resource packs when forcing resources
I wanted to make this into a dedicated option, but it had some side effects (see 4794ba236a).
I'll settle for just disabling this useless behaviour, since we have other ways to force vanilla resources anyway; setting this flag to always-false has no user-facing effects anyway.
2020-01-04 16:14:08 +00:00
4794ba236a Revert "resource packs: added new option remove_client_resources, fixed client packs being removed when forcing resource pack download"
This reverts commit 06ec8b8397.

unfortunately, this had some unanticipated side effects, thanks to
idiotic behaviour in the client ... when having optional downloads but
trying to force resources, the client chokes because it thinks the
server is forcing it to apply a pack that it doesn't have. Since
there's no way to detect when this problem occurs in the protocol, the
only option is to revert this.
2020-01-04 16:04:07 +00:00
6490a49c70 tests: drop lint.sh - no longer needed now that we have PHPStan 2020-01-04 15:23:53 +00:00
5cd7e11b29 Use specialized build script for Travis 2020-01-04 15:15:01 +00:00
08e3b8ffdc build: added specialized script to create a server phar
this is much easier to use than devtools, and allows us to make additional specializations for PM build that would otherwise just be a colossal pain in the ass.
2020-01-04 14:56:53 +00:00
9232f4509c TimingsHandler: don't bail on redundant attempts to stop non-running timers
while it would be nice to bail, providing the environment to allow bailing without breaking stuff requires some complex changes that would reduce performance when timings is not running. Considering the limited usefulness of bailing here anyway, and the fact that it just has to be prevented to not have side effects, it doesn't make a whole lot of sense right now.

closes #3261, closes #3269, closes #3254
2020-01-04 14:44:55 +00:00
cef77907c6 Timings: fixed grandparent timers not working correctly, closes #3229 2020-01-04 13:23:04 +00:00
06ec8b8397 resource packs: added new option remove_client_resources, fixed client packs being removed when forcing resource pack download 2020-01-04 13:16:47 +00:00
ee08286eca moved git hash detection code to its own unit 2020-01-02 21:01:31 +00:00
a83211f96a VersionInfo: add strict_types to stop CS tools screwing with it 2020-01-02 20:05:50 +00:00
0b3c4ee496 bootstrap: don't choke on paths that have spaces in them 2019-12-30 11:58:44 +00:00
54de518634 bootstrap: fixed incorrect git hash detection when cwd is not the repo root 2019-12-30 09:09:47 +00:00
a908197907 Effect: document that duration is expected in ticks 2019-12-29 19:03:32 +00:00
3e23a568ca phpstan: properly fixing FPs on constant comparisons 2019-12-29 14:25:44 +00:00
dadc5c1b87 3.11.3 is next 2019-12-29 13:11:30 +00:00
a37d740111 Release 3.11.2 2019-12-29 13:11:30 +00:00
2de0ec02ba phpstan 0.12.3 2019-12-28 17:22:08 +00:00
d83820477f TimingsHandler: throw on attempt to stop timer that is not running
I do not think that this bug is in effect in the core code, but I can't be sure.
2019-12-21 13:17:40 +00:00
8726604899 Merge #3251: Remove usages of empty() 2019-12-19 11:08:08 +00:00
9cbe378e8c Timezone: fix possible crash on CentOS 2019-12-18 11:23:24 +00:00
494660102e Replace empty() usages with count() 2019-12-18 11:23:24 +00:00
216138a37e PlayerAuthInputPacket: Fix assigning variable in static context 2019-12-17 22:04:24 +08:00
b08c38f8f9 build/make-release: remove redundant require_once
this is included by vendor/autoload.php since 3.7.x.
2019-12-17 11:47:07 +00:00
911b6feaf9 NetworkInventoryAction: remove dead code
the trading & beacon types need to be checked as well, but I don't have the tools to check that right now.
2019-12-17 11:17:40 +00:00
2cb6990698 Enchantment: don't throw exceptions on out of range IDs
this function is used for data deserialization, and data may have bad enchantment IDs in it.
2019-12-14 10:04:51 +00:00
f7d66613df CompletedUsingItemPacket: added missing #include, closes #3219 2019-12-13 19:50:40 +00:00
95c32d26df Explosion: fixed ray trace getting stuck on a block when it encounters an empty subchunk
this might have caused unexpected behaviour in large caves.
2019-12-13 18:07:59 +00:00
9e1f6a2486 protocol: updated particle IDs 2019-12-13 10:52:09 +00:00
76994f15ac phpstan: green on level 5 2019-12-12 18:27:26 +00:00
cf73d74bd0 format/anvil: fixed possible type violation on saving chunk 2019-12-12 18:24:21 +00:00
37a8d95464 world IO: fixed crashes when garbage data found in tile/entity NBT data 2019-12-12 18:21:23 +00:00
9a4b72add5 PlayerInventory: fix type violation when calling equipItem() for non-Player holder 2019-12-12 16:31:22 +00:00
919534d978 EnderChest: fixed crash when plugins overwrite tile classes with incompatible ones
relates to 47a959dace
2019-12-12 16:28:30 +00:00
cb598155a4 Server: add @return annotation to crashDump() to make phpstan happy
this is technically a bug in PHPStan, but it's easier to do this than report a bug.
2019-12-12 16:19:57 +00:00
00888fdc55 TranslationContainer::__construct() accepts float and int too (they can be casted to string) 2019-12-12 16:19:04 +00:00
77795ae3bc BaseLang::translateString() accepts float and int too (they can be casted to string) 2019-12-12 16:18:11 +00:00
f39fc7e525 CompressBatchedTask::__construct() accepts Player[] not string[] 2019-12-12 16:16:48 +00:00
77f7595e0e Location::__construct() accepts floats for x,y,z 2019-12-12 16:16:16 +00:00
e8d3a25028 Position::__construct() accepts floats for x,y,z 2019-12-12 16:15:49 +00:00
1370930ea9 Entity: remove redundant defaults from lastX lastY lastZ, remove nullability
these fields are never null because they are initialized in the constructor, and they are never written to with null nor ever expected to be null.
2019-12-12 16:14:30 +00:00
70c3008b7b phpstan: green on level 4 2019-12-12 13:00:57 +00:00
46930b98b7 Timings: add a dedicated field for checking initialization 2019-12-12 12:59:01 +00:00
92be8c8ec0 PopulationTask: don't assume anything about TLS return values
while these SHOULD be what we say they are, it's possible for something else to overwrite them with junk and make the server catch fire.
2019-12-12 12:19:54 +00:00
62069bc7af Level: fix return type content doc comment for getAdjacentChunks() 2019-12-12 12:18:35 +00:00
26230c1f9b Player: don't report never-played for a disconnected player
this should catch fire like everything else does.
2019-12-12 12:17:52 +00:00
a9fafbc5eb BanEntry: remove nullable return from parseDate()
this function never returns null
2019-12-12 11:59:41 +00:00
b8778cb791 LevelProvider: fix doc comment of ::generate()
this raised false positives on phpstan level 4
2019-12-12 11:59:12 +00:00
73c5fe5cf9 BaseInventory: correctly annotate content type of slots field
fixes warnings on phpstan level 4
2019-12-12 11:58:11 +00:00
b3cfa5a3a0 TimingsHandler: use weak comparison for stopTiming start check
this could be an int or float, and 0 !== 0.0.
2019-12-12 11:48:34 +00:00
6127a02a8b phpstan 0.12.2 2019-12-12 10:43:45 +00:00
dbca36e5e2 SkinImage: throw on wrong data length 2019-12-11 22:45:14 +00:00
1171bae691 login: read the correct key SkinAnimationData 2019-12-11 22:40:05 +00:00
494f8e8251 login: fixed missing base64_decode() for animation images 2019-12-11 22:39:40 +00:00
3c9af56e06 3.11.2 is next 2019-12-11 20:20:26 +00:00
40a2211a5a Release 3.11.1 2019-12-11 20:20:26 +00:00
0196aa21d7 updated BedrockData submodule, close #3222, close #3223 2019-12-11 20:19:17 +00:00
833f3e574b 3.11.1 is next 2019-12-11 18:35:03 +00:00
205 changed files with 2781 additions and 517 deletions

View File

@ -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
View 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();
}

View File

@ -9,3 +9,47 @@ Plugin developers should **only** update their required API to this version if y
# 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.
# 3.11.4
- Fixed performance issue in leaf decay.
- Fixed entity position desync when entities stop moving, but still have velocity on the client.
- Fixed a crash when encountering truncated `level.dat` files in LevelDB worlds.
- Core code is now analyzed using PHPStan level 6.
- The core constants `pocketmine\PATH` and `pocketmine\RESOURCE_PATH` are now unconditionally available when including the Composer autoloader.
- Populate type information in lots of places where it was previously missing; this will improve the quality of static analysis for plugins.
- `MainLogger::logException()` now logs previous exceptions recursively.
- `MainLogger::logException()` now always logs exceptions as `critical`.

View File

@ -25,7 +25,7 @@
"ext-zip": "*",
"ext-zlib": ">=1.2.11",
"pocketmine/raklib": "^0.12.5",
"pocketmine/spl": "^0.3.0",
"pocketmine/spl": "^0.3.5",
"pocketmine/binaryutils": "^0.1.9",
"pocketmine/nbt": "^0.2.10",
"pocketmine/math": "^0.2.0",
@ -38,6 +38,7 @@
"": ["src"]
},
"files": [
"src/pocketmine/CoreConstants.php",
"src/pocketmine/GlobalConstants.php",
"src/pocketmine/VersionInfo.php"
]

14
composer.lock generated
View File

@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
"content-hash": "377d9e0ab5f1a9a4ef9b664706d26f5b",
"content-hash": "f693f278b3bb9c1d266079fa17644dcb",
"packages": [
{
"name": "adhocore/json-comment",
@ -276,16 +276,16 @@
},
{
"name": "pocketmine/spl",
"version": "0.3.3",
"version": "0.3.5",
"source": {
"type": "git",
"url": "https://github.com/pmmp/SPL.git",
"reference": "94d4df142fe837ba836e9348dd00209e4bdcc307"
"reference": "88052c67d3df2cc2dc2d99ebeae3d7ede3fc64ab"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/pmmp/SPL/zipball/94d4df142fe837ba836e9348dd00209e4bdcc307",
"reference": "94d4df142fe837ba836e9348dd00209e4bdcc307",
"url": "https://api.github.com/repos/pmmp/SPL/zipball/88052c67d3df2cc2dc2d99ebeae3d7ede3fc64ab",
"reference": "88052c67d3df2cc2dc2d99ebeae3d7ede3fc64ab",
"shasum": ""
},
"type": "library",
@ -299,10 +299,10 @@
],
"description": "Standard library files required by PocketMine-MP and related projects",
"support": {
"source": "https://github.com/pmmp/SPL/tree/0.3.3",
"source": "https://github.com/pmmp/SPL/tree/0.3",
"issues": "https://github.com/pmmp/SPL/issues"
},
"time": "2019-10-28T11:41:20+00:00"
"time": "2020-01-14T16:23:26+00:00"
}
],
"packages-dev": [],

View File

@ -1,18 +1,25 @@
includes:
- tests/phpstan/configs/com-dotnet-magic.neon
- tests/phpstan/configs/custom-leveldb.neon
- tests/phpstan/configs/gc-hacks.neon
- tests/phpstan/configs/optional-com-dotnet.neon
- 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: 6
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
checkMissingIterableValueType: false #TODO: pthreads Threaded base for too many things, fix this later
ignoreErrors:
-
message: "#^Cannot instantiate interface pocketmine\\\\level\\\\format\\\\io\\\\LevelProvider\\.$#"
@ -80,11 +87,6 @@ parameters:
count: 1
path: src/pocketmine/level/generator/normal/Normal.php
-
message: "#^Used constant pocketmine\\\\RESOURCE_PATH not found\\.$#"
count: 1
path: src/pocketmine/network/mcpe/protocol/StartGamePacket.php
-
message: "#^Constructor of class pocketmine\\\\scheduler\\\\TaskScheduler has an unused parameter \\$logger\\.$#"
count: 1
@ -102,18 +104,10 @@ parameters:
message: "#^Constant pocketmine\\\\GIT_COMMIT not found\\.$#"
path: src
-
message: "#^Constant pocketmine\\\\PATH not found\\.$#"
path: src
-
message: "#^Constant pocketmine\\\\PLUGIN_PATH not found\\.$#"
path: src
-
message: "#^Constant pocketmine\\\\RESOURCE_PATH not found\\.$#"
path: src
-
message: "#^Constant pocketmine\\\\START_TIME not found\\.$#"
path: src

View File

@ -25,12 +25,16 @@ namespace pocketmine;
abstract class Collectable extends \Threaded{
/** @var bool */
private $isGarbage = false;
public function isGarbage() : bool{
return $this->isGarbage;
}
/**
* @return void
*/
public function setGarbage(){
$this->isGarbage = true;
}

View File

@ -0,0 +1,33 @@
<?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;
// composer autoload doesn't use require_once and also pthreads can inherit things
if(defined('pocketmine\_CORE_CONSTANTS_INCLUDED')){
return;
}
define('pocketmine\_CORE_CONSTANTS_INCLUDED', true);
define('pocketmine\PATH', dirname(__DIR__, 2) . '/');
define('pocketmine\RESOURCE_PATH', __DIR__ . '/resources/');

View File

@ -96,8 +96,11 @@ class CrashDump{
/** @var Server */
private $server;
/** @var resource */
private $fp;
/** @var int */
private $time;
/** @var mixed[] */
private $data = [];
/** @var string */
private $encodedData = "";
@ -134,6 +137,9 @@ class CrashDump{
return $this->path;
}
/**
* @return string
*/
public function getEncodedData(){
return $this->encodedData;
}
@ -142,7 +148,7 @@ class CrashDump{
return $this->data;
}
private function encodeData(){
private function encodeData() : void{
$this->addLine();
$this->addLine("----------------------REPORT THE DATA BELOW THIS LINE-----------------------");
$this->addLine();
@ -158,7 +164,7 @@ class CrashDump{
$this->addLine("===END CRASH DUMP===");
}
private function pluginsData(){
private function pluginsData() : void{
if($this->server->getPluginManager() instanceof PluginManager){
$this->addLine();
$this->addLine("Loaded plugins:");
@ -182,7 +188,7 @@ class CrashDump{
}
}
private function extraData(){
private function extraData() : void{
global $argv;
if($this->server->getProperty("auto-report.send-settings", true) !== false){
@ -209,7 +215,7 @@ class CrashDump{
}
}
private function baseCrash(){
private function baseCrash() : void{
global $lastExceptionError, $lastError;
if(isset($lastExceptionError)){
@ -317,7 +323,7 @@ class CrashDump{
return false;
}
private function generalData(){
private function generalData() : void{
$version = new VersionString(\pocketmine\BASE_VERSION, \pocketmine\IS_DEVELOPMENT_BUILD, \pocketmine\BUILD_NUMBER);
$this->data["general"] = [];
$this->data["general"]["name"] = $this->server->getName();
@ -340,10 +346,20 @@ class CrashDump{
$this->addLine("OS : " . PHP_OS . ", " . Utils::getOS());
}
/**
* @param string $line
*
* @return void
*/
public function addLine($line = ""){
fwrite($this->fp, $line . PHP_EOL);
}
/**
* @param string $str
*
* @return void
*/
public function add($str){
fwrite($this->fp, $str);
}

View File

@ -44,6 +44,8 @@ interface IPlayer extends ServerOperator{
/**
* @param bool $banned
*
* @return void
*/
public function setBanned(bool $banned);
@ -54,6 +56,8 @@ interface IPlayer extends ServerOperator{
/**
* @param bool $value
*
* @return void
*/
public function setWhitelisted(bool $value);

View File

@ -115,7 +115,7 @@ class MemoryManager{
$this->init();
}
private function init(){
private function init() : void{
$this->memoryLimit = ((int) $this->server->getProperty("memory.main-limit", 0)) * 1024 * 1024;
$defaultMemory = 1024;
@ -201,6 +201,8 @@ class MemoryManager{
* @param int $limit
* @param bool $global
* @param int $triggerCount
*
* @return void
*/
public function trigger(int $memory, int $limit, bool $global = false, int $triggerCount = 0){
$this->server->getLogger()->debug(sprintf("[Memory Manager] %sLow memory triggered, limit %gMB, using %gMB",
@ -230,6 +232,8 @@ class MemoryManager{
/**
* Called every tick to update the memory manager state.
*
* @return void
*/
public function check(){
Timings::$memoryManagerTimer->startTiming();
@ -297,6 +301,8 @@ class MemoryManager{
* @param string $outputFolder
* @param int $maxNesting
* @param int $maxStringSize
*
* @return void
*/
public function dumpServerMemory(string $outputFolder, int $maxNesting, int $maxStringSize){
$this->server->getLogger()->notice("[Dump] After the memory dump is done, the server might crash");
@ -319,6 +325,7 @@ class MemoryManager{
* @param int $maxStringSize
* @param \Logger $logger
*
* @return void
* @throws \ReflectionException
*/
public static function dumpMemory($startingObject, string $outputFolder, int $maxNesting, int $maxStringSize, \Logger $logger){
@ -472,14 +479,14 @@ class MemoryManager{
/**
* @param mixed $from
* @param mixed &$data
* @param object[] &$objects
* @param int[] &$refCounts
* @param mixed $data reference parameter
* @param object[] $objects reference parameter
* @param int[] $refCounts reference parameter
* @param int $recursion
* @param int $maxNesting
* @param int $maxStringSize
*/
private static function continueDump($from, &$data, array &$objects, array &$refCounts, int $recursion, int $maxNesting, int $maxStringSize){
private static function continueDump($from, &$data, array &$objects, array &$refCounts, int $recursion, int $maxNesting, int $maxStringSize) : void{
if($maxNesting <= 0){
$data = "(error) NESTING LIMIT REACHED";
return;

View File

@ -57,6 +57,9 @@ class OfflinePlayer implements IPlayer, Metadatable{
return $this->name;
}
/**
* @return Server
*/
public function getServer(){
return $this->server;
}

View File

@ -282,6 +282,7 @@ class Player extends Human implements CommandSender, ChunkLoader, IPlayer{
/** @var string */
protected $xuid = "";
/** @var int */
protected $windowCnt = 2;
/** @var int[] */
protected $windows = [];
@ -464,17 +465,22 @@ 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{
return $this->playedBefore;
}
/**
* @param bool $value
*
* @return void
*/
public function setAllowFlight(bool $value){
$this->allowFlight = $value;
$this->sendSettings();
@ -484,6 +490,11 @@ class Player extends Human implements CommandSender, ChunkLoader, IPlayer{
return $this->allowFlight;
}
/**
* @param bool $value
*
* @return void
*/
public function setFlying(bool $value){
if($this->flying !== $value){
$this->flying = $value;
@ -496,6 +507,11 @@ class Player extends Human implements CommandSender, ChunkLoader, IPlayer{
return $this->flying;
}
/**
* @param bool $value
*
* @return void
*/
public function setAutoJump(bool $value){
$this->autoJump = $value;
$this->sendSettings();
@ -509,6 +525,11 @@ class Player extends Human implements CommandSender, ChunkLoader, IPlayer{
return $this->allowMovementCheats;
}
/**
* @param bool $value
*
* @return void
*/
public function setAllowMovementCheats(bool $value = true){
$this->allowMovementCheats = $value;
}
@ -538,6 +559,8 @@ class Player extends Human implements CommandSender, ChunkLoader, IPlayer{
/**
* @param bool $remove
*
* @return void
*/
public function setRemoveFormat(bool $remove = true){
$this->removeFormat = $remove;
@ -565,6 +588,8 @@ class Player extends Human implements CommandSender, ChunkLoader, IPlayer{
/**
* @param Player $player
*
* @return void
*/
public function hidePlayer(Player $player){
if($player === $this){
@ -576,6 +601,8 @@ class Player extends Human implements CommandSender, ChunkLoader, IPlayer{
/**
* @param Player $player
*
* @return void
*/
public function showPlayer(Player $player){
if($player === $this){
@ -604,6 +631,11 @@ class Player extends Human implements CommandSender, ChunkLoader, IPlayer{
return $this->viewDistance;
}
/**
* @param int $distance
*
* @return void
*/
public function setViewDistance(int $distance){
$this->viewDistance = $this->server->getAllowedViewDistance($distance);
@ -634,6 +666,8 @@ class Player extends Human implements CommandSender, ChunkLoader, IPlayer{
/**
* @param bool $value
*
* @return void
*/
public function setOp(bool $value){
if($value === $this->isOp()){
@ -685,6 +719,8 @@ class Player extends Human implements CommandSender, ChunkLoader, IPlayer{
/**
* @param PermissionAttachment $attachment
*
* @return void
*/
public function removeAttachment(PermissionAttachment $attachment){
$this->perm->removeAttachment($attachment);
@ -720,6 +756,9 @@ class Player extends Human implements CommandSender, ChunkLoader, IPlayer{
return $this->perm->getEffectivePermissions();
}
/**
* @return void
*/
public function sendCommandData(){
$pk = new AvailableCommandsPacket();
foreach($this->server->getCommandMap()->getCommands() as $name => $command){
@ -741,7 +780,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;
@ -817,6 +856,8 @@ class Player extends Human implements CommandSender, ChunkLoader, IPlayer{
/**
* @param string $name
*
* @return void
*/
public function setDisplayName(string $name){
$this->displayName = $name;
@ -902,6 +943,8 @@ class Player extends Human implements CommandSender, ChunkLoader, IPlayer{
* @internal Plugins should not use this method.
*
* @param int $pingMS
*
* @return void
*/
public function updatePing(int $pingMS){
$this->lastPingMeasure = $pingMS;
@ -926,6 +969,11 @@ class Player extends Human implements CommandSender, ChunkLoader, IPlayer{
return $this->getGenericFlag(self::DATA_FLAG_ACTION) and $this->startAction > -1;
}
/**
* @param bool $value
*
* @return void
*/
public function setUsingItem(bool $value){
$this->startAction = $value ? $this->server->getTick() : -1;
$this->setGenericFlag(self::DATA_FLAG_ACTION, $value);
@ -995,6 +1043,13 @@ class Player extends Human implements CommandSender, ChunkLoader, IPlayer{
return false;
}
/**
* @param int $x
* @param int $z
* @param Level|null $level
*
* @return void
*/
protected function unloadChunk(int $x, int $z, Level $level = null){
$level = $level ?? $this->level;
$index = Level::chunkHash($x, $z);
@ -1011,6 +1066,13 @@ class Player extends Human implements CommandSender, ChunkLoader, IPlayer{
unset($this->loadQueue[$index]);
}
/**
* @param int $x
* @param int $z
* @param BatchPacket $payload
*
* @return void
*/
public function sendChunk(int $x, int $z, BatchPacket $payload){
if(!$this->isConnected()){
return;
@ -1033,6 +1095,9 @@ class Player extends Human implements CommandSender, ChunkLoader, IPlayer{
}
}
/**
* @return void
*/
protected function sendNextChunk(){
if(!$this->isConnected()){
return;
@ -1067,6 +1132,9 @@ class Player extends Human implements CommandSender, ChunkLoader, IPlayer{
Timings::$playerChunkSendTimer->stopTiming();
}
/**
* @return void
*/
public function doFirstSpawn(){
if($this->spawned){
return; //avoid player spawning twice (this can only happen on 3.x with a custom malicious client)
@ -1116,6 +1184,12 @@ class Player extends Human implements CommandSender, ChunkLoader, IPlayer{
}
}
/**
* @param Vector3 $pos
* @param int $respawnState
*
* @return void
*/
protected function sendRespawnPacket(Vector3 $pos, int $respawnState = RespawnPacket::SEARCHING_FOR_SPAWN){
$pk = new RespawnPacket();
$pk->position = $pos->add(0, $this->baseOffset, 0);
@ -1208,7 +1282,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();
@ -1245,6 +1319,8 @@ class Player extends Human implements CommandSender, ChunkLoader, IPlayer{
* Position object
*
* @param Vector3|Position $pos
*
* @return void
*/
public function setSpawn(Vector3 $pos){
if(!($pos instanceof Position)){
@ -1304,6 +1380,9 @@ class Player extends Human implements CommandSender, ChunkLoader, IPlayer{
return true;
}
/**
* @return void
*/
public function stopSleep(){
if($this->sleeping instanceof Vector3){
$b = $this->level->getBlock($this->sleeping);
@ -1367,6 +1446,8 @@ class Player extends Human implements CommandSender, ChunkLoader, IPlayer{
/**
* @param string $achievementId
*
* @return void
*/
public function removeAchievement(string $achievementId){
if($this->hasAchievement($achievementId)){
@ -1455,6 +1536,8 @@ class Player extends Human implements CommandSender, ChunkLoader, IPlayer{
/**
* @internal
* Sends the player's gamemode to the client.
*
* @return void
*/
public function sendGamemode(){
$pk = new SetPlayerGameTypePacket();
@ -1464,6 +1547,8 @@ class Player extends Human implements CommandSender, ChunkLoader, IPlayer{
/**
* Sends all the option flags
*
* @return void
*/
public function sendSettings(){
$pk = new AdventureSettingsPacket();
@ -1569,6 +1654,9 @@ class Player extends Human implements CommandSender, ChunkLoader, IPlayer{
return false; //currently has no server-side movement
}
/**
* @return void
*/
protected function checkNearEntities(){
foreach($this->level->getNearbyEntities($this->boundingBox->expandedCopy(1, 0.5, 1), $this) as $entity){
$entity->scheduleUpdate();
@ -1581,6 +1669,11 @@ class Player extends Human implements CommandSender, ChunkLoader, IPlayer{
}
}
/**
* @param int $tickDiff
*
* @return void
*/
protected function processMovement(int $tickDiff){
if(!$this->isAlive() or !$this->spawned or $this->newPosition === null or $this->isSleeping()){
return;
@ -1723,6 +1816,11 @@ class Player extends Human implements CommandSender, ChunkLoader, IPlayer{
}
/**
* @param bool $sendAll
*
* @return void
*/
public function sendAttributes(bool $sendAll = false){
$entries = $sendAll ? $this->attributeMap->getAll() : $this->attributeMap->needSend();
if(count($entries) > 0){
@ -1828,6 +1926,9 @@ class Player extends Human implements CommandSender, ChunkLoader, IPlayer{
$this->dataPacket($pk);
}
/**
* @return void
*/
public function checkNetwork(){
if(!$this->isOnline()){
return;
@ -1921,7 +2022,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 +2032,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,
@ -1976,6 +2077,12 @@ class Player extends Human implements CommandSender, ChunkLoader, IPlayer{
return true;
}
/**
* @param int $status
* @param bool $immediate
*
* @return void
*/
public function sendPlayStatus(int $status, bool $immediate = false){
$pk = new PlayStatusPacket();
$pk->status = $status;
@ -2019,6 +2126,9 @@ class Player extends Human implements CommandSender, ChunkLoader, IPlayer{
$this->processLogin();
}
/**
* @return void
*/
protected function processLogin(){
foreach($this->server->getLoggedInPlayers() as $p){
if($p !== $this and ($p->iusername === $this->iusername or $this->getUniqueId()->equals($p->getUniqueId()))){
@ -2118,7 +2228,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:
@ -2132,6 +2245,9 @@ class Player extends Human implements CommandSender, ChunkLoader, IPlayer{
return true;
}
/**
* @return void
*/
protected function completeLoginSequence(){
/** @var float[] $pos */
$pos = $this->namedtag->getListTag("Pos")->getAllValues();
@ -3152,6 +3268,8 @@ class Player extends Human implements CommandSender, ChunkLoader, IPlayer{
* Called when a packet is received from the client. This method will call DataPacketReceiveEvent.
*
* @param DataPacket $packet
*
* @return void
*/
public function handleDataPacket(DataPacket $packet){
if($this->sessionAdapter !== null){
@ -3309,6 +3427,8 @@ class Player extends Human implements CommandSender, ChunkLoader, IPlayer{
* @param int $fadeIn Duration in ticks for fade-in. If -1 is given, client-sided defaults will be used.
* @param int $stay Duration in ticks to stay on screen for
* @param int $fadeOut Duration in ticks for fade-out.
*
* @return void
*/
public function addTitle(string $title, string $subtitle = "", int $fadeIn = -1, int $stay = -1, int $fadeOut = -1){
$this->setTitleDuration($fadeIn, $stay, $fadeOut);
@ -3322,6 +3442,8 @@ class Player extends Human implements CommandSender, ChunkLoader, IPlayer{
* Sets the subtitle message, without sending a title.
*
* @param string $subtitle
*
* @return void
*/
public function addSubTitle(string $subtitle){
$this->sendTitleText($subtitle, SetTitlePacket::TYPE_SET_SUBTITLE);
@ -3331,6 +3453,8 @@ class Player extends Human implements CommandSender, ChunkLoader, IPlayer{
* Adds small text to the user's screen.
*
* @param string $message
*
* @return void
*/
public function addActionBarMessage(string $message){
$this->sendTitleText($message, SetTitlePacket::TYPE_SET_ACTIONBAR_MESSAGE);
@ -3338,6 +3462,8 @@ class Player extends Human implements CommandSender, ChunkLoader, IPlayer{
/**
* Removes the title from the client's screen.
*
* @return void
*/
public function removeTitles(){
$pk = new SetTitlePacket();
@ -3347,6 +3473,8 @@ class Player extends Human implements CommandSender, ChunkLoader, IPlayer{
/**
* Resets the title duration settings to defaults and removes any existing titles.
*
* @return void
*/
public function resetTitles(){
$pk = new SetTitlePacket();
@ -3360,6 +3488,8 @@ class Player extends Human implements CommandSender, ChunkLoader, IPlayer{
* @param int $fadeIn Title fade-in time in ticks.
* @param int $stay Title stay time in ticks.
* @param int $fadeOut Title fade-out time in ticks.
*
* @return void
*/
public function setTitleDuration(int $fadeIn, int $stay, int $fadeOut){
if($fadeIn >= 0 and $stay >= 0 and $fadeOut >= 0){
@ -3377,6 +3507,8 @@ class Player extends Human implements CommandSender, ChunkLoader, IPlayer{
*
* @param string $title
* @param int $type
*
* @return void
*/
protected function sendTitleText(string $title, int $type){
$pk = new SetTitlePacket();
@ -3389,6 +3521,8 @@ class Player extends Human implements CommandSender, ChunkLoader, IPlayer{
* Sends a direct chat message to a player
*
* @param TextContainer|string $message
*
* @return void
*/
public function sendMessage($message){
if($message instanceof TextContainer){
@ -3408,6 +3542,8 @@ class Player extends Human implements CommandSender, ChunkLoader, IPlayer{
/**
* @param string $message
* @param string[] $parameters
*
* @return void
*/
public function sendTranslation(string $message, array $parameters = []){
$pk = new TextPacket();
@ -3433,6 +3569,8 @@ class Player extends Human implements CommandSender, ChunkLoader, IPlayer{
*
* @param string $message
* @param string $subtitle @deprecated
*
* @return void
*/
public function sendPopup(string $message, string $subtitle = ""){
$pk = new TextPacket();
@ -3441,6 +3579,11 @@ class Player extends Human implements CommandSender, ChunkLoader, IPlayer{
$this->dataPacket($pk);
}
/**
* @param string $message
*
* @return void
*/
public function sendTip(string $message){
$pk = new TextPacket();
$pk->type = TextPacket::TYPE_TIP;
@ -3451,6 +3594,8 @@ class Player extends Human implements CommandSender, ChunkLoader, IPlayer{
/**
* @param string $sender
* @param string $message
*
* @return void
*/
public function sendWhisper(string $sender, string $message){
$pk = new TextPacket();
@ -3592,6 +3737,9 @@ class Player extends Human implements CommandSender, ChunkLoader, IPlayer{
}
}
/**
* @return mixed[]
*/
public function __debugInfo(){
return [];
}
@ -3608,6 +3756,8 @@ class Player extends Human implements CommandSender, ChunkLoader, IPlayer{
* Handles player data saving
*
* @throws \InvalidStateException if the player is closed
*
* @return void
*/
public function save(){
if($this->closed){
@ -3770,6 +3920,15 @@ class Player extends Human implements CommandSender, ChunkLoader, IPlayer{
return $result;
}
/**
* @param Vector3 $pos
* @param float|null $yaw
* @param float|null $pitch
* @param int $mode
* @param Player[]|null $targets
*
* @return void
*/
public function sendPosition(Vector3 $pos, float $yaw = null, float $pitch = null, int $mode = MovePlayerPacket::MODE_NORMAL, array $targets = null){
$yaw = $yaw ?? $this->yaw;
$pitch = $pitch ?? $this->pitch;
@ -3821,6 +3980,9 @@ class Player extends Human implements CommandSender, ChunkLoader, IPlayer{
return false;
}
/**
* @return void
*/
protected function addDefaultWindows(){
$this->addWindow($this->getInventory(), ContainerIds::INVENTORY, true);
@ -3946,6 +4108,7 @@ class Player extends Human implements CommandSender, ChunkLoader, IPlayer{
* @param Inventory $inventory
* @param bool $force Forces removal of permanent windows such as normal inventory, cursor
*
* @return void
* @throws \InvalidArgumentException if trying to remove a fixed inventory window without the `force` parameter as true
*/
public function removeWindow(Inventory $inventory, bool $force = false){
@ -3965,6 +4128,8 @@ class Player extends Human implements CommandSender, ChunkLoader, IPlayer{
* Removes all inventory windows from the player. By default this WILL NOT remove permanent windows.
*
* @param bool $removePermanentWindows Whether to remove permanent windows.
*
* @return void
*/
public function removeAllWindows(bool $removePermanentWindows = false){
foreach($this->windowIndex as $id => $window){
@ -3976,6 +4141,9 @@ class Player extends Human implements CommandSender, ChunkLoader, IPlayer{
}
}
/**
* @return void
*/
protected function sendAllInventories(){
foreach($this->windowIndex as $id => $inventory){
$inventory->sendContents($this);

View File

@ -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;
@ -35,6 +36,10 @@ namespace pocketmine {
const MIN_PHP_VERSION = "7.2.0";
/**
* @param string $message
* @return void
*/
function critical_error($message){
echo "[ERROR] $message" . PHP_EOL;
}
@ -116,6 +121,10 @@ namespace pocketmine {
return $messages;
}
/**
* @param \Logger $logger
* @return void
*/
function emit_performance_warnings(\Logger $logger){
if(extension_loaded("xdebug")){
$logger->warning("Xdebug extension is enabled. This has a major impact on performance.");
@ -131,6 +140,9 @@ namespace pocketmine {
}
}
/**
* @return void
*/
function set_ini_entries(){
ini_set("allow_url_fopen", '1');
ini_set("display_errors", '1');
@ -139,8 +151,11 @@ namespace pocketmine {
ini_set('assert.exception', '1');
}
/**
* @return void
*/
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.");
@ -156,17 +171,11 @@ namespace pocketmine {
error_reporting(-1);
set_ini_entries();
if(\Phar::running(true) !== ""){
define('pocketmine\PATH', \Phar::running(true) . "/");
}else{
define('pocketmine\PATH', dirname(__FILE__, 3) . DIRECTORY_SEPARATOR);
}
$opts = getopt("", ["bootstrap:"]);
if(isset($opts["bootstrap"])){
$bootstrap = realpath($opts["bootstrap"]) ?: $opts["bootstrap"];
}else{
$bootstrap = \pocketmine\PATH . 'vendor/autoload.php';
$bootstrap = dirname(__FILE__, 3) . '/vendor/autoload.php';
}
define('pocketmine\COMPOSER_AUTOLOADER_PATH', $bootstrap);
@ -186,12 +195,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();
@ -202,8 +206,6 @@ namespace pocketmine {
define('pocketmine\GIT_COMMIT', $gitHash);
define('pocketmine\RESOURCE_PATH', \pocketmine\PATH . 'src' . DIRECTORY_SEPARATOR . 'pocketmine' . DIRECTORY_SEPARATOR . 'resources' . DIRECTORY_SEPARATOR);
$opts = getopt("", ["data:", "plugins:", "no-wizard", "enable-ansi", "disable-ansi"]);
define('pocketmine\DATA', isset($opts["data"]) ? $opts["data"] . DIRECTORY_SEPARATOR : realpath(getcwd()) . DIRECTORY_SEPARATOR);

View File

@ -483,6 +483,8 @@ class Server{
/**
* @param bool $value
*
* @return void
*/
public function setAutoSave(bool $value){
$this->autoSave = $value;
@ -874,6 +876,8 @@ class Server{
/**
* @param string $name
* @param CompoundTag $nbtTag
*
* @return void
*/
public function saveOfflinePlayerData(string $name, CompoundTag $nbtTag){
$ev = new PlayerDataSaveEvent($nbtTag, $name);
@ -1212,9 +1216,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;
@ -1277,6 +1281,8 @@ class Server{
/**
* @param string $variable
* @param string $value
*
* @return void
*/
public function setConfigString(string $variable, string $value){
$this->properties->set($variable, $value);
@ -1300,6 +1306,8 @@ class Server{
/**
* @param string $variable
* @param int $value
*
* @return void
*/
public function setConfigInt(string $variable, int $value){
$this->properties->set($variable, $value);
@ -1336,6 +1344,8 @@ class Server{
/**
* @param string $variable
* @param bool $value
*
* @return void
*/
public function setConfigBool(string $variable, bool $value){
$this->properties->set($variable, $value ? "1" : "0");
@ -1370,6 +1380,8 @@ class Server{
/**
* @param string $name
*
* @return void
*/
public function addOp(string $name){
$this->operators->set(strtolower($name), true);
@ -1382,6 +1394,8 @@ class Server{
/**
* @param string $name
*
* @return void
*/
public function removeOp(string $name){
$this->operators->remove(strtolower($name));
@ -1394,6 +1408,8 @@ class Server{
/**
* @param string $name
*
* @return void
*/
public function addWhitelist(string $name){
$this->whitelist->set(strtolower($name), true);
@ -1402,6 +1418,8 @@ class Server{
/**
* @param string $name
*
* @return void
*/
public function removeWhitelist(string $name){
$this->whitelist->remove(strtolower($name));
@ -1440,6 +1458,9 @@ class Server{
return $this->operators;
}
/**
* @return void
*/
public function reloadWhitelist(){
$this->whitelist->reload();
}
@ -1476,6 +1497,11 @@ class Server{
return self::$instance;
}
/**
* @param int $microseconds
*
* @return void
*/
public static function microSleep(int $microseconds){
Server::$sleeper->synchronized(function(int $ms){
Server::$sleeper->wait($ms);
@ -1913,6 +1939,8 @@ class Server{
*
* @param Player[] $players
* @param DataPacket $packet
*
* @return void
*/
public function broadcastPacket(array $players, DataPacket $packet){
$packet->encode();
@ -1926,16 +1954,18 @@ class Server{
* @param DataPacket[] $packets
* @param bool $forceSync
* @param bool $immediate
*
* @return void
*/
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){
@ -1964,6 +1994,8 @@ class Server{
* @param BatchPacket $pk
* @param Player[] $players
* @param bool $immediate
*
* @return void
*/
public function broadcastPacketsCallback(BatchPacket $pk, array $players, bool $immediate = false){
if(!$pk->isEncoded){
@ -1978,6 +2010,8 @@ class Server{
/**
* @param int $type
*
* @return void
*/
public function enablePlugins(int $type){
foreach($this->pluginManager->getPlugins() as $plugin){
@ -1994,11 +2028,16 @@ class Server{
/**
* @param Plugin $plugin
*
* @return void
*/
public function enablePlugin(Plugin $plugin){
$this->pluginManager->enablePlugin($plugin);
}
/**
* @return void
*/
public function disablePlugins(){
$this->pluginManager->disablePlugins();
}
@ -2033,6 +2072,9 @@ class Server{
return false;
}
/**
* @return void
*/
public function reload(){
$this->logger->info("Saving worlds...");
@ -2072,11 +2114,16 @@ class Server{
/**
* Shuts the server down correctly
*
* @return void
*/
public function shutdown(){
$this->isRunning = false;
}
/**
* @return void
*/
public function forceShutdown(){
if($this->hasStopped){
return;
@ -2162,7 +2209,7 @@ class Server{
/**
* Starts the PocketMine-MP server and starts processing ticks and packets
*/
private function start(){
private function start() : void{
if($this->getConfigBool("enable-query", true)){
$this->queryHandler = new QueryHandler();
}
@ -2204,6 +2251,11 @@ class Server{
$this->forceShutdown();
}
/**
* @param int $signo
*
* @return void
*/
public function handleSignal($signo){
if($signo === SIGTERM or $signo === SIGINT or $signo === SIGHUP){
$this->shutdown();
@ -2213,6 +2265,8 @@ class Server{
/**
* @param \Throwable $e
* @param array|null $trace
*
* @return void
*/
public function exceptionHandler(\Throwable $e, $trace = null){
while(@ob_end_flush()){}
@ -2246,6 +2300,9 @@ class Server{
$this->crashDump();
}
/**
* @return void
*/
public function crashDump(){
while(@ob_end_flush()){}
if(!$this->isRunning){
@ -2328,6 +2385,9 @@ class Server{
exit(1);
}
/**
* @return mixed[]
*/
public function __debugInfo(){
return [];
}
@ -2336,7 +2396,7 @@ class Server{
return $this->tickSleeper;
}
private function tickProcessor(){
private function tickProcessor() : void{
$this->nextTick = microtime(true);
while($this->isRunning){
@ -2347,6 +2407,11 @@ class Server{
}
}
/**
* @param Player $player
*
* @return void
*/
public function onPlayerLogin(Player $player){
if($this->sendUsageTicker > 0){
$this->uniquePlayers[$player->getRawUniqueId()] = $player->getRawUniqueId();
@ -2355,27 +2420,49 @@ class Server{
$this->loggedInPlayers[$player->getRawUniqueId()] = $player;
}
/**
* @param Player $player
*
* @return void
*/
public function onPlayerLogout(Player $player){
unset($this->loggedInPlayers[$player->getRawUniqueId()]);
}
/**
* @param Player $player
*
* @return void
*/
public function addPlayer(Player $player){
$this->players[spl_object_hash($player)] = $player;
}
/**
* @param Player $player
*
* @return void
*/
public function removePlayer(Player $player){
unset($this->players[spl_object_hash($player)]);
}
/**
* @param Player $player
*
* @return void
*/
public function addOnlinePlayer(Player $player){
$this->updatePlayerListData($player->getUniqueId(), $player->getId(), $player->getDisplayName(), $player->getSkin(), $player->getXuid());
$this->playerList[$player->getRawUniqueId()] = $player;
}
/**
* @param Player $player
*
* @return void
*/
public function removeOnlinePlayer(Player $player){
if(isset($this->playerList[$player->getRawUniqueId()])){
unset($this->playerList[$player->getRawUniqueId()]);
@ -2391,6 +2478,8 @@ class Server{
* @param Skin $skin
* @param string $xboxUserId
* @param Player[]|null $players
*
* @return void
*/
public function updatePlayerListData(UUID $uuid, int $entityId, string $name, Skin $skin, string $xboxUserId = "", array $players = null){
$pk = new PlayerListPacket();
@ -2404,6 +2493,8 @@ class Server{
/**
* @param UUID $uuid
* @param Player[]|null $players
*
* @return void
*/
public function removePlayerListData(UUID $uuid, array $players = null){
$pk = new PlayerListPacket();
@ -2414,6 +2505,8 @@ class Server{
/**
* @param Player $p
*
* @return void
*/
public function sendFullPlayerListData(Player $p){
$pk = new PlayerListPacket();
@ -2449,6 +2542,9 @@ class Server{
}
}
/**
* @return void
*/
public function doAutoSave(){
if($this->getAutoSave()){
Timings::$worldSaveTimer->startTiming();
@ -2467,6 +2563,11 @@ class Server{
}
}
/**
* @param int $type
*
* @return void
*/
public function sendUsage($type = SendUsageTask::TYPE_STATUS){
if((bool) $this->getProperty("anonymous-statistics.enabled", true)){
$this->asyncPool->submitTask(new SendUsageTask($this, $type, $this->uniquePlayers));
@ -2503,7 +2604,7 @@ class Server{
return $this->memoryManager;
}
private function titleTick(){
private function titleTick() : void{
Timings::$titleTickTimer->startTiming();
$d = Utils::getRealMemoryUsage();
@ -2528,6 +2629,8 @@ class Server{
* @param int $port
* @param string $payload
*
* @return void
*
* TODO: move this to Network
*/
public function handlePacket(AdvancedSourceInterface $interface, string $address, int $port, string $payload){

View File

@ -33,12 +33,21 @@ abstract class Thread extends \Thread{
/** @var string|null */
protected $composerAutoloaderPath;
/** @var bool */
protected $isKilled = false;
/**
* @return \ClassLoader|null
*/
public function getClassLoader(){
return $this->classLoader;
}
/**
* @param \ClassLoader|null $loader
*
* @return void
*/
public function setClassLoader(\ClassLoader $loader = null){
$this->composerAutoloaderPath = \pocketmine\COMPOSER_AUTOLOADER_PATH;
@ -54,6 +63,8 @@ abstract class Thread extends \Thread{
* WARNING: This method MUST be called from any descendent threads' run() method to make autoloading usable.
* If you do not do this, you will not be able to use new classes that were not loaded when the thread was started
* (unless you are using a custom autoloader).
*
* @return void
*/
public function registerClassLoader(){
if($this->composerAutoloaderPath !== null){
@ -64,6 +75,11 @@ abstract class Thread extends \Thread{
}
}
/**
* @param int|null $options TODO: pthreads bug
*
* @return bool
*/
public function start(?int $options = \PTHREADS_INHERIT_ALL){
ThreadManager::getInstance()->add($this);
@ -75,6 +91,8 @@ abstract class Thread extends \Thread{
/**
* Stops the thread using the best way possible. Try to stop it yourself before calling this.
*
* @return void
*/
public function quit(){
$this->isKilled = true;

View File

@ -31,6 +31,9 @@ class ThreadManager extends \Volatile{
/** @var ThreadManager */
private static $instance = null;
/**
* @return void
*/
public static function init(){
self::$instance = new ThreadManager();
}
@ -44,6 +47,8 @@ class ThreadManager extends \Volatile{
/**
* @param Worker|Thread $thread
*
* @return void
*/
public function add($thread){
if($thread instanceof Thread or $thread instanceof Worker){
@ -53,6 +58,8 @@ class ThreadManager extends \Volatile{
/**
* @param Worker|Thread $thread
*
* @return void
*/
public function remove($thread){
if($thread instanceof Thread or $thread instanceof Worker){

View File

@ -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.11.0";
const BASE_VERSION = "3.11.4";
const IS_DEVELOPMENT_BUILD = false;
const BUILD_NUMBER = 0;

View File

@ -33,12 +33,21 @@ abstract class Worker extends \Worker{
/** @var string|null */
protected $composerAutoloaderPath;
/** @var bool */
protected $isKilled = false;
/**
* @return \ClassLoader|null
*/
public function getClassLoader(){
return $this->classLoader;
}
/**
* @param \ClassLoader|null $loader
*
* @return void
*/
public function setClassLoader(\ClassLoader $loader = null){
$this->composerAutoloaderPath = \pocketmine\COMPOSER_AUTOLOADER_PATH;
@ -54,6 +63,8 @@ abstract class Worker extends \Worker{
* WARNING: This method MUST be called from any descendent threads' run() method to make autoloading usable.
* If you do not do this, you will not be able to use new classes that were not loaded when the thread was started
* (unless you are using a custom autoloader).
*
* @return void
*/
public function registerClassLoader(){
if($this->composerAutoloaderPath !== null){
@ -64,6 +75,11 @@ abstract class Worker extends \Worker{
}
}
/**
* @param int|null $options TODO: pthreads bug
*
* @return bool
*/
public function start(?int $options = \PTHREADS_INHERIT_ALL){
ThreadManager::getInstance()->add($this);
@ -75,6 +91,8 @@ abstract class Worker extends \Worker{
/**
* Stops the thread using the best way possible. Try to stop it yourself before calling this.
*
* @return void
*/
public function quit(){
$this->isKilled = true;

View File

@ -76,6 +76,11 @@ class Bed extends Transparent{
return ($this->meta & self::BITFLAG_OCCUPIED) !== 0;
}
/**
* @param bool $occupied
*
* @return void
*/
public function setOccupied(bool $occupied = true){
if($occupied){
$this->meta |= self::BITFLAG_OCCUPIED;

View File

@ -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;
}

View File

@ -111,6 +111,11 @@ class CobblestoneWall extends Transparent{
);
}
/**
* @param Block $block
*
* @return bool
*/
public function canConnect(Block $block){
return $block instanceof static or $block instanceof FenceGate or ($block->isSolid() and !$block->isTransparent());
}

View File

@ -36,7 +36,7 @@ abstract class Door extends Transparent{
return false;
}
private function getFullDamage(){
private function getFullDamage() : int{
$damage = $this->getDamage();
$isUp = ($damage & 0x08) > 0;

View File

@ -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()){

View File

@ -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(
@ -102,6 +103,11 @@ abstract class Fence extends Transparent{
return $bbs;
}
/**
* @param Block $block
*
* @return bool
*/
public function canConnect(Block $block){
return $block instanceof static or $block instanceof FenceGate or ($block->isSolid() and !$block->isTransparent());
}

View File

@ -39,6 +39,7 @@ class Leaves extends Transparent{
public const DARK_OAK = 1;
protected $id = self::LEAVES;
/** @var int */
protected $woodType = self::WOOD;
public function __construct(int $meta = 0){
@ -68,7 +69,7 @@ class Leaves extends Transparent{
}
protected function findLog(Block $pos, array $visited, int $distance, ?int $fromSide = null) : bool{
protected function findLog(Block $pos, array &$visited, int $distance, ?int $fromSide = null) : bool{
$index = $pos->x . "." . $pos->y . "." . $pos->z;
if(isset($visited[$index])){
return false;

View File

@ -29,6 +29,7 @@ use pocketmine\item\ItemFactory;
class Leaves2 extends Leaves{
protected $id = self::LEAVES2;
/** @var int */
protected $woodType = self::WOOD2;
public function getName() : string{

View File

@ -38,6 +38,7 @@ use function min;
abstract class Liquid extends Transparent{
/** @var int */
public $adjacentSources = 0;
/** @var Vector3|null */
@ -90,6 +91,9 @@ abstract class Liquid extends Transparent{
abstract public function getBucketEmptySound() : int;
/**
* @return float
*/
public function getFluidHeightPercent(){
$d = $this->meta;
if($d >= 8){
@ -430,6 +434,9 @@ abstract class Liquid extends Transparent{
return ($decay >= 0 && $blockDecay >= $decay) ? $decay : $blockDecay;
}
/**
* @return void
*/
protected function checkForHarden(){
}

View File

@ -74,6 +74,11 @@ class TNT extends Solid{
}
}
/**
* @param int $fuse
*
* @return void
*/
public function ignite(int $fuse = 80){
$this->getLevel()->setBlock($this, BlockFactory::get(Block::AIR), true);

View File

@ -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(

View File

@ -114,6 +114,8 @@ abstract class Command{
/**
* @param string|null $permission
*
* @return void
*/
public function setPermission(string $permission = null){
$this->permission = $permission;
@ -259,6 +261,8 @@ abstract class Command{
/**
* @param string[] $aliases
*
* @return void
*/
public function setAliases(array $aliases){
$this->aliases = $aliases;
@ -269,6 +273,8 @@ abstract class Command{
/**
* @param string $description
*
* @return void
*/
public function setDescription(string $description){
$this->description = $description;
@ -276,6 +282,8 @@ abstract class Command{
/**
* @param string $permissionMessage
*
* @return void
*/
public function setPermissionMessage(string $permissionMessage){
$this->permissionMessage = $permissionMessage;
@ -283,6 +291,8 @@ abstract class Command{
/**
* @param string $usage
*
* @return void
*/
public function setUsage(string $usage){
$this->usageMessage = $usage;
@ -292,6 +302,8 @@ abstract class Command{
* @param CommandSender $source
* @param TextContainer|string $message
* @param bool $sendToSource
*
* @return void
*/
public static function broadcastCommandMessage(CommandSender $source, $message, bool $sendToSource = true){
if($message instanceof TextContainer){

View File

@ -29,6 +29,8 @@ interface CommandMap{
/**
* @param string $fallbackPrefix
* @param Command[] $commands
*
* @return void
*/
public function registerAll(string $fallbackPrefix, array $commands);

View File

@ -54,7 +54,9 @@ class CommandReader extends Thread{
/** @var \Threaded */
protected $buffer;
/** @var bool */
private $shutdown = false;
/** @var int */
private $type = self::TYPE_STREAM;
/** @var SleeperNotifier|null */
@ -71,6 +73,9 @@ class CommandReader extends Thread{
}
}
/**
* @return void
*/
public function shutdown(){
$this->shutdown = true;
}
@ -94,7 +99,7 @@ class CommandReader extends Thread{
throw new \ThreadException($message);
}
private function initStdin(){
private function initStdin() : void{
if(is_resource(self::$stdin)){
fclose(self::$stdin);
}
@ -185,6 +190,9 @@ class CommandReader extends Thread{
return null;
}
/**
* @return void
*/
public function run(){
$this->registerClassLoader();

View File

@ -31,6 +31,8 @@ interface CommandSender extends Permissible{
/**
* @param TextContainer|string $message
*
* @return void
*/
public function sendMessage($message);
@ -56,6 +58,8 @@ interface CommandSender extends Permissible{
* Sets the line height used for command output pagination for this command sender. `null` will reset it to default.
*
* @param int|null $height
*
* @return void
*/
public function setScreenLineHeight(int $height = null);
}

View File

@ -37,6 +37,7 @@ use const PHP_INT_MAX;
class ConsoleCommandSender implements CommandSender{
/** @var PermissibleBase */
private $perm;
/** @var int|null */
@ -104,6 +105,8 @@ class ConsoleCommandSender implements CommandSender{
/**
* @param TextContainer|string $message
*
* @return void
*/
public function sendMessage($message){
if($message instanceof TextContainer){
@ -133,6 +136,8 @@ class ConsoleCommandSender implements CommandSender{
/**
* @param bool $value
*
* @return void
*/
public function setOp(bool $value){

View File

@ -32,6 +32,7 @@ use function strpos;
use function substr;
class FormattedCommandAlias extends Command{
/** @var string[] */
private $formatStrings = [];
/**

View File

@ -70,6 +70,8 @@ class PluginCommand extends Command implements PluginIdentifiableCommand{
/**
* @param CommandExecutor $executor
*
* @return void
*/
public function setExecutor(CommandExecutor $executor){
$this->executor = $executor;

View File

@ -41,6 +41,9 @@ class RemoteConsoleCommandSender extends ConsoleCommandSender{
$this->messages .= trim($message, "\r\n") . "\n";
}
/**
* @return string
*/
public function getMessage(){
return $this->messages;
}

View File

@ -92,7 +92,7 @@ class SimpleCommandMap implements CommandMap{
$this->setDefaultCommands();
}
private function setDefaultCommands(){
private function setDefaultCommands() : void{
$this->registerAll("pocketmine", [
new BanCommand("ban"),
new BanIpCommand("ban-ip"),
@ -226,8 +226,8 @@ class SimpleCommandMap implements CommandMap{
* This method is intended to provide capability for handling commands with spaces in their name.
* The referenced parameters will be modified accordingly depending on the resulting matched command.
*
* @param string &$commandName
* @param string[] &$args
* @param string $commandName reference parameter
* @param string[] $args reference parameter
*
* @return Command|null
*/
@ -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;
}

View File

@ -75,7 +75,7 @@ class BanIpCommand extends VanillaCommand{
return true;
}
private function processIPBan(string $ip, CommandSender $sender, string $reason){
private function processIPBan(string $ip, CommandSender $sender, string $reason) : void{
$sender->getServer()->getIPBans()->addBan($ip, $reason, null, $sender->getName());
foreach($sender->getServer()->getOnlinePlayers() as $player){

View File

@ -84,7 +84,7 @@ class VersionCommand extends VanillaCommand{
return true;
}
private function describeToSender(Plugin $plugin, CommandSender $sender){
private function describeToSender(Plugin $plugin, CommandSender $sender) : void{
$desc = $plugin->getDescription();
$sender->sendMessage(TextFormat::DARK_GREEN . $desc->getName() . TextFormat::WHITE . " version " . TextFormat::DARK_GREEN . $desc->getVersion());

View File

@ -46,14 +46,22 @@ class Attribute{
public const HORSE_JUMP_STRENGTH = 14;
public const ZOMBIE_SPAWN_REINFORCEMENTS = 15;
/** @var int */
private $id;
/** @var float */
protected $minValue;
/** @var float */
protected $maxValue;
/** @var float */
protected $defaultValue;
/** @var float */
protected $currentValue;
/** @var string */
protected $name;
/** @var bool */
protected $shouldSend;
/** @var bool */
protected $desynchronized = true;
/** @var Attribute[] */
@ -137,6 +145,11 @@ class Attribute{
return $this->minValue;
}
/**
* @param float $minValue
*
* @return $this
*/
public function setMinValue(float $minValue){
if($minValue > ($max = $this->getMaxValue())){
throw new \InvalidArgumentException("Minimum $minValue is greater than the maximum $max");
@ -153,6 +166,11 @@ class Attribute{
return $this->maxValue;
}
/**
* @param float $maxValue
*
* @return $this
*/
public function setMaxValue(float $maxValue){
if($maxValue < ($min = $this->getMinValue())){
throw new \InvalidArgumentException("Maximum $maxValue is less than the minimum $min");
@ -169,6 +187,11 @@ class Attribute{
return $this->defaultValue;
}
/**
* @param float $defaultValue
*
* @return $this
*/
public function setDefaultValue(float $defaultValue){
if($defaultValue > $this->getMaxValue() or $defaultValue < $this->getMinValue()){
throw new \InvalidArgumentException("Default $defaultValue is outside the range " . $this->getMinValue() . " - " . $this->getMaxValue());

View File

@ -25,6 +25,9 @@ namespace pocketmine\entity;
use function array_filter;
/**
* @phpstan-implements \ArrayAccess<int, float>
*/
class AttributeMap implements \ArrayAccess{
/** @var Attribute[] */
private $attributes = [];
@ -58,6 +61,11 @@ class AttributeMap implements \ArrayAccess{
});
}
/**
* @param int $offset
*
* @return bool
*/
public function offsetExists($offset) : bool{
return isset($this->attributes[$offset]);
}
@ -79,6 +87,9 @@ class AttributeMap implements \ArrayAccess{
$this->attributes[$offset]->setValue($value);
}
/**
* @param int $offset
*/
public function offsetUnset($offset) : void{
throw new \RuntimeException("Could not unset an attribute from an attribute map");
}

View File

@ -32,8 +32,10 @@ use function is_string;
class DataPropertyManager{
/** @var mixed[][] */
private $properties = [];
/** @var mixed[][] */
private $dirtyProperties = [];
public function __construct(){

View File

@ -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{

View File

@ -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

View File

@ -317,6 +317,7 @@ abstract class Entity extends Location implements Metadatable, EntityIds{
public const DATA_PLAYER_FLAG_SLEEP = 1;
public const DATA_PLAYER_FLAG_DEAD = 2; //TODO: CHECK
/** @var int */
public static $entityCount = 1;
/** @var string[] */
private static $knownEntities = [];
@ -463,12 +464,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;
@ -504,6 +505,7 @@ abstract class Entity extends Location implements Metadatable, EntityIds{
/** @var float */
private $health = 20.0;
/** @var int */
private $maxHealth = 20;
/** @var float */
@ -1102,7 +1104,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();
}
@ -1210,15 +1212,19 @@ abstract class Entity extends Location implements Metadatable, EntityIds{
}
protected function updateMovement(bool $teleport = false) : void{
//TODO: hack for client-side AI interference: prevent client sided movement when motion is 0
$this->setImmobile($this->motion->x == 0 and $this->motion->y == 0 and $this->motion->z == 0);
$diffPosition = ($this->x - $this->lastX) ** 2 + ($this->y - $this->lastY) ** 2 + ($this->z - $this->lastZ) ** 2;
$diffRotation = ($this->yaw - $this->lastYaw) ** 2 + ($this->pitch - $this->lastPitch) ** 2;
$diffMotion = $this->motion->subtract($this->lastMotion)->lengthSquared();
if($teleport or $diffPosition > 0.0001 or $diffRotation > 1.0){
$still = $this->motion->lengthSquared() == 0.0;
$wasStill = $this->lastMotion->lengthSquared() == 0.0;
if($wasStill !== $still){
//TODO: hack for client-side AI interference: prevent client sided movement when motion is 0
$this->setImmobile($still);
}
if($teleport or $diffPosition > 0.0001 or $diffRotation > 1.0 or (!$wasStill and $still)){
$this->lastX = $this->x;
$this->lastY = $this->y;
$this->lastZ = $this->z;
@ -1229,7 +1235,7 @@ abstract class Entity extends Location implements Metadatable, EntityIds{
$this->broadcastMovement($teleport);
}
if($diffMotion > 0.0025 or ($diffMotion > 0.0001 and $this->motion->lengthSquared() <= 0.0001)){ //0.05 ** 2
if($diffMotion > 0.0025 or $wasStill !== $still){ //0.05 ** 2
$this->lastMotion = clone $this->motion;
$this->broadcastMotion();
@ -2279,6 +2285,7 @@ abstract class Entity extends Location implements Metadatable, EntityIds{
* @param string $name
* @param mixed $value
*
* @return void
* @throws \ErrorException
* @throws \InvalidArgumentException
*/

View File

@ -26,5 +26,8 @@ namespace pocketmine\entity;
interface Explosive{
/**
* @return void
*/
public function explode();
}

View File

@ -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;
@ -80,6 +81,7 @@ class Human extends Creature implements ProjectileSource, InventoryHolder{
/** @var UUID */
protected $uuid;
/** @var string */
protected $rawUUID;
public $width = 0.6;
@ -89,10 +91,14 @@ class Human extends Creature implements ProjectileSource, InventoryHolder{
/** @var Skin */
protected $skin;
/** @var int */
protected $foodTickTimer = 0;
/** @var int */
protected $totalXp = 0;
/** @var int */
protected $xpSeed;
/** @var int */
protected $xpCooldown = 0;
protected $baseOffset = 1.62;
@ -554,7 +560,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);

View File

@ -70,6 +70,7 @@ abstract class Living extends Entity implements Damageable{
protected $gravity = 0.08;
protected $drag = 0.02;
/** @var int */
protected $attackTime = 0;
/** @var int */
@ -77,6 +78,7 @@ abstract class Living extends Entity implements Damageable{
/** @var int */
protected $maxDeadTicks = 25;
/** @var float */
protected $jumpVelocity = 0.42;
/** @var EffectInstance[] */
@ -263,7 +265,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 +334,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 +715,7 @@ abstract class Living extends Entity implements Damageable{
}
}
return !empty($this->effects);
return count($this->effects) > 0;
}
/**
@ -893,7 +895,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);
}

View File

@ -42,8 +42,10 @@ class Squid extends WaterAnimal{
/** @var Vector3|null */
public $swimDirection = null;
/** @var float */
public $swimSpeed = 0.1;
/** @var int */
private $switchDirectionTicker = 0;
public function initEntity() : void{

View File

@ -43,6 +43,7 @@ class PrimedTNT extends Entity implements Explosive{
protected $gravity = 0.04;
protected $drag = 0.02;
/** @var int */
protected $fuse;
public $canCollide = false;

View File

@ -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.
];

View File

@ -35,6 +35,8 @@ interface Cancellable{
/**
* @param bool $value
*
* @return void
*/
public function setCancelled(bool $value = true);
}

View File

@ -27,6 +27,7 @@ use pocketmine\entity\Entity;
use pocketmine\event\Cancellable;
class EntityCombustEvent extends EntityEvent implements Cancellable{
/** @var int */
protected $duration;
/**

View File

@ -99,6 +99,8 @@ class PlayerCreationEvent extends Event{
/**
* @param string $class
*
* @return void
*/
public function setBaseClass($class){
if(!is_a($class, $this->baseClass, true)){
@ -117,6 +119,8 @@ class PlayerCreationEvent extends Event{
/**
* @param string $class
*
* @return void
*/
public function setPlayerClass($class){
if(!is_a($class, $this->baseClass, true)){

View File

@ -40,6 +40,7 @@ class PlayerDeathEvent extends EntityDeathEvent{
/** @var TextContainer|string */
private $deathMessage;
/** @var bool */
private $keepInventory = false;
/**

View File

@ -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 = [];
@ -84,6 +84,8 @@ abstract class BaseInventory implements Inventory{
* WARNING: If the size is smaller, any items past the new size will be lost.
*
* @param int $size
*
* @return void
*/
public function setSize(int $size){
$this->slots->setSize($size);

View File

@ -142,6 +142,9 @@ class DoubleChestInventory extends ChestInventory implements InventoryHolder{
return $this->right;
}
/**
* @return void
*/
public function invalidate(){
$this->left = null;
$this->right = null;

View File

@ -53,6 +53,8 @@ class EnderChestInventory extends ChestInventory{
* Set the holder's position to that of a tile
*
* @param EnderChest $enderChest
*
* @return void
*/
public function setHolderPosition(EnderChest $enderChest){
$this->holder->setComponents($enderChest->getFloorX(), $enderChest->getFloorY(), $enderChest->getFloorZ());

View File

@ -44,6 +44,8 @@ class FurnaceRecipe implements Recipe{
/**
* @param Item $item
*
* @return void
*/
public function setInput(Item $item){
$this->ingredient = clone $item;

View File

@ -39,6 +39,7 @@ class MultiRecipe{
public const TYPE_FIREWORKS = "00000000-0000-0000-0000-000000000002";
public const TYPE_MAP_LOCKING_CARTOGRAPHY = "602234E4-CAC1-4353-8BB7-B1EBFF70024B";
/** @var UUID */
private $uuid;
public function __construct(UUID $uuid){

View File

@ -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;
@ -93,7 +97,7 @@ class PlayerInventory extends BaseInventory{
*
* @throws \InvalidArgumentException
*/
private function throwIfNotHotbarSlot(int $slot){
private function throwIfNotHotbarSlot(int $slot) : void{
if(!$this->isHotbarSlot($slot)){
throw new \InvalidArgumentException("$slot is not a valid hotbar slot index (expected 0 - " . ($this->getHotbarSize() - 1) . ")");
}
@ -128,6 +132,7 @@ class PlayerInventory extends BaseInventory{
* @param bool $send Whether to send updates back to the inventory holder. This should usually be true for plugin calls.
* It should only be false to prevent feedback loops of equipment packets between client and server.
*
* @return void
* @throws \InvalidArgumentException if the hotbar slot is out of range
*/
public function setHeldItemIndex(int $hotbarSlot, bool $send = true){
@ -166,6 +171,8 @@ class PlayerInventory extends BaseInventory{
* Sends the currently-held item to specified targets.
*
* @param Player|Player[] $target
*
* @return void
*/
public function sendHeldItem($target){
$item = $this->getItemInHand();
@ -197,6 +204,9 @@ class PlayerInventory extends BaseInventory{
return 9;
}
/**
* @return void
*/
public function sendCreativeContents(){
//TODO: this mess shouldn't be in here
$holder = $this->getHolder();

View File

@ -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
}
}

View File

@ -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));
}

View File

@ -53,6 +53,7 @@ use function spl_object_hash;
* @see InventoryAction
*/
class InventoryTransaction{
/** @var bool */
protected $hasExecuted = false;
/** @var Player */
protected $source;
@ -237,13 +238,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);

View File

@ -37,6 +37,7 @@ class CreativeInventoryAction extends InventoryAction{
*/
public const TYPE_CREATE_ITEM = 1;
/** @var int */
protected $actionType;
public function __construct(Item $sourceItem, Item $targetItem, int $actionType){

View File

@ -49,6 +49,8 @@ interface Consumable{
* Called when this Consumable is consumed by mob, after standard resulting effects have been applied.
*
* @param Living $consumer
*
* @return void
*/
public function onConsume(Living $consumer);
}

View File

@ -42,6 +42,8 @@ abstract class Durable extends Item{
* Sets whether the item will take damage when used.
*
* @param bool $value
*
* @return void
*/
public function setUnbreakable(bool $value = true){
$this->setNamedTagEntry(new ByteTag("Unbreakable", $value ? 1 : 0));

View File

@ -123,6 +123,9 @@ class Item implements ItemIds, \JsonSerializable{
/** @var Item[] */
private static $creative = [];
/**
* @return void
*/
public static function initCreativeItems(){
self::clearCreativeItems();
@ -140,6 +143,8 @@ class Item implements ItemIds, \JsonSerializable{
/**
* Removes all previously added items from the creative menu.
* Note: Players who are already online when this is called will not see this change.
*
* @return void
*/
public static function clearCreativeItems(){
Item::$creative = [];
@ -154,6 +159,8 @@ class Item implements ItemIds, \JsonSerializable{
* Note: Players who are already online when this is called will not see this change.
*
* @param Item $item
*
* @return void
*/
public static function addCreativeItem(Item $item){
Item::$creative[] = clone $item;
@ -164,6 +171,8 @@ class Item implements ItemIds, \JsonSerializable{
* Note: Players who are already online when this is called will not see this change.
*
* @param Item $item
*
* @return void
*/
public static function removeCreativeItem(Item $item){
$index = self::getCreativeItemIndex($item);
@ -233,7 +242,7 @@ class Item implements ItemIds, \JsonSerializable{
*
* @param CompoundTag|string|null $tags
*
* @return Item
* @return $this
*/
public function setCompoundTag($tags) : Item{
if($tags instanceof CompoundTag){
@ -272,6 +281,9 @@ class Item implements ItemIds, \JsonSerializable{
return $this->getNamedTagEntry(self::TAG_BLOCK_ENTITY_TAG) instanceof CompoundTag;
}
/**
* @return $this
*/
public function clearCustomBlockData(){
$this->removeNamedTagEntry(self::TAG_BLOCK_ENTITY_TAG);
return $this;
@ -280,7 +292,7 @@ class Item implements ItemIds, \JsonSerializable{
/**
* @param CompoundTag $compound
*
* @return Item
* @return $this
*/
public function setCustomBlockData(CompoundTag $compound) : Item{
$tags = clone $compound;
@ -479,7 +491,7 @@ class Item implements ItemIds, \JsonSerializable{
/**
* @param string $name
*
* @return Item
* @return $this
*/
public function setCustomName(string $name) : Item{
if($name === ""){
@ -499,7 +511,7 @@ class Item implements ItemIds, \JsonSerializable{
}
/**
* @return Item
* @return $this
*/
public function clearCustomName() : Item{
$display = $this->getNamedTagEntry(self::TAG_DISPLAY);
@ -531,7 +543,7 @@ class Item implements ItemIds, \JsonSerializable{
/**
* @param string[] $lines
*
* @return Item
* @return $this
*/
public function setLore(array $lines) : Item{
$display = $this->getNamedTagEntry(self::TAG_DISPLAY);
@ -588,7 +600,7 @@ class Item implements ItemIds, \JsonSerializable{
*
* @param CompoundTag $tag
*
* @return Item
* @return $this
*/
public function setNamedTag(CompoundTag $tag) : Item{
if($tag->getCount() === 0){
@ -603,7 +615,7 @@ class Item implements ItemIds, \JsonSerializable{
/**
* Removes the Item's NBT.
* @return Item
* @return $this
*/
public function clearNamedTag() : Item{
return $this->setCompoundTag("");
@ -619,7 +631,7 @@ class Item implements ItemIds, \JsonSerializable{
/**
* @param int $count
*
* @return Item
* @return $this
*/
public function setCount(int $count) : Item{
$this->count = $count;
@ -632,7 +644,7 @@ class Item implements ItemIds, \JsonSerializable{
*
* @param int $count
*
* @return Item
* @return $this
* @throws \InvalidArgumentException if trying to pop more items than are on the stack
*/
public function pop(int $count = 1) : Item{
@ -700,7 +712,7 @@ class Item implements ItemIds, \JsonSerializable{
/**
* @param int $meta
*
* @return Item
* @return $this
*/
public function setDamage(int $meta) : Item{
$this->meta = $meta !== -1 ? $meta & 0x7FFF : -1;

View File

@ -46,6 +46,9 @@ class ItemFactory{
/** @var \SplFixedArray */
private static $list = null;
/**
* @return void
*/
public static function init(){
self::$list = new \SplFixedArray(65536);
@ -285,6 +288,7 @@ class ItemFactory{
* @param Item $item
* @param bool $override
*
* @return void
* @throws \RuntimeException if something attempted to override an already-registered item without specifying the
* $override parameter.
*/

View File

@ -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;
}

View File

@ -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;
}

View File

@ -105,6 +105,12 @@ class BaseLang{
return $this->langName;
}
/**
* @param string $path
* @param string[] $d reference parameter
*
* @return bool
*/
protected static function loadLang(string $path, array &$d){
if(file_exists($path)){
$d = array_map('\stripcslashes', parse_ini_file($path, false, INI_SCANNER_RAW));
@ -115,9 +121,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
*/
@ -132,6 +138,11 @@ class BaseLang{
return $baseText;
}
/**
* @param TextContainer $c
*
* @return string
*/
public function translate(TextContainer $c){
if($c instanceof TranslationContainer){
$baseText = $this->internalGet($c->getText());

View File

@ -37,6 +37,8 @@ class TextContainer{
/**
* @param string $text
*
* @return void
*/
public function setText(string $text){
$this->text = $text;

View File

@ -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);
@ -59,6 +59,8 @@ class TranslationContainer extends TextContainer{
/**
* @param int $i
* @param string $str
*
* @return void
*/
public function setParameter(int $i, string $str){
if($i < 0 or $i > count($this->params)){ //Intended, allow to set the last
@ -70,6 +72,8 @@ class TranslationContainer extends TextContainer{
/**
* @param string[] $params
*
* @return void
*/
public function setParameters(array $params){
$i = 0;

View File

@ -78,6 +78,8 @@ interface ChunkLoader{
* This method will be called when a Chunk is replaced by a new one
*
* @param Chunk $chunk
*
* @return void
*/
public function onChunkChanged(Chunk $chunk);
@ -85,6 +87,8 @@ interface ChunkLoader{
* This method will be called when a registered chunk is loaded
*
* @param Chunk $chunk
*
* @return void
*/
public function onChunkLoaded(Chunk $chunk);
@ -93,6 +97,8 @@ interface ChunkLoader{
* This method will be called when a registered chunk is unloaded
*
* @param Chunk $chunk
*
* @return void
*/
public function onChunkUnloaded(Chunk $chunk);
@ -101,6 +107,8 @@ interface ChunkLoader{
* Usually it'll be sent with another call to onChunkChanged()
*
* @param Chunk $chunk
*
* @return void
*/
public function onChunkPopulated(Chunk $chunk);
@ -108,6 +116,8 @@ interface ChunkLoader{
* This method will be called when a block changes in a registered chunk
*
* @param Block|Vector3 $block
*
* @return void
*/
public function onBlockChanged(Vector3 $block);

View File

@ -44,6 +44,8 @@ interface ChunkManager{
* @param int $y
* @param int $z
* @param int $id 0-255
*
* @return void
*/
public function setBlockIdAt(int $x, int $y, int $z, int $id);
@ -65,6 +67,8 @@ interface ChunkManager{
* @param int $y
* @param int $z
* @param int $data 0-15
*
* @return void
*/
public function setBlockDataAt(int $x, int $y, int $z, int $data);
@ -86,6 +90,8 @@ interface ChunkManager{
* @param int $y
* @param int $z
* @param int $level
*
* @return void
*/
public function setBlockLightAt(int $x, int $y, int $z, int $level);
@ -107,6 +113,8 @@ interface ChunkManager{
* @param int $y
* @param int $z
* @param int $level
*
* @return void
*/
public function setBlockSkyLightAt(int $x, int $y, int $z, int $level);
@ -122,6 +130,8 @@ interface ChunkManager{
* @param int $chunkX
* @param int $chunkZ
* @param Chunk|null $chunk
*
* @return void
*/
public function setChunk(int $chunkX, int $chunkZ, Chunk $chunk = null);

View File

@ -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;
}
}
}

View File

@ -120,7 +120,9 @@ use const PHP_INT_MIN;
class Level implements ChunkManager, Metadatable{
/** @var int */
private static $levelIdCounter = 1;
/** @var int */
private static $chunkLoaderCounter = 1;
public const Y_MASK = 0xFF;
@ -433,6 +435,8 @@ class Level implements ChunkManager, Metadatable{
/**
* @deprecated does nothing
* @param int $tickRate
*
* @return void
*/
public function setTickRate(int $tickRate){
@ -443,6 +447,9 @@ class Level implements ChunkManager, Metadatable{
$this->server->getAsyncPool()->submitTaskToWorker(new GeneratorRegisterTask($this, $this->generator, $this->provider->getGeneratorOptions()), $worker);
}
/**
* @return void
*/
public function unregisterGenerator(){
$pool = $this->server->getAsyncPool();
foreach($pool->getRunningWorkers() as $i){
@ -476,6 +483,9 @@ class Level implements ChunkManager, Metadatable{
return $this->closed;
}
/**
* @return void
*/
public function close(){
if($this->closed){
throw new \InvalidStateException("Tried to close a world which is already closed");
@ -498,12 +508,18 @@ class Level implements ChunkManager, Metadatable{
$this->closed = true;
}
/**
* @param Sound $sound
* @param Player[]|null $players
*
* @return void
*/
public function addSound(Sound $sound, array $players = null){
$pk = $sound->encode();
if(!is_array($pk)){
$pk = [$pk];
}
if(!empty($pk)){
if(count($pk) > 0){
if($players === null){
foreach($pk as $e){
$this->broadcastPacketToViewers($sound, $e);
@ -514,12 +530,18 @@ class Level implements ChunkManager, Metadatable{
}
}
/**
* @param Particle $particle
* @param Player[]|null $players
*
* @return void
*/
public function addParticle(Particle $particle, array $players = null){
$pk = $particle->encode();
if(!is_array($pk)){
$pk = [$pk];
}
if(!empty($pk)){
if(count($pk) > 0){
if($players === null){
foreach($pk as $e){
$this->broadcastPacketToViewers($particle, $e);
@ -536,6 +558,8 @@ class Level implements ChunkManager, Metadatable{
* @param Vector3|null $pos If null, broadcasts to every player in the Level
* @param int $evid
* @param int $data
*
* @return void
*/
public function broadcastLevelEvent(?Vector3 $pos, int $evid, int $data = 0){
$pk = new LevelEventPacket();
@ -559,6 +583,8 @@ class Level implements ChunkManager, Metadatable{
* @param int $entityTypeId
* @param bool $isBabyMob
* @param bool $disableRelativeVolume If true, all players receiving this sound-event will hear the sound at full volume regardless of distance
*
* @return void
*/
public function broadcastLevelSoundEvent(Vector3 $pos, int $soundId, int $extraData = -1, int $entityTypeId = -1, bool $isBabyMob = false, bool $disableRelativeVolume = false){
$pk = new LevelSoundEventPacket();
@ -575,6 +601,11 @@ class Level implements ChunkManager, Metadatable{
return $this->autoSave;
}
/**
* @param bool $value
*
* @return void
*/
public function setAutoSave(bool $value){
$this->autoSave = $value;
}
@ -672,6 +703,8 @@ class Level implements ChunkManager, Metadatable{
* @param int $chunkX
* @param int $chunkZ
* @param DataPacket $packet
*
* @return void
*/
public function addChunkPacket(int $chunkX, int $chunkZ, DataPacket $packet){
if(!isset($this->chunkPackets[$index = Level::chunkHash($chunkX, $chunkZ)])){
@ -710,6 +743,14 @@ class Level implements ChunkManager, Metadatable{
$this->globalPackets[] = $packet;
}
/**
* @param ChunkLoader $loader
* @param int $chunkX
* @param int $chunkZ
* @param bool $autoLoad
*
* @return void
*/
public function registerChunkLoader(ChunkLoader $loader, int $chunkX, int $chunkZ, bool $autoLoad = true){
$loaderId = $loader->getLoaderId();
@ -739,6 +780,13 @@ class Level implements ChunkManager, Metadatable{
}
}
/**
* @param ChunkLoader $loader
* @param int $chunkX
* @param int $chunkZ
*
* @return void
*/
public function unregisterChunkLoader(ChunkLoader $loader, int $chunkX, int $chunkZ){
$chunkHash = Level::chunkHash($chunkX, $chunkZ);
$loaderId = $loader->getLoaderId();
@ -762,6 +810,8 @@ class Level implements ChunkManager, Metadatable{
* @internal
*
* @param Player ...$targets If empty, will send to all players in the level.
*
* @return void
*/
public function sendTime(Player ...$targets){
$pk = new SetTimePacket();
@ -775,6 +825,7 @@ class Level implements ChunkManager, Metadatable{
*
* @param int $currentTick
*
* @return void
*/
public function doTick(int $currentTick){
if($this->closed){
@ -881,7 +932,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 +960,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 = [];
@ -927,6 +978,9 @@ class Level implements ChunkManager, Metadatable{
$this->chunkPackets = [];
}
/**
* @return void
*/
public function checkSleep(){
if(count($this->players) === 0){
return;
@ -962,6 +1016,8 @@ class Level implements ChunkManager, Metadatable{
* @param Vector3[] $blocks
* @param int $flags
* @param bool $optimizeRebuilds
*
* @return void
*/
public function sendBlocks(array $target, array $blocks, int $flags = UpdateBlockPacket::FLAG_NONE, bool $optimizeRebuilds = false){
$packets = [];
@ -1021,6 +1077,11 @@ class Level implements ChunkManager, Metadatable{
$this->server->batchPackets($target, $packets, false, false);
}
/**
* @param bool $force
*
* @return void
*/
public function clearCache(bool $force = false){
if($force){
$this->chunkCache = [];
@ -1037,6 +1098,12 @@ class Level implements ChunkManager, Metadatable{
}
}
/**
* @param int $chunkX
* @param int $chunkZ
*
* @return void
*/
public function clearChunkCache(int $chunkX, int $chunkZ){
unset($this->chunkCache[Level::chunkHash($chunkX, $chunkZ)]);
}
@ -1045,15 +1112,25 @@ class Level implements ChunkManager, Metadatable{
return $this->randomTickBlocks;
}
/**
* @param int $id
*
* @return void
*/
public function addRandomTickedBlock(int $id){
$this->randomTickBlocks[$id] = BlockFactory::get($id);
}
/**
* @param int $id
*
* @return void
*/
public function removeRandomTickedBlock(int $id){
$this->randomTickBlocks[$id] = null;
}
private function tickChunks(){
private function tickChunks() : void{
if($this->chunksPerTick <= 0 or count($this->loaders) === 0){
$this->chunkTickList = [];
return;
@ -1161,6 +1238,9 @@ class Level implements ChunkManager, Metadatable{
return true;
}
/**
* @return void
*/
public function saveChunks(){
$this->timings->syncChunkSaveTimer->startTiming();
try{
@ -1181,6 +1261,8 @@ class Level implements ChunkManager, Metadatable{
*
* @param Vector3 $pos
* @param int $delay
*
* @return void
*/
public function scheduleDelayedBlockUpdate(Vector3 $pos, int $delay){
if(
@ -1198,6 +1280,8 @@ class Level implements ChunkManager, Metadatable{
* Blocks will be updated with the normal update type.
*
* @param Vector3 $pos
*
* @return void
*/
public function scheduleNeighbourBlockUpdates(Vector3 $pos){
$pos = $pos->floor();
@ -1489,6 +1573,11 @@ class Level implements ChunkManager, Metadatable{
return $block;
}
/**
* @param Vector3 $pos
*
* @return void
*/
public function updateAllLight(Vector3 $pos){
$this->updateBlockSkyLight($pos->x, $pos->y, $pos->z);
$this->updateBlockLight($pos->x, $pos->y, $pos->z);
@ -1514,6 +1603,13 @@ class Level implements ChunkManager, Metadatable{
]);
}
/**
* @param int $x
* @param int $y
* @param int $z
*
* @return void
*/
public function updateBlockSkyLight(int $x, int $y, int $z){
$this->timings->doBlockSkyLightUpdates->startTiming();
@ -1574,6 +1670,13 @@ class Level implements ChunkManager, Metadatable{
]);
}
/**
* @param int $x
* @param int $y
* @param int $z
*
* @return void
*/
public function updateBlockLight(int $x, int $y, int $z){
$this->timings->doBlockLightUpdates->startTiming();
@ -1776,7 +1879,7 @@ class Level implements ChunkManager, Metadatable{
* It'll try to lower the durability if Item is a tool, and set it to Air if broken.
*
* @param Vector3 $vector
* @param Item &$item (if null, can break anything)
* @param Item $item reference parameter (if null, can break anything)
* @param Player $player
* @param bool $createParticles
*
@ -1845,7 +1948,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 +2052,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
}
@ -2240,6 +2343,8 @@ class Level implements ChunkManager, Metadatable{
* @param int $y
* @param int $z
* @param int $id 0-255
*
* @return void
*/
public function setBlockIdAt(int $x, int $y, int $z, int $id){
if(!$this->isInWorld($x, $y, $z)){ //TODO: bad hack but fixing this requires BC breaks to do properly :(
@ -2279,6 +2384,8 @@ class Level implements ChunkManager, Metadatable{
* @param int $y
* @param int $z
* @param int $data 0-15
*
* @return void
*/
public function setBlockDataAt(int $x, int $y, int $z, int $data){
if(!$this->isInWorld($x, $y, $z)){ //TODO: bad hack but fixing this requires BC breaks to do properly :(
@ -2319,6 +2426,8 @@ class Level implements ChunkManager, Metadatable{
* @param int $y
* @param int $z
* @param int $level 0-15
*
* @return void
*/
public function setBlockSkyLightAt(int $x, int $y, int $z, int $level){
$this->getChunk($x >> 4, $z >> 4, true)->setBlockSkyLight($x & 0x0f, $y, $z & 0x0f, $level & 0x0f);
@ -2344,6 +2453,8 @@ class Level implements ChunkManager, Metadatable{
* @param int $y
* @param int $z
* @param int $level 0-15
*
* @return void
*/
public function setBlockLightAt(int $x, int $y, int $z, int $level){
$this->getChunk($x >> 4, $z >> 4, true)->setBlockLight($x & 0x0f, $y, $z & 0x0f, $level & 0x0f);
@ -2373,6 +2484,8 @@ class Level implements ChunkManager, Metadatable{
* @param int $x
* @param int $z
* @param int $biomeId
*
* @return void
*/
public function setBiomeId(int $x, int $z, int $biomeId){
$this->getChunk($x >> 4, $z >> 4, true)->setBiomeId($x & 0x0f, $z & 0x0f, $biomeId);
@ -2392,6 +2505,8 @@ class Level implements ChunkManager, Metadatable{
* @param int $x
* @param int $z
* @param int $value
*
* @return void
*/
public function setHeightMap(int $x, int $z, int $value){
$this->getChunk($x >> 4, $z >> 4, true)->setHeightMap($x & 0x0f, $z & 0x0f, $value);
@ -2442,7 +2557,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 = [];
@ -2459,6 +2574,13 @@ class Level implements ChunkManager, Metadatable{
return $result;
}
/**
* @param int $x
* @param int $z
* @param Chunk|null $chunk
*
* @return void
*/
public function generateChunkCallback(int $x, int $z, ?Chunk $chunk){
Timings::$generationCallbackTimer->startTiming();
if(isset($this->chunkPopulationQueue[$index = Level::chunkHash($x, $z)])){
@ -2496,6 +2618,8 @@ class Level implements ChunkManager, Metadatable{
* @param int $chunkZ
* @param Chunk|null $chunk
* @param bool $deleteEntitiesAndTiles Whether to delete entities and tiles on the old chunk, or transfer them to the new one
*
* @return void
*/
public function setChunk(int $chunkX, int $chunkZ, Chunk $chunk = null, bool $deleteEntitiesAndTiles = true){
if($chunk === null){
@ -2621,6 +2745,8 @@ class Level implements ChunkManager, Metadatable{
* Sets the level spawn location
*
* @param Vector3 $pos
*
* @return void
*/
public function setSpawnLocation(Vector3 $pos){
$previousSpawn = $this->getSpawnLocation();
@ -2628,6 +2754,13 @@ class Level implements ChunkManager, Metadatable{
(new SpawnChangeEvent($this, $previousSpawn))->call();
}
/**
* @param int $x
* @param int $z
* @param Player $player
*
* @return void
*/
public function requestChunk(int $x, int $z, Player $player){
$index = Level::chunkHash($x, $z);
if(!isset($this->chunkSendQueue[$index])){
@ -2637,7 +2770,7 @@ class Level implements ChunkManager, Metadatable{
$this->chunkSendQueue[$index][$player->getLoaderId()] = $player;
}
private function sendChunkFromCache(int $x, int $z){
private function sendChunkFromCache(int $x, int $z) : void{
if(isset($this->chunkSendQueue[$index = Level::chunkHash($x, $z)])){
foreach($this->chunkSendQueue[$index] as $player){
/** @var Player $player */
@ -2649,7 +2782,7 @@ class Level implements ChunkManager, Metadatable{
}
}
private function processChunkRequest(){
private function processChunkRequest() : void{
if(count($this->chunkSendQueue) > 0){
$this->timings->syncChunkSendTimer->startTiming();
@ -2687,6 +2820,13 @@ class Level implements ChunkManager, Metadatable{
}
}
/**
* @param int $x
* @param int $z
* @param BatchPacket $payload
*
* @return void
*/
public function chunkRequestCallback(int $x, int $z, BatchPacket $payload){
$this->timings->syncChunkSendTimer->startTiming();
@ -2705,6 +2845,7 @@ class Level implements ChunkManager, Metadatable{
/**
* @param Entity $entity
*
* @return void
* @throws LevelException
*/
public function addEntity(Entity $entity){
@ -2726,6 +2867,7 @@ class Level implements ChunkManager, Metadatable{
*
* @param Entity $entity
*
* @return void
* @throws LevelException
*/
public function removeEntity(Entity $entity){
@ -2745,6 +2887,7 @@ class Level implements ChunkManager, Metadatable{
/**
* @param Tile $tile
*
* @return void
* @throws LevelException
*/
public function addTile(Tile $tile){
@ -2771,6 +2914,7 @@ class Level implements ChunkManager, Metadatable{
/**
* @param Tile $tile
*
* @return void
* @throws LevelException
*/
public function removeTile(Tile $tile){
@ -2866,11 +3010,18 @@ class Level implements ChunkManager, Metadatable{
return true;
}
private function queueUnloadChunk(int $x, int $z){
private function queueUnloadChunk(int $x, int $z) : void{
$this->unloadQueue[$index = Level::chunkHash($x, $z)] = microtime(true);
unset($this->chunkTickList[$index]);
}
/**
* @param int $x
* @param int $z
* @param bool $safe
*
* @return bool
*/
public function unloadChunkRequest(int $x, int $z, bool $safe = true){
if(($safe and $this->isChunkInUse($x, $z)) or $this->isSpawnChunk($x, $z)){
return false;
@ -2881,6 +3032,12 @@ class Level implements ChunkManager, Metadatable{
return true;
}
/**
* @param int $x
* @param int $z
*
* @return void
*/
public function cancelUnloadChunkRequest(int $x, int $z){
unset($this->unloadQueue[Level::chunkHash($x, $z)]);
}
@ -3032,6 +3189,8 @@ class Level implements ChunkManager, Metadatable{
* Sets the current time on the level
*
* @param int $time
*
* @return void
*/
public function setTime(int $time){
$this->time = $time;
@ -3040,6 +3199,8 @@ class Level implements ChunkManager, Metadatable{
/**
* Stops the time for the level, will not save the lock state to disk
*
* @return void
*/
public function stopTime(){
$this->stopTime = true;
@ -3048,6 +3209,8 @@ class Level implements ChunkManager, Metadatable{
/**
* Start the time again, if it was stopped
*
* @return void
*/
public function startTime(){
$this->stopTime = false;
@ -3067,6 +3230,8 @@ class Level implements ChunkManager, Metadatable{
* Sets the seed for the level
*
* @param int $seed
*
* @return void
*/
public function setSeed(int $seed){
$this->provider->setSeed($seed);
@ -3085,6 +3250,8 @@ class Level implements ChunkManager, Metadatable{
/**
* @param int $difficulty
*
* @return void
*/
public function setDifficulty(int $difficulty){
if($difficulty < 0 or $difficulty > 3){
@ -3097,6 +3264,8 @@ class Level implements ChunkManager, Metadatable{
/**
* @param Player ...$targets
*
* @return void
*/
public function sendDifficulty(Player ...$targets){
if(count($targets) === 0){
@ -3145,6 +3314,9 @@ class Level implements ChunkManager, Metadatable{
return true;
}
/**
* @return void
*/
public function doChunkGarbageCollection(){
$this->timings->doChunkGC->startTiming();
@ -3163,6 +3335,11 @@ class Level implements ChunkManager, Metadatable{
$this->timings->doChunkGC->stopTiming();
}
/**
* @param bool $force
*
* @return void
*/
public function unloadChunks(bool $force = false){
if(count($this->unloadQueue) > 0){
$maxUnload = 96;

View File

@ -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;
@ -67,10 +67,16 @@ class Location extends Position{
return new Location($this->x, $this->y, $this->z, $this->yaw, $this->pitch, $this->level);
}
/**
* @return float
*/
public function getYaw(){
return $this->yaw;
}
/**
* @return float
*/
public function getPitch(){
return $this->pitch;
}

View File

@ -33,16 +33,22 @@ 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);
$this->setLevel($level);
}
/**
* @param Vector3 $pos
* @param Level|null $level
*
* @return Position
*/
public static function fromObject(Vector3 $pos, Level $level = null){
return new Position($pos->x, $pos->y, $pos->z, $level);
}

View File

@ -32,7 +32,9 @@ class SimpleChunkManager implements ChunkManager{
/** @var Chunk[] */
protected $chunks = [];
/** @var int */
protected $seed;
/** @var int */
protected $worldHeight;
/**
@ -69,6 +71,8 @@ class SimpleChunkManager implements ChunkManager{
* @param int $y
* @param int $z
* @param int $id 0-255
*
* @return void
*/
public function setBlockIdAt(int $x, int $y, int $z, int $id){
if($chunk = $this->getChunk($x >> 4, $z >> 4)){
@ -99,6 +103,8 @@ class SimpleChunkManager implements ChunkManager{
* @param int $y
* @param int $z
* @param int $data 0-15
*
* @return void
*/
public function setBlockDataAt(int $x, int $y, int $z, int $data){
if($chunk = $this->getChunk($x >> 4, $z >> 4)){
@ -148,6 +154,8 @@ class SimpleChunkManager implements ChunkManager{
* @param int $chunkX
* @param int $chunkZ
* @param Chunk|null $chunk
*
* @return void
*/
public function setChunk(int $chunkX, int $chunkZ, Chunk $chunk = null){
if($chunk === null){
@ -157,6 +165,9 @@ class SimpleChunkManager implements ChunkManager{
$this->chunks[Level::chunkHash($chunkX, $chunkZ)] = $chunk;
}
/**
* @return void
*/
public function cleanChunks(){
$this->chunks = [];
}

View File

@ -76,11 +76,20 @@ abstract class Biome{
/** @var float */
protected $temperature = 0.5;
/**
* @param int $id
* @param Biome $biome
*
* @return void
*/
protected static function register(int $id, Biome $biome){
self::$biomes[$id] = $biome;
$biome->setId($id);
}
/**
* @return void
*/
public static function init(){
self::$biomes = new \SplFixedArray(self::MAX_BIOMES);
@ -113,10 +122,18 @@ abstract class Biome{
return self::$biomes[$id];
}
/**
* @return void
*/
public function clearPopulators(){
$this->populators = [];
}
/**
* @param Populator $populator
*
* @return void
*/
public function addPopulator(Populator $populator){
$this->populators[] = $populator;
}
@ -126,6 +143,8 @@ abstract class Biome{
* @param int $chunkX
* @param int $chunkZ
* @param Random $random
*
* @return void
*/
public function populateChunk(ChunkManager $level, int $chunkX, int $chunkZ, Random $random){
foreach($this->populators as $populator){
@ -140,6 +159,11 @@ abstract class Biome{
return $this->populators;
}
/**
* @param int $id
*
* @return void
*/
public function setId(int $id){
if(!$this->registered){
$this->registered = true;
@ -161,6 +185,12 @@ abstract class Biome{
return $this->maxElevation;
}
/**
* @param int $min
* @param int $max
*
* @return void
*/
public function setElevation(int $min, int $max){
$this->minElevation = $min;
$this->maxElevation = $max;
@ -175,6 +205,8 @@ abstract class Biome{
/**
* @param Block[] $covers
*
* @return void
*/
public function setGroundCover(array $covers){
$this->groundCover = $covers;

View File

@ -32,6 +32,7 @@ class ForestBiome extends GrassyBiome{
public const TYPE_NORMAL = 0;
public const TYPE_BIRCH = 1;
/** @var int */
public $type;
public function __construct(int $type = self::TYPE_NORMAL){

View File

@ -153,12 +153,19 @@ class Chunk{
return $this->z;
}
/**
* @param int $x
*
* @return void
*/
public function setX(int $x){
$this->x = $x;
}
/**
* @param int $z
*
* @return void
*/
public function setZ(int $z){
$this->z = $z;
@ -225,6 +232,8 @@ class Chunk{
* @param int $y
* @param int $z 0-15
* @param int $id 0-255
*
* @return void
*/
public function setBlockId(int $x, int $y, int $z, int $id){
if($this->getSubChunk($y >> 4, true)->setBlockId($x, $y & 0x0f, $z, $id)){
@ -252,6 +261,8 @@ class Chunk{
* @param int $y
* @param int $z 0-15
* @param int $data 0-15
*
* @return void
*/
public function setBlockData(int $x, int $y, int $z, int $data){
if($this->getSubChunk($y >> 4, true)->setBlockData($x, $y & 0x0f, $z, $data)){
@ -279,6 +290,8 @@ class Chunk{
* @param int $y
* @param int $z 0-15
* @param int $level 0-15
*
* @return void
*/
public function setBlockSkyLight(int $x, int $y, int $z, int $level){
if($this->getSubChunk($y >> 4, true)->setBlockSkyLight($x, $y & 0x0f, $z, $level)){
@ -288,6 +301,8 @@ class Chunk{
/**
* @param int $level
*
* @return void
*/
public function setAllBlockSkyLight(int $level){
$char = chr(($level & 0x0f) | ($level << 4));
@ -317,6 +332,8 @@ class Chunk{
* @param int $y 0-15
* @param int $z 0-15
* @param int $level 0-15
*
* @return void
*/
public function setBlockLight(int $x, int $y, int $z, int $level){
if($this->getSubChunk($y >> 4, true)->setBlockLight($x, $y & 0x0f, $z, $level)){
@ -326,6 +343,8 @@ class Chunk{
/**
* @param int $level
*
* @return void
*/
public function setAllBlockLight(int $level){
$char = chr(($level & 0x0f) | ($level << 4));
@ -381,6 +400,8 @@ class Chunk{
* @param int $x 0-15
* @param int $z 0-15
* @param int $value
*
* @return void
*/
public function setHeightMap(int $x, int $z, int $value){
$this->heightMap[($z << 4) | $x] = $value;
@ -388,6 +409,8 @@ class Chunk{
/**
* Recalculates the heightmap for the whole chunk.
*
* @return void
*/
public function recalculateHeightMap(){
for($z = 0; $z < 16; ++$z){
@ -423,6 +446,8 @@ class Chunk{
* if the chunk is light-populated after being terrain-populated.
*
* TODO: fast adjacent light spread
*
* @return void
*/
public function populateSkyLight(){
$maxY = $this->getMaxY();
@ -469,6 +494,8 @@ class Chunk{
* @param int $x 0-15
* @param int $z 0-15
* @param int $biomeId 0-255
*
* @return void
*/
public function setBiomeId(int $x, int $z, int $biomeId){
$this->hasChanged = true;
@ -549,6 +576,8 @@ class Chunk{
/**
* @param bool $value
*
* @return void
*/
public function setLightPopulated(bool $value = true){
$this->lightPopulated = $value;
@ -563,6 +592,8 @@ class Chunk{
/**
* @param bool $value
*
* @return void
*/
public function setPopulated(bool $value = true){
$this->terrainPopulated = $value;
@ -577,6 +608,8 @@ class Chunk{
/**
* @param bool $value
*
* @return void
*/
public function setGenerated(bool $value = true){
$this->terrainGenerated = $value;
@ -584,6 +617,8 @@ class Chunk{
/**
* @param Entity $entity
*
* @return void
*/
public function addEntity(Entity $entity){
if($entity->isClosed()){
@ -597,6 +632,8 @@ class Chunk{
/**
* @param Entity $entity
*
* @return void
*/
public function removeEntity(Entity $entity){
unset($this->entities[$entity->getId()]);
@ -607,6 +644,8 @@ class Chunk{
/**
* @param Tile $tile
*
* @return void
*/
public function addTile(Tile $tile){
if($tile->isClosed()){
@ -624,6 +663,8 @@ class Chunk{
/**
* @param Tile $tile
*
* @return void
*/
public function removeTile(Tile $tile){
unset($this->tiles[$tile->getId()]);
@ -690,6 +731,8 @@ class Chunk{
* Deserializes tiles and entities from NBT
*
* @param Level $level
*
* @return void
*/
public function initChunk(Level $level){
if(!$this->isInit){
@ -766,6 +809,8 @@ class Chunk{
/**
* @param bool $value
*
* @return void
*/
public function setChanged(bool $value = true){
$this->hasChanged = $value;

View File

@ -38,25 +38,28 @@ if(!defined(__NAMESPACE__ . '\ZERO_NIBBLE_ARRAY')){
}
class SubChunk implements SubChunkInterface{
/** @var string */
protected $ids;
/** @var string */
protected $data;
/** @var string */
protected $blockLight;
/** @var string */
protected $skyLight;
private static function assignData(&$target, string $data, int $length, string $value = "\x00"){
private static function assignData(string $data, int $length, string $value = "\x00") : string{
if(strlen($data) !== $length){
assert($data === "", "Invalid non-zero length given, expected $length, got " . strlen($data));
$target = str_repeat($value, $length);
}else{
$target = $data;
return str_repeat($value, $length);
}
return $data;
}
public function __construct(string $ids = "", string $data = "", string $skyLight = "", string $blockLight = ""){
self::assignData($this->ids, $ids, 4096);
self::assignData($this->data, $data, 2048);
self::assignData($this->skyLight, $skyLight, 2048, "\xff");
self::assignData($this->blockLight, $blockLight, 2048);
$this->ids = self::assignData($ids, 4096);
$this->data = self::assignData($data, 2048);
$this->skyLight = self::assignData($skyLight, 2048, "\xff");
$this->blockLight = self::assignData($blockLight, 2048);
$this->collectGarbage();
}
@ -214,6 +217,9 @@ class SubChunk implements SubChunkInterface{
return "\x00" . $this->ids . $this->data;
}
/**
* @return mixed[]
*/
public function __debugInfo(){
return [];
}

View File

@ -185,6 +185,8 @@ interface SubChunkInterface{
/**
* @param string $data
*
* @return void
*/
public function setBlockSkyLightArray(string $data);
@ -195,6 +197,8 @@ interface SubChunkInterface{
/**
* @param string $data
*
* @return void
*/
public function setBlockLightArray(string $data);

View File

@ -150,6 +150,9 @@ abstract class BaseLevelProvider implements LevelProvider{
return $this->levelData;
}
/**
* @return void
*/
public function saveLevelData(){
$nbt = new BigEndianNBTStream();
$buffer = $nbt->writeCompressed(new CompoundTag("", [

View File

@ -34,12 +34,17 @@ use function strlen;
class ChunkRequestTask extends AsyncTask{
/** @var int */
protected $levelId;
/** @var string */
protected $chunk;
/** @var int */
protected $chunkX;
/** @var int */
protected $chunkZ;
/** @var int */
protected $compressionLevel;
/** @var int */

View File

@ -71,7 +71,9 @@ interface LevelProvider{
* @param string $name
* @param int $seed
* @param string $generator
* @param array[] $options
* @param array $options
*
* @return void
*/
public static function generate(string $path, string $name, int $seed, string $generator, array $options = []);
@ -119,6 +121,8 @@ interface LevelProvider{
/**
* @param int $value
*
* @return void
*/
public function setTime(int $value);
@ -129,6 +133,8 @@ interface LevelProvider{
/**
* @param int $value
*
* @return void
*/
public function setSeed(int $value);
@ -139,6 +145,8 @@ interface LevelProvider{
/**
* @param Vector3 $pos
*
* @return void
*/
public function setSpawn(Vector3 $pos);
@ -152,16 +160,22 @@ interface LevelProvider{
* Sets the world difficulty.
*
* @param int $difficulty
*
* @return void
*/
public function setDifficulty(int $difficulty);
/**
* Performs garbage collection in the level provider, such as cleaning up regions in Region-based worlds.
*
* @return void
*/
public function doGarbageCollection();
/**
* Performs cleanups necessary when the level provider is closed and no longer needed.
*
* @return void
*/
public function close();

View File

@ -31,6 +31,7 @@ use function strtolower;
use function trim;
abstract class LevelProviderManager{
/** @var string[] */
protected static $providers = [];
public static function init() : void{
@ -43,6 +44,7 @@ abstract class LevelProviderManager{
/**
* @param string $class
*
* @return void
* @throws \InvalidArgumentException
*/
public static function addProvider(string $class){

View File

@ -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;
@ -44,6 +45,7 @@ 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;
@ -100,7 +102,7 @@ class LevelDB extends BaseLevelProvider{
/** @var \LevelDB */
protected $db;
private static function checkForLevelDBExtension(){
private static function checkForLevelDBExtension() : void{
if(!extension_loaded('leveldb')){
throw new LevelException("The leveldb PHP extension is required to use this world format");
}
@ -124,8 +126,12 @@ class LevelDB extends BaseLevelProvider{
}
protected function loadLevelData() : void{
$rawLevelData = file_get_contents($this->getPath() . "level.dat");
if($rawLevelData === false or strlen($rawLevelData) <= 8){
throw new LevelException("Truncated level.dat");
}
$nbt = new LittleEndianNBTStream();
$levelData = $nbt->read(substr(file_get_contents($this->getPath() . "level.dat"), 8));
$levelData = $nbt->read(substr($rawLevelData, 8));
if($levelData instanceof CompoundTag){
$this->levelData = $levelData;
}else{
@ -414,24 +420,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;
}
}
@ -514,8 +523,8 @@ class LevelDB extends BaseLevelProvider{
* @param CompoundTag[] $targets
* @param string $index
*/
private function writeTags(array $targets, string $index){
if(!empty($targets)){
private function writeTags(array $targets, string $index) : void{
if(count($targets) > 0){
$nbt = new LittleEndianNBTStream();
$this->db->put($index, $nbt->write($targets));
}else{

View File

@ -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", [])
);

View File

@ -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";
}
@ -306,8 +331,10 @@ class McRegion extends BaseLevelProvider{
/**
* @param int $chunkX
* @param int $chunkZ
* @param int &$regionX
* @param int &$regionZ
* @param int $regionX reference parameter
* @param int $regionZ reference parameter
*
* @return void
*/
public static function getRegionIndex(int $chunkX, int $chunkZ, &$regionX, &$regionZ){
$regionX = $chunkX >> 5;
@ -339,6 +366,8 @@ class McRegion extends BaseLevelProvider{
/**
* @param int $regionX
* @param int $regionZ
*
* @return void
*/
protected function loadRegion(int $regionX, int $regionZ){
if(!isset($this->regions[$index = Level::chunkHash($regionX, $regionZ)])){

View File

@ -62,6 +62,7 @@ class RegionLoader{
private const FIRST_SECTOR = 2; //location table occupies 0 and 1
/** @var int */
public static $COMPRESSION_LEVEL = 7;
/** @var int */
@ -86,6 +87,7 @@ class RegionLoader{
}
/**
* @return void
* @throws CorruptedRegionException
*/
public function open(){
@ -187,6 +189,7 @@ class RegionLoader{
* @param int $z
* @param string $chunkData
*
* @return void
* @throws ChunkException
* @throws \InvalidArgumentException
*/
@ -219,6 +222,7 @@ class RegionLoader{
* @param int $x
* @param int $z
*
* @return void
* @throws \InvalidArgumentException
*/
public function removeChunk(int $x, int $z){
@ -243,8 +247,8 @@ class RegionLoader{
/**
* @param int $offset
* @param int &$x
* @param int &$z
* @param int $x reference parameter
* @param int $z reference parameter
*/
protected static function getChunkCoords(int $offset, ?int &$x, ?int &$z) : void{
$x = $offset & 0x1f;
@ -255,6 +259,8 @@ class RegionLoader{
* Writes the region header and closes the file
*
* @param bool $writeHeader
*
* @return void
*/
public function close(bool $writeHeader = true){
if(is_resource($this->filePointer)){
@ -267,6 +273,7 @@ class RegionLoader{
}
/**
* @return void
* @throws CorruptedRegionException
*/
protected function loadLocationTable(){
@ -328,7 +335,7 @@ class RegionLoader{
}
}
private function writeLocationTable(){
private function writeLocationTable() : void{
$write = [];
for($i = 0; $i < 1024; ++$i){
@ -341,6 +348,11 @@ class RegionLoader{
fwrite($this->filePointer, pack("N*", ...$write), 4096 * 2);
}
/**
* @param int $index
*
* @return void
*/
protected function writeLocationIndex($index){
fseek($this->filePointer, $index << 2);
fwrite($this->filePointer, Binary::writeInt(($this->locationTable[$index]->getFirstSector() << 8) | $this->locationTable[$index]->getSectorCount()), 4);
@ -348,6 +360,9 @@ class RegionLoader{
fwrite($this->filePointer, Binary::writeInt($this->locationTable[$index]->getTimestamp()), 4);
}
/**
* @return void
*/
protected function createBlank(){
fseek($this->filePointer, 0);
ftruncate($this->filePointer, 8192); // this fills the file with the null byte

View File

@ -34,10 +34,15 @@ use function unserialize;
class GeneratorRegisterTask extends AsyncTask{
/** @var string */
public $generatorClass;
/** @var string */
public $settings;
/** @var int */
public $seed;
/** @var int */
public $levelId;
/** @var int */
public $worldHeight = Level::Y_MAX;
public function __construct(Level $level, string $generatorClass, array $generatorSettings = []){

View File

@ -28,6 +28,7 @@ use pocketmine\scheduler\AsyncTask;
class GeneratorUnregisterTask extends AsyncTask{
/** @var int */
public $levelId;
public function __construct(Level $level){

View File

@ -31,18 +31,31 @@ use pocketmine\Server;
class PopulationTask extends AsyncTask{
/** @var bool */
public $state;
/** @var int */
public $levelId;
/** @var string */
public $chunk;
/** @var string */
public $chunk0;
/** @var string */
public $chunk1;
/** @var string */
public $chunk2;
/** @var string */
public $chunk3;
//center chunk
/** @var string */
public $chunk5;
/** @var string */
public $chunk6;
/** @var string */
public $chunk7;
/** @var string */
public $chunk8;
public function __construct(Level $level, Chunk $chunk){
@ -56,11 +69,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;
}

View File

@ -52,6 +52,9 @@ abstract class BiomeSelector{
*/
abstract protected function lookup(float $temperature, float $rainfall) : int;
/**
* @return void
*/
public function recalculate(){
$this->map = new \SplFixedArray(64 * 64);
@ -66,18 +69,29 @@ abstract class BiomeSelector{
}
}
/**
* @param float $x
* @param float $z
*
* @return float
*/
public function getTemperature($x, $z){
return ($this->temperature->noise2D($x, $z, true) + 1) / 2;
}
/**
* @param float $x
* @param float $z
*
* @return float
*/
public function getRainfall($x, $z){
return ($this->rainfall->noise2D($x, $z, true) + 1) / 2;
}
/**
* TODO: not sure on types here
* @param int|float $x
* @param int|float $z
* @param int $x
* @param int $z
*
* @return Biome
*/

Some files were not shown because too many files have changed in this diff Show More