Compare commits

...

457 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
a386ff8ce7 Release 3.11.0 2019-12-11 18:35:03 +00:00
e6c3b0fc0d Changes for 1.14
there are no protocol changes in 1.14 that matter; the reason the protocol version has been bumped is because of new blocks, items, mobs and recipes.
2019-12-11 18:32:22 +00:00
9568364277 fix minor formatting issue in SkinAdapterSingleton 2019-12-09 21:19:15 +00:00
73d4ff6b52 more missed function imports 2019-12-09 21:16:35 +00:00
7e98aa1497 leveldb: remove usage of multi-import statement
this doesn't conform to the code style.
2019-12-09 20:28:02 +00:00
f00c69c513 added missing function imports 2019-12-09 20:13:02 +00:00
50a4c42f3f NetworkBinaryStream: fix misplaced import 2019-12-09 19:53:32 +00:00
6b61efcfc8 remove unused imports 2019-12-09 19:49:21 +00:00
1a99938e4b LegacySkinAdapter: clean up nonsensical code ordering 2019-12-09 18:26:20 +00:00
a4d68fb32b LegacySkinAdapter: fix some wacky cape handling logic
I added checks for length validity locally and ran into some interesting behaviour because of this code.
2019-12-09 18:16:46 +00:00
5682cc8d53 3.10.2 is next 2019-12-07 16:41:41 +00:00
4eb59c0372 Release 3.10.1 2019-12-07 16:41:41 +00:00
3486db3f1b update RakLib to 0.12.6 2019-12-07 14:20:35 +00:00
733d530ed0 fixing EOF newlines on new files 2019-12-07 10:08:29 +00:00
c10ce84035 fix invisible legacy skins which have empty geometry names 2019-12-07 10:02:22 +00:00
82d9e481d2 3.10.1 is next 2019-12-06 20:53:15 +00:00
d27c7f7141 Release 3.10.0 2019-12-06 20:53:15 +00:00
394c999710 Merge branch 'drew-1.13' into stable 2019-12-06 20:38:49 +00:00
6399dacba7 Release 3.9.8 2019-12-06 20:33:51 +00:00
b6bbf655d7 InventoryTransactionPacket: fixed crafting flags being set on useless empty transactions
this fixes some misleading debug noise when getting stuff from creative inventory and triggers some different spam instead.
2019-12-06 20:08:09 +00:00
3d2c018442 BiomeDefinitionListPacket: load pregenerated data from file 2019-12-06 11:32:33 +00:00
da8c54cf8b AvailableEntityIdentifiersPacket: load pregenerated data from file 2019-12-06 11:31:55 +00:00
8e984a1bc3 RuntimeBlockMapping: use new data, item frames & doors fixed
floor & ceiling item frames not supported though
2019-12-06 11:31:18 +00:00
124e60301a updated submodule to pmmp/BedrockData@a38b427888 2019-12-06 11:26:58 +00:00
4d13c48e5c UPnP: COM constructor never returns false anymore 2019-12-05 16:07:06 +00:00
9159e8f002 MainLogger: mark static logger field as nullable 2019-12-05 15:48:58 +00:00
f5aa461945 GlobalConstants: assume we are on 64-bit when declaring INT32_MASK
fixes a FP reported by phpstan level 4
2019-12-05 15:48:11 +00:00
16817ff301 Player: remove superfluous conditions for RESPAWN action handling
spawned is always true here because of the condition at the top of the function.
isOnline() is always true here because the handler won't even be called if it isn't.
2019-12-05 14:52:12 +00:00
18863b1098 Player: remove superfluous check from processMovement()
if we reached this branch, revert is always false because it is not modified between this branch and the parent one.
detected by phpstan level 4
2019-12-05 14:47:15 +00:00
e3cffca34b StartGamePacket: fixed possible type violation on decoding block table 2019-12-05 11:05:34 +00:00
d20d9fb689 Merge branch 'stable' into drew-1.13 2019-12-05 10:59:53 +00:00
7b1ae2a822 phpstan: green on level 3 2019-12-04 22:12:14 +00:00
8ecf5e02b9 bad fix for WritableBook phpstan warning
master has this shit so much better
2019-12-04 22:00:19 +00:00
39c607cbd5 Position: mark level field as nullable
allowing the level to be null is, to be honest, a big design flaw, but one that can't be fixed without BC breaks.
2019-12-04 21:31:35 +00:00
d867ffc60d MetadataStore: fix some doc comments 2019-12-04 21:14:09 +00:00
c57eb26fd5 phpstan-bugs: add some extra patterns for level 3 false positives 2019-12-04 19:50:15 +00:00
c35d91a104 phpstan: allow blanket ignoreErrors in src to reduce merge work for master 2019-12-04 19:42:18 +00:00
9fc260fb1a keep phpstan.neon.dist ignoreErrors sorted by file 2019-12-04 19:38:54 +00:00
73d0f799c2 Update to PHPStan 0.12.0 2019-12-04 10:29:49 +00:00
ecb2e6e3af PluginManager: remove useless information from softDepend debug
we don't report the parameter type anywhere else, and since PHP doesn't support overloading, we don't need to.
This fixes PHPStan 0.12 complaints about ReflectionNamedType. I figured this was the best solution instead of adding an extra few lines of code.
2019-12-04 10:17:25 +00:00
7b75b6928d AvailableCommandsPacket: fixed foreach docs
these probably aren't necessary at all to be honest.
2019-12-04 10:15:50 +00:00
753a8a6937 Event: remove useless @var $this annotations
we are not in a trait here, the scope is always Event.
2019-12-04 10:15:04 +00:00
bc76b1cafe Server: remove several redundant @var annotations (copy pasta)
these are all useless because it is implied by the parameter type anyway.
2019-12-04 10:14:15 +00:00
00e415fc79 move phpstan.neon to phpstan.neon.dist to allow phpstan.neon to be locally modified for development 2019-12-03 19:57:19 +00:00
dbbe1f2d5c Revert "Entity: remove redundant check from spawnTo()"
This reverts commit 3028832cd3.

When I created this commit, I made the flawed assumption that spawnTo()
would not be used by plugins. In addition, I was not aware that there
are some usages of spawnTo() in the core which do not check for chunk
usage, such as in Player->showPlayer().

This caused a collection of problems including memory leaks and crashes
due to disconnecting players not removing their references from viewed
entities.

The reverted commit may be the cause of #3178.
2019-12-03 10:41:13 +00:00
740f0a2314 crafting now works on 1.13, but it's not good 2019-12-02 21:50:52 +00:00
7fdfe947b0 inventory: fix some transactions being rejected for no good reason
since 1.13, transactions such as interacting with creative inventory cause a spoof windowID 124 slot 50 action to appear which changes air -> air. This currently gets rejected because only cursor is mapped to ID 124, and it only has a single slot.

It is not clear what the purpose of 124:50 is, but this fix filters out any actions which do not change anything, since they won't affect transaction balance anyway.
2019-12-02 21:41:08 +00:00
b7c4379700 StartGamePacket: fixed asymmetry in block table handling 2019-12-02 19:35:55 +00:00
20b7418916 PlayerAuthInputPacket: added encode & decode, and some aux classes 2019-12-02 15:14:59 +00:00
85521f5e7a EducationSettingsPacket: added encode & decode 2019-12-02 13:57:19 +00:00
f37ea6a203 AvailableCommandsPacket: fix nonsensical placement of HARDCODED_ENUMS 2019-12-02 12:57:05 +00:00
abf8081ebc RuntimeBlockMapping: add a type check for decoded NBT root type
this is kinda redundant since this function can blow up in so many other ways anyway, but it makes PHPStan happy, so it'll do.
2019-12-02 08:21:42 +00:00
8594cb3e74 AvailableCommandsPacket: fixed doc comment for putEnumConstraint() 2019-12-02 08:17:00 +00:00
d155de35ed Merge branch 'dktapps-drew-1.13' into stable 2019-12-01 22:03:03 -05:00
e37c8e3a5d Merge branch 'drew-1.13' of https://github.com/dktapps/PocketMine-MP into dktapps-drew-1.13 2019-12-01 22:02:40 -05:00
e38c0c0fe1 Merge remote-tracking branch 'upstream/stable' into stable 2019-12-01 21:55:50 -05:00
ce27c03774 PlayerChatEvent: fixed crash when non-CommandSender permissibles subscribe to broadcast permission
doing such a thing doesn't make any sense, but the system allows it, so it has to be accounted for.
2019-12-01 21:44:13 +00:00
c4a8781b5c Fixed doc type inconsistencies surrounding chat broadcast handling (several problems that are all related) 2019-12-01 21:40:11 +00:00
dbab8b5733 Level: fixed type doc of tickRateTime field 2019-12-01 21:21:42 +00:00
2b08bbc7b1 Server: fixed type doc comment of nextTick field 2019-12-01 21:18:20 +00:00
17037f5e9c Chunk: clean up nonsensical code in initChunk()
I have no idea why the extra check was there, or why the null assignment was used, because it doesn't make any sense.
2019-12-01 21:14:23 +00:00
fee3c17148 CraftingManager: fixed type doc of craftingDataCache field 2019-12-01 21:06:34 +00:00
25e6cb74b3 Squid: fixed type doc comment of swimDirection field 2019-12-01 21:06:03 +00:00
8d2e59222e Entity: fixed not calculating surrounding blocks on entity creation
it's unclear if this was actually causing any bugs, but if it was it would likely manifest in the form of, for example, not burning in lava.
2019-12-01 21:05:36 +00:00
cd778661c2 Entity: fixed type doc comment for blocksAround field 2019-12-01 21:03:57 +00:00
c2afc05e7c Entity: fix type doc comment for static knownEntities field 2019-12-01 21:03:29 +00:00
9be95bf263 Block: return [] instead of null in getMetadata() (return type is non-nullable) 2019-12-01 21:02:49 +00:00
4b65e1cbe1 Command: fix type doc comment for commandMap field 2019-12-01 21:01:57 +00:00
5caae37768 Server: fixed return type doc comment for getCommandAliases() 2019-12-01 21:00:49 +00:00
92e1811b06 DataPacket: fixed bad null assignment to buffer in clean()
this is never expected to be null, so implicitly relies on PHP magic behaviour to convert it to string when appended.
2019-12-01 20:36:56 +00:00
293c2710d0 PlayerCreationEvent: fixed doc comments for baseClass and playerClass fields 2019-12-01 20:19:59 +00:00
8a7017fd6b Enchantment: fixed doc comment for static enchantments field 2019-12-01 20:16:45 +00:00
15f8886958 phpstan: separate non-PM bugs from the main neon config
everything left in here is now a PM problem that needs to be looked into.
2019-12-01 20:12:41 +00:00
3226a9dc6a phpstan: ignore more optional-leveldb errors 2019-12-01 19:52:49 +00:00
1a1e3ff63b BaseInventory: fixed incorrect & redundant default value for slots field 2019-12-01 19:45:16 +00:00
ea413d0882 phpstan: analyze on level 2, close #3193 2019-12-01 19:32:03 +00:00
0890b5fc99 AsyncPool: assert() that the unstacked task is actually an AsyncTask
it's possible that it might not be if the workers were accessed directly, but that shouldn't be possible.
This also silences a PHPStan warning on level 2.
2019-12-01 19:28:05 +00:00
163ed225f2 NetworkBinaryStream: fixed crash when non-compound root tag is provided for itemstack 2019-12-01 18:41:02 +00:00
a4a6d3e094 PlayerCreationEvent: fixed illegal doc comment types 2019-12-01 18:08:25 +00:00
ecbf3e9722 GamemodeCommand: fix CommandSender assignment causing troubles for type inference on static analyzers
this would never crash, but in strongly typed code it would be a compile failure.
2019-12-01 09:33:12 +00:00
47a959dace block: fix some possible crashes when plugins overwrite tile classes in bad ways
phpstan was complaining on level 2, and it's not wrong to ...
2019-12-01 09:29:22 +00:00
3968f85c82 sync composer dependencies 2019-12-01 08:54:48 +00:00
d8188b807a CraftingDataPacket: read & write potion recipes 2019-11-30 21:18:54 +00:00
8e68655fc7 Merge branch 'stable' into drew-1.13 2019-11-30 21:15:50 +00:00
6d109bfc6f CraftingDataPacket: fixed not retaining cleanRecipes during decode 2019-11-30 21:15:37 +00:00
b7a5a53c9d MoveActorDeltaPacket: flags is now a short 2019-11-30 12:56:16 +00:00
76bd0f452c AvailableCommandsPacket: add special handling for enums which aren't referenced by any command directly
the CommandName enum is a magic enum used by the  argtype.

TODO: It's possible that not sending the CommandName enum might be causing client sided crashes. Investigate.
2019-11-30 12:41:44 +00:00
363556e9b6 AvailableCommandsPacket: encode & decode for enum value constraints
This is a peculiarly overengineered system that is used for restricting access to enum members under certain conditions, e.g. to disallow changing specific gamerules in survival.
2019-11-30 12:31:31 +00:00
6f08853b29 Merge branch 'stable' into drew-1.13 2019-11-30 12:04:46 +00:00
42d8357821 AvailableCommandsPacket: fixed missing decoded overloads with 0 arguments
these should be listed even if they have 0 arguments
2019-11-30 11:58:29 +00:00
f2ac63d235 update build/php submodule to pmmp/php-build-scripts@8308571448 2019-11-29 11:54:42 +00:00
5d17405b92 Better checks on resource patch 2019-11-28 19:48:34 -05:00
3dd53ad998 Remove offset for crafting grid 2019-11-28 19:42:34 -05:00
a303c4b294 Add some isset checks to prevent server from crashing on an invalid resourcepatch 2019-11-21 17:58:33 -05:00
fa56290bb4 Reflect StartGamePacket changes in Player 2019-11-21 15:05:09 -05:00
01d6cbe9c3 Added : void typehint to SkinAdapterSingleton & provide documentation 2019-11-21 15:01:34 -05:00
f682c16740 Changed eduMode to eduEditionOffer and added an unsignedVarInt in availablecommandspacket 2019-11-21 14:55:29 -05:00
74c09dc202 Remove inline assignment 2019-11-21 14:49:01 -05:00
0917b67573 Generate param docs for constructor 2019-11-21 14:46:10 -05:00
5cb0eafcb2 Should be checking the string, not an object 2019-11-21 14:24:47 -05:00
221e6db47d Remove persona capes off of classic skins, add checks for empty cape data when converting 2019-11-21 14:21:08 -05:00
8d06018d81 make toSkinData return statement multi lined 2019-11-21 13:54:22 -05:00
600e16d9f6 Fixed floatingtextparticle yet again 2019-11-21 13:54:00 -05:00
4340349db7 Generate getters for SkinData, applied suggested change, and fixed an underfined variable in PlayerListPacket 2019-11-21 13:52:27 -05:00
6105198313 Update AvailableCommandsPacket constants 2019-11-20 22:47:48 -05:00
c96ba13c23 Extract geometry name from resource patch 2019-11-20 22:42:56 -05:00
c8d0cb315b Move persona skin hack to legacyskinadapter 2019-11-20 21:52:49 -05:00
be9c413a9e Added network components for skins, to collect instead of throw out data 2019-11-20 21:43:41 -05:00
3e4366b30d readme: add XLM since Keybase made it so easy
... and also gave lots of keybase users free XLM. Well played, Keybase, you managed to make me adopt Stellar.
2019-11-20 10:51:07 +00:00
7f3460190b Merge pull request #5 from dktapps/drew-1.13
more 1.13
2019-11-12 14:19:31 -05:00
10d44292e1 fix classic capes 2019-11-12 12:27:50 -05:00
70f81334ae MultiplayerSettingsPacket 2019-11-12 11:58:40 -05:00
ead572fab9 fix skin sharing stupidity 2019-11-12 07:08:48 -05:00
ef8e286277 Merge branch 'stable' of https://github.com/drew-mcbe/pocketmine-mp into drew-1.13 2019-11-12 06:57:57 -05:00
ba5a5981a0 Update Player.php 2019-11-12 08:19:05 +00:00
c428596009 AddPlayerPacket: missing field 2019-11-11 16:36:55 -05:00
a81d8dd6d5 Return false in unexpected condition 2019-11-11 16:25:53 -05:00
5bcbef90ea Added variables for getSkin's animation for easier readability 2019-11-11 15:32:48 -05:00
1c67f094e3 Change get and put SkinImage visibility to private 2019-11-11 15:29:57 -05:00
99d350914e Remove convertToLegacyName 2019-11-11 15:29:42 -05:00
49a9e0a880 Remove changes to FloatingTextParticle 2019-11-11 15:26:36 -05:00
7b152def7d Move SkinAnimation and changed SerializedImage to SkinImage
Also change putImage and getImage to getSkinImage and putSkinImage
2019-11-11 15:23:48 -05:00
3eb78fb0ff Merge pull request #4 from dktapps/drew-1.13
moar 1.13 changes
2019-11-11 15:04:33 -05:00
38c759c86e ResourcePackStack: missing field 2019-11-11 14:58:45 -05:00
314ce1d012 build/make-release: push after 5 seconds instead of 10 2019-11-11 16:41:50 +00:00
7fcd40df15 add encode/decode for some new packets 2019-11-11 11:20:37 -05:00
ba39327b28 Merge remote-tracking branch 'origin/stable' into drew-1.13 2019-11-11 10:42:25 -05:00
8d2e3894ef DataPacket: fixed var_dump() not showing private & protected subclass properties 2019-11-11 15:41:08 +00:00
8ee0fbccc5 Merge branch 'stable' of https://github.com/drew-mcbe/pocketmine-mp into drew-1.13 2019-11-11 05:48:17 -05:00
fe4354959b SkinAnimation: fix typo 2019-11-11 10:07:45 +00:00
19377c86a4 PlayerSkinPacket: reduce diff pollution 2019-11-11 09:47:04 +00:00
fb23aade34 Clean up unused imports 2019-11-10 21:49:58 -05:00
57e9fe78a3 change buildPlatform parameter to -1 2019-11-10 21:45:33 -05:00
6b97281c58 Update SkinAnimation constants and docs 2019-11-10 21:41:00 -05:00
da67a085fc Remove unused imports and unused todo 2019-11-10 21:37:55 -05:00
e2fc7cdf88 Friendly BC skins (persona not supported) 2019-11-10 21:04:38 -05:00
635bb08fb9 Update playerskinpacket to use the strings 2019-11-10 19:39:07 -05:00
308d9ce3a8 auto generated baseline 2019-11-10 17:40:04 -05:00
5a76c38363 Merge remote-tracking branch 'origin/stable' into drew-1.13 2019-11-10 17:02:46 -05:00
54530da6c1 reduce visibility of offset to private 2019-11-10 00:09:29 -05:00
dd55a0bccd Use unknown os for PlayerListEntry 2019-11-10 00:01:12 -05:00
f03bd982b5 Empty fields in PlayerSkinPacket, thanks @Minejong 2019-11-09 23:56:18 -05:00
025cb73bf5 update travis pthreads 2019-11-09 17:34:04 +00:00
2a6ffb5aa9 updated build/php submodule 2019-11-09 17:33:25 +00:00
d53b84386f Merge pull request #3 from dktapps/drew-1.13
clean up 1.13 a little
2019-11-08 16:46:01 +05:00
a7ed933b37 superfluous import 2019-11-08 11:32:09 +00:00
29cc9283f8 reverse unnecessary formatting changes 2019-11-08 11:29:00 +00:00
e60962c31f reverse BC-breaking change to Player->changeSkin()
this change would cause LSP violations for subclasses
2019-11-08 11:22:55 +00:00
f6b5301e17 Player: remove unused import 2019-11-08 11:10:20 +00:00
73b923e3a1 cleanup eating clusterfuck 2019-11-08 11:08:22 +00:00
d2e4eb40b3 CompletedUsingItemPacket is superfluous 2019-11-08 08:29:25 +00:00
6a31628e78 Clean up whitespace disaster and add getIngredient back 2019-11-07 23:43:26 -05:00
bfb1ad1327 Removed PlayerUIInventory and BaseUIInventory 2019-11-07 23:17:01 -05:00
dfa603c335 Simplify if null statement 2019-11-07 20:06:46 -05:00
eef979db4c Switch to isUsingItem()
I don't plan on using this, as you informed me on discord that I didn't need the extra step, and it's a BC break anyway
2019-11-07 19:49:04 -05:00
6166c90bfd No need for a try catch statement around reading a file 2019-11-07 19:45:47 -05:00
35d1d0080a Removed count const and fixed BC break 2019-11-07 19:45:33 -05:00
3bacb1a9cb Moved skin back
Not too sure what I planned on doing with that
2019-11-07 19:45:20 -05:00
898af49e97 Add typehints to completedusingitempacket 2019-11-07 19:45:06 -05:00
3061eb4157 Fixed convertToLegacyName not using variables, add typehints to it too 2019-11-07 19:44:49 -05:00
b8d1d8f212 Clean up unused imports 2019-11-07 19:43:53 -05:00
8c6189775b Removed root directory runtime states 2019-11-07 19:33:53 -05:00
932418b951 fixing some PHPStan complaints about bootstrap
this isn't an ideal fix, but it'll do.
2019-11-07 18:22:37 +00:00
95812252d6 NetworkBinaryStream: fix a mistake in doc for putEntityRuntimeId() 2019-11-07 18:22:37 +00:00
7dec912d15 Fixed FloatingTextParticles 2019-11-06 23:22:41 -05:00
dbd36d66ae Cape data can be null 2019-11-06 23:01:06 -05:00
40b4166a6e created method sendCompletedUsingItemPacket for less duplication 2019-11-06 22:30:05 -05:00
51d18ffb89 Merge branch 'stable' of https://github.com/pmmp/PocketMine-MP into stable 2019-11-06 22:10:41 -05:00
af3c7b7c76 Updated ResourcePackType 2019-11-06 21:57:09 -05:00
3511ac010d Fixed crafting 2019-11-06 20:42:53 -05:00
cac3c356a5 Painting: fix dropping multiple items when multiple blockupdates occur in the same tick
test case: place sand on top of a line of signs, put a painting on the sand and break the supporting sign
fixes #2774 for stable
2019-11-06 14:29:43 -05:00
07f19dd4a1 Fixed respawning 2019-11-05 22:33:12 -05:00
17a17c31f3 Fixed items, but I'm not so sure how well this'll work out, it'll need improved in the future 2019-11-05 22:25:11 -05:00
75742b487f Fixed stupid mistake 2019-11-05 21:56:20 -05:00
4e9a2b6d8c Added CompletedUsingItemPacket 2019-11-05 21:19:49 -05:00
4ea907ae1a Start saving new skin data 2019-11-05 21:01:01 -05:00
8b912c1363 Removed some useless casts 2019-11-05 20:59:48 -05:00
080209c469 Fixed persona skins being messed up on join 2019-11-05 20:35:33 -05:00
5b11ddee35 Clean up duplicated skin entries 2019-11-05 20:30:41 -05:00
3b7ded0ba3 Fixed changing skins crashing the server 2019-11-05 20:25:45 -05:00
c5d3e9be76 phpstan: silence leveldb noise
maybe there's a better way to do this, but I don't know it yet.
2019-11-05 20:21:36 +00:00
714f4dc023 fortify CI with PHPStan 2019-11-05 19:42:37 +00:00
a86bcd5110 travis.sh: don't redownload phpunit if it already locally exists 2019-11-05 19:39:04 +00:00
7ffc477d76 introduced baseline PHPStan configuration 2019-11-05 11:16:49 +00:00
4cb0b319c0 load some non-class constants with composer
this makes PHPStan happy and also makes working with PM code externally less of a pain in the ass.
2019-11-05 11:16:22 +00:00
5ebe9859e9 Moved runtime_block_states to vanilla 2019-11-04 21:47:44 -05:00
cd2b60a860 Initial update to 1.13 2019-10-30 21:36:08 -04:00
5edff79f5f 3.9.8 is next 2019-10-28 16:07:35 +00:00
0c91d568b4 Release 3.9.7 2019-10-28 16:07:35 +00:00
35fabc7765 updated DevTools submodule to 1.13.5 2019-10-28 16:03:26 +00:00
b5a98a993f lazy-init RuntimeBlockMapping 2019-10-27 20:58:43 +00:00
0840ba8067 PocketMine.php: reduce unnecessary pocketmine\NAME dependencies 2019-10-26 21:37:15 +01:00
274cf58ccf PocketMine.php: remove useless ini_set() (this is a PHP_INI_SYSTEM directive which can't be changed at runtime) 2019-10-25 21:38:47 +01:00
1bce5d0bc2 PocketMine.php: move BaseClassLoader creation to where it's actually used 2019-10-25 21:26:22 +01:00
0d5d5e21a8 CommandReader: define $w and $e to make PHPStan happy 2019-10-25 16:11:02 +01:00
a145e18c1e CrashDump: use fully qualified reference for GIT_COMMIT constant
this makes it easier to filter out PHPStan noise.
2019-10-25 16:08:37 +01:00
d1ca779c1a fix PHPStan @throws incompatible warning 2019-10-25 15:49:47 +01:00
abbb8bbf55 travis.sh: allow latest phpunit v7 now that we have XML
not ready to move to v8 yet because of BC breaks
2019-10-24 13:37:24 +01:00
86c7870427 update build/php submodule 2019-10-24 13:28:27 +01:00
48080b7f90 PocketMine.php: define INT32_MASK earlier
this is non-dependent on any of the PM crap.
2019-10-24 09:23:37 +01:00
b216fb8910 PocketMine.php: set INI entries as early as possible 2019-10-24 09:18:50 +01:00
d3171d6a8e backport a53f698d38: PocketMine.php: remove useless set_time_limit() call
this is hardcoded to zero in the PHP core anyway.
2019-10-24 09:14:18 +01:00
c063a4da29 backport 5c1f1f00cb: move assert.exception to PocketMine.php with the other stuff 2019-10-24 09:12:05 +01:00
cc79dfa64c backport 8b40a8f217: PocketMine.php: move INI entry setting to a separate function 2019-10-24 09:09:53 +01:00
d6b9950901 backport fdfbaf4e95: make startup performance warnings a little more coherent 2019-10-24 09:06:28 +01:00
1815fe5b46 backport 647f86a5b8: PocketMine.php: remove redundant ini_set()
this is overridden later on by MemoryManager.
2019-10-24 09:02:37 +01:00
3e993250d8 backport 0c31b8731f: PocketMine.php: use main logger to emit force-kill debug 2019-10-24 08:57:31 +01:00
1163ac1d7a backport 0c31b8731f: PocketMine.php: get rid of redundant LOCK_FILE_PATH constant 2019-10-24 08:55:28 +01:00
9a51ba697a PocketMine.php: move some mission-critical stuff earlier in boot sequence
fixes #3161
2019-10-24 08:50:13 +01:00
32ad9d0c1a Squid: fix spammy rotation in enclosed spaces
this bug was caused by 2f3c77c68a. It looks unrelated to the commit title, so it may have been committed by mistake.
2019-10-22 22:50:35 +01:00
3d840e969d 3.9.7 is next 2019-10-22 14:38:02 +01:00
d1b70bd400 Release 3.9.6 2019-10-22 14:38:02 +01:00
29f002b32c LightUpdate: fixed type doc for updateNodes field 2019-10-22 12:23:42 +01:00
da17ade575 AvailableCommandsPacket: fixed wrong parameter type doc for putEnum() 2019-10-22 12:23:01 +01:00
f0c36f3413 ClientCacheMissResponsePacket: fix broken type assert in create()
ouch! PhpStorm never saw these...
2019-10-22 11:57:10 +01:00
77d8f133f1 LevelChunkPacket: fixed broken type assert in withCache() 2019-10-22 11:54:37 +01:00
43ebb23085 Permission: remove dead code from loadPermission() 2019-10-22 10:42:22 +01:00
e198c8fa8b Task: mark taskHandler field as nullable 2019-10-22 10:26:49 +01:00
cc3285c8fe Chest: fixed type doc of doubleChestInventory field 2019-10-22 10:25:24 +01:00
305c63ba4d MainLogger: initialize shutdown field in the conventional manner
this avoids uninitialized uses
2019-10-22 10:21:17 +01:00
acaa0e33b0 update DevTools submodule to pmmp/PocketMine-DevTools@3fadb2c3f4 2019-10-22 10:16:44 +01:00
f63857deed update build/php submodule to pmmp/php-build-scripts@1b3fe3120c 2019-10-22 10:15:29 +01:00
eda3d9b5e4 sync composer dependencies 2019-10-22 10:13:47 +01:00
c3872619cd Block: mark boundingBox as nullable 2019-10-22 10:07:27 +01:00
39cc590829 Skin: accommodate JSON geometry containing comments, closes #3121 2019-10-21 22:26:48 +01:00
f347345bb3 Human::getInventory(): explicitly declare return type
the lack of this causes type inference bugs and documentation problems.
thanks PHPStan
2019-10-21 15:25:57 +01:00
bb05cfb36c Shears: fixed always-false hardness check
thanks PHPStan
2019-10-21 15:21:22 +01:00
7d5c3c9b46 backport 4364d2a94: AvailableCommandsPacket: Clean up internals
this is still disgusting, but it's a little more bearable now.
2019-10-21 14:51:36 +01:00
cff2d37add backport ec0558597b: CommandParameter: change byte1 field to "flags" (#3115) 2019-10-21 10:03:59 +01:00
447477c5fb RegionLoader: Write location table changes when deleting chunks 2019-10-20 20:54:46 +01:00
abdbb2bf0e backport 3f6660027: RegionLoader: Extract location table validation to separate function 2019-10-20 20:53:47 +01:00
783c13926f backport f2404804d: RegionLoader: clean up lastSector handling 2019-10-20 20:48:29 +01:00
45329ddf67 backport 07a9c35ee: RegionLoader: Use objects instead of arrays 2019-10-20 20:42:55 +01:00
20af789963 backport 3e58708130: Add some missing @throws annotations 2019-10-20 20:23:51 +01:00
93cb9390e0 RegionLoader: backport 62185d476b 2019-10-20 19:59:02 +01:00
0aed7f86f5 Updated BossEventPacket comments (#3155)
* Updated BossBar comments

* Fixed comments
2019-10-20 19:23:07 +01:00
bf44bd016d TransferServerCommand: add missing boilerplate permission check 2019-10-20 14:28:53 +01:00
04e4a36653 LevelDB: remove unnecessary \pocketmine\NAME dependency
this is non-obvious and makes it a pain the ass to use outside of PM.
2019-10-17 18:56:51 +01:00
7439e1971d Server: stop spamming crashdumps on unsupported / corrupted worlds
really we should look into making the server stop if any world fails to load, but flooding the place with crashdumps isn't the way to do it.
This is a simplified version of cf73c7f5c1
2019-10-17 11:27:00 +01:00
b961b4e003 SetupWizard: use constant for default gamemode 2019-10-16 11:48:25 +01:00
d9eac8fc0a Server: fixed default difficulty being EASY instead of NORMAL 2019-10-16 11:45:30 +01:00
aeeee5eb53 Added encode/decode for StructureTemplateDataExport(Request|Response)Packet (#3145) 2019-10-14 11:14:42 +01:00
13994055d9 SetupWizard: disable spawn protection by default
we can't change anything else wrt. this on a patch version, disabling it in the main core by default involves possible behavioural breaks
2019-10-09 11:26:58 +01:00
247875e3d5 Explosion: add documentation for explodeA() and explodeB()
these functions really ought to be renamed, or possibly redesigned entirely. However, that's no task for a patch version.

[ci skip]
2019-10-07 09:44:17 +01:00
ee60a7bc36 Item: add documentation for addCreativeItem(), removeCreativeItem() and clearCreativeItems()
[ci skip]
2019-10-07 09:37:59 +01:00
348c2a599b Internet: report PM version in user agent
this is useful for statistics
2019-10-04 10:59:32 +01:00
562b47a1e5 Player: guard against repeated resource pack sequence
this can happen because of the client being super broken in 1.12
close #3036
2019-10-03 11:20:44 +01:00
4e060bc13f EventPacket: Added some new constants (#3132) 2019-10-02 13:37:05 +01:00
2807f14fcd 3.9.6 is next 2019-10-01 15:02:34 +01:00
f0539f4898 Release 3.9.5 2019-10-01 15:02:33 +01:00
63d7e7b811 Fixed decoding form responses with double commas inside quotes (#3131)
closes #3113
2019-10-01 14:28:55 +01:00
4da06078ed Server: promote Patreon on startup 2019-10-01 14:22:07 +01:00
8a6381c3fa StupidJsonDecodeTest: add some extra test vectors 2019-10-01 13:25:20 +01:00
d0d61597c7 StupidJsonDecodeTest: use getClosure() instead of traditional mess
this is faster and requires less code.
2019-09-26 11:28:40 +01:00
7a2a4e2aa3 change some heading sizes [ci skip] 2019-09-25 12:59:04 +01:00
e41a2c0792 Link to StackOverflow in README (#3084) 2019-09-23 11:56:37 +01:00
11a6e04a28 EnderPearl: remove collision box hack (this isn't needed for MCPE anyway)
This was intended to address the problem that ender pearls would not stop on grass, saplings, and other similar objects. However, they don't stop on such objects in MCPE anyway, only PC.
2019-09-18 10:02:52 +01:00
70b1ac856d ZippedResourcePack: fix mishandling of wrong root JSON type (crashdump #2840512) 2019-09-17 11:01:33 +01:00
d724374d1a StupidJsonDecodeTest: add failing test case for #3113 2019-09-16 15:53:00 +01:00
a19143cae7 3.9.5 is next 2019-08-16 17:58:02 +01:00
1be6783c34 Release 3.9.4 2019-08-16 17:58:01 +01:00
092edc9d43 avoid breaking concrete powder 2019-08-16 17:41:50 +01:00
2ba8eac27f FallingBlock: fix endless falling on top of fences
this is a shitty fix, but I don't think there's a better way to do it on 3.x. This also fixes dropping on cactus.
close #2449, close #2895
2019-08-16 17:27:41 +01:00
25ff90b2c6 PluginManager: fix chained softdepend plugins load order
Test case:
- plugin2 depends on nonexistent plugin1
- plugin3 depends on plugin2

At random occasions, plugin3 would be loaded before plugin2, because plugin2 load would be deferred in the expectation of plugin1 being loaded. This would result in the assumption that plugin3's softdepend plugins would not be loaded, so they were ignored.
We fix this problem by removing missing plugins from softdepend if they were not present on a scan of the directory. This way, we don't ignore any unresolved deferred dependency resolutions.
2019-08-16 16:46:59 +01:00
b912ae78bc Merge branch 'stable' of https://github.com/pmmp/PocketMine-MP into stable 2019-08-14 18:21:24 +01:00
677d43028a add php-build-scripts as a submodule 2019-08-14 18:08:26 +01:00
7bfb55ec9a Fixed some errors in support.yml (#3095)
[ci skip]
2019-08-13 14:09:03 +01:00
2f61d42518 backport d23eeff832: FallingBlock: remove useless check 2019-08-11 19:38:12 +01:00
dbb669b156 Entity: add some deprecation warnings to despawnFrom() and despawnFromAll() 2019-08-11 19:34:57 +01:00
4d0e8741fe Added a deprecation notice to Entity->getBlocksAround() 2019-08-11 19:32:21 +01:00
53dc6e2050 fix TallGrass and Tree random/base amounts never being initialized, closes #2996 2019-08-11 19:06:20 +01:00
807b860cfe protocol: fixup data type changes, closes #3072 2019-08-11 19:02:16 +01:00
d756500928 Also updated Discord link in suppor template and README 2019-08-08 00:03:10 +08:00
7ef27a1a21 support.yml Discord link should point to #rules 2019-08-07 14:54:01 +08:00
6b4d8b91c6 fix crashdump plugin detection
some things which were copy pasting PM classes into plugins were causing incorrect detection here. The path cleaning guarantees that all plugin paths will start with "plugins/", so we can use that to check instead.
2019-07-30 18:58:31 +01:00
8f5eb7ef37 Level: fix memory leak on scheduled blockupdate in unloaded chunk 2019-07-30 15:37:24 +01:00
0ea9a08963 3.9.4 is next 2019-07-29 17:27:21 +01:00
18a1bfe4dd Release 3.9.3 2019-07-29 17:27:21 +01:00
2d3562c687 World: fixed scheduled updates causing chunk loading
this probably needs to be backported.
2019-07-29 17:21:54 +01:00
cb40484a2e AsyncTask: Remove a bunch of reference-management drivel from documentation of storeLocal()
this works (mostly) the same way regular properties do, so the usual rules are implied.
2019-07-27 14:52:53 +01:00
e75a08a5a3 AsyncPool: ensure TLS is always cleaned on task removal, closes #3059 2019-07-27 14:39:40 +01:00
95dfff727e Wrap PocketMine.php body inside a function
this isolates variables from the global scope and also prevents doxygen documenting these variables.
2019-07-26 19:47:03 +01:00
d55889d85f AsyncTask: fixing docs 2019-07-26 19:41:45 +01:00
99f65f19ac BulkCurlTask: point to the right place in docs 2019-07-26 19:18:09 +01:00
581eeee01d fix rogue @package doc making doxygen choke 2019-07-26 19:15:02 +01:00
17341d7406 Load Mathjax from https to prevent unsafe scripts error (#3058) 2019-07-26 18:49:02 +01:00
04c0cd142d 3.9.3 is next 2019-07-22 17:28:33 +01:00
7a747d6f93 Release 3.9.2 2019-07-22 17:28:33 +01:00
e93d034a4e fix bucket empty sound position, close #3051 2019-07-22 17:17:15 +01:00
5a08a10448 update dependency requirements 2019-07-22 17:15:18 +01:00
622f93df45 remove usages of deprecated {} string access, closes #3035 2019-07-22 16:39:33 +01:00
b788982d60 Item: fixed setCustomName() not removing display NBT tag with empty name (#3049) 2019-07-19 20:07:53 +01:00
26faf4a952 Player: fixed sendTranslation() passing parent parameters to translate parameters 2019-07-19 18:15:35 +01:00
670bf2b9d1 doxygen: sort more things, for our sanity (#3045) 2019-07-19 10:52:32 +01:00
f5491346ce doxygen: set HIDE_IN_BODY_DOCS = yes (#3044)
fixes #3043
2019-07-19 10:34:41 +01:00
73d3f9f7f7 Fix loadbefore sometimes not working (#3040)
loadbefore operates by injecting self into the target plugin's soft-dependencies. The problem is that these soft-dependency lists are overwritten if the target plugin's soft-dependencies are resolved after the loadbefore of the origin plugin.
2019-07-17 16:52:29 +01:00
d874be99a6 PrimedTNT: fix explosion position, close #3037 2019-07-16 13:55:31 +01:00
1767cbe80d Player: Lower moved-too-fast warning and illegal-move warning to debug
many users have complained that this spams their consoles and they can't turn it off.
2019-07-16 13:51:38 +01:00
64fbf5025a 3.9.2 is next 2019-07-14 19:10:29 +01:00
aaa01bb6f8 Release 3.9.1 2019-07-14 19:10:29 +01:00
50d71809e1 Entity: fixed onfire flag being set when setting fire ticks to zero, closes #3031 2019-07-14 19:03:06 +01:00
6839712394 added new PlayerActionPacket constant, silence debug noise every time a player clicks a block 2019-07-14 17:30:37 +01:00
9b5ae7ec75 regenerate LevelSoundEventPacket sound IDs 2019-07-14 17:28:29 +01:00
94eb64c2be 1.12: fix resource packs, closes #3023 2019-07-14 17:22:44 +01:00
3fae57508b update particle ids 2019-07-13 20:08:17 +01:00
a883c35fd0 clean up yesterday's mess 2019-07-13 18:15:14 +01:00
740398282f [ci skip] added some detail about packet changes in 3.9.0 release 2019-07-13 15:35:00 +01:00
9d14bc54d6 3.9.1 is next 2019-07-12 19:03:24 +01:00
bd69c66d03 Release 3.9.0 2019-07-12 19:03:23 +01:00
c58a1bf9b7 Protocol changes for 1.12.0.28 2019-07-12 19:00:15 +01:00
59c310b914 unfuck the make-release script 2019-07-12 18:59:54 +01:00
317 changed files with 7714 additions and 1935 deletions

View File

@ -11,4 +11,4 @@ We don't accept support requests on the issue tracker. Please try the following
Documentation: http://pmmp.rtfd.io
Forums: https://forums.pmmp.io
Discord: https://discord.gg/bge7dYQ
Discord: https://discord.gg/bmSAZBG

4
.github/support.yml vendored
View File

@ -5,10 +5,10 @@ supportLabel: "Support request"
# Comment to post on issues marked as support requests. Add a link
# to a support page, or set to `false` to disable
supportComment: >
Thanks, but this issue tracker not intended for support requests. Please read the guidelines on [submitting an issue](https://github.com/pmmp/PocketMine-MP/blob/master/CONTRIBUTING.md#creating-an-issue).
Thanks, but this issue tracker is not intended for support requests. Please read the guidelines on [submitting an issue](https://github.com/pmmp/PocketMine-MP/blob/master/CONTRIBUTING.md#creating-an-issue).
[Docs](https://pmmp.rtfd.io) | [Discord](https://discord.gg/bge7dYQ) | [Forums](https://forums.pmmp.io)
[Docs](https://pmmp.rtfd.io) | [Discord](https://discord.gg/bmSAZBG) | [Forums](https://forums.pmmp.io)
# Whether to close issues marked as support requests
close: true

1
.gitignore vendored
View File

@ -13,6 +13,7 @@ server.properties
memory_dumps/*
resource_packs/
server.lock
/phpstan.neon
# Common IDEs
.idea/

3
.gitmodules vendored
View File

@ -10,3 +10,6 @@
[submodule "src/pocketmine/resources/vanilla"]
path = src/pocketmine/resources/vanilla
url = https://github.com/pmmp/BedrockData.git
[submodule "build/php"]
path = build/php
url = https://github.com/pmmp/php-build-scripts.git

View File

@ -9,7 +9,7 @@ before_script:
- echo | pecl install channel://pecl.php.net/yaml-2.0.4
- git clone https://github.com/pmmp/pthreads.git
- cd pthreads
- git checkout 6ca019c58b4fa09ee2ff490f2444e34bef0773d0
- git checkout 1b7da492b944146fa9680f6399bd9c6c6c6095e0
- phpize
- ./configure
- make

View File

@ -5,25 +5,27 @@
[![Build Status](https://travis-ci.org/pmmp/PocketMine-MP.svg?branch=master)](https://travis-ci.org/pmmp/PocketMine-MP)
### Getting started
## Getting started
- [Documentation](http://pmmp.readthedocs.org/)
- [Installation instructions](https://pmmp.readthedocs.io/en/rtfd/installation.html)
- [Docker image](https://hub.docker.com/r/pmmp/pocketmine-mp)
- [Plugin repository](https://poggit.pmmp.io/plugins)
### Discussion
## Discussion/Help
- [Forums](https://forums.pmmp.io/)
- [Community Discord](https://discord.gg/bge7dYQ)
- [Community Discord](https://discord.gg/bmSAZBG)
- [StackOverflow](https://stackoverflow.com/tags/pocketmine)
### For developers
## For developers
* [Latest API documentation](https://jenkins.pmmp.io/job/PocketMine-MP-doc/doxygen/) - Doxygen documentation generated from development
* [DevTools](https://github.com/pmmp/PocketMine-DevTools/) - Development tools plugin for creating plugins
* [ExamplePlugin](https://github.com/pmmp/ExamplePlugin/) - Example plugin demonstrating some basic API features
* [Contributing Guidelines](CONTRIBUTING.md)
### Donate
## Donate
- Bitcoin Cash (BCH): `qq3r46hn6ljnhnqnfwxt5pg3g447eq9jhvw5ddfear`
- Bitcoin (BTC): `171u8K9e4FtU6j3e5sqNoxKUgEw9qWQdRV`
- Stellar Lumens (XLM): `GAAC5WZ33HCTE3BFJFZJXONMEIBNHFLBXM2HJVAZHXXPYA3HP5XPPS7T`
- [Patreon](https://www.patreon.com/pocketminemp)
## Licensing information

View File

@ -36,41 +36,45 @@ 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])){
$nextVer = new VersionString($argv[1]);
$currentVer = new VersionString($argv[1]);
}else{
$currentVer = new VersionString(BASE_VERSION);
$nextVer = new VersionString(sprintf(
"%u.%u.%u",
$currentVer->getMajor(),
$currentVer->getMinor(),
$currentVer->getPatch() + 1
));
}
$versionInfoPath = dirname(__DIR__) . '/src/pocketmine/VersionInfo.php';
$versionInfo = file_get_contents($versionInfoPath);
file_put_contents($versionInfoPath, preg_replace(
'/^const IS_DEVELOPMENT_BUILD = true;$/m',
'const IS_DEVELOPMENT_BUILD = false;',
$versionInfo
$nextVer = new VersionString(sprintf(
"%u.%u.%u",
$currentVer->getMajor(),
$currentVer->getMinor(),
$currentVer->getPatch() + 1
));
function replaceVersion(string $versionInfoPath, string $newVersion, bool $isDev) : void{
$versionInfo = file_get_contents($versionInfoPath);
$versionInfo = preg_replace(
$pattern = '/^const BASE_VERSION = "(\d+)\.(\d+)\.(\d+)(?:-(.*))?";$/m',
'const BASE_VERSION = "' . $newVersion . '";',
$versionInfo
);
$versionInfo = preg_replace(
'/^const IS_DEVELOPMENT_BUILD = (?:true|false);$/m',
'const IS_DEVELOPMENT_BUILD = ' . ($isDev ? 'true' : 'false'). ';',
$versionInfo
);
file_put_contents($versionInfoPath, $versionInfo);
}
$versionInfoPath = dirname(__DIR__) . '/src/pocketmine/VersionInfo.php';
replaceVersion($versionInfoPath, $currentVer->getBaseVersion(), false);
echo "please add appropriate notes to the changelog and press enter...";
fgets(STDIN);
system('git add "' . dirname(__DIR__) . '/changelogs"');
system('git commit -m "Release ' . BASE_VERSION . '" --include "' . $versionInfoPath . '"');
system('git tag ' . BASE_VERSION);
file_put_contents($versionInfoPath, $mod = preg_replace(
$pattern = '/^const BASE_VERSION = "' . preg_quote(BASE_VERSION, '/') . '";$/m',
'const BASE_VERSION = "' . $nextVer->getBaseVersion() . '";',
$versionInfo
));
system('git commit -m "Release ' . $currentVer->getBaseVersion() . '" --include "' . $versionInfoPath . '"');
system('git tag ' . $currentVer->getBaseVersion());
replaceVersion($versionInfoPath, $nextVer->getBaseVersion(), true);
system('git add "' . $versionInfoPath . '"');
system('git commit -m "' . $nextVer->getBaseVersion() . ' is next" --include "' . $versionInfoPath . '"');
echo "pushing changes in 10 seconds\n";
sleep(10);
system('git push origin HEAD ' . BASE_VERSION);
echo "pushing changes in 5 seconds\n";
sleep(5);
system('git push origin HEAD ' . $currentVer->getBaseVersion());

1
build/php Submodule

Submodule build/php added at 8308571448

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

20
changelogs/3.10.md Normal file
View File

@ -0,0 +1,20 @@
**For Minecraft: Bedrock Edition 1.13.0**
### Note about API versions
Plugins which don't touch the protocol and compatible with any previous 3.x.y version will also run on these releases and do not need API bumps.
Plugin developers should **only** update their required API to this version if you need the changes in this build.
**WARNING: If your plugin uses the protocol, you're not shielded by API change constraints.** You should consider using the `mcpe-protocol` directive in `plugin.yml` as a constraint if you do.
# 3.10.0
- Added support for Minecraft: Bedrock Edition 1.13.0
- Removed compatibility with 1.12.0
## Note about skins
PocketMine-MP **does not support skins made in the Charactor Creator** (known as Persona skins), due to technical changes which would require premature backwards compatibility breaks. The dev team has decided not to support Persona yet.
These skins will be **replaced with a random solid-colour skin. This is not a bug.**
Skins chosen from the Classic tab (classic skins) will continue to work as normal.
# 3.10.1
- Fixed custom plugin-created skins being invisible when no geometry name was specified.
- Updated RakLib to 0.12.6 to fix security bugs.

55
changelogs/3.11.md Normal file
View File

@ -0,0 +1,55 @@
**For Minecraft: Bedrock Edition 1.14.0**
### Note about API versions
Plugins which don't touch the protocol and compatible with any previous 3.x.y version will also run on these releases and do not need API bumps.
Plugin developers should **only** update their required API to this version if you need the changes in this build.
**WARNING: If your plugin uses the protocol, you're not shielded by API change constraints.** You should consider using the `mcpe-protocol` directive in `plugin.yml` as a constraint if you do.
# 3.11.0
- Added support for Minecraft: Bedrock Edition 1.14.0
- Removed compatibility with 1.13.0
# 3.11.1
- Fixed blocks with incorrect properties when placed or interacted with.
# 3.11.2
## Core
- PHPStan 0.12.3 with level 5 is now used for automated static analysis.
- Fixed a possible crash when plugins override the `EnderChest` tile class with something incompatible.
- Fixed disconnected players being considered as never played.
- Fixed enchantments with IDs outside the range 0-255 in item NBT crashing the server.
- Fixed particles rendering incorrectly.
- Timings handlers are no longer able to underflow; they now throw exceptions when attempting to be stopped more times than they were started.
- Fixed explosion rays getting stuck in empty subchunks (possible incorrect behaviour in large caves).
- Fixed bad tile/entity NBT data being propagated from world providers in some cases.
- Fixed a possible crash when detecting timezone on CentOS.
- Fixed many cases of incorrectly documented types in the API found by PHPStan.
- Generation tasks no longer assume that generator instances stored in TLS are always valid, fixing a possible crash.
## Protocol
- Fixed skin animation image corruption in LoginPacket handling caused by incorrect data handling.
- Fixed skin animation extra data not being decoded from LoginPacket.
- `SkinImage` now throws `InvalidArgumentException` if it receives an unexpected amount of bytes for the given image heigh/width.
- Fixed broken code in `PlayerAuthInputPacket::create()`.
- Removed some dead constants from `NetworkInventoryAction`.
# 3.11.3
- Fixed some PHPStan false-positives in release builds.
- Git hash is now correctly detected for source builds when the working directory is not the repository root.
- Added a specialized build script `build/server-phar.php` for creating server phars.
- Fixed timings crashing the server.
- Timings chains now work correctly.
- Fixed some minor timing errors in chained timings.
- Forcing resource packs no longer causes removal of client-sided resource packs. If this behaviour is desired, use a vanilla resource pack at the bottom of your resource stack (as was necessary for non-forced packs).
- Added documentation to the API to clarify that effect durations are in ticks.
# 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`.

129
changelogs/3.9.md Normal file
View File

@ -0,0 +1,129 @@
**For Minecraft: Bedrock Edition 1.12.0**
### Note about API versions
Plugins which don't touch the protocol and compatible with any previous 3.x.y version will also run on these releases and do not need API bumps.
Plugin developers should **only** update their required API to this version if you need the changes in this build.
**WARNING: If your plugin uses the protocol, you're not shielded by API change constraints.** You should consider using the `mcpe-protocol` directive in `plugin.yml` as a constraint if you do.
# 3.9.0
- Added support for Minecraft: Bedrock Edition 1.12.0
- Removed compatibility with 1.11.0
## Protocol
- The following classes in the `\pocketmine\network\mcpe\protocol` namespace have been renamed:
- `AddEntityPacket` -> `AddActorPacket`
- `AddItemEntityPacket` -> `AddItemActorPacket`
- `AvailableEntityIdentifiersPacket` -> `AvailableActorIdentifiersPacket`
- `BlockEntityDataPacket` -> `BlockActorDataPacket`
- `EntityEventPacket` -> `ActorEventPacket`
- `EntityFallPacket` -> `ActorFallPacket`
- `EntityPickRequestPacket` -> `ActorPickRequestPacket`
- `MoveEntityAbsolutePacket` -> `MoveActorAbsolutePacket`
- `MoveEntityDeltaPacket` -> `MoveActorDeltaPacket`
- `RemoveEntityPacket` -> `RemoveActorPacket`
- `SetEntityDataPacket` -> `SetActorDataPacket`
- `SetEntityLinkPacket` -> `SetActorLinkPacket`
- `SetEntityMotionPacket` -> `SetActorMotionPacket`
- `TakeItemEntityPacket` -> `TakeItemActorPacket`
- The following classes in the `\pocketmine\network\mcpe\protocol` namespace have been removed:
- `FullChunkDataPacket`
- The following classes in the `\pocketmine\network\mcpe\protocol` namespace have been added:
- `AddEntityPacket` (not to be confused with the old one)
- `ClientCacheBlobStatusPacket`
- `ClientCacheMissResponsePacket`
- `ClientCacheStatusPacket`
- `LevelChunkPacket`
- `RemoveEntityPacket` (not to be confused with the old one)
- `StructureTemplateDataExportRequestPacket`
- `StructureTemplateDataExportResponsePacket`
# 3.9.1
- Fixed resource packs not working on 1.12 clients.
- Fixed some particles displaying incorrectly (some still don't render at all).
- Fixed `Entity->setFireTicks()` with a value of `0` setting the on-fire flag.
- Silenced a debug message which appeared every time a player right-clicked a block.
- Updated constants for `LevelSoundEventPacket`.
# 3.9.2
- Logger warnings for illegal player movements have been lowered to debug.
- TNT explosions now start from the center instead of the base. This fixes unexpected results when TNT is lit on top of obsidian.
- Fixed the `loadbefore` directive in `plugin.yml` sometimes being ignored.
- Fixed `Item->setCustomName()` with an empty string leaving behind an empty tag.
- Fixed incorrect positioning of bucket empty sound.
- Fixed some incorrect tag parsing in `/give` involving quoted numbers.
# 3.9.3
- Fixed a memory leak on async task removal in error conditions.
- Fixed scheduled block updates (for example liquid) triggering chunk reloading. This could cause a significant performance issue in some conditions.
- Fixed some minor cosmetic issues in documentation.
# 3.9.4
- Fixed a memory leak when scheduled updates were pending on a chunk being unloaded.
- Fixed plugin detection in crashdumps. Previously `src/pocketmine` anywhere in the path would cause the error to be considered a core crash, regardless of the preceding path.
- Fixed entity metadata types for 1.12. The SLOT type was removed and a COMPOUND_TAG type added. This change involves changes to internal API which may break plugins. **See the warning at the top of this changelog about API versioning.**
- Fixed random and base populator amounts of trees and tallgrass never being initialized. This bug had no obvious effect, but may have become a problem in future PHP versions.
- The following internal methods have been marked as `@deprecated` and documentation warnings added:
- `Entity->getBlocksAround()`
- `Entity->despawnFrom()`
- `Entity->despawnFromAll()`
- Fixed plugin `softdepend` not influencing load order when a soft-depended plugin had an unresolved soft dependency of its own.
- Fixed endless falling of sand on top of fences.
# 3.9.5
- Fixed some issues with multiple consecutive commas inside quotes in form responses.
- Fixed server crash when the manifest json does not contain a json object in a resource pack.
- Ender pearls no longer collide with blocks that do not have any collision boxes.
# 3.9.6
- Updated Composer dependencies to their latest versions.
- Prevent clients repeating the resource pack sequence. This fixes error spam with bugged 1.12 clients.
- `Internet::simpleCurl()` now includes the PocketMine-MP version in the user-agent string.
- Spawn protection is now disabled by default in the setup wizard.
- Default difficulty is now NORMAL(2) instead of EASY(1).
- Fixed crashing on corrupted world manifest and unsupported world formats.
- Fixed `/transferserver` being usable without appropriate permissions.
- `RegionLoader->removeChunk()` now writes the region header as appropriate.
- Fixed performance issue when loading large regions (bug in header validation).
- Fixed skin geometry being removed when the JSON contained comments.
- Added new constants to `EventPacket`.
- Added encode/decode for `StructureTemplateDataExportRequestPacket` and `StructureTemplateDataExportResponsePacket`.
- Fixed broken type asserts in `LevelChunkPacket::withCache()` and `ClientCacheMissResponsePacket::create()`.
- `types\CommandParameter` field `byte1` has been renamed to `flags`.
- Cleaned up public interface of `AvailableCommandsPacket`, removing fields which exposed details of the encoding scheme.
- Improved documentation for the following API methods:
- `pocketmine\item\Item`:
- `addCreativeItem()`
- `removeCreativeItem()`
- `clearCreativeItems()`
- `pocketmine\level\Explosion`:
- `explodeA()`
- `explodeB()`
- Fixed various cosmetic documentation inconsistencies in the core and dependencies.
# 3.9.7
- Fixed a crash that could occur during timezone detection.
- Squid no longer spin around constantly in enclosed spaces. Their performance impact is reduced.
- Cleaned up the bootstrap file.
# 3.9.8
- Added [PHPStan](https://github.com/phpstan/phpstan) configuration. PHPStan is now used on CI for automated QA, which should improve stability and quality going forward.
- The following constants are now autoloaded when loading the Composer autoloader:
- `pocketmine\NAME`
- `pocketmine\BASE_VERSION`
- `pocketmine\IS_DEVELOPMENT_BUILD`
- `pocketmine\BUILD_NUMBER`
- `INT32_MIN`
- `INT32_MAX`
- `INT32_MASK`
- Fixed memory leaks and crashes caused by plugin use of `Player->showPlayer()` and `Entity->spawnTo()`.
- Fixed crashes that could occur when tile classes were overridden with classes incompatible with the originals.
- Fixed improper handling of non-Compound root NBT tags on network itemstack decoding.
- Fixed paintings dropping multiple items when destroyed by block updates.
- Fixed `var_dump()` not showing private and protected properties of `DataPacket` subclasses.
- Fixed overloads with zero arguments being missing when decoding `AvailableCommandsPacket`.
- `CraftingDataPacket` now retains the `cleanRecipes` field when decoding.
- Fixed `Block->getMetadata()` returning null (non-iterable).
- `PlayerChatEvent` documentation has been updated to specify that `CommandSender` recipients are accepted. This behaviour was already present in previous versions, but incorrectly documented.
- Fixed various issues with PHPDoc comments reported by PHPStan.
- Fixed various minor code nits reported by PHPStan.

View File

@ -17,17 +17,17 @@
"ext-openssl": "*",
"ext-pcre": "*",
"ext-phar": "*",
"ext-pthreads": ">=3.1.7dev",
"ext-pthreads": "~3.2.0",
"ext-reflection": "*",
"ext-sockets": "*",
"ext-spl": "*",
"ext-yaml": ">=2.0.0",
"ext-zip": "*",
"ext-zlib": ">=1.2.11",
"pocketmine/raklib": "^0.12.0",
"pocketmine/spl": "^0.3.0",
"pocketmine/binaryutils": "^0.1.0",
"pocketmine/nbt": "^0.2.6",
"pocketmine/raklib": "^0.12.5",
"pocketmine/spl": "^0.3.5",
"pocketmine/binaryutils": "^0.1.9",
"pocketmine/nbt": "^0.2.10",
"pocketmine/math": "^0.2.0",
"pocketmine/snooze": "^0.1.0",
"daverandom/callback-validator": "dev-master",
@ -36,7 +36,12 @@
"autoload": {
"psr-4": {
"": ["src"]
}
},
"files": [
"src/pocketmine/CoreConstants.php",
"src/pocketmine/GlobalConstants.php",
"src/pocketmine/VersionInfo.php"
]
},
"autoload-dev": {
"psr-4": {

75
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": "2f5313e4ebd7b62c785cf683b27464b4",
"content-hash": "f693f278b3bb9c1d266079fa17644dcb",
"packages": [
{
"name": "adhocore/json-comment",
@ -92,16 +92,16 @@
},
{
"name": "pocketmine/binaryutils",
"version": "0.1.8",
"version": "0.1.10",
"source": {
"type": "git",
"url": "https://github.com/pmmp/BinaryUtils.git",
"reference": "33f511715d22418c03368b49b45a6c25d6b33806"
"reference": "435f2ee265bce75ef1aa9563f9b60ff36d705e80"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/pmmp/BinaryUtils/zipball/33f511715d22418c03368b49b45a6c25d6b33806",
"reference": "33f511715d22418c03368b49b45a6c25d6b33806",
"url": "https://api.github.com/repos/pmmp/BinaryUtils/zipball/435f2ee265bce75ef1aa9563f9b60ff36d705e80",
"reference": "435f2ee265bce75ef1aa9563f9b60ff36d705e80",
"shasum": ""
},
"require": {
@ -119,23 +119,23 @@
],
"description": "Classes and methods for conveniently handling binary data",
"support": {
"source": "https://github.com/pmmp/BinaryUtils/tree/0.1.8",
"source": "https://github.com/pmmp/BinaryUtils/tree/0.1.10",
"issues": "https://github.com/pmmp/BinaryUtils/issues"
},
"time": "2019-01-16T17:31:44+00:00"
"time": "2019-10-21T14:40:32+00:00"
},
{
"name": "pocketmine/math",
"version": "0.2.2",
"version": "0.2.3",
"source": {
"type": "git",
"url": "https://github.com/pmmp/Math.git",
"reference": "b755d3fb7025c4ddb7d9d6df0ba7e0b65125e51c"
"reference": "68be8a79fd0169043ef514797c304517cb8a6071"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/pmmp/Math/zipball/b755d3fb7025c4ddb7d9d6df0ba7e0b65125e51c",
"reference": "b755d3fb7025c4ddb7d9d6df0ba7e0b65125e51c",
"url": "https://api.github.com/repos/pmmp/Math/zipball/68be8a79fd0169043ef514797c304517cb8a6071",
"reference": "68be8a79fd0169043ef514797c304517cb8a6071",
"shasum": ""
},
"require": {
@ -153,30 +153,30 @@
],
"description": "PHP library containing math related code used in PocketMine-MP",
"support": {
"source": "https://github.com/pmmp/Math/tree/0.2.2",
"source": "https://github.com/pmmp/Math/tree/0.2.3",
"issues": "https://github.com/pmmp/Math/issues"
},
"time": "2019-01-04T15:42:36+00:00"
"time": "2019-10-21T14:35:10+00:00"
},
{
"name": "pocketmine/nbt",
"version": "0.2.7",
"version": "0.2.12",
"source": {
"type": "git",
"url": "https://github.com/pmmp/NBT.git",
"reference": "2f176c9f2fd9b31db8bc2ada2f38990157ec8f1a"
"reference": "b5777265329753b74dd40bb105eedabeefb98724"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/pmmp/NBT/zipball/2f176c9f2fd9b31db8bc2ada2f38990157ec8f1a",
"reference": "2f176c9f2fd9b31db8bc2ada2f38990157ec8f1a",
"url": "https://api.github.com/repos/pmmp/NBT/zipball/b5777265329753b74dd40bb105eedabeefb98724",
"reference": "b5777265329753b74dd40bb105eedabeefb98724",
"shasum": ""
},
"require": {
"ext-zlib": "*",
"php": ">=7.2.0",
"php-64bit": "*",
"pocketmine/binaryutils": "^0.1.0"
"pocketmine/binaryutils": "^0.1.9"
},
"type": "library",
"autoload": {
@ -194,33 +194,33 @@
],
"description": "PHP library for working with Named Binary Tags",
"support": {
"source": "https://github.com/pmmp/NBT/tree/0.2.7",
"source": "https://github.com/pmmp/NBT/tree/0.2",
"issues": "https://github.com/pmmp/NBT/issues"
},
"time": "2019-03-29T19:39:42+00:00"
"time": "2019-12-01T08:20:26+00:00"
},
{
"name": "pocketmine/raklib",
"version": "0.12.4",
"version": "0.12.6",
"source": {
"type": "git",
"url": "https://github.com/pmmp/RakLib.git",
"reference": "fc1ccc8e61b9033e5372436b2e28a7a95388373f"
"reference": "18450e01185e6064790bda563ac672e7141c6992"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/pmmp/RakLib/zipball/fc1ccc8e61b9033e5372436b2e28a7a95388373f",
"reference": "fc1ccc8e61b9033e5372436b2e28a7a95388373f",
"url": "https://api.github.com/repos/pmmp/RakLib/zipball/18450e01185e6064790bda563ac672e7141c6992",
"reference": "18450e01185e6064790bda563ac672e7141c6992",
"shasum": ""
},
"require": {
"ext-bcmath": "*",
"ext-pthreads": ">=3.1.7dev",
"ext-pthreads": "~3.2.0",
"ext-sockets": "*",
"php": ">=7.2.0",
"php-64bit": "*",
"php-ipv6": "*",
"pocketmine/binaryutils": "^0.1.0",
"pocketmine/binaryutils": "^0.1.9",
"pocketmine/snooze": "^0.1.0",
"pocketmine/spl": "^0.3.0"
},
@ -235,10 +235,10 @@
],
"description": "A RakNet server implementation written in PHP",
"support": {
"source": "https://github.com/pmmp/RakLib/tree/0.12.4",
"source": "https://github.com/pmmp/RakLib/tree/0.12.6",
"issues": "https://github.com/pmmp/RakLib/issues"
},
"time": "2019-05-02T14:53:51+00:00"
"time": "2019-12-07T13:43:34+00:00"
},
{
"name": "pocketmine/snooze",
@ -276,23 +276,20 @@
},
{
"name": "pocketmine/spl",
"version": "0.3.2",
"version": "0.3.5",
"source": {
"type": "git",
"url": "https://github.com/pmmp/SPL.git",
"reference": "7fd53857cd000491ba69e8db865792a024dd2c49"
"reference": "88052c67d3df2cc2dc2d99ebeae3d7ede3fc64ab"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/pmmp/SPL/zipball/7fd53857cd000491ba69e8db865792a024dd2c49",
"reference": "7fd53857cd000491ba69e8db865792a024dd2c49",
"url": "https://api.github.com/repos/pmmp/SPL/zipball/88052c67d3df2cc2dc2d99ebeae3d7ede3fc64ab",
"reference": "88052c67d3df2cc2dc2d99ebeae3d7ede3fc64ab",
"shasum": ""
},
"type": "library",
"autoload": {
"exclude-from-classmap": [
"stubs"
],
"classmap": [
"./"
]
@ -302,16 +299,16 @@
],
"description": "Standard library files required by PocketMine-MP and related projects",
"support": {
"source": "https://github.com/pmmp/SPL/tree/0.3.2"
"source": "https://github.com/pmmp/SPL/tree/0.3",
"issues": "https://github.com/pmmp/SPL/issues"
},
"time": "2018-08-12T15:17:39+00:00"
"time": "2020-01-14T16:23:26+00:00"
}
],
"packages-dev": [],
"aliases": [],
"minimum-stability": "stable",
"stability-flags": {
"ext-pthreads": 20,
"daverandom/callback-validator": 20
},
"prefer-stable": false,
@ -329,7 +326,7 @@
"ext-openssl": "*",
"ext-pcre": "*",
"ext-phar": "*",
"ext-pthreads": ">=3.1.7dev",
"ext-pthreads": "~3.2.0",
"ext-reflection": "*",
"ext-sockets": "*",
"ext-spl": "*",

View File

@ -530,7 +530,7 @@ HIDE_FRIEND_COMPOUNDS = NO
# blocks will be appended to the function's detailed documentation block.
# The default value is: NO.
HIDE_IN_BODY_DOCS = NO
HIDE_IN_BODY_DOCS = YES
# The INTERNAL_DOCS tag determines if documentation that is typed after a
# \internal command is included. If the tag is set to NO then the documentation
@ -600,7 +600,7 @@ SORT_MEMBER_DOCS = YES
# this will also influence the order of the classes in the class list.
# The default value is: NO.
SORT_BRIEF_DOCS = NO
SORT_BRIEF_DOCS = YES
# If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen will sort the
# (brief and detailed) documentation of class members so that constructors and
@ -612,7 +612,7 @@ SORT_BRIEF_DOCS = NO
# detailed member documentation.
# The default value is: NO.
SORT_MEMBERS_CTORS_1ST = NO
SORT_MEMBERS_CTORS_1ST = YES
# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the hierarchy
# of group names into alphabetical order. If set to NO the group names will
@ -1565,7 +1565,7 @@ MATHJAX_FORMAT = HTML-CSS
# The default value is: https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.5/.
# This tag requires that the tag USE_MATHJAX is set to YES.
MATHJAX_RELPATH = http://cdn.mathjax.org/mathjax/latest
MATHJAX_RELPATH = https://cdn.mathjax.org/mathjax/latest
# The MATHJAX_EXTENSIONS tag can be used to specify one or more MathJax
# extension names that should be enabled during MathJax rendering. For example

118
phpstan.neon.dist Normal file
View File

@ -0,0 +1,118 @@
includes:
- tests/phpstan/configs/com-dotnet-magic.neon
- tests/phpstan/configs/custom-leveldb.neon
- tests/phpstan/configs/gc-hacks.neon
- tests/phpstan/configs/phpstan-bugs.neon
- tests/phpstan/configs/pthreads-bugs.neon
- tests/phpstan/configs/runtime-type-checks.neon
parameters:
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\\.$#"
count: 1
path: src/pocketmine/Server.php
-
message: "#^Call to an undefined method pocketmine\\\\command\\\\CommandSender\\:\\:teleport\\(\\)\\.$#"
count: 1
path: src/pocketmine/command/defaults/TeleportCommand.php
# comment: "not actually possible, but high cost to fix warning"
-
message: "#^Array \\(array\\<string\\>\\) does not accept pocketmine\\\\entity\\\\Entity\\.$#"
count: 2
path: src/pocketmine/entity/Entity.php
-
message: "#^Invalid array key type pocketmine\\\\entity\\\\Entity\\.$#"
count: 1
path: src/pocketmine/entity/Entity.php
-
message: "#^Method pocketmine\\\\event\\\\entity\\\\EntityDeathEvent\\:\\:getEntity\\(\\) should return pocketmine\\\\entity\\\\Living but returns pocketmine\\\\entity\\\\Entity\\.$#"
count: 1
path: src/pocketmine/event/entity/EntityDeathEvent.php
-
message: "#^Method pocketmine\\\\event\\\\entity\\\\EntityShootBowEvent\\:\\:getEntity\\(\\) should return pocketmine\\\\entity\\\\Living but returns pocketmine\\\\entity\\\\Entity\\.$#"
count: 1
path: src/pocketmine/event/entity/EntityShootBowEvent.php
-
message: "#^Property pocketmine\\\\event\\\\entity\\\\EntityShootBowEvent\\:\\:\\$projectile \\(pocketmine\\\\entity\\\\projectile\\\\Projectile\\) does not accept pocketmine\\\\entity\\\\Entity\\.$#"
count: 1
path: src/pocketmine/event/entity/EntityShootBowEvent.php
-
message: "#^Method pocketmine\\\\event\\\\entity\\\\ItemDespawnEvent\\:\\:getEntity\\(\\) should return pocketmine\\\\entity\\\\object\\\\ItemEntity but returns pocketmine\\\\entity\\\\Entity\\.$#"
count: 1
path: src/pocketmine/event/entity/ItemDespawnEvent.php
-
message: "#^Method pocketmine\\\\event\\\\entity\\\\ItemSpawnEvent\\:\\:getEntity\\(\\) should return pocketmine\\\\entity\\\\object\\\\ItemEntity but returns pocketmine\\\\entity\\\\Entity\\.$#"
count: 1
path: src/pocketmine/event/entity/ItemSpawnEvent.php
-
message: "#^Method pocketmine\\\\event\\\\entity\\\\ProjectileHitEvent\\:\\:getEntity\\(\\) should return pocketmine\\\\entity\\\\projectile\\\\Projectile but returns pocketmine\\\\entity\\\\Entity\\.$#"
count: 1
path: src/pocketmine/event/entity/ProjectileHitEvent.php
-
message: "#^Method pocketmine\\\\event\\\\entity\\\\ProjectileLaunchEvent\\:\\:getEntity\\(\\) should return pocketmine\\\\entity\\\\projectile\\\\Projectile but returns pocketmine\\\\entity\\\\Entity\\.$#"
count: 1
path: src/pocketmine/event/entity/ProjectileLaunchEvent.php
-
message: "#^Constructor of class pocketmine\\\\level\\\\generator\\\\hell\\\\Nether has an unused parameter \\$options\\.$#"
count: 1
path: src/pocketmine/level/generator/hell/Nether.php
-
message: "#^Constructor of class pocketmine\\\\level\\\\generator\\\\normal\\\\Normal has an unused parameter \\$options\\.$#"
count: 1
path: src/pocketmine/level/generator/normal/Normal.php
-
message: "#^Constructor of class pocketmine\\\\scheduler\\\\TaskScheduler has an unused parameter \\$logger\\.$#"
count: 1
path: src/pocketmine/scheduler/TaskScheduler.php
-
message: "#^Constant pocketmine\\\\COMPOSER_AUTOLOADER_PATH not found\\.$#"
path: src
-
message: "#^Constant pocketmine\\\\DATA not found\\.$#"
path: src
-
message: "#^Constant pocketmine\\\\GIT_COMMIT not found\\.$#"
path: src
-
message: "#^Constant pocketmine\\\\PLUGIN_PATH not found\\.$#"
path: src
-
message: "#^Constant pocketmine\\\\START_TIME not found\\.$#"
path: src
-
message: "#^Constant pocketmine\\\\VERSION 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)){
@ -291,7 +297,7 @@ class CrashDump{
private function determinePluginFromFile(string $filePath, bool $crashFrame) : bool{
$frameCleanPath = Utils::cleanPath($filePath); //this will be empty in phar stub
if($frameCleanPath !== "" and strpos($frameCleanPath, "src/pocketmine/") === false and strpos($frameCleanPath, "vendor/pocketmine/") === false and file_exists($filePath)){
if(strpos($frameCleanPath, "plugins") === 0 and file_exists($filePath)){
$this->addLine();
if($crashFrame){
$this->addLine("THIS CRASH WAS CAUSED BY A PLUGIN");
@ -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();
@ -333,17 +339,27 @@ class CrashDump{
$this->data["general"]["php_os"] = PHP_OS;
$this->data["general"]["os"] = Utils::getOS();
$this->addLine($this->server->getName() . " version: " . $version->getFullVersion(true) . " [Protocol " . ProtocolInfo::CURRENT_PROTOCOL . "]");
$this->addLine("Git commit: " . GIT_COMMIT);
$this->addLine("Git commit: " . \pocketmine\GIT_COMMIT);
$this->addLine("uname -a: " . php_uname("a"));
$this->addLine("PHP Version: " . phpversion());
$this->addLine("Zend version: " . zend_version());
$this->addLine("OS : " . PHP_OS . ", " . Utils::getOS());
}
/**
* @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

@ -0,0 +1,30 @@
<?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/
*
*
*/
// composer autoload doesn't use require_once and also pthreads can inherit things
if(defined('pocketmine\_GLOBAL_CONSTANTS_INCLUDED')){
return;
}
define('pocketmine\_GLOBAL_CONSTANTS_INCLUDED', true);
const INT32_MIN = -0x80000000;
const INT32_MAX = 0x7fffffff;
const INT32_MASK = 0xffffffff;

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

@ -99,20 +99,20 @@ use pocketmine\nbt\tag\CompoundTag;
use pocketmine\nbt\tag\DoubleTag;
use pocketmine\nbt\tag\ListTag;
use pocketmine\network\mcpe\PlayerNetworkSessionAdapter;
use pocketmine\network\mcpe\protocol\ActorEventPacket;
use pocketmine\network\mcpe\protocol\AdventureSettingsPacket;
use pocketmine\network\mcpe\protocol\AnimatePacket;
use pocketmine\network\mcpe\protocol\AvailableActorIdentifiersPacket;
use pocketmine\network\mcpe\protocol\AvailableCommandsPacket;
use pocketmine\network\mcpe\protocol\AvailableEntityIdentifiersPacket;
use pocketmine\network\mcpe\protocol\BatchPacket;
use pocketmine\network\mcpe\protocol\BiomeDefinitionListPacket;
use pocketmine\network\mcpe\protocol\BlockEntityDataPacket;
use pocketmine\network\mcpe\protocol\BlockActorDataPacket;
use pocketmine\network\mcpe\protocol\BlockPickRequestPacket;
use pocketmine\network\mcpe\protocol\BookEditPacket;
use pocketmine\network\mcpe\protocol\ChunkRadiusUpdatedPacket;
use pocketmine\network\mcpe\protocol\ContainerClosePacket;
use pocketmine\network\mcpe\protocol\DataPacket;
use pocketmine\network\mcpe\protocol\DisconnectPacket;
use pocketmine\network\mcpe\protocol\EntityEventPacket;
use pocketmine\network\mcpe\protocol\InteractPacket;
use pocketmine\network\mcpe\protocol\InventoryTransactionPacket;
use pocketmine\network\mcpe\protocol\ItemFrameDropItemPacket;
@ -146,6 +146,10 @@ use pocketmine\network\mcpe\protocol\types\CommandParameter;
use pocketmine\network\mcpe\protocol\types\ContainerIds;
use pocketmine\network\mcpe\protocol\types\DimensionIds;
use pocketmine\network\mcpe\protocol\types\PlayerPermissions;
use pocketmine\network\mcpe\protocol\types\SkinAdapterSingleton;
use pocketmine\network\mcpe\protocol\types\SkinAnimation;
use pocketmine\network\mcpe\protocol\types\SkinData;
use pocketmine\network\mcpe\protocol\types\SkinImage;
use pocketmine\network\mcpe\protocol\UpdateAttributesPacket;
use pocketmine\network\mcpe\protocol\UpdateBlockPacket;
use pocketmine\network\mcpe\VerifyLoginTask;
@ -261,6 +265,9 @@ class Player extends Human implements CommandSender, ChunkLoader, IPlayer{
/** @var bool */
public $loggedIn = false;
/** @var bool */
private $resourcePacksDone = false;
/** @var bool */
public $spawned = false;
@ -275,6 +282,7 @@ class Player extends Human implements CommandSender, ChunkLoader, IPlayer{
/** @var string */
protected $xuid = "";
/** @var int */
protected $windowCnt = 2;
/** @var int[] */
protected $windows = [];
@ -457,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();
@ -477,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;
@ -489,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();
@ -502,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;
}
@ -531,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;
@ -558,6 +588,8 @@ class Player extends Human implements CommandSender, ChunkLoader, IPlayer{
/**
* @param Player $player
*
* @return void
*/
public function hidePlayer(Player $player){
if($player === $this){
@ -569,6 +601,8 @@ class Player extends Human implements CommandSender, ChunkLoader, IPlayer{
/**
* @param Player $player
*
* @return void
*/
public function showPlayer(Player $player){
if($player === $this){
@ -597,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);
@ -627,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()){
@ -678,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);
@ -713,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){
@ -734,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;
@ -810,6 +856,8 @@ class Player extends Human implements CommandSender, ChunkLoader, IPlayer{
/**
* @param string $name
*
* @return void
*/
public function setDisplayName(string $name){
$this->displayName = $name;
@ -895,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;
@ -919,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);
@ -988,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);
@ -1004,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;
@ -1026,6 +1095,9 @@ class Player extends Human implements CommandSender, ChunkLoader, IPlayer{
}
}
/**
* @return void
*/
protected function sendNextChunk(){
if(!$this->isConnected()){
return;
@ -1060,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)
@ -1109,9 +1184,17 @@ class Player extends Human implements CommandSender, ChunkLoader, IPlayer{
}
}
protected function sendRespawnPacket(Vector3 $pos){
/**
* @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);
$pk->respawnState = $respawnState;
$pk->entityRuntimeId = $this->getId();
$this->dataPacket($pk);
}
@ -1199,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();
@ -1236,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)){
@ -1295,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);
@ -1358,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)){
@ -1446,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();
@ -1455,6 +1547,8 @@ class Player extends Human implements CommandSender, ChunkLoader, IPlayer{
/**
* Sends all the option flags
*
* @return void
*/
public function sendSettings(){
$pk = new AdventureSettingsPacket();
@ -1560,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();
@ -1572,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;
@ -1596,7 +1698,7 @@ class Player extends Human implements CommandSender, ChunkLoader, IPlayer{
* If you must tamper with this code, be aware that this can cause very nasty results. Do not waste our time
* asking for help if you suffer the consequences of messing with this.
*/
$this->server->getLogger()->warning($this->getName() . " moved too fast, reverting movement");
$this->server->getLogger()->debug($this->getName() . " moved too fast, reverting movement");
$this->server->getLogger()->debug("Old position: " . $this->asVector3() . ", new position: " . $this->newPosition);
$revert = true;
}elseif(!$this->level->isInLoadedTerrain($newPos) or !$this->level->isChunkGenerated($newPos->getFloorX() >> 4, $newPos->getFloorZ() >> 4)){
@ -1613,7 +1715,7 @@ class Player extends Human implements CommandSender, ChunkLoader, IPlayer{
$diff = $this->distanceSquared($newPos) / $tickDiff ** 2;
if($this->isSurvival() and !$revert and $diff > 0.0625){
if($this->isSurvival() and $diff > 0.0625){
$ev = new PlayerIllegalMoveEvent($this, $newPos, new Vector3($this->lastX, $this->lastY, $this->lastZ));
$ev->setCancelled($this->allowMovementCheats);
@ -1621,7 +1723,7 @@ class Player extends Human implements CommandSender, ChunkLoader, IPlayer{
if(!$ev->isCancelled()){
$revert = true;
$this->server->getLogger()->warning($this->getServer()->getLanguage()->translateString("pocketmine.player.invalidMove", [$this->getName()]));
$this->server->getLogger()->debug($this->getServer()->getLanguage()->translateString("pocketmine.player.invalidMove", [$this->getName()]));
$this->server->getLogger()->debug("Old position: " . $this->asVector3() . ", new position: " . $this->newPosition);
}
}
@ -1714,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){
@ -1819,6 +1926,9 @@ class Player extends Human implements CommandSender, ChunkLoader, IPlayer{
$this->dataPacket($pk);
}
/**
* @return void
*/
public function checkNetwork(){
if(!$this->isOnline()){
return;
@ -1910,14 +2020,27 @@ class Player extends Human implements CommandSender, ChunkLoader, IPlayer{
$this->uuid = UUID::fromString($packet->clientUUID);
$this->rawUUID = $this->uuid->toBinary();
$skin = new Skin(
$animations = [];
foreach($packet->clientData["AnimatedImageData"] as $animation){
$animations[] = new SkinAnimation(new SkinImage($animation["ImageHeight"], $animation["ImageWidth"], base64_decode($animation["Image"], true)), $animation["Type"], $animation["Frames"]);
}
$skinData = new SkinData(
$packet->clientData["SkinId"],
base64_decode($packet->clientData["SkinData"] ?? ""),
base64_decode($packet->clientData["CapeData"] ?? ""),
$packet->clientData["SkinGeometryName"] ?? "",
base64_decode($packet->clientData["SkinGeometry"] ?? "")
base64_decode($packet->clientData["SkinResourcePatch"] ?? ""),
new SkinImage($packet->clientData["SkinImageHeight"], $packet->clientData["SkinImageWidth"], base64_decode($packet->clientData["SkinData"])),
$animations,
new SkinImage($packet->clientData["CapeImageHeight"], $packet->clientData["CapeImageWidth"], base64_decode($packet->clientData["CapeData"] ?? "")),
base64_decode($packet->clientData["SkinGeometryData"] ?? ""),
base64_decode($packet->clientData["SkinAnimationData"] ?? ""),
$packet->clientData["PremiumSkin"] ?? false,
$packet->clientData["PersonaSkin"] ?? false,
$packet->clientData["CapeOnClassicSkin"] ?? false,
$packet->clientData["CapeId"] ?? ""
);
$skin = SkinAdapterSingleton::get()->fromSkinData($skinData);
if(!$skin->isValid()){
$this->close("", "disconnectionScreen.invalidSkin");
@ -1954,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;
@ -1997,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()))){
@ -2056,6 +2188,9 @@ class Player extends Human implements CommandSender, ChunkLoader, IPlayer{
}
public function handleResourcePackClientResponse(ResourcePackClientResponsePacket $packet) : bool{
if($this->resourcePacksDone){
return false;
}
switch($packet->status){
case ResourcePackClientResponsePacket::STATUS_REFUSED:
//TODO: add lang strings for this
@ -2093,10 +2228,14 @@ 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:
$this->resourcePacksDone = true;
$this->completeLoginSequence();
break;
default:
@ -2106,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();
@ -2149,7 +2291,7 @@ class Player extends Human implements CommandSender, ChunkLoader, IPlayer{
$pk->spawnZ = $spawnPosition->getFloorZ();
$pk->hasAchievementsDisabled = true;
$pk->time = $this->level->getTime();
$pk->eduMode = false;
$pk->eduEditionOffer = 0;
$pk->rainLevel = 0; //TODO: implement these properly
$pk->lightningLevel = 0;
$pk->commandsEnabled = true;
@ -2157,7 +2299,7 @@ class Player extends Human implements CommandSender, ChunkLoader, IPlayer{
$pk->worldName = $this->server->getMotd();
$this->dataPacket($pk);
$this->sendDataPacket(new AvailableEntityIdentifiersPacket());
$this->sendDataPacket(new AvailableActorIdentifiersPacket());
$this->sendDataPacket(new BiomeDefinitionListPacket());
$this->level->sendTime($this);
@ -2279,14 +2421,14 @@ class Player extends Human implements CommandSender, ChunkLoader, IPlayer{
return true;
}
public function handleEntityEvent(EntityEventPacket $packet) : bool{
public function handleEntityEvent(ActorEventPacket $packet) : bool{
if(!$this->spawned or !$this->isAlive()){
return true;
}
$this->doCloseInventory();
switch($packet->event){
case EntityEventPacket::EATING_ITEM:
case ActorEventPacket::EATING_ITEM:
if($packet->data === 0){
return false;
}
@ -2484,6 +2626,27 @@ class Player extends Human implements CommandSender, ChunkLoader, IPlayer{
return true;
case InventoryTransactionPacket::USE_ITEM_ACTION_CLICK_AIR:
if($this->isUsingItem()){
$slot = $this->inventory->getItemInHand();
if($slot instanceof Consumable){
$ev = new PlayerItemConsumeEvent($this, $slot);
if($this->hasItemCooldown($slot)){
$ev->setCancelled();
}
$ev->call();
if($ev->isCancelled() or !$this->consumeObject($slot)){
$this->inventory->sendContents($this);
return true;
}
$this->resetItemCooldown($slot);
if($this->isSurvival()){
$slot->pop();
$this->inventory->setItemInHand($slot);
$this->inventory->addItem($slot->getResidue());
}
$this->setUsingItem(false);
}
}
$directionVector = $this->getDirectionVector();
if($this->isCreative()){
@ -2637,33 +2800,6 @@ class Player extends Human implements CommandSender, ChunkLoader, IPlayer{
}
return true;
case InventoryTransactionPacket::RELEASE_ITEM_ACTION_CONSUME:
$slot = $this->inventory->getItemInHand();
if($slot instanceof Consumable){
$ev = new PlayerItemConsumeEvent($this, $slot);
if($this->hasItemCooldown($slot)){
$ev->setCancelled();
}
$ev->call();
if($ev->isCancelled() or !$this->consumeObject($slot)){
$this->inventory->sendContents($this);
return true;
}
$this->resetItemCooldown($slot);
if($this->isSurvival()){
$slot->pop();
$this->inventory->setItemInHand($slot);
$this->inventory->addItem($slot->getResidue());
}
return true;
}
break;
default:
break;
}
@ -2821,7 +2957,7 @@ class Player extends Human implements CommandSender, ChunkLoader, IPlayer{
$this->stopSleep();
break;
case PlayerActionPacket::ACTION_RESPAWN:
if(!$this->spawned or $this->isAlive() or !$this->isOnline()){
if($this->isAlive()){
break;
}
@ -2855,6 +2991,8 @@ class Player extends Human implements CommandSender, ChunkLoader, IPlayer{
case PlayerActionPacket::ACTION_STOP_SWIMMING:
//TODO: handle this when it doesn't spam every damn tick (yet another spam bug!!)
break;
case PlayerActionPacket::ACTION_INTERACT_BLOCK: //ignored (for now)
break;
default:
$this->server->getLogger()->debug("Unhandled/unknown player action type " . $packet->action . " from " . $this->getName());
return false;
@ -2904,6 +3042,15 @@ class Player extends Human implements CommandSender, ChunkLoader, IPlayer{
return true;
}
public function handleRespawn(RespawnPacket $packet) : bool{
if(!$this->isAlive() && $packet->respawnState === RespawnPacket::CLIENT_READY_TO_SPAWN){
$this->sendRespawnPacket($this, RespawnPacket::READY_TO_SPAWN);
return true;
}
return false;
}
/**
* Drops an item on the ground in front of the player. Returns if the item drop was successful.
*
@ -2981,7 +3128,7 @@ class Player extends Human implements CommandSender, ChunkLoader, IPlayer{
return $handled;
}
public function handleBlockEntityData(BlockEntityDataPacket $packet) : bool{
public function handleBlockEntityData(BlockActorDataPacket $packet) : bool{
if(!$this->spawned or !$this->isAlive()){
return true;
}
@ -3047,6 +3194,9 @@ class Player extends Human implements CommandSender, ChunkLoader, IPlayer{
}
public function handleResourcePackChunkRequest(ResourcePackChunkRequestPacket $packet) : bool{
if($this->resourcePacksDone){
return false;
}
$manager = $this->server->getResourcePackManager();
$pack = $manager->getPackById($packet->packId);
if(!($pack instanceof ResourcePack)){
@ -3118,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){
@ -3275,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);
@ -3288,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);
@ -3297,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);
@ -3304,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();
@ -3313,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();
@ -3326,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){
@ -3343,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();
@ -3355,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){
@ -3374,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();
@ -3382,7 +3552,7 @@ class Player extends Human implements CommandSender, ChunkLoader, IPlayer{
$pk->needsTranslation = true;
$pk->message = $this->server->getLanguage()->translateString($message, $parameters, "pocketmine.");
foreach($parameters as $i => $p){
$parameters[$i] = $this->server->getLanguage()->translateString($p, $parameters, "pocketmine.");
$parameters[$i] = $this->server->getLanguage()->translateString($p, [], "pocketmine.");
}
$pk->parameters = $parameters;
}else{
@ -3399,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();
@ -3407,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;
@ -3417,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();
@ -3558,6 +3737,9 @@ class Player extends Human implements CommandSender, ChunkLoader, IPlayer{
}
}
/**
* @return mixed[]
*/
public function __debugInfo(){
return [];
}
@ -3574,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){
@ -3736,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;
@ -3787,13 +3980,16 @@ class Player extends Human implements CommandSender, ChunkLoader, IPlayer{
return false;
}
/**
* @return void
*/
protected function addDefaultWindows(){
$this->addWindow($this->getInventory(), ContainerIds::INVENTORY, true);
$this->addWindow($this->getArmorInventory(), ContainerIds::ARMOR, true);
$this->cursorInventory = new PlayerCursorInventory($this);
$this->addWindow($this->cursorInventory, ContainerIds::CURSOR, true);
$this->addWindow($this->cursorInventory, ContainerIds::UI, true);
$this->craftingGrid = new CraftingGrid($this, CraftingGrid::SIZE_SMALL);
@ -3912,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){
@ -3931,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){
@ -3942,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

@ -21,13 +21,9 @@
declare(strict_types=1);
namespace {
const INT32_MIN = -0x80000000;
const INT32_MAX = 0x7fffffff;
}
namespace pocketmine {
use pocketmine\utils\Git;
use pocketmine\utils\MainLogger;
use pocketmine\utils\ServerKiller;
use pocketmine\utils\Terminal;
@ -40,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;
}
@ -57,18 +57,18 @@ namespace pocketmine {
if(version_compare(MIN_PHP_VERSION, PHP_VERSION) > 0){
//If PHP version isn't high enough, anything below might break, so don't bother checking it.
return [
\pocketmine\NAME . " requires PHP >= " . MIN_PHP_VERSION . ", but you have PHP " . PHP_VERSION . "."
"PHP >= " . MIN_PHP_VERSION . " is required, but you have PHP " . PHP_VERSION . "."
];
}
$messages = [];
if(PHP_INT_SIZE < 8){
$messages[] = "Running " . \pocketmine\NAME . " with 32-bit systems/PHP is no longer supported. Please upgrade to a 64-bit system, or use a 64-bit PHP binary if this is a 64-bit system.";
$messages[] = "32-bit systems/PHP are no longer supported. Please upgrade to a 64-bit system, or use a 64-bit PHP binary if this is a 64-bit system.";
}
if(php_sapi_name() !== "cli"){
$messages[] = "You must run " . \pocketmine\NAME . " using the CLI.";
$messages[] = "Only PHP CLI is supported.";
}
$extensions = [
@ -102,8 +102,8 @@ namespace pocketmine {
if(substr_count($pthreads_version, ".") < 2){
$pthreads_version = "0.$pthreads_version";
}
if(version_compare($pthreads_version, "3.1.7dev") < 0){
$messages[] = "pthreads >= 3.1.7dev is required, while you have $pthreads_version.";
if(version_compare($pthreads_version, "3.2.0") < 0){
$messages[] = "pthreads >= 3.2.0 is required, while you have $pthreads_version.";
}
}
@ -121,176 +121,179 @@ namespace pocketmine {
return $messages;
}
if(!empty($messages = check_platform_dependencies())){
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.");
foreach($messages as $m){
echo " - $m" . PHP_EOL;
}
critical_error("Please recompile PHP with the needed configuration, or refer to the installation instructions at http://pmmp.rtfd.io/en/rtfd/installation.html.");
echo PHP_EOL;
exit(1);
}
unset($messages);
error_reporting(-1);
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';
}
define('pocketmine\COMPOSER_AUTOLOADER_PATH', $bootstrap);
if(\pocketmine\COMPOSER_AUTOLOADER_PATH !== false and is_file(\pocketmine\COMPOSER_AUTOLOADER_PATH)){
require_once(\pocketmine\COMPOSER_AUTOLOADER_PATH);
}else{
critical_error("Composer autoloader not found at " . $bootstrap);
critical_error("Please install/update Composer dependencies or use provided builds.");
exit(1);
}
set_error_handler([Utils::class, 'errorExceptionHandler']);
/*
* We now use the Composer autoloader, but this autoloader is still for loading plugins.
/**
* @param \Logger $logger
* @return void
*/
$autoloader = new \BaseClassLoader();
$autoloader->register(false);
set_time_limit(0); //Who set it to 30 seconds?!?!
ini_set("allow_url_fopen", '1');
ini_set("display_errors", '1');
ini_set("display_startup_errors", '1');
ini_set("default_charset", "utf-8");
ini_set("memory_limit", '-1');
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);
define('pocketmine\PLUGIN_PATH', isset($opts["plugins"]) ? $opts["plugins"] . DIRECTORY_SEPARATOR : realpath(getcwd()) . DIRECTORY_SEPARATOR . "plugins" . DIRECTORY_SEPARATOR);
if(!file_exists(\pocketmine\DATA)){
mkdir(\pocketmine\DATA, 0777, true);
function emit_performance_warnings(\Logger $logger){
if(extension_loaded("xdebug")){
$logger->warning("Xdebug extension is enabled. This has a major impact on performance.");
}
if(!extension_loaded("pocketmine_chunkutils")){
$logger->warning("ChunkUtils extension is missing. Anvil-format worlds will experience degraded performance.");
}
if(((int) ini_get('zend.assertions')) !== -1){
$logger->warning("Debugging assertions are enabled. This may degrade performance. To disable them, set `zend.assertions = -1` in php.ini.");
}
if(\Phar::running(true) === ""){
$logger->warning("Non-packaged installation detected. This will degrade autoloading speed and make startup times longer.");
}
}
define('pocketmine\LOCK_FILE_PATH', \pocketmine\DATA . 'server.lock');
define('pocketmine\LOCK_FILE', fopen(\pocketmine\LOCK_FILE_PATH, "a+b"));
if(!flock(\pocketmine\LOCK_FILE, LOCK_EX | LOCK_NB)){
//wait for a shared lock to avoid race conditions if two servers started at the same time - this makes sure the
//other server wrote its PID and released exclusive lock before we get our lock
flock(\pocketmine\LOCK_FILE, LOCK_SH);
$pid = stream_get_contents(\pocketmine\LOCK_FILE);
critical_error("Another " . \pocketmine\NAME . " instance (PID $pid) is already using this folder (" . realpath(\pocketmine\DATA) . ").");
critical_error("Please stop the other server first before running a new one.");
exit(1);
}
ftruncate(\pocketmine\LOCK_FILE, 0);
fwrite(\pocketmine\LOCK_FILE, (string) getmypid());
fflush(\pocketmine\LOCK_FILE);
flock(\pocketmine\LOCK_FILE, LOCK_SH); //prevent acquiring an exclusive lock from another process, but allow reading
//Logger has a dependency on timezone
$tzError = Timezone::init();
if(isset($opts["enable-ansi"])){
Terminal::init(true);
}elseif(isset($opts["disable-ansi"])){
Terminal::init(false);
}else{
Terminal::init();
/**
* @return void
*/
function set_ini_entries(){
ini_set("allow_url_fopen", '1');
ini_set("display_errors", '1');
ini_set("display_startup_errors", '1');
ini_set("default_charset", "utf-8");
ini_set('assert.exception', '1');
}
$logger = new MainLogger(\pocketmine\DATA . "server.log");
$logger->registerStatic();
foreach($tzError as $e){
$logger->warning($e);
}
unset($tzError);
if(extension_loaded("xdebug")){
$logger->warning(PHP_EOL . PHP_EOL . PHP_EOL . "\tYou are running " . \pocketmine\NAME . " with xdebug enabled. This has a major impact on performance." . PHP_EOL . PHP_EOL);
}
if(!extension_loaded("pocketmine_chunkutils")){
$logger->warning("ChunkUtils extension is missing. Anvil-format worlds will experience degraded performance.");
}
if(\Phar::running(true) === ""){
$logger->warning("Non-packaged " . \pocketmine\NAME . " installation detected. Consider using a phar in production for better performance.");
}
$version = new VersionString(\pocketmine\BASE_VERSION, \pocketmine\IS_DEVELOPMENT_BUILD, \pocketmine\BUILD_NUMBER);
define('pocketmine\VERSION', $version->getFullVersion(true));
$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";
/**
* @return void
*/
function server(){
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.");
foreach($messages as $m){
echo " - $m" . PHP_EOL;
}
critical_error("Please recompile PHP with the needed configuration, or refer to the installation instructions at http://pmmp.rtfd.io/en/rtfd/installation.html.");
echo PHP_EOL;
exit(1);
}
}else{
$phar = new \Phar(\Phar::running(false));
$meta = $phar->getMetadata();
if(isset($meta["git"])){
$gitHash = $meta["git"];
unset($messages);
error_reporting(-1);
set_ini_entries();
$opts = getopt("", ["bootstrap:"]);
if(isset($opts["bootstrap"])){
$bootstrap = realpath($opts["bootstrap"]) ?: $opts["bootstrap"];
}else{
$bootstrap = dirname(__FILE__, 3) . '/vendor/autoload.php';
}
}
define('pocketmine\COMPOSER_AUTOLOADER_PATH', $bootstrap);
define('pocketmine\GIT_COMMIT', $gitHash);
if(\pocketmine\COMPOSER_AUTOLOADER_PATH !== false and is_file(\pocketmine\COMPOSER_AUTOLOADER_PATH)){
require_once(\pocketmine\COMPOSER_AUTOLOADER_PATH);
}else{
critical_error("Composer autoloader not found at " . $bootstrap);
critical_error("Please install/update Composer dependencies or use provided builds.");
exit(1);
}
set_error_handler([Utils::class, 'errorExceptionHandler']);
@define("INT32_MASK", is_int(0xffffffff) ? 0xffffffff : -1);
@ini_set("opcache.mmap_base", bin2hex(random_bytes(8))); //Fix OPCache address errors
$version = new VersionString(\pocketmine\BASE_VERSION, \pocketmine\IS_DEVELOPMENT_BUILD, \pocketmine\BUILD_NUMBER);
define('pocketmine\VERSION', $version->getFullVersion(true));
$exitCode = 0;
do{
if(!file_exists(\pocketmine\DATA . "server.properties") and !isset($opts["no-wizard"])){
$installer = new SetupWizard();
if(!$installer->run()){
$exitCode = -1;
break;
$gitHash = str_repeat("00", 20);
if(\Phar::running(true) === ""){
$gitHash = Git::getRepositoryStatePretty(\pocketmine\PATH);
}else{
$phar = new \Phar(\Phar::running(false));
$meta = $phar->getMetadata();
if(isset($meta["git"])){
$gitHash = $meta["git"];
}
}
//TODO: move this to a Server field
define('pocketmine\START_TIME', microtime(true));
ThreadManager::init();
new Server($autoloader, $logger, \pocketmine\DATA, \pocketmine\PLUGIN_PATH);
define('pocketmine\GIT_COMMIT', $gitHash);
$logger->info("Stopping other threads");
$opts = getopt("", ["data:", "plugins:", "no-wizard", "enable-ansi", "disable-ansi"]);
$killer = new ServerKiller(8);
$killer->start(PTHREADS_INHERIT_NONE);
usleep(10000); //Fixes ServerKiller not being able to start on single-core machines
define('pocketmine\DATA', isset($opts["data"]) ? $opts["data"] . DIRECTORY_SEPARATOR : realpath(getcwd()) . DIRECTORY_SEPARATOR);
define('pocketmine\PLUGIN_PATH', isset($opts["plugins"]) ? $opts["plugins"] . DIRECTORY_SEPARATOR : realpath(getcwd()) . DIRECTORY_SEPARATOR . "plugins" . DIRECTORY_SEPARATOR);
if(ThreadManager::getInstance()->stopAll() > 0){
if(\pocketmine\DEBUG > 1){
echo "Some threads could not be stopped, performing a force-kill" . PHP_EOL . PHP_EOL;
}
Utils::kill(getmypid());
if(!file_exists(\pocketmine\DATA)){
mkdir(\pocketmine\DATA, 0777, true);
}
}while(false);
$logger->shutdown();
$logger->join();
define('pocketmine\LOCK_FILE', fopen(\pocketmine\DATA . 'server.lock', "a+b"));
if(!flock(\pocketmine\LOCK_FILE, LOCK_EX | LOCK_NB)){
//wait for a shared lock to avoid race conditions if two servers started at the same time - this makes sure the
//other server wrote its PID and released exclusive lock before we get our lock
flock(\pocketmine\LOCK_FILE, LOCK_SH);
$pid = stream_get_contents(\pocketmine\LOCK_FILE);
critical_error("Another " . \pocketmine\NAME . " instance (PID $pid) is already using this folder (" . realpath(\pocketmine\DATA) . ").");
critical_error("Please stop the other server first before running a new one.");
exit(1);
}
ftruncate(\pocketmine\LOCK_FILE, 0);
fwrite(\pocketmine\LOCK_FILE, (string) getmypid());
fflush(\pocketmine\LOCK_FILE);
flock(\pocketmine\LOCK_FILE, LOCK_SH); //prevent acquiring an exclusive lock from another process, but allow reading
echo Terminal::$FORMAT_RESET . PHP_EOL;
//Logger has a dependency on timezone
$tzError = Timezone::init();
exit($exitCode);
if(isset($opts["enable-ansi"])){
Terminal::init(true);
}elseif(isset($opts["disable-ansi"])){
Terminal::init(false);
}else{
Terminal::init();
}
$logger = new MainLogger(\pocketmine\DATA . "server.log");
$logger->registerStatic();
foreach($tzError as $e){
$logger->warning($e);
}
unset($tzError);
emit_performance_warnings($logger);
$exitCode = 0;
do{
if(!file_exists(\pocketmine\DATA . "server.properties") and !isset($opts["no-wizard"])){
$installer = new SetupWizard();
if(!$installer->run()){
$exitCode = -1;
break;
}
}
//TODO: move this to a Server field
define('pocketmine\START_TIME', microtime(true));
ThreadManager::init();
/*
* We now use the Composer autoloader, but this autoloader is still for loading plugins.
*/
$autoloader = new \BaseClassLoader();
$autoloader->register(false);
new Server($autoloader, $logger, \pocketmine\DATA, \pocketmine\PLUGIN_PATH);
$logger->info("Stopping other threads");
$killer = new ServerKiller(8);
$killer->start(PTHREADS_INHERIT_NONE);
usleep(10000); //Fixes ServerKiller not being able to start on single-core machines
if(ThreadManager::getInstance()->stopAll() > 0){
$logger->debug("Some threads could not be stopped, performing a force-kill");
Utils::kill(getmypid());
}
}while(false);
$logger->shutdown();
$logger->join();
echo Terminal::$FORMAT_RESET . PHP_EOL;
exit($exitCode);
}
if(!defined('pocketmine\_PHPSTAN_ANALYSIS')){
\pocketmine\server();
}
}

View File

@ -76,6 +76,7 @@ use pocketmine\network\mcpe\protocol\DataPacket;
use pocketmine\network\mcpe\protocol\PlayerListPacket;
use pocketmine\network\mcpe\protocol\ProtocolInfo;
use pocketmine\network\mcpe\protocol\types\PlayerListEntry;
use pocketmine\network\mcpe\protocol\types\SkinAdapterSingleton;
use pocketmine\network\mcpe\RakLibInterface;
use pocketmine\network\Network;
use pocketmine\network\query\QueryHandler;
@ -113,6 +114,7 @@ use function asort;
use function assert;
use function base64_encode;
use function class_exists;
use function cli_set_process_title;
use function count;
use function define;
use function explode;
@ -127,7 +129,6 @@ use function getmypid;
use function getopt;
use function gettype;
use function implode;
use function ini_get;
use function ini_set;
use function is_array;
use function is_bool;
@ -227,7 +228,7 @@ class Server{
* @var int
*/
private $tickCounter = 0;
/** @var int */
/** @var float */
private $nextTick = 0;
/** @var float[] */
private $tickAverage = [20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20];
@ -482,6 +483,8 @@ class Server{
/**
* @param bool $value
*
* @return void
*/
public function setAutoSave(bool $value){
$this->autoSave = $value;
@ -593,7 +596,7 @@ class Server{
* @return int
*/
public function getDifficulty() : int{
return $this->getConfigInt("difficulty", 1);
return $this->getConfigInt("difficulty", Level::DIFFICULTY_NORMAL);
}
/**
@ -873,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);
@ -1101,11 +1106,17 @@ class Server{
return false;
}
/**
* @var LevelProvider $provider
* @see LevelProvider::__construct()
*/
$provider = new $providerClass($path);
try{
/**
* @var LevelProvider $provider
* @see LevelProvider::__construct()
*/
$provider = new $providerClass($path);
}catch(LevelException $e){
$this->logger->error($this->getLanguage()->translateString("pocketmine.level.loadError", [$name, $e->getMessage()]));
return false;
}
try{
GeneratorManager::getGenerator($provider->getGenerator(), true);
}catch(\InvalidArgumentException $e){
@ -1205,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;
@ -1270,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);
@ -1293,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);
@ -1329,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");
@ -1363,6 +1380,8 @@ class Server{
/**
* @param string $name
*
* @return void
*/
public function addOp(string $name){
$this->operators->set(strtolower($name), true);
@ -1375,6 +1394,8 @@ class Server{
/**
* @param string $name
*
* @return void
*/
public function removeOp(string $name){
$this->operators->remove(strtolower($name));
@ -1387,6 +1408,8 @@ class Server{
/**
* @param string $name
*
* @return void
*/
public function addWhitelist(string $name){
$this->whitelist->set(strtolower($name), true);
@ -1395,6 +1418,8 @@ class Server{
/**
* @param string $name
*
* @return void
*/
public function removeWhitelist(string $name){
$this->whitelist->remove(strtolower($name));
@ -1433,12 +1458,15 @@ class Server{
return $this->operators;
}
/**
* @return void
*/
public function reloadWhitelist(){
$this->whitelist->reload();
}
/**
* @return string[]
* @return string[][]
*/
public function getCommandAliases() : array{
$section = $this->getProperty("aliases");
@ -1469,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);
@ -1529,7 +1562,7 @@ class Server{
"force-gamemode" => false,
"hardcore" => false,
"pvp" => true,
"difficulty" => 1,
"difficulty" => Level::DIFFICULTY_NORMAL,
"generator-settings" => "",
"level-name" => "world",
"level-seed" => "",
@ -1559,12 +1592,6 @@ class Server{
return;
}
if(((int) ini_get('zend.assertions')) !== -1){
$this->logger->warning("Debugging assertions are enabled, this may impact on performance. To disable them, set `zend.assertions = -1` in php.ini.");
}
ini_set('assert.exception', '1');
if($this->logger instanceof MainLogger){
$this->logger->setLogDebug(\pocketmine\DEBUG > 1);
}
@ -1789,7 +1816,7 @@ class Server{
/**
* @param TextContainer|string $message
* @param Player[] $recipients
* @param CommandSender[] $recipients
*
* @return int
*/
@ -1798,7 +1825,6 @@ class Server{
return $this->broadcast($message, self::BROADCAST_CHANNEL_USERS);
}
/** @var Player[] $recipients */
foreach($recipients as $recipient){
$recipient->sendMessage($message);
}
@ -1823,7 +1849,6 @@ class Server{
}
}
/** @var Player[] $recipients */
foreach($recipients as $recipient){
$recipient->sendTip($tip);
}
@ -1849,7 +1874,6 @@ class Server{
}
}
/** @var Player[] $recipients */
foreach($recipients as $recipient){
$recipient->sendPopup($popup);
}
@ -1879,7 +1903,6 @@ class Server{
}
}
/** @var Player[] $recipients */
foreach($recipients as $recipient){
$recipient->addTitle($title, $subtitle, $fadeIn, $stay, $fadeOut);
}
@ -1916,6 +1939,8 @@ class Server{
*
* @param Player[] $players
* @param DataPacket $packet
*
* @return void
*/
public function broadcastPacket(array $players, DataPacket $packet){
$packet->encode();
@ -1929,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){
@ -1967,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){
@ -1981,6 +2010,8 @@ class Server{
/**
* @param int $type
*
* @return void
*/
public function enablePlugins(int $type){
foreach($this->pluginManager->getPlugins() as $plugin){
@ -1997,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();
}
@ -2036,6 +2072,9 @@ class Server{
return false;
}
/**
* @return void
*/
public function reload(){
$this->logger->info("Saving worlds...");
@ -2075,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;
@ -2165,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();
}
@ -2200,12 +2244,18 @@ class Server{
$this->logger->info($this->getLanguage()->translateString("pocketmine.server.defaultGameMode", [self::getGamemodeString($this->getGamemode())]));
$this->logger->info($this->getLanguage()->translateString("pocketmine.server.donate", [TextFormat::AQUA . "https://patreon.com/pocketminemp" . TextFormat::RESET]));
$this->logger->info($this->getLanguage()->translateString("pocketmine.server.startFinished", [round(microtime(true) - \pocketmine\START_TIME, 3)]));
$this->tickProcessor();
$this->forceShutdown();
}
/**
* @param int $signo
*
* @return void
*/
public function handleSignal($signo){
if($signo === SIGTERM or $signo === SIGINT or $signo === SIGHUP){
$this->shutdown();
@ -2215,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()){}
@ -2248,6 +2300,9 @@ class Server{
$this->crashDump();
}
/**
* @return void
*/
public function crashDump(){
while(@ob_end_flush()){}
if(!$this->isRunning){
@ -2330,6 +2385,9 @@ class Server{
exit(1);
}
/**
* @return mixed[]
*/
public function __debugInfo(){
return [];
}
@ -2338,7 +2396,7 @@ class Server{
return $this->tickSleeper;
}
private function tickProcessor(){
private function tickProcessor() : void{
$this->nextTick = microtime(true);
while($this->isRunning){
@ -2349,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();
@ -2357,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()]);
@ -2393,12 +2478,14 @@ 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();
$pk->type = PlayerListPacket::TYPE_ADD;
$pk->entries[] = PlayerListEntry::createAdditionEntry($uuid, $entityId, $name, $skin, $xboxUserId);
$pk->entries[] = PlayerListEntry::createAdditionEntry($uuid, $entityId, $name, SkinAdapterSingleton::get()->toSkinData($skin), $xboxUserId);
$this->broadcastPacket($players ?? $this->playerList, $pk);
}
@ -2406,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();
@ -2416,12 +2505,14 @@ class Server{
/**
* @param Player $p
*
* @return void
*/
public function sendFullPlayerListData(Player $p){
$pk = new PlayerListPacket();
$pk->type = PlayerListPacket::TYPE_ADD;
foreach($this->playerList as $player){
$pk->entries[] = PlayerListEntry::createAdditionEntry($player->getUniqueId(), $player->getId(), $player->getDisplayName(), $player->getSkin(), $player->getXuid());
$pk->entries[] = PlayerListEntry::createAdditionEntry($player->getUniqueId(), $player->getId(), $player->getDisplayName(), SkinAdapterSingleton::get()->toSkinData($player->getSkin()), $player->getXuid());
}
$p->dataPacket($pk);
@ -2451,6 +2542,9 @@ class Server{
}
}
/**
* @return void
*/
public function doAutoSave(){
if($this->getAutoSave()){
Timings::$worldSaveTimer->startTiming();
@ -2469,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));
@ -2505,7 +2604,7 @@ class Server{
return $this->memoryManager;
}
private function titleTick(){
private function titleTick() : void{
Timings::$titleTickTimer->startTiming();
$d = Utils::getRealMemoryUsage();
@ -2530,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,9 +19,19 @@
*
*/
declare(strict_types=1);
namespace pocketmine;
// composer autoload doesn't use require_once and also pthreads can inherit things
// TODO: drop this file and use a final class with constants
if(defined('pocketmine\_VERSION_INFO_INCLUDED')){
return;
}
const _VERSION_INFO_INCLUDED = true;
const NAME = "PocketMine-MP";
const BASE_VERSION = "3.8.7";
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;
@ -69,7 +70,7 @@ class Block extends Position implements BlockIds, Metadatable{
/** @var int|null */
protected $itemId;
/** @var AxisAlignedBB */
/** @var AxisAlignedBB|null */
protected $boundingBox = null;
@ -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;
}
@ -763,7 +764,7 @@ class Block extends Position implements BlockIds, Metadatable{
return $this->level->getBlockMetadata()->getMetadata($this, $metadataKey);
}
return null;
return [];
}
public function hasMetadata(string $metadataKey) : bool{

View File

@ -80,6 +80,9 @@ class BurningFurnace extends Solid{
$furnace = $this->getLevel()->getTile($this);
if(!($furnace instanceof TileFurnace)){
$furnace = Tile::createTile(Tile::FURNACE, $this->getLevel(), TileFurnace::createNBT($this));
if(!($furnace instanceof TileFurnace)){
return true;
}
}
if(!$furnace->canOpenWith($item->getCustomName())){

View File

@ -109,6 +109,9 @@ class Chest extends Transparent{
$chest = $t;
}else{
$chest = Tile::createTile(Tile::CHEST, $this->getLevel(), TileChest::createNBT($this));
if(!($chest instanceof TileChest)){
return true;
}
}
if(

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

@ -47,6 +47,9 @@ class ItemFrame extends Flowable{
$tile = $this->level->getTile($this);
if(!($tile instanceof TileItemFrame)){
$tile = Tile::createTile(Tile::ITEM_FRAME, $this->getLevel(), TileItemFrame::createNBT($this));
if(!($tile instanceof TileItemFrame)){
return true;
}
}
if($tile->hasItem()){

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

@ -55,7 +55,7 @@ abstract class Command{
*/
private $activeAliases = [];
/** @var CommandMap */
/** @var CommandMap|null */
private $commandMap = null;
/** @var string */
@ -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);
}
@ -141,6 +146,7 @@ class CommandReader extends Thread{
case self::TYPE_STREAM:
//stream_select doesn't work on piped streams for some reason
$r = [self::$stdin];
$w = $e = null;
if(($count = stream_select($r, $w, $e, 0, 200000)) === 0){ //nothing changed in 200000 microseconds
return true;
}elseif($count === false){ //stream error
@ -184,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 = [];
/**
@ -74,14 +75,14 @@ class FormattedCommandAlias extends Command{
$index = strpos($formatString, '$');
while($index !== false){
$start = $index;
if($index > 0 and $formatString{$start - 1} === "\\"){
if($index > 0 and $formatString[$start - 1] === "\\"){
$formatString = substr($formatString, 0, $start - 1) . substr($formatString, $start);
$index = strpos($formatString, '$', $index);
continue;
}
$required = false;
if($formatString{$index + 1} == '$'){
if($formatString[$index + 1] == '$'){
$required = true;
++$index;
@ -91,7 +92,7 @@ class FormattedCommandAlias extends Command{
$argStart = $index;
while($index < strlen($formatString) and self::inRange(ord($formatString{$index}) - 48, 0, 9)){
while($index < strlen($formatString) and self::inRange(ord($formatString[$index]) - 48, 0, 9)){
++$index;
}
@ -109,7 +110,7 @@ class FormattedCommandAlias extends Command{
$rest = false;
if($index < strlen($formatString) and $formatString{$index} === "-"){
if($index < strlen($formatString) and $formatString[$index] === "-"){
$rest = true;
++$index;
}

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

@ -60,7 +60,6 @@ class GamemodeCommand extends VanillaCommand{
return true;
}
$target = $sender;
if(isset($args[1])){
$target = $sender->getServer()->getPlayer($args[1]);
if($target === null){
@ -68,7 +67,9 @@ class GamemodeCommand extends VanillaCommand{
return true;
}
}elseif(!($sender instanceof Player)){
}elseif($sender instanceof Player){
$target = $sender;
}else{
throw new InvalidCommandSyntaxException();
}

View File

@ -42,6 +42,10 @@ class TransferServerCommand extends VanillaCommand{
}
public function execute(CommandSender $sender, string $commandLabel, array $args){
if(!$this->testPermission($sender)){
return true;
}
if(count($args) < 1){
throw new InvalidCommandSyntaxException();
}elseif(!($sender instanceof Player)){

View File

@ -65,7 +65,7 @@ abstract class VanillaCommand extends Command{
* @return float
*/
protected function getRelativeDouble(float $original, CommandSender $sender, string $input, float $min = self::MIN_COORD, float $max = self::MAX_COORD) : float{
if($input{0} === "~"){
if($input[0] === "~"){
$value = $this->getDouble($sender, substr($input, 1));
return $original + $value;

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

@ -23,8 +23,8 @@ declare(strict_types=1);
namespace pocketmine\entity;
use pocketmine\item\Item;
use pocketmine\math\Vector3;
use pocketmine\nbt\tag\CompoundTag;
use function assert;
use function is_float;
use function is_int;
@ -32,8 +32,10 @@ use function is_string;
class DataPropertyManager{
/** @var mixed[][] */
private $properties = [];
/** @var mixed[][] */
private $dirtyProperties = [];
public function __construct(){
@ -140,25 +142,14 @@ class DataPropertyManager{
$this->setPropertyValue($key, Entity::DATA_TYPE_STRING, $value, $force);
}
/**
* @param int $key
*
* @return null|Item
*/
public function getItem(int $key) : ?Item{
$value = $this->getPropertyValue($key, Entity::DATA_TYPE_SLOT);
assert($value instanceof Item or $value === null);
public function getCompoundTag(int $key) : ?CompoundTag{
$value = $this->getPropertyValue($key, Entity::DATA_TYPE_COMPOUND_TAG);
assert($value instanceof CompoundTag or $value === null);
return $value;
}
/**
* @param int $key
* @param Item $value
* @param bool $force
*/
public function setItem(int $key, Item $value, bool $force = false) : void{
$this->setPropertyValue($key, Entity::DATA_TYPE_SLOT, $value, $force);
public function setCompoundTag(int $key, CompoundTag $value, bool $force = false) : void{
$this->setPropertyValue($key, Entity::DATA_TYPE_COMPOUND_TAG, $value, $force);
}
/**

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

@ -62,12 +62,12 @@ use pocketmine\nbt\tag\DoubleTag;
use pocketmine\nbt\tag\FloatTag;
use pocketmine\nbt\tag\ListTag;
use pocketmine\nbt\tag\StringTag;
use pocketmine\network\mcpe\protocol\AddEntityPacket;
use pocketmine\network\mcpe\protocol\EntityEventPacket;
use pocketmine\network\mcpe\protocol\MoveEntityAbsolutePacket;
use pocketmine\network\mcpe\protocol\RemoveEntityPacket;
use pocketmine\network\mcpe\protocol\SetEntityDataPacket;
use pocketmine\network\mcpe\protocol\SetEntityMotionPacket;
use pocketmine\network\mcpe\protocol\ActorEventPacket;
use pocketmine\network\mcpe\protocol\AddActorPacket;
use pocketmine\network\mcpe\protocol\MoveActorAbsolutePacket;
use pocketmine\network\mcpe\protocol\RemoveActorPacket;
use pocketmine\network\mcpe\protocol\SetActorDataPacket;
use pocketmine\network\mcpe\protocol\SetActorMotionPacket;
use pocketmine\Player;
use pocketmine\plugin\Plugin;
use pocketmine\Server;
@ -102,7 +102,7 @@ abstract class Entity extends Location implements Metadatable, EntityIds{
public const DATA_TYPE_INT = 2;
public const DATA_TYPE_FLOAT = 3;
public const DATA_TYPE_STRING = 4;
public const DATA_TYPE_SLOT = 5;
public const DATA_TYPE_COMPOUND_TAG = 5;
public const DATA_TYPE_POS = 6;
public const DATA_TYPE_LONG = 7;
public const DATA_TYPE_VECTOR3F = 8;
@ -154,70 +154,76 @@ abstract class Entity extends Location implements Metadatable, EntityIds{
public const DATA_LEAD_HOLDER_EID = 37; //long
public const DATA_SCALE = 38; //float
public const DATA_HAS_NPC_COMPONENT = 39; //byte (???)
public const DATA_SKIN_ID = 40; //string
public const DATA_NPC_SKIN_ID = 41; //string
public const DATA_URL_TAG = 42; //string
public const DATA_MAX_AIR = 43; //short
public const DATA_MARK_VARIANT = 44; //int
public const DATA_CONTAINER_TYPE = 45; //byte (ContainerComponent)
public const DATA_CONTAINER_BASE_SIZE = 46; //int (ContainerComponent)
public const DATA_CONTAINER_EXTRA_SLOTS_PER_STRENGTH = 47; //int (used for llamas, inventory size is baseSize + thisProp * strength)
public const DATA_BLOCK_TARGET = 48; //block coords (ender crystal)
public const DATA_WITHER_INVULNERABLE_TICKS = 49; //int
public const DATA_WITHER_TARGET_1 = 50; //long
public const DATA_WITHER_TARGET_2 = 51; //long
public const DATA_WITHER_TARGET_3 = 52; //long
/* 53 (short) */
public const DATA_BOUNDING_BOX_WIDTH = 54; //float
public const DATA_BOUNDING_BOX_HEIGHT = 55; //float
public const DATA_FUSE_LENGTH = 56; //int
public const DATA_RIDER_SEAT_POSITION = 57; //vector3f
public const DATA_RIDER_ROTATION_LOCKED = 58; //byte
public const DATA_RIDER_MAX_ROTATION = 59; //float
public const DATA_RIDER_MIN_ROTATION = 60; //float
public const DATA_AREA_EFFECT_CLOUD_RADIUS = 61; //float
public const DATA_AREA_EFFECT_CLOUD_WAITING = 62; //int
public const DATA_AREA_EFFECT_CLOUD_PARTICLE_ID = 63; //int
/* 64 (int) shulker-related */
public const DATA_SHULKER_ATTACH_FACE = 65; //byte
/* 66 (short) shulker-related */
public const DATA_SHULKER_ATTACH_POS = 67; //block coords
public const DATA_TRADING_PLAYER_EID = 68; //long
public const DATA_NPC_SKIN_INDEX = 40; //string
public const DATA_NPC_ACTIONS = 41; //string (maybe JSON blob?)
public const DATA_MAX_AIR = 42; //short
public const DATA_MARK_VARIANT = 43; //int
public const DATA_CONTAINER_TYPE = 44; //byte (ContainerComponent)
public const DATA_CONTAINER_BASE_SIZE = 45; //int (ContainerComponent)
public const DATA_CONTAINER_EXTRA_SLOTS_PER_STRENGTH = 46; //int (used for llamas, inventory size is baseSize + thisProp * strength)
public const DATA_BLOCK_TARGET = 47; //block coords (ender crystal)
public const DATA_WITHER_INVULNERABLE_TICKS = 48; //int
public const DATA_WITHER_TARGET_1 = 49; //long
public const DATA_WITHER_TARGET_2 = 50; //long
public const DATA_WITHER_TARGET_3 = 51; //long
/* 52 (short) */
public const DATA_BOUNDING_BOX_WIDTH = 53; //float
public const DATA_BOUNDING_BOX_HEIGHT = 54; //float
public const DATA_FUSE_LENGTH = 55; //int
public const DATA_RIDER_SEAT_POSITION = 56; //vector3f
public const DATA_RIDER_ROTATION_LOCKED = 57; //byte
public const DATA_RIDER_MAX_ROTATION = 58; //float
public const DATA_RIDER_MIN_ROTATION = 59; //float
public const DATA_AREA_EFFECT_CLOUD_RADIUS = 60; //float
public const DATA_AREA_EFFECT_CLOUD_WAITING = 61; //int
public const DATA_AREA_EFFECT_CLOUD_PARTICLE_ID = 62; //int
/* 63 (int) shulker-related */
public const DATA_SHULKER_ATTACH_FACE = 64; //byte
/* 65 (short) shulker-related */
public const DATA_SHULKER_ATTACH_POS = 66; //block coords
public const DATA_TRADING_PLAYER_EID = 67; //long
/* 70 (byte) command-block */
public const DATA_COMMAND_BLOCK_COMMAND = 71; //string
public const DATA_COMMAND_BLOCK_LAST_OUTPUT = 72; //string
public const DATA_COMMAND_BLOCK_TRACK_OUTPUT = 73; //byte
public const DATA_CONTROLLING_RIDER_SEAT_NUMBER = 74; //byte
public const DATA_STRENGTH = 75; //int
public const DATA_MAX_STRENGTH = 76; //int
/* 77 (int) */
public const DATA_LIMITED_LIFE = 78;
public const DATA_ARMOR_STAND_POSE_INDEX = 79; //int
public const DATA_ENDER_CRYSTAL_TIME_OFFSET = 80; //int
public const DATA_ALWAYS_SHOW_NAMETAG = 81; //byte: -1 = default, 0 = only when looked at, 1 = always
public const DATA_COLOR_2 = 82; //byte
/* 83 (unknown) */
public const DATA_SCORE_TAG = 84; //string
public const DATA_BALLOON_ATTACHED_ENTITY = 85; //int64, entity unique ID of owner
public const DATA_PUFFERFISH_SIZE = 86; //byte
public const DATA_BOAT_BUBBLE_TIME = 87; //int (time in bubble column)
public const DATA_PLAYER_AGENT_EID = 88; //long
/* 89 (float) related to panda sitting
* 90 (float) related to panda sitting */
public const DATA_EAT_COUNTER = 91; //int (used by pandas)
public const DATA_FLAGS2 = 92; //long (extended data flags)
/* 93 (float) related to panda lying down
* 94 (float) related to panda lying down */
public const DATA_AREA_EFFECT_CLOUD_DURATION = 95; //int
public const DATA_AREA_EFFECT_CLOUD_SPAWN_TIME = 96; //int
public const DATA_AREA_EFFECT_CLOUD_RADIUS_PER_TICK = 97; //float, usually negative
public const DATA_AREA_EFFECT_CLOUD_RADIUS_CHANGE_ON_PICKUP = 98; //float
public const DATA_AREA_EFFECT_CLOUD_PICKUP_COUNT = 99; //int
public const DATA_INTERACTIVE_TAG = 100; //string (button text)
public const DATA_TRADE_TIER = 101; //int
public const DATA_MAX_TRADE_TIER = 102; //int
public const DATA_TRADE_XP = 103; //int
/* 69 (byte) command-block */
public const DATA_COMMAND_BLOCK_COMMAND = 70; //string
public const DATA_COMMAND_BLOCK_LAST_OUTPUT = 71; //string
public const DATA_COMMAND_BLOCK_TRACK_OUTPUT = 72; //byte
public const DATA_CONTROLLING_RIDER_SEAT_NUMBER = 73; //byte
public const DATA_STRENGTH = 74; //int
public const DATA_MAX_STRENGTH = 75; //int
/* 76 (int) */
public const DATA_LIMITED_LIFE = 77;
public const DATA_ARMOR_STAND_POSE_INDEX = 78; //int
public const DATA_ENDER_CRYSTAL_TIME_OFFSET = 79; //int
public const DATA_ALWAYS_SHOW_NAMETAG = 80; //byte: -1 = default, 0 = only when looked at, 1 = always
public const DATA_COLOR_2 = 81; //byte
/* 82 (unknown) */
public const DATA_SCORE_TAG = 83; //string
public const DATA_BALLOON_ATTACHED_ENTITY = 84; //int64, entity unique ID of owner
public const DATA_PUFFERFISH_SIZE = 85; //byte
public const DATA_BOAT_BUBBLE_TIME = 86; //int (time in bubble column)
public const DATA_PLAYER_AGENT_EID = 87; //long
/* 88 (float) related to panda sitting
* 89 (float) related to panda sitting */
public const DATA_EAT_COUNTER = 90; //int (used by pandas)
public const DATA_FLAGS2 = 91; //long (extended data flags)
/* 92 (float) related to panda lying down
* 93 (float) related to panda lying down */
public const DATA_AREA_EFFECT_CLOUD_DURATION = 94; //int
public const DATA_AREA_EFFECT_CLOUD_SPAWN_TIME = 95; //int
public const DATA_AREA_EFFECT_CLOUD_RADIUS_PER_TICK = 96; //float, usually negative
public const DATA_AREA_EFFECT_CLOUD_RADIUS_CHANGE_ON_PICKUP = 97; //float
public const DATA_AREA_EFFECT_CLOUD_PICKUP_COUNT = 98; //int
public const DATA_INTERACTIVE_TAG = 99; //string (button text)
public const DATA_TRADE_TIER = 100; //int
public const DATA_MAX_TRADE_TIER = 101; //int
public const DATA_TRADE_XP = 102; //int
public const DATA_SKIN_ID = 103; //int ???
/* 104 (int) related to wither */
public const DATA_COMMAND_BLOCK_TICK_DELAY = 105; //int
public const DATA_COMMAND_BLOCK_EXECUTE_ON_FIRST_TICK = 106; //byte
public const DATA_AMBIENT_SOUND_INTERVAL_MIN = 107; //float
public const DATA_AMBIENT_SOUND_INTERVAL_RANGE = 108; //float
public const DATA_AMBIENT_SOUND_EVENT = 109; //string
public const DATA_FLAG_ONFIRE = 0;
public const DATA_FLAG_SNEAKING = 1;
@ -311,8 +317,9 @@ 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 Entity[] */
/** @var string[] */
private static $knownEntities = [];
/** @var string[][] */
private static $saveNames = [];
@ -454,15 +461,15 @@ abstract class Entity extends Location implements Metadatable, EntityIds{
/** @var EntityDamageEvent|null */
protected $lastDamageCause = null;
/** @var Block[] */
protected $blocksAround = [];
/** @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;
@ -498,6 +505,7 @@ abstract class Entity extends Location implements Metadatable, EntityIds{
/** @var float */
private $health = 20.0;
/** @var int */
private $maxHealth = 20;
/** @var float */
@ -1096,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();
}
@ -1137,7 +1145,7 @@ abstract class Entity extends Location implements Metadatable, EntityIds{
$this->setFireTicks($ticks);
}
$this->setGenericFlag(self::DATA_FLAG_ONFIRE, true);
$this->setGenericFlag(self::DATA_FLAG_ONFIRE, $this->isOnFire());
}
/**
@ -1204,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;
@ -1223,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();
@ -1235,7 +1247,7 @@ abstract class Entity extends Location implements Metadatable, EntityIds{
}
protected function broadcastMovement(bool $teleport = false) : void{
$pk = new MoveEntityAbsolutePacket();
$pk = new MoveActorAbsolutePacket();
$pk->entityRuntimeId = $this->id;
$pk->position = $this->getOffsetPosition($this);
@ -1247,14 +1259,14 @@ abstract class Entity extends Location implements Metadatable, EntityIds{
$pk->zRot = $this->yaw;
if($teleport){
$pk->flags |= MoveEntityAbsolutePacket::FLAG_TELEPORT;
$pk->flags |= MoveActorAbsolutePacket::FLAG_TELEPORT;
}
$this->level->broadcastPacketToViewers($this, $pk);
}
protected function broadcastMotion() : void{
$pk = new SetEntityMotionPacket();
$pk = new SetActorMotionPacket();
$pk->entityRuntimeId = $this->id;
$pk->motion = $this->getMotion();
@ -1776,6 +1788,9 @@ abstract class Entity extends Location implements Metadatable, EntityIds{
}
/**
* @deprecated WARNING: Despite what its name implies, this function DOES NOT return all the blocks around the entity.
* Instead, it returns blocks which have reactions for an entity intersecting with them.
*
* @return Block[]
*/
public function getBlocksAround() : array{
@ -2021,7 +2036,7 @@ abstract class Entity extends Location implements Metadatable, EntityIds{
* @param Player $player
*/
protected function sendSpawnPacket(Player $player) : void{
$pk = new AddEntityPacket();
$pk = new AddActorPacket();
$pk->entityRuntimeId = $this->getId();
$pk->type = static::NETWORK_ID;
$pk->position = $this->asVector3();
@ -2039,7 +2054,7 @@ abstract class Entity extends Location implements Metadatable, EntityIds{
* @param Player $player
*/
public function spawnTo(Player $player) : void{
if(!isset($this->hasSpawned[$player->getLoaderId()])){
if(!isset($this->hasSpawned[$player->getLoaderId()]) and $this->chunk !== null and isset($player->usedChunks[Level::chunkHash($this->chunk->getX(), $this->chunk->getZ())])){
$this->hasSpawned[$player->getLoaderId()] = $player;
$this->sendSpawnPacket($player);
@ -2065,13 +2080,16 @@ abstract class Entity extends Location implements Metadatable, EntityIds{
}
/**
* @deprecated WARNING: This function DOES NOT permanently hide the entity from the player. As soon as the entity or
* player moves, the player will once again be able to see the entity.
*
* @param Player $player
* @param bool $send
*/
public function despawnFrom(Player $player, bool $send = true) : void{
if(isset($this->hasSpawned[$player->getLoaderId()])){
if($send){
$pk = new RemoveEntityPacket();
$pk = new RemoveActorPacket();
$pk->entityUniqueId = $this->id;
$player->dataPacket($pk);
}
@ -2079,6 +2097,10 @@ abstract class Entity extends Location implements Metadatable, EntityIds{
}
}
/**
* @deprecated WARNING: This function DOES NOT permanently hide the entity from viewers. As soon as the entity or
* player moves, viewers will once again be able to see the entity.
*/
public function despawnFromAll() : void{
foreach($this->hasSpawned as $player){
$this->despawnFrom($player);
@ -2193,7 +2215,7 @@ abstract class Entity extends Location implements Metadatable, EntityIds{
$player = [$player];
}
$pk = new SetEntityDataPacket();
$pk = new SetActorDataPacket();
$pk->entityRuntimeId = $this->getId();
$pk->metadata = $data ?? $this->propertyManager->getAll();
@ -2210,7 +2232,7 @@ abstract class Entity extends Location implements Metadatable, EntityIds{
}
public function broadcastEntityEvent(int $eventId, ?int $eventData = null, ?array $players = null) : void{
$pk = new EntityEventPacket();
$pk = new ActorEventPacket();
$pk->entityRuntimeId = $this->id;
$pk->event = $eventId;
$pk->data = $eventData ?? 0;
@ -2263,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

@ -46,13 +46,14 @@ use pocketmine\nbt\tag\CompoundTag;
use pocketmine\nbt\tag\IntTag;
use pocketmine\nbt\tag\ListTag;
use pocketmine\nbt\tag\StringTag;
use pocketmine\network\mcpe\protocol\ActorEventPacket;
use pocketmine\network\mcpe\protocol\AddPlayerPacket;
use pocketmine\network\mcpe\protocol\EntityEventPacket;
use pocketmine\network\mcpe\protocol\LevelEventPacket;
use pocketmine\network\mcpe\protocol\LevelSoundEventPacket;
use pocketmine\network\mcpe\protocol\PlayerListPacket;
use pocketmine\network\mcpe\protocol\PlayerSkinPacket;
use pocketmine\network\mcpe\protocol\types\PlayerListEntry;
use pocketmine\network\mcpe\protocol\types\SkinAdapterSingleton;
use pocketmine\Player;
use pocketmine\utils\UUID;
use function array_filter;
@ -60,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;
@ -79,6 +81,7 @@ class Human extends Creature implements ProjectileSource, InventoryHolder{
/** @var UUID */
protected $uuid;
/** @var string */
protected $rawUUID;
public $width = 0.6;
@ -88,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;
@ -182,7 +189,7 @@ class Human extends Creature implements ProjectileSource, InventoryHolder{
public function sendSkin(?array $targets = null) : void{
$pk = new PlayerSkinPacket();
$pk->uuid = $this->getUniqueId();
$pk->skin = $this->skin;
$pk->skin = SkinAdapterSingleton::get()->toSkinData($this->skin);
$this->server->broadcastPacket($targets ?? $this->hasSpawned, $pk);
}
@ -553,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);
@ -587,6 +594,9 @@ class Human extends Creature implements ProjectileSource, InventoryHolder{
return (int) min(100, 7 * $this->getXpLevel());
}
/**
* @return PlayerInventory
*/
public function getInventory(){
return $this->inventory;
}
@ -754,7 +764,7 @@ class Human extends Creature implements ProjectileSource, InventoryHolder{
$this->addEffect(new EffectInstance(Effect::getEffect(Effect::FIRE_RESISTANCE), 40 * 20, 1));
$this->addEffect(new EffectInstance(Effect::getEffect(Effect::ABSORPTION), 5 * 20, 1));
$this->broadcastEntityEvent(EntityEventPacket::CONSUME_TOTEM);
$this->broadcastEntityEvent(ActorEventPacket::CONSUME_TOTEM);
$this->level->broadcastLevelEvent($this->add(0, $this->eyeHeight, 0), LevelEventPacket::EVENT_SOUND_TOTEM);
$hand = $this->inventory->getItemInHand();
@ -847,7 +857,7 @@ class Human extends Creature implements ProjectileSource, InventoryHolder{
/* we don't use Server->updatePlayerListData() because that uses batches, which could cause race conditions in async compression mode */
$pk = new PlayerListPacket();
$pk->type = PlayerListPacket::TYPE_ADD;
$pk->entries = [PlayerListEntry::createAdditionEntry($this->uuid, $this->id, $this->getName(), $this->skin)];
$pk->entries = [PlayerListEntry::createAdditionEntry($this->uuid, $this->id, $this->getName(), SkinAdapterSingleton::get()->toSkinData($this->skin))];
$player->dataPacket($pk);
}

View File

@ -44,7 +44,7 @@ use pocketmine\nbt\tag\CompoundTag;
use pocketmine\nbt\tag\FloatTag;
use pocketmine\nbt\tag\IntTag;
use pocketmine\nbt\tag\ListTag;
use pocketmine\network\mcpe\protocol\EntityEventPacket;
use pocketmine\network\mcpe\protocol\ActorEventPacket;
use pocketmine\network\mcpe\protocol\LevelSoundEventPacket;
use pocketmine\network\mcpe\protocol\MobEffectPacket;
use pocketmine\Player;
@ -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[] */
@ -143,7 +145,7 @@ abstract class Living extends Entity implements Damageable{
parent::setHealth($amount);
$this->attributeMap->getAttribute(Attribute::HEALTH)->setValue(ceil($this->getHealth()), true);
if($this->isAlive() and !$wasAlive){
$this->broadcastEntityEvent(EntityEventPacket::RESPAWN);
$this->broadcastEntityEvent(ActorEventPacket::RESPAWN);
}
}
@ -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{
@ -606,7 +608,7 @@ abstract class Living extends Entity implements Damageable{
}
protected function doHitAnimation() : void{
$this->broadcastEntityEvent(EntityEventPacket::HURT_ANIMATION);
$this->broadcastEntityEvent(ActorEventPacket::HURT_ANIMATION);
}
public function knockBack(Entity $attacker, float $damage, float $x, float $z, float $base = 0.4) : void{
@ -664,7 +666,7 @@ abstract class Living extends Entity implements Damageable{
}
protected function startDeathAnimation() : void{
$this->broadcastEntityEvent(EntityEventPacket::DEATH_ANIMATION);
$this->broadcastEntityEvent(ActorEventPacket::DEATH_ANIMATION);
}
protected function endDeathAnimation() : void{
@ -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

@ -23,9 +23,9 @@ declare(strict_types=1);
namespace pocketmine\entity;
use Ahc\Json\Comment as CommentedJsonDecoder;
use function implode;
use function in_array;
use function json_decode;
use function json_encode;
use function strlen;
@ -129,7 +129,7 @@ class Skin{
*/
public function debloatGeometryData() : void{
if($this->geometryData !== ""){
$this->geometryData = (string) json_encode(json_decode($this->geometryData));
$this->geometryData = (string) json_encode((new CommentedJsonDecoder())->decode($this->geometryData));
}
}
}

View File

@ -28,7 +28,7 @@ use pocketmine\event\entity\EntityDamageEvent;
use pocketmine\item\Item;
use pocketmine\item\ItemFactory;
use pocketmine\math\Vector3;
use pocketmine\network\mcpe\protocol\EntityEventPacket;
use pocketmine\network\mcpe\protocol\ActorEventPacket;
use function atan2;
use function mt_rand;
use function sqrt;
@ -40,10 +40,12 @@ class Squid extends WaterAnimal{
public $width = 0.95;
public $height = 0.95;
/** @var Vector3 */
/** @var Vector3|null */
public $swimDirection = null;
/** @var float */
public $swimSpeed = 0.1;
/** @var int */
private $switchDirectionTicker = 0;
public function initEntity() : void{
@ -68,7 +70,7 @@ class Squid extends WaterAnimal{
$this->swimDirection = (new Vector3($this->x - $e->x, $this->y - $e->y, $this->z - $e->z))->normalize();
}
$this->broadcastEntityEvent(EntityEventPacket::SQUID_INK_CLOUD);
$this->broadcastEntityEvent(ActorEventPacket::SQUID_INK_CLOUD);
}
}
@ -82,7 +84,7 @@ class Squid extends WaterAnimal{
return false;
}
if(++$this->switchDirectionTicker === 100 or $this->isCollided){
if(++$this->switchDirectionTicker === 100){
$this->switchDirectionTicker = 0;
if(mt_rand(0, 100) < 50){
$this->swimDirection = null;

View File

@ -33,6 +33,7 @@ use pocketmine\item\ItemFactory;
use pocketmine\level\Position;
use pocketmine\nbt\tag\ByteTag;
use pocketmine\nbt\tag\IntTag;
use function abs;
use function get_class;
class FallingBlock extends Entity{
@ -110,7 +111,7 @@ class FallingBlock extends Entity{
$this->flagForDespawn();
$block = $this->level->getBlock($pos);
if($block->getId() > 0 and $block->isTransparent() and !$block->canBeReplaced()){
if(($block->isTransparent() and !$block->canBeReplaced()) or ($this->onGround and abs($this->y - $this->getFloorY()) > 0.001)){
//FIXME: anvils are supposed to destroy torches
$this->getLevel()->dropItem($this, ItemFactory::get($this->getBlock(), $this->getDamage()));
}else{

View File

@ -28,8 +28,8 @@ use pocketmine\event\entity\ItemDespawnEvent;
use pocketmine\event\entity\ItemSpawnEvent;
use pocketmine\event\inventory\InventoryPickupItemEvent;
use pocketmine\item\Item;
use pocketmine\network\mcpe\protocol\AddItemEntityPacket;
use pocketmine\network\mcpe\protocol\TakeItemEntityPacket;
use pocketmine\network\mcpe\protocol\AddItemActorPacket;
use pocketmine\network\mcpe\protocol\TakeItemActorPacket;
use pocketmine\Player;
use function get_class;
@ -192,7 +192,7 @@ class ItemEntity extends Entity{
}
protected function sendSpawnPacket(Player $player) : void{
$pk = new AddItemEntityPacket();
$pk = new AddItemActorPacket();
$pk->entityRuntimeId = $this->getId();
$pk->position = $this->asVector3();
$pk->motion = $this->getMotion();
@ -229,7 +229,7 @@ class ItemEntity extends Entity{
break;
}
$pk = new TakeItemEntityPacket();
$pk = new TakeItemActorPacket();
$pk->eid = $player->getId();
$pk->target = $this->getId();
$this->server->broadcastPacket($this->getViewers(), $pk);

View File

@ -90,6 +90,9 @@ class Painting extends Entity{
}
public function kill() : void{
if(!$this->isAlive()){
return;
}
parent::kill();
$drops = true;
@ -152,9 +155,11 @@ class Painting extends Entity{
protected function sendSpawnPacket(Player $player) : void{
$pk = new AddPaintingPacket();
$pk->entityRuntimeId = $this->getId();
$pk->x = $this->blockIn->x;
$pk->y = $this->blockIn->y;
$pk->z = $this->blockIn->z;
$pk->position = new Vector3(
($this->boundingBox->minX + $this->boundingBox->maxX) / 2,
($this->boundingBox->minY + $this->boundingBox->maxY) / 2,
($this->boundingBox->minZ + $this->boundingBox->maxZ) / 2
);
$pk->direction = $this->direction;
$pk->title = $this->motive;

View File

@ -28,6 +28,7 @@ use pocketmine\entity\Explosive;
use pocketmine\event\entity\EntityDamageEvent;
use pocketmine\event\entity\ExplosionPrimeEvent;
use pocketmine\level\Explosion;
use pocketmine\level\Position;
use pocketmine\nbt\tag\ShortTag;
use pocketmine\network\mcpe\protocol\LevelEventPacket;
@ -42,6 +43,7 @@ class PrimedTNT extends Entity implements Explosive{
protected $gravity = 0.04;
protected $drag = 0.02;
/** @var int */
protected $fuse;
public $canCollide = false;
@ -105,7 +107,7 @@ class PrimedTNT extends Entity implements Explosive{
$ev = new ExplosionPrimeEvent($this, 4);
$ev->call();
if(!$ev->isCancelled()){
$explosion = new Explosion($this, $ev->getForce(), $this);
$explosion = new Explosion(Position::fromObject($this->add(0, $this->height / 2, 0), $this->level), $ev->getForce(), $this);
if($ev->isBlockBreaking()){
$explosion->explodeA();
}

View File

@ -32,9 +32,9 @@ use pocketmine\item\ItemFactory;
use pocketmine\level\Level;
use pocketmine\math\RayTraceResult;
use pocketmine\nbt\tag\CompoundTag;
use pocketmine\network\mcpe\protocol\EntityEventPacket;
use pocketmine\network\mcpe\protocol\ActorEventPacket;
use pocketmine\network\mcpe\protocol\LevelSoundEventPacket;
use pocketmine\network\mcpe\protocol\TakeItemEntityPacket;
use pocketmine\network\mcpe\protocol\TakeItemActorPacket;
use pocketmine\Player;
use function mt_rand;
use function sqrt;
@ -143,7 +143,7 @@ class Arrow extends Projectile{
protected function onHitBlock(Block $blockHit, RayTraceResult $hitResult) : void{
parent::onHitBlock($blockHit, $hitResult);
$this->broadcastEntityEvent(EntityEventPacket::ARROW_SHAKE, 7); //7 ticks
$this->broadcastEntityEvent(ActorEventPacket::ARROW_SHAKE, 7); //7 ticks
}
protected function onHitEntity(Entity $entityHit, RayTraceResult $hitResult) : void{
@ -193,7 +193,7 @@ class Arrow extends Projectile{
return;
}
$pk = new TakeItemEntityPacket();
$pk = new TakeItemActorPacket();
$pk->eid = $player->getId();
$pk->target = $this->getId();
$this->server->broadcastPacket($this->getViewers(), $pk);

View File

@ -23,36 +23,14 @@ declare(strict_types=1);
namespace pocketmine\entity\projectile;
use pocketmine\block\Block;
use pocketmine\event\entity\EntityDamageEvent;
use pocketmine\event\entity\ProjectileHitEvent;
use pocketmine\level\sound\EndermanTeleportSound;
use pocketmine\math\AxisAlignedBB;
use pocketmine\math\RayTraceResult;
use pocketmine\math\Vector3;
use pocketmine\network\mcpe\protocol\LevelEventPacket;
class EnderPearl extends Throwable{
public const NETWORK_ID = self::ENDER_PEARL;
protected function calculateInterceptWithBlock(Block $block, Vector3 $start, Vector3 $end) : ?RayTraceResult{
if($block->getId() !== Block::AIR and empty($block->getCollisionBoxes())){
//TODO: remove this once block collision boxes are fixed properly
$bb = new AxisAlignedBB(
$block->x,
$block->y,
$block->z,
$block->x + 1,
$block->y + 1,
$block->z + 1
);
return $bb->calculateIntercept($start, $end);
}
return parent::calculateInterceptWithBlock($block, $start, $end);
}
protected function onHit(ProjectileHitEvent $event) : void{
$owner = $this->getOwningEntity();
if($owner !== null){

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

@ -56,7 +56,6 @@ abstract class Event{
throw new \BadMethodCallException(get_class($this) . " is not Cancellable");
}
/** @var Event $this */
return $this->isCancelled;
}
@ -70,7 +69,6 @@ abstract class Event{
throw new \BadMethodCallException(get_class($this) . " is not Cancellable");
}
/** @var Event $this */
$this->isCancelled = $value;
}
@ -78,8 +76,6 @@ abstract class Event{
* Calls event handlers registered for this event.
*
* @throws \RuntimeException if event call recursion reaches the max depth limit
*
* @throws \ReflectionException
*/
public function call() : void{
if(self::$eventCallDepth >= self::MAX_EVENT_CALL_DEPTH){

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

@ -23,10 +23,12 @@ declare(strict_types=1);
namespace pocketmine\event\player;
use pocketmine\command\CommandSender;
use pocketmine\event\Cancellable;
use pocketmine\permission\PermissionManager;
use pocketmine\Player;
use pocketmine\Server;
use function spl_object_id;
/**
* Called when a player chats something
@ -39,15 +41,15 @@ class PlayerChatEvent extends PlayerEvent implements Cancellable{
protected $format;
/**
* @var Player[]
* @var CommandSender[]
*/
protected $recipients = [];
/**
* @param Player $player
* @param string $message
* @param string $format
* @param Player[] $recipients
* @param Player $player
* @param string $message
* @param string $format
* @param CommandSender[] $recipients
*/
public function __construct(Player $player, string $message, string $format = "chat.type.text", array $recipients = null){
$this->player = $player;
@ -56,7 +58,11 @@ class PlayerChatEvent extends PlayerEvent implements Cancellable{
$this->format = $format;
if($recipients === null){
$this->recipients = PermissionManager::getInstance()->getPermissionSubscriptions(Server::BROADCAST_CHANNEL_USERS);
foreach(PermissionManager::getInstance()->getPermissionSubscriptions(Server::BROADCAST_CHANNEL_USERS) as $permissible){
if($permissible instanceof CommandSender){
$this->recipients[spl_object_id($permissible)] = $permissible;
}
}
}else{
$this->recipients = $recipients;
}
@ -100,14 +106,14 @@ class PlayerChatEvent extends PlayerEvent implements Cancellable{
}
/**
* @return Player[]
* @return CommandSender[]
*/
public function getRecipients() : array{
return $this->recipients;
}
/**
* @param Player[] $recipients
* @param CommandSender[] $recipients
*/
public function setRecipients(array $recipients) : void{
$this->recipients = $recipients;

View File

@ -39,15 +39,15 @@ class PlayerCreationEvent extends Event{
/** @var int */
private $port;
/** @var Player::class */
/** @var string */
private $baseClass;
/** @var Player::class */
/** @var string */
private $playerClass;
/**
* @param SourceInterface $interface
* @param Player::class $baseClass
* @param Player::class $playerClass
* @param string $baseClass
* @param string $playerClass
* @param string $address
* @param int $port
*/
@ -91,14 +91,16 @@ class PlayerCreationEvent extends Event{
}
/**
* @return Player::class
* @return string
*/
public function getBaseClass(){
return $this->baseClass;
}
/**
* @param Player::class $class
* @param string $class
*
* @return void
*/
public function setBaseClass($class){
if(!is_a($class, $this->baseClass, true)){
@ -109,14 +111,16 @@ class PlayerCreationEvent extends Event{
}
/**
* @return Player::class
* @return string
*/
public function getPlayerClass(){
return $this->playerClass;
}
/**
* @param Player::class $class
* @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,8 +46,8 @@ abstract class BaseInventory implements Inventory{
protected $name;
/** @var string */
protected $title;
/** @var \SplFixedArray|Item[] */
protected $slots = [];
/** @var \SplFixedArray|(Item|null)[] */
protected $slots;
/** @var Player[] */
protected $viewers = [];
/** @var InventoryEventProcessor */
@ -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

@ -43,7 +43,7 @@ class CraftingManager{
/** @var FurnaceRecipe[] */
protected $furnaceRecipes = [];
/** @var BatchPacket */
/** @var BatchPacket|null */
private $craftingDataCache;
public function __construct(){

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

@ -79,8 +79,8 @@ class ShapedRecipe implements CraftingRecipe{
}
for($x = 0; $x < $this->width; ++$x){
if($row{$x} !== ' ' and !isset($ingredients[$row{$x}])){
throw new \InvalidArgumentException("No item specified for symbol '" . $row{$x} . "'");
if($row[$x] !== ' ' and !isset($ingredients[$row[$x]])){
throw new \InvalidArgumentException("No item specified for symbol '" . $row[$x] . "'");
}
}
}

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

@ -65,16 +65,17 @@ class CraftingTransaction extends InventoryTransaction{
* @param int $iterations
*
* @return int
* @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();
@ -113,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

@ -85,7 +85,7 @@ class Bucket extends Item implements Consumable{
$ev->call();
if(!$ev->isCancelled()){
$player->getLevel()->setBlock($blockReplace, $resultBlock->getFlowingForm(), true, true);
$player->getLevel()->broadcastLevelSoundEvent($blockClicked->add(0.5, 0.5, 0.5), $resultBlock->getBucketEmptySound());
$player->getLevel()->broadcastLevelSoundEvent($blockReplace->add(0.5, 0.5, 0.5), $resultBlock->getBucketEmptySound());
if($player->isSurvival()){
$player->getInventory()->setItemInHand($ev->getItem());

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();
@ -137,6 +140,12 @@ 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 = [];
}
@ -145,10 +154,26 @@ class Item implements ItemIds, \JsonSerializable{
return Item::$creative;
}
/**
* Adds an item to the creative menu.
* 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;
}
/**
* Removes an item from the creative menu.
* 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);
if($index !== -1){
@ -217,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){
@ -256,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;
@ -264,7 +292,7 @@ class Item implements ItemIds, \JsonSerializable{
/**
* @param CompoundTag $compound
*
* @return Item
* @return $this
*/
public function setCustomBlockData(CompoundTag $compound) : Item{
$tags = clone $compound;
@ -463,11 +491,11 @@ class Item implements ItemIds, \JsonSerializable{
/**
* @param string $name
*
* @return Item
* @return $this
*/
public function setCustomName(string $name) : Item{
if($name === ""){
$this->clearCustomName();
return $this->clearCustomName();
}
/** @var CompoundTag $display */
@ -483,7 +511,7 @@ class Item implements ItemIds, \JsonSerializable{
}
/**
* @return Item
* @return $this
*/
public function clearCustomName() : Item{
$display = $this->getNamedTagEntry(self::TAG_DISPLAY);
@ -515,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);
@ -572,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){
@ -587,7 +615,7 @@ class Item implements ItemIds, \JsonSerializable{
/**
* Removes the Item's NBT.
* @return Item
* @return $this
*/
public function clearNamedTag() : Item{
return $this->setCompoundTag("");
@ -603,7 +631,7 @@ class Item implements ItemIds, \JsonSerializable{
/**
* @param int $count
*
* @return Item
* @return $this
*/
public function setCount(int $count) : Item{
$this->count = $count;
@ -616,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{
@ -684,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;
}

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