Compare commits

..

195 Commits

Author SHA1 Message Date
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
101 changed files with 2586 additions and 491 deletions

1
.gitignore vendored
View File

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

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

@ -25,6 +25,7 @@
## Donate
- Bitcoin Cash (BCH): `qq3r46hn6ljnhnqnfwxt5pg3g447eq9jhvw5ddfear`
- Bitcoin (BTC): `171u8K9e4FtU6j3e5sqNoxKUgEw9qWQdRV`
- Stellar Lumens (XLM): `GAAC5WZ33HCTE3BFJFZJXONMEIBNHFLBXM2HJVAZHXXPYA3HP5XPPS7T`
- [Patreon](https://www.patreon.com/pocketminemp)
## Licensing information

View File

@ -76,6 +76,6 @@ 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);
echo "pushing changes in 5 seconds\n";
sleep(5);
system('git push origin HEAD ' . $currentVer->getBaseVersion());

16
changelogs/3.10.md Normal file
View File

@ -0,0 +1,16 @@
**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.

View File

@ -99,4 +99,31 @@ Plugin developers should **only** update their required API to this version if y
- `pocketmine\level\Explosion`:
- `explodeA()`
- `explodeB()`
- Fixed various cosmetic documentation inconsistencies in the core and dependencies.
- 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

@ -36,7 +36,11 @@
"autoload": {
"psr-4": {
"": ["src"]
}
},
"files": [
"src/pocketmine/GlobalConstants.php",
"src/pocketmine/VersionInfo.php"
]
},
"autoload-dev": {
"psr-4": {

28
composer.lock generated
View File

@ -160,16 +160,16 @@
},
{
"name": "pocketmine/nbt",
"version": "0.2.11",
"version": "0.2.12",
"source": {
"type": "git",
"url": "https://github.com/pmmp/NBT.git",
"reference": "78784b93632c51f0fad0719b2d6ffe072529db6d"
"reference": "b5777265329753b74dd40bb105eedabeefb98724"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/pmmp/NBT/zipball/78784b93632c51f0fad0719b2d6ffe072529db6d",
"reference": "78784b93632c51f0fad0719b2d6ffe072529db6d",
"url": "https://api.github.com/repos/pmmp/NBT/zipball/b5777265329753b74dd40bb105eedabeefb98724",
"reference": "b5777265329753b74dd40bb105eedabeefb98724",
"shasum": ""
},
"require": {
@ -194,10 +194,10 @@
],
"description": "PHP library for working with Named Binary Tags",
"support": {
"source": "https://github.com/pmmp/NBT/tree/0.2.11",
"source": "https://github.com/pmmp/NBT/tree/0.2",
"issues": "https://github.com/pmmp/NBT/issues"
},
"time": "2019-10-21T14:50:43+00:00"
"time": "2019-12-01T08:20:26+00:00"
},
{
"name": "pocketmine/raklib",
@ -276,23 +276,20 @@
},
{
"name": "pocketmine/spl",
"version": "0.3.2",
"version": "0.3.3",
"source": {
"type": "git",
"url": "https://github.com/pmmp/SPL.git",
"reference": "7fd53857cd000491ba69e8db865792a024dd2c49"
"reference": "94d4df142fe837ba836e9348dd00209e4bdcc307"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/pmmp/SPL/zipball/7fd53857cd000491ba69e8db865792a024dd2c49",
"reference": "7fd53857cd000491ba69e8db865792a024dd2c49",
"url": "https://api.github.com/repos/pmmp/SPL/zipball/94d4df142fe837ba836e9348dd00209e4bdcc307",
"reference": "94d4df142fe837ba836e9348dd00209e4bdcc307",
"shasum": ""
},
"type": "library",
"autoload": {
"exclude-from-classmap": [
"stubs"
],
"classmap": [
"./"
]
@ -302,9 +299,10 @@
],
"description": "Standard library files required by PocketMine-MP and related projects",
"support": {
"source": "https://github.com/pmmp/SPL/tree/master"
"source": "https://github.com/pmmp/SPL/tree/0.3.3",
"issues": "https://github.com/pmmp/SPL/issues"
},
"time": "2018-08-12T15:17:39+00:00"
"time": "2019-10-28T11:41:20+00:00"
}
],
"packages-dev": [],

124
phpstan.neon.dist Normal file
View File

@ -0,0 +1,124 @@
includes:
- tests/phpstan/configs/gc-hacks.neon
- tests/phpstan/configs/optional-com-dotnet.neon
- tests/phpstan/configs/optional-leveldb.neon
- tests/phpstan/configs/phpstan-bugs.neon
- tests/phpstan/configs/pthreads-bugs.neon
parameters:
level: 3
autoload_files:
- tests/phpstan/bootstrap.php
- src/pocketmine/PocketMine.php
paths:
- src
reportUnmatchedIgnoredErrors: false #no other way to silence platform-specific non-warnings
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: "#^Used constant pocketmine\\\\RESOURCE_PATH not found\\.$#"
count: 1
path: src/pocketmine/network/mcpe/protocol/StartGamePacket.php
-
message: "#^Constructor of class pocketmine\\\\scheduler\\\\TaskScheduler has an unused parameter \\$logger\\.$#"
count: 1
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\\\\PATH not found\\.$#"
path: src
-
message: "#^Constant pocketmine\\\\PLUGIN_PATH not found\\.$#"
path: src
-
message: "#^Constant pocketmine\\\\RESOURCE_PATH not found\\.$#"
path: src
-
message: "#^Constant pocketmine\\\\START_TIME not found\\.$#"
path: src
-
message: "#^Constant pocketmine\\\\VERSION not found\\.$#"
path: src

View File

@ -333,7 +333,7 @@ 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());

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

@ -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;
@ -1112,9 +1116,11 @@ class Player extends Human implements CommandSender, ChunkLoader, IPlayer{
}
}
protected function sendRespawnPacket(Vector3 $pos){
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);
}
@ -1616,7 +1622,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);
@ -1913,14 +1919,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"], $animation["Image"]), $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["AnimationData"] ?? ""),
$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");
@ -2156,7 +2175,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;
@ -2491,6 +2510,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()){
@ -2644,33 +2684,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;
}
@ -2828,7 +2841,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;
}
@ -2913,6 +2926,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.
*
@ -3805,7 +3827,7 @@ class Player extends Human implements CommandSender, ChunkLoader, IPlayer{
$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);

View File

@ -21,11 +21,6 @@
declare(strict_types=1);
namespace {
const INT32_MIN = -0x80000000;
const INT32_MAX = 0x7fffffff;
}
namespace pocketmine {
use pocketmine\utils\MainLogger;
@ -57,18 +52,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 = [
@ -121,6 +116,29 @@ namespace pocketmine {
return $messages;
}
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.");
}
}
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');
}
function server(){
if(!empty($messages = check_platform_dependencies())){
echo PHP_EOL;
@ -136,6 +154,7 @@ namespace pocketmine {
unset($messages);
error_reporting(-1);
set_ini_entries();
if(\Phar::running(true) !== ""){
define('pocketmine\PATH', \Phar::running(true) . "/");
@ -161,20 +180,27 @@ namespace pocketmine {
set_error_handler([Utils::class, 'errorExceptionHandler']);
/*
* We now use the Composer autoloader, but this autoloader is still for loading plugins.
*/
$autoloader = new \BaseClassLoader();
$autoloader->register(false);
$version = new VersionString(\pocketmine\BASE_VERSION, \pocketmine\IS_DEVELOPMENT_BUILD, \pocketmine\BUILD_NUMBER);
define('pocketmine\VERSION', $version->getFullVersion(true));
set_time_limit(0); //Who set it to 30 seconds?!?!
$gitHash = str_repeat("00", 20);
ini_set("allow_url_fopen", '1');
ini_set("display_errors", '1');
ini_set("display_startup_errors", '1');
ini_set("default_charset", "utf-8");
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";
}
}
}else{
$phar = new \Phar(\Phar::running(false));
$meta = $phar->getMetadata();
if(isset($meta["git"])){
$gitHash = $meta["git"];
}
}
ini_set("memory_limit", '-1');
define('pocketmine\GIT_COMMIT', $gitHash);
define('pocketmine\RESOURCE_PATH', \pocketmine\PATH . 'src' . DIRECTORY_SEPARATOR . 'pocketmine' . DIRECTORY_SEPARATOR . 'resources' . DIRECTORY_SEPARATOR);
@ -187,8 +213,7 @@ namespace pocketmine {
mkdir(\pocketmine\DATA, 0777, true);
}
define('pocketmine\LOCK_FILE_PATH', \pocketmine\DATA . 'server.lock');
define('pocketmine\LOCK_FILE', fopen(\pocketmine\LOCK_FILE_PATH, "a+b"));
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
@ -222,42 +247,7 @@ namespace pocketmine {
}
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";
}
}
}else{
$phar = new \Phar(\Phar::running(false));
$meta = $phar->getMetadata();
if(isset($meta["git"])){
$gitHash = $meta["git"];
}
}
define('pocketmine\GIT_COMMIT', $gitHash);
@define("INT32_MASK", is_int(0xffffffff) ? 0xffffffff : -1);
@ini_set("opcache.mmap_base", bin2hex(random_bytes(8))); //Fix OPCache address errors
emit_performance_warnings($logger);
$exitCode = 0;
do{
@ -272,6 +262,13 @@ namespace pocketmine {
//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");
@ -281,9 +278,7 @@ namespace pocketmine {
usleep(10000); //Fixes ServerKiller not being able to start on single-core machines
if(ThreadManager::getInstance()->stopAll() > 0){
if(\pocketmine\DEBUG > 1){
echo "Some threads could not be stopped, performing a force-kill" . PHP_EOL . PHP_EOL;
}
$logger->debug("Some threads could not be stopped, performing a force-kill");
Utils::kill(getmypid());
}
}while(false);
@ -296,5 +291,7 @@ namespace pocketmine {
exit($exitCode);
}
\pocketmine\server();
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;
@ -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];
@ -1444,7 +1445,7 @@ class Server{
}
/**
* @return string[]
* @return string[][]
*/
public function getCommandAliases() : array{
$section = $this->getProperty("aliases");
@ -1565,12 +1566,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);
}
@ -1795,7 +1790,7 @@ class Server{
/**
* @param TextContainer|string $message
* @param Player[] $recipients
* @param CommandSender[] $recipients
*
* @return int
*/
@ -1804,7 +1799,6 @@ class Server{
return $this->broadcast($message, self::BROADCAST_CHANNEL_USERS);
}
/** @var Player[] $recipients */
foreach($recipients as $recipient){
$recipient->sendMessage($message);
}
@ -1829,7 +1823,6 @@ class Server{
}
}
/** @var Player[] $recipients */
foreach($recipients as $recipient){
$recipient->sendTip($tip);
}
@ -1855,7 +1848,6 @@ class Server{
}
}
/** @var Player[] $recipients */
foreach($recipients as $recipient){
$recipient->sendPopup($popup);
}
@ -1885,7 +1877,6 @@ class Server{
}
}
/** @var Player[] $recipients */
foreach($recipients as $recipient){
$recipient->addTitle($title, $subtitle, $fadeIn, $stay, $fadeOut);
}
@ -2405,7 +2396,7 @@ class Server{
$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);
}
@ -2428,7 +2419,7 @@ class Server{
$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);

View File

@ -21,7 +21,15 @@
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.9.6";
const BASE_VERSION = "3.10.0";
const IS_DEVELOPMENT_BUILD = false;
const BUILD_NUMBER = 0;

View File

@ -763,7 +763,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

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

@ -55,7 +55,7 @@ abstract class Command{
*/
private $activeAliases = [];
/** @var CommandMap */
/** @var CommandMap|null */
private $commandMap = null;
/** @var string */

View File

@ -141,6 +141,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

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

@ -318,7 +318,7 @@ abstract class Entity extends Location implements Metadatable, EntityIds{
public const DATA_PLAYER_FLAG_DEAD = 2; //TODO: CHECK
public static $entityCount = 1;
/** @var Entity[] */
/** @var string[] */
private static $knownEntities = [];
/** @var string[][] */
private static $saveNames = [];
@ -460,8 +460,8 @@ 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;
@ -2048,7 +2048,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);

View File

@ -53,6 +53,7 @@ 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;
@ -182,7 +183,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);
}
@ -850,7 +851,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

@ -40,7 +40,7 @@ class Squid extends WaterAnimal{
public $width = 0.95;
public $height = 0.95;
/** @var Vector3 */
/** @var Vector3|null */
public $swimDirection = null;
public $swimSpeed = 0.1;
@ -82,7 +82,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

@ -90,6 +90,9 @@ class Painting extends Entity{
}
public function kill() : void{
if(!$this->isAlive()){
return;
}
parent::kill();
$drops = 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;
}

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,14 @@ class PlayerCreationEvent extends Event{
}
/**
* @return Player::class
* @return string
*/
public function getBaseClass(){
return $this->baseClass;
}
/**
* @param Player::class $class
* @param string $class
*/
public function setBaseClass($class){
if(!is_a($class, $this->baseClass, true)){
@ -109,14 +109,14 @@ class PlayerCreationEvent extends Event{
}
/**
* @return Player::class
* @return string
*/
public function getPlayerClass(){
return $this->playerClass;
}
/**
* @param Player::class $class
* @param string $class
*/
public function setPlayerClass($class){
if(!is_a($class, $this->baseClass, true)){

View File

@ -47,7 +47,7 @@ abstract class BaseInventory implements Inventory{
/** @var string */
protected $title;
/** @var \SplFixedArray|Item[] */
protected $slots = [];
protected $slots;
/** @var Player[] */
protected $viewers = [];
/** @var InventoryEventProcessor */

View File

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

View File

@ -186,16 +186,18 @@ class WritableBook extends Item{
* @return CompoundTag[]
*/
public function getPages() : array{
$pages = $this->getNamedTag()->getListTag(self::TAG_PAGES);
if($pages === null){
return [];
}
/** @var CompoundTag[] $pages */
$pages = $this->getPagesTag()->getValue();
return $pages->getValue();
return $pages;
}
protected function getPagesTag() : ListTag{
return $this->getNamedTag()->getListTag(self::TAG_PAGES) ?? new ListTag(self::TAG_PAGES, [], NBT::TAG_Compound);
$pagesTag = $this->getNamedTag()->getListTag(self::TAG_PAGES);
if($pagesTag !== null and $pagesTag->getTagType() === NBT::TAG_Compound){
return $pagesTag;
}
return new ListTag(self::TAG_PAGES, [], NBT::TAG_Compound);
}
/**

View File

@ -94,7 +94,7 @@ class Enchantment{
public const SLOT_ELYTRA = 0x4000;
public const SLOT_TRIDENT = 0x8000;
/** @var Enchantment[] */
/** @var \SplFixedArray|Enchantment[] */
protected static $enchantments;
public static function init() : void{

View File

@ -38,7 +38,6 @@ use pocketmine\level\particle\HugeExplodeSeedParticle;
use pocketmine\level\utils\SubChunkIteratorManager;
use pocketmine\math\AxisAlignedBB;
use pocketmine\math\Vector3;
use pocketmine\network\mcpe\protocol\ExplodePacket;
use pocketmine\network\mcpe\protocol\LevelSoundEventPacket;
use pocketmine\tile\Chest;
use pocketmine\tile\Container;
@ -260,12 +259,6 @@ class Explosion{
$send[] = new Vector3($block->x - $source->x, $block->y - $source->y, $block->z - $source->z);
}
$pk = new ExplodePacket();
$pk->position = $this->source->asVector3();
$pk->radius = $this->size;
$pk->records = $send;
$this->level->broadcastPacketToViewers($source, $pk);
$this->level->addParticle(new HugeExplodeSeedParticle($source));
$this->level->broadcastLevelSoundEvent($source, LevelSoundEventPacket::SOUND_EXPLODE);

View File

@ -265,7 +265,7 @@ class Level implements ChunkManager, Metadatable{
/** @var LevelTimings */
public $timings;
/** @var int */
/** @var float */
public $tickRateTime = 0;
/**
* @deprecated

View File

@ -29,7 +29,7 @@ use function assert;
class Position extends Vector3{
/** @var Level */
/** @var Level|null */
public $level = null;
/**

View File

@ -694,50 +694,48 @@ class Chunk{
public function initChunk(Level $level){
if(!$this->isInit){
$changed = false;
if($this->NBTentities !== null){
$level->timings->syncChunkLoadEntitiesTimer->startTiming();
foreach($this->NBTentities as $nbt){
if($nbt instanceof CompoundTag){
if(!$nbt->hasTag("id")){ //allow mixed types (because of leveldb)
$changed = true;
continue;
}
try{
$entity = Entity::createEntity($nbt->getTag("id")->getValue(), $level, $nbt);
if(!($entity instanceof Entity)){
$changed = true;
continue;
}
}catch(\Throwable $t){
$level->getServer()->getLogger()->logException($t);
$level->timings->syncChunkLoadEntitiesTimer->startTiming();
foreach($this->NBTentities as $nbt){
if($nbt instanceof CompoundTag){
if(!$nbt->hasTag("id")){ //allow mixed types (because of leveldb)
$changed = true;
continue;
}
try{
$entity = Entity::createEntity($nbt->getTag("id")->getValue(), $level, $nbt);
if(!($entity instanceof Entity)){
$changed = true;
continue;
}
}catch(\Throwable $t){
$level->getServer()->getLogger()->logException($t);
$changed = true;
continue;
}
}
$level->timings->syncChunkLoadEntitiesTimer->stopTiming();
$level->timings->syncChunkLoadTileEntitiesTimer->startTiming();
foreach($this->NBTtiles as $nbt){
if($nbt instanceof CompoundTag){
if(!$nbt->hasTag(Tile::TAG_ID, StringTag::class)){
$changed = true;
continue;
}
if(Tile::createTile($nbt->getString(Tile::TAG_ID), $level, $nbt) === null){
$changed = true;
continue;
}
}
}
$level->timings->syncChunkLoadTileEntitiesTimer->stopTiming();
$this->NBTentities = null;
$this->NBTtiles = null;
}
$this->NBTentities = [];
$level->timings->syncChunkLoadEntitiesTimer->stopTiming();
$level->timings->syncChunkLoadTileEntitiesTimer->startTiming();
foreach($this->NBTtiles as $nbt){
if($nbt instanceof CompoundTag){
if(!$nbt->hasTag(Tile::TAG_ID, StringTag::class)){
$changed = true;
continue;
}
if(Tile::createTile($nbt->getString(Tile::TAG_ID), $level, $nbt) === null){
$changed = true;
continue;
}
}
}
$this->NBTtiles = [];
$level->timings->syncChunkLoadTileEntitiesTimer->stopTiming();
$this->hasChanged = $changed;

View File

@ -32,6 +32,7 @@ use pocketmine\network\mcpe\protocol\AddPlayerPacket;
use pocketmine\network\mcpe\protocol\PlayerListPacket;
use pocketmine\network\mcpe\protocol\RemoveActorPacket;
use pocketmine\network\mcpe\protocol\types\PlayerListEntry;
use pocketmine\network\mcpe\protocol\types\SkinAdapterSingleton;
use pocketmine\utils\UUID;
use function str_repeat;
@ -96,7 +97,9 @@ class FloatingTextParticle extends Particle{
$add = new PlayerListPacket();
$add->type = PlayerListPacket::TYPE_ADD;
$add->entries = [PlayerListEntry::createAdditionEntry($uuid, $this->entityId, $name, new Skin("Standard_Custom", str_repeat("\x00", 8192)))];
$add->entries = [PlayerListEntry::createAdditionEntry($uuid, $this->entityId, $name, SkinAdapterSingleton::get()->toSkinData(new Skin(
"Standard_Custom", str_repeat("\x00", 8192), "", "geometry.humanoid.custom"
)))];
$p[] = $add;
$pk = new AddPlayerPacket();

View File

@ -29,7 +29,7 @@ namespace pocketmine\metadata;
use pocketmine\plugin\Plugin;
abstract class MetadataStore{
/** @var \SplObjectStorage[] */
/** @var \SplObjectStorage[]|MetadataValue[][] */
private $metadataMap;
/**
@ -100,7 +100,7 @@ abstract class MetadataStore{
* @param Plugin $owningPlugin
*/
public function invalidateAll(Plugin $owningPlugin){
/** @var MetadataValue[] $values */
/** @var \SplObjectStorage|MetadataValue[] $values */
foreach($this->metadataMap as $values){
if(isset($values[$owningPlugin])){
$values[$owningPlugin]->invalidate();

View File

@ -27,6 +27,7 @@ namespace pocketmine\network\mcpe;
use pocketmine\entity\Attribute;
use pocketmine\entity\Entity;
use pocketmine\entity\Skin;
use pocketmine\item\Durable;
use pocketmine\item\Item;
use pocketmine\item\ItemFactory;
@ -37,6 +38,9 @@ use pocketmine\nbt\tag\CompoundTag;
use pocketmine\nbt\tag\IntTag;
use pocketmine\network\mcpe\protocol\types\CommandOriginData;
use pocketmine\network\mcpe\protocol\types\EntityLink;
use pocketmine\network\mcpe\protocol\types\SkinData;
use pocketmine\network\mcpe\protocol\types\SkinImage;
use pocketmine\network\mcpe\protocol\types\SkinAnimation;
use pocketmine\network\mcpe\protocol\types\StructureSettings;
use pocketmine\utils\BinaryStream;
use pocketmine\utils\UUID;
@ -74,6 +78,66 @@ class NetworkBinaryStream extends BinaryStream{
$this->putLInt($uuid->getPart(2));
}
public function getSkin() : SkinData{
$skinId = $this->getString();
$skinResourcePatch = $this->getString();
$skinData = $this->getSkinImage();
$animationCount = $this->getLInt();
$animations = [];
for($i = 0; $i < $animationCount; ++$i){
$animations[] = new SkinAnimation(
$skinImage = $this->getSkinImage(),
$animationType = $this->getLInt(),
$animationFrames = $this->getLFloat()
);
}
$capeData = $this->getSkinImage();
$geometryData = $this->getString();
$animationData = $this->getString();
$premium = $this->getBool();
$persona = $this->getBool();
$capeOnClassic = $this->getBool();
$capeId = $this->getString();
$fullSkinId = $this->getString();
return new SkinData($skinId, $skinResourcePatch, $skinData, $animations, $capeData, $geometryData, $animationData, $premium, $persona, $capeOnClassic, $capeId);
}
public function putSkin(SkinData $skin){
$this->putString($skin->getSkinId());
$this->putString($skin->getResourcePatch());
$this->putSkinImage($skin->getSkinImage());
$this->putLInt(count($skin->getAnimations()));
foreach($skin->getAnimations() as $animation){
$this->putSkinImage($animation->getImage());
$this->putLInt($animation->getType());
$this->putLFloat($animation->getFrames());
}
$this->putSkinImage($skin->getCapeImage());
$this->putString($skin->getGeometryData());
$this->putString($skin->getAnimationData());
$this->putBool($skin->isPremium());
$this->putBool($skin->isPersona());
$this->putBool($skin->isPersonaCapeOnClassic());
$this->putString($skin->getCapeId());
//this has to be unique or the client will do stupid things
$this->putString(UUID::fromRandom()->toString()); //full skin ID
}
private function getSkinImage() : SkinImage{
$width = $this->getLInt();
$height = $this->getLInt();
$data = $this->getString();
return new SkinImage($height, $width, $data);
}
private function putSkinImage(SkinImage $image) : void{
$this->putLInt($image->getWidth());
$this->putLInt($image->getHeight());
$this->putString($image->getData());
}
public function getSlot() : Item{
$id = $this->getVarInt();
if($id === 0){
@ -93,7 +157,11 @@ class NetworkBinaryStream extends BinaryStream{
if($c !== 1){
throw new \UnexpectedValueException("Unexpected NBT count $c");
}
$nbt = (new NetworkLittleEndianNBTStream())->read($this->buffer, false, $this->offset, 512);
$decodedNBT = (new NetworkLittleEndianNBTStream())->read($this->buffer, false, $this->offset, 512);
if(!($decodedNBT instanceof CompoundTag)){
throw new \UnexpectedValueException("Unexpected root tag type for itemstack");
}
$nbt = $decodedNBT;
}elseif($nbtLen !== 0){
throw new \UnexpectedValueException("Unexpected fake NBT length $nbtLen");
}
@ -378,7 +446,7 @@ class NetworkBinaryStream extends BinaryStream{
}
/**
* Writes an EntityUniqueID
* Writes an EntityRuntimeID
*
* @param int $eid
*/

View File

@ -34,6 +34,7 @@ use pocketmine\network\mcpe\protocol\AddPaintingPacket;
use pocketmine\network\mcpe\protocol\AddPlayerPacket;
use pocketmine\network\mcpe\protocol\AdventureSettingsPacket;
use pocketmine\network\mcpe\protocol\AnimatePacket;
use pocketmine\network\mcpe\protocol\AnvilDamagePacket;
use pocketmine\network\mcpe\protocol\AutomationClientConnectPacket;
use pocketmine\network\mcpe\protocol\AvailableActorIdentifiersPacket;
use pocketmine\network\mcpe\protocol\AvailableCommandsPacket;
@ -54,6 +55,7 @@ use pocketmine\network\mcpe\protocol\ClientToServerHandshakePacket;
use pocketmine\network\mcpe\protocol\CommandBlockUpdatePacket;
use pocketmine\network\mcpe\protocol\CommandOutputPacket;
use pocketmine\network\mcpe\protocol\CommandRequestPacket;
use pocketmine\network\mcpe\protocol\CompletedUsingItemPacket;
use pocketmine\network\mcpe\protocol\ContainerClosePacket;
use pocketmine\network\mcpe\protocol\ContainerOpenPacket;
use pocketmine\network\mcpe\protocol\ContainerSetDataPacket;
@ -61,8 +63,9 @@ use pocketmine\network\mcpe\protocol\CraftingDataPacket;
use pocketmine\network\mcpe\protocol\CraftingEventPacket;
use pocketmine\network\mcpe\protocol\DataPacket;
use pocketmine\network\mcpe\protocol\DisconnectPacket;
use pocketmine\network\mcpe\protocol\EducationSettingsPacket;
use pocketmine\network\mcpe\protocol\EmotePacket;
use pocketmine\network\mcpe\protocol\EventPacket;
use pocketmine\network\mcpe\protocol\ExplodePacket;
use pocketmine\network\mcpe\protocol\GameRulesChangedPacket;
use pocketmine\network\mcpe\protocol\GuiDataPickItemPacket;
use pocketmine\network\mcpe\protocol\HurtArmorPacket;
@ -90,12 +93,15 @@ use pocketmine\network\mcpe\protocol\ModalFormResponsePacket;
use pocketmine\network\mcpe\protocol\MoveActorAbsolutePacket;
use pocketmine\network\mcpe\protocol\MoveActorDeltaPacket;
use pocketmine\network\mcpe\protocol\MovePlayerPacket;
use pocketmine\network\mcpe\protocol\MultiplayerSettingsPacket;
use pocketmine\network\mcpe\protocol\NetworkChunkPublisherUpdatePacket;
use pocketmine\network\mcpe\protocol\NetworkSettingsPacket;
use pocketmine\network\mcpe\protocol\NetworkStackLatencyPacket;
use pocketmine\network\mcpe\protocol\NpcRequestPacket;
use pocketmine\network\mcpe\protocol\OnScreenTextureAnimationPacket;
use pocketmine\network\mcpe\protocol\PhotoTransferPacket;
use pocketmine\network\mcpe\protocol\PlayerActionPacket;
use pocketmine\network\mcpe\protocol\PlayerAuthInputPacket;
use pocketmine\network\mcpe\protocol\PlayerHotbarPacket;
use pocketmine\network\mcpe\protocol\PlayerInputPacket;
use pocketmine\network\mcpe\protocol\PlayerListPacket;
@ -134,6 +140,7 @@ use pocketmine\network\mcpe\protocol\SetScoreboardIdentityPacket;
use pocketmine\network\mcpe\protocol\SetScorePacket;
use pocketmine\network\mcpe\protocol\SetSpawnPositionPacket;
use pocketmine\network\mcpe\protocol\SetTimePacket;
use pocketmine\network\mcpe\protocol\SettingsCommandPacket;
use pocketmine\network\mcpe\protocol\SetTitlePacket;
use pocketmine\network\mcpe\protocol\ShowCreditsPacket;
use pocketmine\network\mcpe\protocol\ShowProfilePacket;
@ -144,11 +151,12 @@ use pocketmine\network\mcpe\protocol\SpawnParticleEffectPacket;
use pocketmine\network\mcpe\protocol\StartGamePacket;
use pocketmine\network\mcpe\protocol\StopSoundPacket;
use pocketmine\network\mcpe\protocol\StructureBlockUpdatePacket;
use pocketmine\network\mcpe\protocol\StructureTemplateDataExportRequestPacket;
use pocketmine\network\mcpe\protocol\StructureTemplateDataExportResponsePacket;
use pocketmine\network\mcpe\protocol\StructureTemplateDataRequestPacket;
use pocketmine\network\mcpe\protocol\StructureTemplateDataResponsePacket;
use pocketmine\network\mcpe\protocol\SubClientLoginPacket;
use pocketmine\network\mcpe\protocol\TakeItemActorPacket;
use pocketmine\network\mcpe\protocol\TextPacket;
use pocketmine\network\mcpe\protocol\TickSyncPacket;
use pocketmine\network\mcpe\protocol\TransferPacket;
use pocketmine\network\mcpe\protocol\UpdateAttributesPacket;
use pocketmine\network\mcpe\protocol\UpdateBlockPacket;
@ -247,7 +255,7 @@ abstract class NetworkSession{
return false;
}
public function handleExplode(ExplodePacket $packet) : bool{
public function handleTickSync(TickSyncPacket $packet) : bool{
return false;
}
@ -679,11 +687,11 @@ abstract class NetworkSession{
return false;
}
public function handleStructureTemplateDataExportRequest(StructureTemplateDataExportRequestPacket $packet) : bool{
public function handleStructureTemplateDataRequest(StructureTemplateDataRequestPacket $packet) : bool{
return false;
}
public function handleStructureTemplateDataExportResponse(StructureTemplateDataExportResponsePacket $packet) : bool{
public function handleStructureTemplateDataResponse(StructureTemplateDataResponsePacket $packet) : bool{
return false;
}
@ -698,4 +706,36 @@ abstract class NetworkSession{
public function handleClientCacheMissResponse(ClientCacheMissResponsePacket $packet) : bool{
return false;
}
public function handleEducationSettings(EducationSettingsPacket $packet) : bool{
return false;
}
public function handleEmote(EmotePacket $packet) : bool{
return false;
}
public function handleMultiplayerSettings(MultiplayerSettingsPacket $packet) : bool{
return false;
}
public function handleSettingsCommand(SettingsCommandPacket $packet) : bool{
return false;
}
public function handleAnvilDamage(AnvilDamagePacket $packet) : bool{
return false;
}
public function handleCompletedUsingItem(CompletedUsingItemPacket $packet) : bool{
return false;
}
public function handleNetworkSettings(NetworkSettingsPacket $packet) : bool{
return false;
}
public function handlePlayerAuthInput(PlayerAuthInputPacket $packet) : bool{
return false;
}
}

View File

@ -59,12 +59,15 @@ use pocketmine\network\mcpe\protocol\PlayerSkinPacket;
use pocketmine\network\mcpe\protocol\RequestChunkRadiusPacket;
use pocketmine\network\mcpe\protocol\ResourcePackChunkRequestPacket;
use pocketmine\network\mcpe\protocol\ResourcePackClientResponsePacket;
use pocketmine\network\mcpe\protocol\RespawnPacket;
use pocketmine\network\mcpe\protocol\ServerSettingsRequestPacket;
use pocketmine\network\mcpe\protocol\SetLocalPlayerAsInitializedPacket;
use pocketmine\network\mcpe\protocol\SetPlayerGameTypePacket;
use pocketmine\network\mcpe\protocol\ShowCreditsPacket;
use pocketmine\network\mcpe\protocol\SpawnExperienceOrbPacket;
use pocketmine\network\mcpe\protocol\TextPacket;
use pocketmine\network\mcpe\protocol\types\SkinAdapterSingleton;
use pocketmine\network\mcpe\protocol\types\SkinData;
use pocketmine\Player;
use pocketmine\Server;
use pocketmine\timings\Timings;
@ -181,6 +184,10 @@ class PlayerNetworkSessionAdapter extends NetworkSession{
return $this->player->handleAnimate($packet);
}
public function handleRespawn(RespawnPacket $packet) : bool{
return $this->player->handleRespawn($packet);
}
public function handleContainerClose(ContainerClosePacket $packet) : bool{
return $this->player->handleContainerClose($packet);
}
@ -248,7 +255,7 @@ class PlayerNetworkSessionAdapter extends NetworkSession{
}
public function handlePlayerSkin(PlayerSkinPacket $packet) : bool{
return $this->player->changeSkin($packet->skin, $packet->newSkinName, $packet->oldSkinName);
return $this->player->changeSkin(SkinAdapterSingleton::get()->fromSkinData($packet->skin), $packet->newSkinName, $packet->oldSkinName);
}
public function handleBookEdit(BookEditPacket $packet) : bool{

View File

@ -74,6 +74,8 @@ class AddPlayerPacket extends DataPacket{
/** @var string */
public $deviceId = ""; //TODO: fill player's device ID (???)
/** @var int */
public $buildPlatform = -1;
protected function decodePayload(){
$this->uuid = $this->getUUID();
@ -103,6 +105,7 @@ class AddPlayerPacket extends DataPacket{
}
$this->deviceId = $this->getString();
$this->buildPlatform = $this->getLInt();
}
protected function encodePayload(){
@ -133,6 +136,7 @@ class AddPlayerPacket extends DataPacket{
}
$this->putString($this->deviceId);
$this->putLInt($this->buildPlatform);
}
public function handle(NetworkSession $session) : bool{

View File

@ -0,0 +1,78 @@
<?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\network\mcpe\protocol;
#include <rules/DataPacket.h>
use pocketmine\network\mcpe\NetworkSession;
class AnvilDamagePacket extends DataPacket/* implements ServerboundPacket*/{
public const NETWORK_ID = ProtocolInfo::ANVIL_DAMAGE_PACKET;
/** @var int */
private $x;
/** @var int */
private $y;
/** @var int */
private $z;
/** @var int */
private $damageAmount;
public static function create(int $x, int $y, int $z, int $damageAmount) : self{
$result = new self;
[$result->x, $result->y, $result->z] = [$x, $y, $z];
$result->damageAmount = $damageAmount;
return $result;
}
public function getDamageAmount() : int{
return $this->damageAmount;
}
public function getX() : int{
return $this->x;
}
public function getY() : int{
return $this->y;
}
public function getZ() : int{
return $this->z;
}
protected function decodePayload() : void{
$this->damageAmount = $this->getByte();
$this->getBlockPosition($this->x, $this->y, $this->z);
}
protected function encodePayload() : void{
$this->putByte($this->damageAmount);
$this->putBlockPosition($this->x, $this->y, $this->z);
}
public function handle(NetworkSession $handler) : bool{
return $handler->handleAnvilDamage($this);
}
}

File diff suppressed because one or more lines are too long

View File

@ -28,7 +28,9 @@ namespace pocketmine\network\mcpe\protocol;
use pocketmine\network\mcpe\NetworkSession;
use pocketmine\network\mcpe\protocol\types\CommandData;
use pocketmine\network\mcpe\protocol\types\CommandEnum;
use pocketmine\network\mcpe\protocol\types\CommandEnumConstraint;
use pocketmine\network\mcpe\protocol\types\CommandParameter;
use pocketmine\utils\BinaryDataException;
use function count;
use function dechex;
@ -55,17 +57,17 @@ class AvailableCommandsPacket extends DataPacket{
public const ARG_TYPE_FILEPATH = 0x0e;
public const ARG_TYPE_STRING = 0x1b;
public const ARG_TYPE_STRING = 0x1d;
public const ARG_TYPE_POSITION = 0x1d;
public const ARG_TYPE_POSITION = 0x25;
public const ARG_TYPE_MESSAGE = 0x20;
public const ARG_TYPE_MESSAGE = 0x29;
public const ARG_TYPE_RAWTEXT = 0x22;
public const ARG_TYPE_RAWTEXT = 0x2b;
public const ARG_TYPE_JSON = 0x25;
public const ARG_TYPE_JSON = 0x2f;
public const ARG_TYPE_COMMAND = 0x2c;
public const ARG_TYPE_COMMAND = 0x36;
/**
* Enums are a little different: they are composed as follows:
@ -78,12 +80,23 @@ class AvailableCommandsPacket extends DataPacket{
*/
public const ARG_FLAG_POSTFIX = 0x1000000;
public const HARDCODED_ENUM_NAMES = [
"CommandName" => true
];
/**
* @var CommandData[]
* List of command data, including name, description, alias indexes and parameters.
*/
public $commandData = [];
/**
* @var CommandEnum[]
* List of enums which aren't directly referenced by any vanilla command.
* This is used for the `CommandName` enum, which is a magic enum used by the `command` argument type.
*/
public $hardcodedEnums = [];
/**
* @var CommandEnum[]
* List of dynamic command enums, also referred to as "soft" enums. These can by dynamically updated mid-game
@ -91,6 +104,12 @@ class AvailableCommandsPacket extends DataPacket{
*/
public $softEnums = [];
/**
* @var CommandEnumConstraint[]
* List of constraints for enum members. Used to constrain gamerules that can bechanged in nocheats mode and more.
*/
public $enumConstraints = [];
protected function decodePayload(){
/** @var string[] $enumValues */
$enumValues = [];
@ -107,7 +126,10 @@ class AvailableCommandsPacket extends DataPacket{
/** @var CommandEnum[] $enums */
$enums = [];
for($i = 0, $count = $this->getUnsignedVarInt(); $i < $count; ++$i){
$enums[] = $this->getEnum($enumValues);
$enums[] = $enum = $this->getEnum($enumValues);
if(isset(self::HARDCODED_ENUM_NAMES[$enum->enumName])){
$this->hardcodedEnums[] = $enum;
}
}
for($i = 0, $count = $this->getUnsignedVarInt(); $i < $count; ++$i){
@ -117,6 +139,10 @@ class AvailableCommandsPacket extends DataPacket{
for($i = 0, $count = $this->getUnsignedVarInt(); $i < $count; ++$i){
$this->softEnums[] = $this->getSoftEnum();
}
for($i = 0, $count = $this->getUnsignedVarInt(); $i < $count; ++$i){
$this->enumConstraints[] = $this->getEnumConstraint($enums, $enumValues);
}
}
/**
@ -209,6 +235,50 @@ class AvailableCommandsPacket extends DataPacket{
}
}
/**
* @param CommandEnum[] $enums
* @param string[] $enumValues
*
* @return CommandEnumConstraint
*/
protected function getEnumConstraint(array $enums, array $enumValues) : CommandEnumConstraint{
//wtf, what was wrong with an offset inside the enum? :(
$valueIndex = $this->getLInt();
if(!isset($enumValues[$valueIndex])){
throw new \UnexpectedValueException("Enum constraint refers to unknown enum value index $valueIndex");
}
$enumIndex = $this->getLInt();
if(!isset($enums[$enumIndex])){
throw new \UnexpectedValueException("Enum constraint refers to unknown enum index $enumIndex");
}
$enum = $enums[$enumIndex];
$valueOffset = array_search($enumValues[$valueIndex], $enum->enumValues, true);
if($valueOffset === false){
throw new \UnexpectedValueException("Value \"" . $enumValues[$valueIndex] . "\" does not belong to enum \"$enum->enumName\"");
}
$constraintIds = [];
for($i = 0, $count = $this->getUnsignedVarInt(); $i < $count; ++$i){
$constraintIds[] = $this->getByte();
}
return new CommandEnumConstraint($enum, $valueOffset, $constraintIds);
}
/**
* @param CommandEnumConstraint $constraint
* @param int[] $enumIndexes string enum name -> int index
* @param int[] $enumValueIndexes string value -> int index
*/
protected function putEnumConstraint(CommandEnumConstraint $constraint, array $enumIndexes, array $enumValueIndexes) : void{
$this->putLInt($enumValueIndexes[$constraint->getAffectedValue()]);
$this->putLInt($enumIndexes[$constraint->getEnum()->enumName]);
$this->putUnsignedVarInt(count($constraint->getConstraints()));
foreach($constraint->getConstraints() as $v){
$this->putByte($v);
}
}
/**
* @param CommandEnum[] $enums
* @param string[] $postfixes
@ -226,6 +296,7 @@ class AvailableCommandsPacket extends DataPacket{
$retval->aliases = $enums[$this->getLInt()] ?? null;
for($overloadIndex = 0, $overloadCount = $this->getUnsignedVarInt(); $overloadIndex < $overloadCount; ++$overloadIndex){
$retval->overloads[$overloadIndex] = [];
for($paramIndex = 0, $paramCount = $this->getUnsignedVarInt(); $paramIndex < $paramCount; ++$paramIndex){
$parameter = new CommandParameter();
$parameter->paramName = $this->getString();
@ -347,30 +418,28 @@ class AvailableCommandsPacket extends DataPacket{
$enumIndexes = [];
/** @var CommandEnum[] $enums */
$enums = [];
$addEnumFn = static function(CommandEnum $enum) use (&$enums, &$enumIndexes, &$enumValueIndexes){
if(!isset($enumIndexes[$enum->enumName])){
$enums[$enumIndexes[$enum->enumName] = count($enumIndexes)] = $enum;
}
foreach($enum->enumValues as $str){
$enumValueIndexes[$str] = $enumValueIndexes[$str] ?? count($enumValueIndexes);
}
};
foreach($this->hardcodedEnums as $enum){
$addEnumFn($enum);
}
foreach($this->commandData as $commandData){
if($commandData->aliases !== null){
if(!isset($enumIndexes[$commandData->aliases->enumName])){
$enums[$enumIndexes[$commandData->aliases->enumName] = count($enumIndexes)] = $commandData->aliases;
}
foreach($commandData->aliases->enumValues as $str){
$enumValueIndexes[$str] = $enumValueIndexes[$str] ?? count($enumValueIndexes); //latest index
}
$addEnumFn($commandData->aliases);
}
/** @var CommandParameter[] $overload */
foreach($commandData->overloads as $overload){
/**
* @var CommandParameter[] $overload
* @var CommandParameter $parameter
*/
/** @var CommandParameter $parameter */
foreach($overload as $parameter){
if($parameter->enum !== null){
if(!isset($enumIndexes[$parameter->enum->enumName])){
$enums[$enumIndexes[$parameter->enum->enumName] = count($enumIndexes)] = $parameter->enum;
}
foreach($parameter->enum->enumValues as $str){
$enumValueIndexes[$str] = $enumValueIndexes[$str] ?? count($enumValueIndexes);
}
$addEnumFn($parameter->enum);
}
if($parameter->postfix !== null){
@ -404,6 +473,11 @@ class AvailableCommandsPacket extends DataPacket{
foreach($this->softEnums as $enum){
$this->putSoftEnum($enum);
}
$this->putUnsignedVarInt(count($this->enumConstraints));
foreach($this->enumConstraints as $constraint){
$this->putEnumConstraint($constraint, $enumIndexes, $enumValueIndexes);
}
}
public function handle(NetworkSession $session) : bool{

View File

@ -26,11 +26,14 @@ namespace pocketmine\network\mcpe\protocol;
#include <rules/DataPacket.h>
use pocketmine\network\mcpe\NetworkSession;
use function file_get_contents;
class BiomeDefinitionListPacket extends DataPacket{
public const NETWORK_ID = ProtocolInfo::BIOME_DEFINITION_LIST_PACKET;
public const HARDCODED_NBT_BLOB = "CgAKDWJhbWJvb19qdW5nbGUFCGRvd25mYWxsZmZmPwULdGVtcGVyYXR1cmUzM3M/AAoTYmFtYm9vX2p1bmdsZV9oaWxscwUIZG93bmZhbGxmZmY/BQt0ZW1wZXJhdHVyZTMzcz8ACgViZWFjaAUIZG93bmZhbGzNzMw+BQt0ZW1wZXJhdHVyZc3MTD8ACgxiaXJjaF9mb3Jlc3QFCGRvd25mYWxsmpkZPwULdGVtcGVyYXR1cmWamRk/AAoSYmlyY2hfZm9yZXN0X2hpbGxzBQhkb3duZmFsbJqZGT8FC3RlbXBlcmF0dXJlmpkZPwAKGmJpcmNoX2ZvcmVzdF9oaWxsc19tdXRhdGVkBQhkb3duZmFsbM3MTD8FC3RlbXBlcmF0dXJlMzMzPwAKFGJpcmNoX2ZvcmVzdF9tdXRhdGVkBQhkb3duZmFsbM3MTD8FC3RlbXBlcmF0dXJlMzMzPwAKCmNvbGRfYmVhY2gFCGRvd25mYWxsmpmZPgULdGVtcGVyYXR1cmXNzEw9AAoKY29sZF9vY2VhbgUIZG93bmZhbGwAAAA/BQt0ZW1wZXJhdHVyZQAAAD8ACgpjb2xkX3RhaWdhBQhkb3duZmFsbM3MzD4FC3RlbXBlcmF0dXJlAAAAvwAKEGNvbGRfdGFpZ2FfaGlsbHMFCGRvd25mYWxszczMPgULdGVtcGVyYXR1cmUAAAC/AAoSY29sZF90YWlnYV9tdXRhdGVkBQhkb3duZmFsbM3MzD4FC3RlbXBlcmF0dXJlAAAAvwAKD2RlZXBfY29sZF9vY2VhbgUIZG93bmZhbGwAAAA/BQt0ZW1wZXJhdHVyZQAAAD8AChFkZWVwX2Zyb3plbl9vY2VhbgUIZG93bmZhbGwAAAA/BQt0ZW1wZXJhdHVyZQAAAAAAChNkZWVwX2x1a2V3YXJtX29jZWFuBQhkb3duZmFsbAAAAD8FC3RlbXBlcmF0dXJlAAAAPwAKCmRlZXBfb2NlYW4FCGRvd25mYWxsAAAAPwULdGVtcGVyYXR1cmUAAAA/AAoPZGVlcF93YXJtX29jZWFuBQhkb3duZmFsbAAAAD8FC3RlbXBlcmF0dXJlAAAAPwAKBmRlc2VydAUIZG93bmZhbGwAAAAABQt0ZW1wZXJhdHVyZQAAAEAACgxkZXNlcnRfaGlsbHMFCGRvd25mYWxsAAAAAAULdGVtcGVyYXR1cmUAAABAAAoOZGVzZXJ0X211dGF0ZWQFCGRvd25mYWxsAAAAAAULdGVtcGVyYXR1cmUAAABAAAoNZXh0cmVtZV9oaWxscwUIZG93bmZhbGyamZk+BQt0ZW1wZXJhdHVyZc3MTD4AChJleHRyZW1lX2hpbGxzX2VkZ2UFCGRvd25mYWxsmpmZPgULdGVtcGVyYXR1cmXNzEw+AAoVZXh0cmVtZV9oaWxsc19tdXRhdGVkBQhkb3duZmFsbJqZmT4FC3RlbXBlcmF0dXJlzcxMPgAKGGV4dHJlbWVfaGlsbHNfcGx1c190cmVlcwUIZG93bmZhbGyamZk+BQt0ZW1wZXJhdHVyZc3MTD4ACiBleHRyZW1lX2hpbGxzX3BsdXNfdHJlZXNfbXV0YXRlZAUIZG93bmZhbGyamZk+BQt0ZW1wZXJhdHVyZc3MTD4ACg1mbG93ZXJfZm9yZXN0BQhkb3duZmFsbM3MTD8FC3RlbXBlcmF0dXJlMzMzPwAKBmZvcmVzdAUIZG93bmZhbGzNzEw/BQt0ZW1wZXJhdHVyZTMzMz8ACgxmb3Jlc3RfaGlsbHMFCGRvd25mYWxszcxMPwULdGVtcGVyYXR1cmUzMzM/AAoMZnJvemVuX29jZWFuBQhkb3duZmFsbAAAAD8FC3RlbXBlcmF0dXJlAAAAAAAKDGZyb3plbl9yaXZlcgUIZG93bmZhbGwAAAA/BQt0ZW1wZXJhdHVyZQAAAAAACgRoZWxsBQhkb3duZmFsbAAAAAAFC3RlbXBlcmF0dXJlAAAAQAAKDWljZV9tb3VudGFpbnMFCGRvd25mYWxsAAAAPwULdGVtcGVyYXR1cmUAAAAAAAoKaWNlX3BsYWlucwUIZG93bmZhbGwAAAA/BQt0ZW1wZXJhdHVyZQAAAAAAChFpY2VfcGxhaW5zX3NwaWtlcwUIZG93bmZhbGwAAIA/BQt0ZW1wZXJhdHVyZQAAAAAACgZqdW5nbGUFCGRvd25mYWxsZmZmPwULdGVtcGVyYXR1cmUzM3M/AAoLanVuZ2xlX2VkZ2UFCGRvd25mYWxszcxMPwULdGVtcGVyYXR1cmUzM3M/AAoTanVuZ2xlX2VkZ2VfbXV0YXRlZAUIZG93bmZhbGzNzEw/BQt0ZW1wZXJhdHVyZTMzcz8ACgxqdW5nbGVfaGlsbHMFCGRvd25mYWxsZmZmPwULdGVtcGVyYXR1cmUzM3M/AAoOanVuZ2xlX211dGF0ZWQFCGRvd25mYWxsZmZmPwULdGVtcGVyYXR1cmUzM3M/AAoTbGVnYWN5X2Zyb3plbl9vY2VhbgUIZG93bmZhbGwAAAA/BQt0ZW1wZXJhdHVyZQAAAAAACg5sdWtld2FybV9vY2VhbgUIZG93bmZhbGwAAAA/BQt0ZW1wZXJhdHVyZQAAAD8ACgptZWdhX3RhaWdhBQhkb3duZmFsbM3MTD8FC3RlbXBlcmF0dXJlmpmZPgAKEG1lZ2FfdGFpZ2FfaGlsbHMFCGRvd25mYWxszcxMPwULdGVtcGVyYXR1cmWamZk+AAoEbWVzYQUIZG93bmZhbGwAAAAABQt0ZW1wZXJhdHVyZQAAAEAACgptZXNhX2JyeWNlBQhkb3duZmFsbAAAAAAFC3RlbXBlcmF0dXJlAAAAQAAKDG1lc2FfcGxhdGVhdQUIZG93bmZhbGwAAAAABQt0ZW1wZXJhdHVyZQAAAEAAChRtZXNhX3BsYXRlYXVfbXV0YXRlZAUIZG93bmZhbGwAAAAABQt0ZW1wZXJhdHVyZQAAAEAAChJtZXNhX3BsYXRlYXVfc3RvbmUFCGRvd25mYWxsAAAAAAULdGVtcGVyYXR1cmUAAABAAAoabWVzYV9wbGF0ZWF1X3N0b25lX211dGF0ZWQFCGRvd25mYWxsAAAAAAULdGVtcGVyYXR1cmUAAABAAAoPbXVzaHJvb21faXNsYW5kBQhkb3duZmFsbAAAgD8FC3RlbXBlcmF0dXJlZmZmPwAKFW11c2hyb29tX2lzbGFuZF9zaG9yZQUIZG93bmZhbGwAAIA/BQt0ZW1wZXJhdHVyZWZmZj8ACgVvY2VhbgUIZG93bmZhbGwAAAA/BQt0ZW1wZXJhdHVyZQAAAD8ACgZwbGFpbnMFCGRvd25mYWxszczMPgULdGVtcGVyYXR1cmXNzEw/AAobcmVkd29vZF90YWlnYV9oaWxsc19tdXRhdGVkBQhkb3duZmFsbM3MTD8FC3RlbXBlcmF0dXJlmpmZPgAKFXJlZHdvb2RfdGFpZ2FfbXV0YXRlZAUIZG93bmZhbGzNzEw/BQt0ZW1wZXJhdHVyZQAAgD4ACgVyaXZlcgUIZG93bmZhbGwAAAA/BQt0ZW1wZXJhdHVyZQAAAD8ACg1yb29mZWRfZm9yZXN0BQhkb3duZmFsbM3MTD8FC3RlbXBlcmF0dXJlMzMzPwAKFXJvb2ZlZF9mb3Jlc3RfbXV0YXRlZAUIZG93bmZhbGzNzEw/BQt0ZW1wZXJhdHVyZTMzMz8ACgdzYXZhbm5hBQhkb3duZmFsbAAAAAAFC3RlbXBlcmF0dXJlmpmZPwAKD3NhdmFubmFfbXV0YXRlZAUIZG93bmZhbGwAAAA/BQt0ZW1wZXJhdHVyZc3MjD8ACg9zYXZhbm5hX3BsYXRlYXUFCGRvd25mYWxsAAAAAAULdGVtcGVyYXR1cmUAAIA/AAoXc2F2YW5uYV9wbGF0ZWF1X211dGF0ZWQFCGRvd25mYWxsAAAAPwULdGVtcGVyYXR1cmUAAIA/AAoLc3RvbmVfYmVhY2gFCGRvd25mYWxsmpmZPgULdGVtcGVyYXR1cmXNzEw+AAoQc3VuZmxvd2VyX3BsYWlucwUIZG93bmZhbGzNzMw+BQt0ZW1wZXJhdHVyZc3MTD8ACglzd2FtcGxhbmQFCGRvd25mYWxsAAAAPwULdGVtcGVyYXR1cmXNzEw/AAoRc3dhbXBsYW5kX211dGF0ZWQFCGRvd25mYWxsAAAAPwULdGVtcGVyYXR1cmXNzEw/AAoFdGFpZ2EFCGRvd25mYWxszcxMPwULdGVtcGVyYXR1cmUAAIA+AAoLdGFpZ2FfaGlsbHMFCGRvd25mYWxszcxMPwULdGVtcGVyYXR1cmUAAIA+AAoNdGFpZ2FfbXV0YXRlZAUIZG93bmZhbGzNzEw/BQt0ZW1wZXJhdHVyZQAAgD4ACgd0aGVfZW5kBQhkb3duZmFsbAAAAD8FC3RlbXBlcmF0dXJlAAAAPwAKCndhcm1fb2NlYW4FCGRvd25mYWxsAAAAPwULdGVtcGVyYXR1cmUAAAA/AAA=";
/** @var string|null */
private static $DEFAULT_NBT_CACHE = null;
/** @var string */
public $namedtag;
@ -39,7 +42,11 @@ class BiomeDefinitionListPacket extends DataPacket{
}
protected function encodePayload(){
$this->put($this->namedtag ?? self::HARDCODED_NBT_BLOB);
$this->put(
$this->namedtag ??
self::$DEFAULT_NBT_CACHE ??
(self::$DEFAULT_NBT_CACHE = file_get_contents(\pocketmine\RESOURCE_PATH . '/vanilla/biome_definitions.nbt'))
);
}
public function handle(NetworkSession $session) : bool{

View File

@ -0,0 +1,66 @@
<?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\network\mcpe\protocol;
use pocketmine\network\mcpe\NetworkSession;
class CompletedUsingItemPacket extends DataPacket{
public const NETWORK_ID = ProtocolInfo::COMPLETED_USING_ITEM_PACKET;
public const ACTION_UNKNOWN = -1;
public const ACTION_EQUIP_ARMOR = 0;
public const ACTION_EAT = 1;
public const ACTION_ATTACK = 2;
public const ACTION_CONSUME = 3;
public const ACTION_THROW = 4;
public const ACTION_SHOOT = 5;
public const ACTION_PLACE = 6;
public const ACTION_FILL_BOTTLE = 7;
public const ACTION_FILL_BUCKET = 8;
public const ACTION_POUR_BUCKET = 9;
public const ACTION_USE_TOOL = 10;
public const ACTION_INTERACT = 11;
public const ACTION_RETRIEVED = 12;
public const ACTION_DYED = 13;
public const ACTION_TRADED = 14;
/** @var int */
public $itemId;
/** @var int */
public $action;
public function decodePayload() : void{
$this->itemId = $this->getShort();
$this->action = $this->getLInt();
}
public function encodePayload() : void{
$this->putShort($this->itemId);
$this->putLInt($this->action);
}
public function handle(NetworkSession $session) : bool{
return $session->handleCompletedUsingItem($this);
}
}

View File

@ -33,6 +33,8 @@ use pocketmine\item\Item;
use pocketmine\item\ItemFactory;
use pocketmine\network\mcpe\NetworkBinaryStream;
use pocketmine\network\mcpe\NetworkSession;
use pocketmine\network\mcpe\protocol\types\PotionContainerChangeRecipe;
use pocketmine\network\mcpe\protocol\types\PotionTypeRecipe;
#ifndef COMPILE
use pocketmine\utils\Binary;
#endif
@ -53,6 +55,10 @@ class CraftingDataPacket extends DataPacket{
/** @var object[] */
public $entries = [];
/** @var PotionTypeRecipe[] */
public $potionTypeRecipes = [];
/** @var PotionContainerChangeRecipe[] */
public $potionContainerRecipes = [];
/** @var bool */
public $cleanRecipes = false;
@ -140,7 +146,19 @@ class CraftingDataPacket extends DataPacket{
}
$this->decodedEntries[] = $entry;
}
$this->getBool(); //cleanRecipes
for($i = 0, $count = $this->getUnsignedVarInt(); $i < $count; ++$i){
$input = $this->getVarInt();
$ingredient = $this->getVarInt();
$output = $this->getVarInt();
$this->potionTypeRecipes[] = new PotionTypeRecipe($input, $ingredient, $output);
}
for($i = 0, $count = $this->getUnsignedVarInt(); $i < $count; ++$i){
$input = $this->getVarInt();
$ingredient = $this->getVarInt();
$output = $this->getVarInt();
$this->potionContainerRecipes[] = new PotionContainerChangeRecipe($input, $ingredient, $output);
}
$this->cleanRecipes = $this->getBool();
}
private static function writeEntry($entry, NetworkBinaryStream $stream, int $pos){
@ -240,6 +258,18 @@ class CraftingDataPacket extends DataPacket{
$writer->reset();
}
$this->putUnsignedVarInt(count($this->potionTypeRecipes));
foreach($this->potionTypeRecipes as $recipe){
$this->putVarInt($recipe->getInputPotionType());
$this->putVarInt($recipe->getIngredientItemId());
$this->putVarInt($recipe->getOutputPotionType());
}
$this->putUnsignedVarInt(count($this->potionContainerRecipes));
foreach($this->potionContainerRecipes as $recipe){
$this->putVarInt($recipe->getInputItemId());
$this->putVarInt($recipe->getIngredientItemId());
$this->putVarInt($recipe->getOutputItemId());
}
$this->putBool($this->cleanRecipes);
}

View File

@ -135,7 +135,7 @@ abstract class DataPacket extends NetworkBinaryStream{
abstract public function handle(NetworkSession $session) : bool;
public function clean(){
$this->buffer = null;
$this->buffer = "";
$this->isEncoded = false;
$this->offset = 0;
return $this;
@ -143,7 +143,7 @@ abstract class DataPacket extends NetworkBinaryStream{
public function __debugInfo(){
$data = [];
foreach($this as $k => $v){
foreach((array) $this as $k => $v){
if($k === "buffer" and is_string($v)){
$data[$k] = bin2hex($v);
}elseif(is_string($v) or (is_object($v) and method_exists($v, "__toString"))){

View File

@ -0,0 +1,66 @@
<?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\network\mcpe\protocol;
#include <rules/DataPacket.h>
use pocketmine\network\mcpe\NetworkSession;
class EducationSettingsPacket extends DataPacket{
public const NETWORK_ID = ProtocolInfo::EDUCATION_SETTINGS_PACKET;
/** @var string */
private $codeBuilderDefaultUri;
/** @var bool */
private $hasQuiz;
public static function create(string $codeBuilderDefaultUri, bool $hasQuiz) : self{
$result = new self;
$result->codeBuilderDefaultUri = $codeBuilderDefaultUri;
$result->hasQuiz = $hasQuiz;
return $result;
}
public function getCodeBuilderDefaultUri() : string{
return $this->codeBuilderDefaultUri;
}
public function getHasQuiz() : bool{
return $this->hasQuiz;
}
protected function decodePayload() : void{
$this->codeBuilderDefaultUri = $this->getString();
$this->hasQuiz = $this->getBool();
}
protected function encodePayload() : void{
$this->putString($this->codeBuilderDefaultUri);
$this->putBool($this->hasQuiz);
}
public function handle(NetworkSession $handler) : bool{
return $handler->handleEducationSettings($this);
}
}

View File

@ -0,0 +1,81 @@
<?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\network\mcpe\protocol;
#include <rules/DataPacket.h>
use pocketmine\network\mcpe\NetworkSession;
class EmotePacket extends DataPacket/* implements ClientboundPacket, ServerboundPacket*/{
public const NETWORK_ID = ProtocolInfo::EMOTE_PACKET;
private const FLAG_SERVER = 1 << 0;
/** @var int */
private $entityRuntimeId;
/** @var string */
private $emoteId;
/** @var int */
private $flags;
public static function create(int $entityRuntimeId, string $emoteId, int $flags) : self{
$result = new self;
$result->entityRuntimeId = $entityRuntimeId;
$result->emoteId = $emoteId;
$result->flags = $flags;
return $result;
}
/**
* TODO: we can't call this getEntityRuntimeId() because of base class collision (crap architecture, thanks Shoghi)
* @return int
*/
public function getEntityRuntimeIdField() : int{
return $this->entityRuntimeId;
}
public function getEmoteId() : string{
return $this->emoteId;
}
public function getFlags() : int{
return $this->flags;
}
protected function decodePayload() : void{
$this->entityRuntimeId = $this->getEntityRuntimeId();
$this->emoteId = $this->getString();
$this->flags = $this->getByte();
}
protected function encodePayload() : void{
$this->putEntityRuntimeId($this->entityRuntimeId);
$this->putString($this->emoteId);
$this->putByte($this->flags);
}
public function handle(NetworkSession $handler) : bool{
return $handler->handleEmote($this);
}
}

View File

@ -1,73 +0,0 @@
<?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\network\mcpe\protocol;
#include <rules/DataPacket.h>
use pocketmine\math\Vector3;
use pocketmine\network\mcpe\NetworkSession;
use function count;
class ExplodePacket extends DataPacket{
public const NETWORK_ID = ProtocolInfo::EXPLODE_PACKET;
/** @var Vector3 */
public $position;
/** @var float */
public $radius;
/** @var Vector3[] */
public $records = [];
public function clean(){
$this->records = [];
return parent::clean();
}
protected function decodePayload(){
$this->position = $this->getVector3();
$this->radius = (float) ($this->getVarInt() / 32);
$count = $this->getUnsignedVarInt();
for($i = 0; $i < $count; ++$i){
$x = $y = $z = null;
$this->getSignedBlockPosition($x, $y, $z);
$this->records[$i] = new Vector3($x, $y, $z);
}
}
protected function encodePayload(){
$this->putVector3($this->position);
$this->putVarInt((int) ($this->radius * 32));
$this->putUnsignedVarInt(count($this->records));
if(count($this->records) > 0){
foreach($this->records as $record){
$this->putSignedBlockPosition((int) $record->x, (int) $record->y, (int) $record->z);
}
}
}
public function handle(NetworkSession $session) : bool{
return $session->handleExplode($this);
}
}

View File

@ -26,6 +26,7 @@ namespace pocketmine\network\mcpe\protocol;
#include <rules/DataPacket.h>
use pocketmine\network\mcpe\NetworkSession;
use pocketmine\network\mcpe\protocol\types\ContainerIds;
use pocketmine\network\mcpe\protocol\types\NetworkInventoryAction;
use function count;
@ -74,7 +75,26 @@ class InventoryTransactionPacket extends DataPacket{
$this->transactionType = $this->getUnsignedVarInt();
for($i = 0, $count = $this->getUnsignedVarInt(); $i < $count; ++$i){
$this->actions[] = (new NetworkInventoryAction())->read($this);
$this->actions[] = $action = (new NetworkInventoryAction())->read($this);
if(
$action->sourceType === NetworkInventoryAction::SOURCE_CONTAINER and
$action->windowId === ContainerIds::UI and
$action->inventorySlot === 50 and
!$action->oldItem->equalsExact($action->newItem)
){
$this->isCraftingPart = true;
if(!$action->oldItem->isNull() and $action->newItem->isNull()){
$this->isFinalCraftingPart = true;
}
}elseif(
$action->sourceType === NetworkInventoryAction::SOURCE_TODO and (
$action->windowId === NetworkInventoryAction::SOURCE_TYPE_CRAFTING_RESULT or
$action->windowId === NetworkInventoryAction::SOURCE_TYPE_CRAFTING_USE_INGREDIENT
)
){
$this->isCraftingPart = true;
}
}
$this->trData = new \stdClass();

View File

@ -70,7 +70,7 @@ class MoveActorDeltaPacket extends DataPacket{
protected function decodePayload(){
$this->entityRuntimeId = $this->getEntityRuntimeId();
$this->flags = $this->getByte();
$this->flags = $this->getLShort();
$this->xDiff = $this->maybeReadCoord(self::FLAG_HAS_X);
$this->yDiff = $this->maybeReadCoord(self::FLAG_HAS_Y);
$this->zDiff = $this->maybeReadCoord(self::FLAG_HAS_Z);
@ -93,7 +93,7 @@ class MoveActorDeltaPacket extends DataPacket{
protected function encodePayload(){
$this->putEntityRuntimeId($this->entityRuntimeId);
$this->putByte($this->flags);
$this->putLShort($this->flags);
$this->maybeWriteCoord(self::FLAG_HAS_X, $this->xDiff);
$this->maybeWriteCoord(self::FLAG_HAS_Y, $this->yDiff);
$this->maybeWriteCoord(self::FLAG_HAS_Z, $this->zDiff);

View File

@ -0,0 +1,61 @@
<?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\network\mcpe\protocol;
#include <rules/DataPacket.h>
use pocketmine\network\mcpe\NetworkSession;
class MultiplayerSettingsPacket extends DataPacket/* implements ServerboundPacket*/{ //TODO: this might be clientbound too, but unsure
public const NETWORK_ID = ProtocolInfo::MULTIPLAYER_SETTINGS_PACKET;
public const ACTION_ENABLE_MULTIPLAYER = 0;
public const ACTION_DISABLE_MULTIPLAYER = 1;
public const ACTION_REFRESH_JOIN_CODE = 2;
/** @var int */
private $action;
public static function create(int $action) : self{
$result = new self;
$result->action = $action;
return $result;
}
public function getAction() : int{
return $this->action;
}
protected function decodePayload() : void{
$this->action = $this->getVarInt();
}
protected function encodePayload() : void{
$this->putVarInt($this->action);
}
public function handle(NetworkSession $handler) : bool{
return $handler->handleMultiplayerSettings($this);
}
}

View File

@ -0,0 +1,60 @@
<?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\network\mcpe\protocol;
#include <rules/DataPacket.h>
use pocketmine\network\mcpe\NetworkSession;
class NetworkSettingsPacket extends DataPacket/* implements ClientboundPacket*/{
public const NETWORK_ID = ProtocolInfo::NETWORK_SETTINGS_PACKET;
public const COMPRESS_NOTHING = 0;
public const COMPRESS_EVERYTHING = 1;
/** @var int */
private $compressionThreshold;
public static function create(int $compressionThreshold) : self{
$result = new self;
$result->compressionThreshold = $compressionThreshold;
return $result;
}
public function getCompressionThreshold() : int{
return $this->compressionThreshold;
}
protected function decodePayload() : void{
$this->compressionThreshold = $this->getLShort();
}
protected function encodePayload() : void{
$this->putLShort($this->compressionThreshold);
}
public function handle(NetworkSession $handler) : bool{
return $handler->handleNetworkSettings($this);
}
}

View File

@ -54,7 +54,7 @@ class PacketPool{
static::registerPacket(new RiderJumpPacket());
static::registerPacket(new UpdateBlockPacket());
static::registerPacket(new AddPaintingPacket());
static::registerPacket(new ExplodePacket());
static::registerPacket(new TickSyncPacket());
static::registerPacket(new LevelSoundEventPacketV1());
static::registerPacket(new LevelEventPacket());
static::registerPacket(new BlockEventPacket());
@ -162,11 +162,19 @@ class PacketPool{
static::registerPacket(new ClientCacheStatusPacket());
static::registerPacket(new OnScreenTextureAnimationPacket());
static::registerPacket(new MapCreateLockedCopyPacket());
static::registerPacket(new StructureTemplateDataExportRequestPacket());
static::registerPacket(new StructureTemplateDataExportResponsePacket());
static::registerPacket(new StructureTemplateDataRequestPacket());
static::registerPacket(new StructureTemplateDataResponsePacket());
static::registerPacket(new UpdateBlockPropertiesPacket());
static::registerPacket(new ClientCacheBlobStatusPacket());
static::registerPacket(new ClientCacheMissResponsePacket());
static::registerPacket(new EducationSettingsPacket());
static::registerPacket(new EmotePacket());
static::registerPacket(new MultiplayerSettingsPacket());
static::registerPacket(new SettingsCommandPacket());
static::registerPacket(new AnvilDamagePacket());
static::registerPacket(new CompletedUsingItemPacket());
static::registerPacket(new NetworkSettingsPacket());
static::registerPacket(new PlayerAuthInputPacket());
}
/**

View File

@ -0,0 +1,175 @@
<?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\network\mcpe\protocol;
#include <rules/DataPacket.h>
use pocketmine\math\Vector3;
use pocketmine\network\mcpe\NetworkSession;
use pocketmine\network\mcpe\protocol\types\InputMode;
use pocketmine\network\mcpe\protocol\types\PlayMode;
use function assert;
class PlayerAuthInputPacket extends DataPacket/* implements ServerboundPacket*/{
public const NETWORK_ID = ProtocolInfo::PLAYER_AUTH_INPUT_PACKET;
/** @var Vector3 */
private $position;
/** @var float */
private $pitch;
/** @var float */
private $yaw;
/** @var float */
private $headYaw;
/** @var float */
private $moveVecX;
/** @var float */
private $moveVecZ;
/** @var int */
private $inputFlags;
/** @var int */
private $inputMode;
/** @var int */
private $playMode;
/** @var Vector3|null */
private $vrGazeDirection = null;
/**
* @param Vector3 $position
* @param float $pitch
* @param float $yaw
* @param float $headYaw
* @param float $moveVecX
* @param float $moveVecZ
* @param int $inputFlags
* @param int $inputMode @see InputMode
* @param int $playMode @see PlayMode
* @param Vector3|null $vrGazeDirection only used when PlayMode::VR
*
* @return self
*/
public static function create(Vector3 $position, float $pitch, float $yaw, float $headYaw, float $moveVecX, float $moveVecZ, int $inputFlags, int $inputMode, int $playMode, ?Vector3 $vrGazeDirection = null) : self{
if($playMode === PlayMode::VR and $vrGazeDirection === null){
//yuck, can we get a properly written packet just once? ...
throw new \InvalidArgumentException("Gaze direction must be provided for VR play mode");
}
$result = new self;
$result->position = $position->asVector3();
$result->pitch = $pitch;
$result->yaw = $yaw;
$result->headYaw = $headYaw;
$result->moveVecX = $moveVecX;
$result->moveVecZ = $moveVecZ;
$result->inputFlags = $inputFlags;
$result->inputMode = $inputMode;
$result->playMode = $playMode;
if($vrGazeDirection !== null){
$this->vrGazeDirection = $vrGazeDirection->asVector3();
}
return $result;
}
public function getPosition() : Vector3{
return $this->position;
}
public function getPitch() : float{
return $this->pitch;
}
public function getYaw() : float{
return $this->yaw;
}
public function getHeadYaw() : float{
return $this->headYaw;
}
public function getMoveVecX() : float{
return $this->moveVecX;
}
public function getMoveVecZ() : float{
return $this->moveVecZ;
}
public function getInputFlags() : int{
return $this->inputFlags;
}
/**
* @see InputMode
* @return int
*/
public function getInputMode() : int{
return $this->inputMode;
}
/**
* @see PlayMode
* @return int
*/
public function getPlayMode() : int{
return $this->playMode;
}
public function getVrGazeDirection() : ?Vector3{
return $this->vrGazeDirection;
}
protected function decodePayload() : void{
$this->yaw = $this->getLFloat();
$this->pitch = $this->getLFloat();
$this->position = $this->getVector3();
$this->moveVecX = $this->getLFloat();
$this->moveVecZ = $this->getLFloat();
$this->headYaw = $this->getLFloat();
$this->inputFlags = $this->getUnsignedVarLong();
$this->inputMode = $this->getUnsignedVarInt();
$this->playMode = $this->getUnsignedVarInt();
if($this->playMode === PlayMode::VR){
$this->vrGazeDirection = $this->getVector3();
}
}
protected function encodePayload() : void{
$this->putLFloat($this->yaw);
$this->putLFloat($this->pitch);
$this->putVector3($this->position);
$this->putLFloat($this->moveVecX);
$this->putLFloat($this->moveVecZ);
$this->putLFloat($this->headYaw);
$this->putUnsignedVarLong($this->inputFlags);
$this->putUnsignedVarInt($this->inputMode);
$this->putUnsignedVarInt($this->playMode);
if($this->playMode === PlayMode::VR){
assert($this->vrGazeDirection !== null);
$this->putVector3($this->vrGazeDirection);
}
}
public function handle(NetworkSession $handler) : bool{
return $handler->handlePlayerAuthInput($this);
}
}

View File

@ -26,8 +26,8 @@ namespace pocketmine\network\mcpe\protocol;
#include <rules/DataPacket.h>
use pocketmine\entity\Skin;
use pocketmine\network\mcpe\NetworkSession;
use pocketmine\network\mcpe\protocol\types\SkinData;
use pocketmine\network\mcpe\protocol\types\PlayerListEntry;
use function count;
@ -57,22 +57,12 @@ class PlayerListPacket extends DataPacket{
$entry->uuid = $this->getUUID();
$entry->entityUniqueId = $this->getEntityUniqueId();
$entry->username = $this->getString();
$skinId = $this->getString();
$skinData = $this->getString();
$capeData = $this->getString();
$geometryName = $this->getString();
$geometryData = $this->getString();
$entry->skin = new Skin(
$skinId,
$skinData,
$capeData,
$geometryName,
$geometryData
);
$entry->xboxUserId = $this->getString();
$entry->platformChatId = $this->getString();
$entry->buildPlatform = $this->getLInt();
$entry->skinData = $this->getSkin();
$entry->isTeacher = $this->getBool();
$entry->isHost = $this->getBool();
}else{
$entry->uuid = $this->getUUID();
}
@ -89,13 +79,12 @@ class PlayerListPacket extends DataPacket{
$this->putUUID($entry->uuid);
$this->putEntityUniqueId($entry->entityUniqueId);
$this->putString($entry->username);
$this->putString($entry->skin->getSkinId());
$this->putString($entry->skin->getSkinData());
$this->putString($entry->skin->getCapeData());
$this->putString($entry->skin->getGeometryName());
$this->putString($entry->skin->getGeometryData());
$this->putString($entry->xboxUserId);
$this->putString($entry->platformChatId);
$this->putLInt($entry->buildPlatform);
$this->putSkin($entry->skinData);
$this->putBool($entry->isTeacher);
$this->putBool($entry->isHost);
}else{
$this->putUUID($entry->uuid);
}

View File

@ -25,8 +25,8 @@ namespace pocketmine\network\mcpe\protocol;
#include <rules/DataPacket.h>
use pocketmine\entity\Skin;
use pocketmine\network\mcpe\NetworkSession;
use pocketmine\network\mcpe\protocol\types\SkinData;
use pocketmine\utils\UUID;
class PlayerSkinPacket extends DataPacket{
@ -38,39 +38,21 @@ class PlayerSkinPacket extends DataPacket{
public $oldSkinName = "";
/** @var string */
public $newSkinName = "";
/** @var Skin */
/** @var SkinData */
public $skin;
/** @var bool */
public $premiumSkin = false;
protected function decodePayload(){
$this->uuid = $this->getUUID();
$skinId = $this->getString();
$this->skin = $this->getSkin();
$this->newSkinName = $this->getString();
$this->oldSkinName = $this->getString();
$skinData = $this->getString();
$capeData = $this->getString();
$geometryModel = $this->getString();
$geometryData = $this->getString();
$this->skin = new Skin($skinId, $skinData, $capeData, $geometryModel, $geometryData);
$this->premiumSkin = $this->getBool();
}
protected function encodePayload(){
$this->putUUID($this->uuid);
$this->putString($this->skin->getSkinId());
$this->putSkin($this->skin);
$this->putString($this->newSkinName);
$this->putString($this->oldSkinName);
$this->putString($this->skin->getSkinData());
$this->putString($this->skin->getCapeData());
$this->putString($this->skin->getGeometryName());
$this->putString($this->skin->getGeometryData());
$this->putBool($this->premiumSkin);
}
public function handle(NetworkSession $session) : bool{

View File

@ -39,15 +39,15 @@ interface ProtocolInfo{
/**
* Actual Minecraft: PE protocol version
*/
public const CURRENT_PROTOCOL = 361;
public const CURRENT_PROTOCOL = 388;
/**
* Current Minecraft PE version reported by the server. This is usually the earliest currently supported version.
*/
public const MINECRAFT_VERSION = 'v1.12.0';
public const MINECRAFT_VERSION = 'v1.13.0';
/**
* Version number sent to clients in ping responses.
*/
public const MINECRAFT_VERSION_NETWORK = '1.12.0';
public const MINECRAFT_VERSION_NETWORK = '1.13.0';
public const LOGIN_PACKET = 0x01;
public const PLAY_STATUS_PACKET = 0x02;
@ -71,7 +71,7 @@ interface ProtocolInfo{
public const RIDER_JUMP_PACKET = 0x14;
public const UPDATE_BLOCK_PACKET = 0x15;
public const ADD_PAINTING_PACKET = 0x16;
public const EXPLODE_PACKET = 0x17;
public const TICK_SYNC_PACKET = 0x17;
public const LEVEL_SOUND_EVENT_PACKET_V1 = 0x18;
public const LEVEL_EVENT_PACKET = 0x19;
public const BLOCK_EVENT_PACKET = 0x1a;
@ -180,10 +180,18 @@ interface ProtocolInfo{
public const CLIENT_CACHE_STATUS_PACKET = 0x81;
public const ON_SCREEN_TEXTURE_ANIMATION_PACKET = 0x82;
public const MAP_CREATE_LOCKED_COPY_PACKET = 0x83;
public const STRUCTURE_TEMPLATE_DATA_EXPORT_REQUEST_PACKET = 0x84;
public const STRUCTURE_TEMPLATE_DATA_EXPORT_RESPONSE_PACKET = 0x85;
public const STRUCTURE_TEMPLATE_DATA_REQUEST_PACKET = 0x84;
public const STRUCTURE_TEMPLATE_DATA_RESPONSE_PACKET = 0x85;
public const UPDATE_BLOCK_PROPERTIES_PACKET = 0x86;
public const CLIENT_CACHE_BLOB_STATUS_PACKET = 0x87;
public const CLIENT_CACHE_MISS_RESPONSE_PACKET = 0x88;
public const EDUCATION_SETTINGS_PACKET = 0x89;
public const EMOTE_PACKET = 0x8a;
public const MULTIPLAYER_SETTINGS_PACKET = 0x8b;
public const SETTINGS_COMMAND_PACKET = 0x8c;
public const ANVIL_DAMAGE_PACKET = 0x8d;
public const COMPLETED_USING_ITEM_PACKET = 0x8e;
public const NETWORK_SETTINGS_PACKET = 0x8f;
public const PLAYER_AUTH_INPUT_PACKET = 0x90;
}

View File

@ -46,15 +46,14 @@ class ResourcePackChunkDataPacket extends DataPacket{
$this->packId = $this->getString();
$this->chunkIndex = $this->getLInt();
$this->progress = $this->getLLong();
$this->data = $this->get($this->getLInt());
$this->data = $this->getString();
}
protected function encodePayload(){
$this->putString($this->packId);
$this->putLInt($this->chunkIndex);
$this->putLLong($this->progress);
$this->putLInt(strlen($this->data));
$this->put($this->data);
$this->putString($this->data);
}
public function handle(NetworkSession $session) : bool{

View File

@ -44,6 +44,8 @@ class ResourcePackStackPacket extends DataPacket{
/** @var bool */
public $isExperimental = false;
/** @var string */
public $baseGameVersion = ProtocolInfo::MINECRAFT_VERSION_NETWORK;
protected function decodePayload(){
$this->mustAccept = $this->getBool();
@ -62,6 +64,7 @@ class ResourcePackStackPacket extends DataPacket{
}
$this->isExperimental = $this->getBool();
$this->baseGameVersion = $this->getString();
}
protected function encodePayload(){
@ -82,6 +85,7 @@ class ResourcePackStackPacket extends DataPacket{
}
$this->putBool($this->isExperimental);
$this->putString($this->baseGameVersion);
}
public function handle(NetworkSession $session) : bool{

View File

@ -32,15 +32,27 @@ use pocketmine\network\mcpe\NetworkSession;
class RespawnPacket extends DataPacket{
public const NETWORK_ID = ProtocolInfo::RESPAWN_PACKET;
public const SEARCHING_FOR_SPAWN = 0;
public const READY_TO_SPAWN = 1;
public const CLIENT_READY_TO_SPAWN = 2;
/** @var Vector3 */
public $position;
/** @var int */
public $respawnState = self::SEARCHING_FOR_SPAWN;
/** @var int */
public $entityRuntimeId;
protected function decodePayload(){
$this->position = $this->getVector3();
$this->respawnState = $this->getByte();
$this->entityRuntimeId = $this->getEntityRuntimeId();
}
protected function encodePayload(){
$this->putVector3($this->position);
$this->putByte($this->respawnState);
$this->putEntityRuntimeId($this->entityRuntimeId);
}
public function handle(NetworkSession $session) : bool{

View File

@ -0,0 +1,66 @@
<?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\network\mcpe\protocol;
#include <rules/DataPacket.h>
use pocketmine\network\mcpe\NetworkSession;
class SettingsCommandPacket extends DataPacket/* implements ServerboundPacket*/{
public const NETWORK_ID = ProtocolInfo::SETTINGS_COMMAND_PACKET;
/** @var string */
private $command;
/** @var bool */
private $suppressOutput;
public static function create(string $command, bool $suppressOutput) : self{
$result = new self;
$result->command = $command;
$result->suppressOutput = $suppressOutput;
return $result;
}
public function getCommand() : string{
return $this->command;
}
public function getSuppressOutput() : bool{
return $this->suppressOutput;
}
protected function decodePayload() : void{
$this->command = $this->getString();
$this->suppressOutput = $this->getBool();
}
protected function encodePayload() : void{
$this->putString($this->command);
$this->putBool($this->suppressOutput);
}
public function handle(NetworkSession $handler) : bool{
return $handler->handleSettingsCommand($this);
}
}

View File

@ -27,6 +27,10 @@ namespace pocketmine\network\mcpe\protocol;
use pocketmine\math\Vector3;
use pocketmine\nbt\NetworkLittleEndianNBTStream;
use pocketmine\nbt\tag\CompoundTag;
use pocketmine\nbt\tag\ListTag;
use pocketmine\nbt\tag\StringTag;
use pocketmine\network\mcpe\NetworkBinaryStream;
use pocketmine\network\mcpe\NetworkSession;
use pocketmine\network\mcpe\protocol\types\PlayerPermissions;
@ -79,8 +83,8 @@ class StartGamePacket extends DataPacket{
public $hasAchievementsDisabled = true;
/** @var int */
public $time = -1;
/** @var bool */
public $eduMode = false;
/** @var int */
public $eduEditionOffer = 0;
/** @var bool */
public $hasEduFeaturesEnabled = false;
/** @var float */
@ -130,6 +134,8 @@ class StartGamePacket extends DataPacket{
/** @var bool */
public $onlySpawnV1Villagers = false;
/** @var string */
public $vanillaVersion = ProtocolInfo::MINECRAFT_VERSION_NETWORK;
/** @var string */
public $levelId = ""; //base64 string, usually the same as world folder name in vanilla
/** @var string */
@ -138,6 +144,8 @@ class StartGamePacket extends DataPacket{
public $premiumWorldTemplateId = "";
/** @var bool */
public $isTrial = false;
/** @var bool */
public $isMovementServerAuthoritative = false;
/** @var int */
public $currentTick = 0; //only used if isTrial is true
/** @var int */
@ -145,7 +153,7 @@ class StartGamePacket extends DataPacket{
/** @var string */
public $multiplayerCorrelationId = ""; //TODO: this should be filled with a UUID of some sort
/** @var array|null ["name" (string), "data" (int16), "legacy_id" (int16)] */
/** @var ListTag|null */
public $blockTable = null;
/** @var array|null string (name) => int16 (legacyID) */
public $itemTable = null;
@ -169,7 +177,7 @@ class StartGamePacket extends DataPacket{
$this->getBlockPosition($this->spawnX, $this->spawnY, $this->spawnZ);
$this->hasAchievementsDisabled = $this->getBool();
$this->time = $this->getVarInt();
$this->eduMode = $this->getBool();
$this->eduEditionOffer = $this->getVarInt();
$this->hasEduFeaturesEnabled = $this->getBool();
$this->rainLevel = $this->getLFloat();
$this->lightningLevel = $this->getLFloat();
@ -193,22 +201,22 @@ class StartGamePacket extends DataPacket{
$this->isWorldTemplateOptionLocked = $this->getBool();
$this->onlySpawnV1Villagers = $this->getBool();
$this->vanillaVersion = $this->getString();
$this->levelId = $this->getString();
$this->worldName = $this->getString();
$this->premiumWorldTemplateId = $this->getString();
$this->isTrial = $this->getBool();
$this->isMovementServerAuthoritative = $this->getBool();
$this->currentTick = $this->getLLong();
$this->enchantmentSeed = $this->getVarInt();
$this->blockTable = [];
for($i = 0, $count = $this->getUnsignedVarInt(); $i < $count; ++$i){
$id = $this->getString();
$data = $this->getSignedLShort();
$unknown = $this->getSignedLShort();
$this->blockTable[$i] = ["name" => $id, "data" => $data, "legacy_id" => $unknown];
$blockTable = (new NetworkLittleEndianNBTStream())->read($this->buffer, false, $this->offset, 512);
if(!($blockTable instanceof ListTag)){
throw new \UnexpectedValueException("Wrong block table root NBT tag type");
}
$this->blockTable = $blockTable;
$this->itemTable = [];
for($i = 0, $count = $this->getUnsignedVarInt(); $i < $count; ++$i){
$id = $this->getString();
@ -239,7 +247,7 @@ class StartGamePacket extends DataPacket{
$this->putBlockPosition($this->spawnX, $this->spawnY, $this->spawnZ);
$this->putBool($this->hasAchievementsDisabled);
$this->putVarInt($this->time);
$this->putBool($this->eduMode);
$this->putVarInt($this->eduEditionOffer);
$this->putBool($this->hasEduFeaturesEnabled);
$this->putLFloat($this->rainLevel);
$this->putLFloat($this->lightningLevel);
@ -263,10 +271,12 @@ class StartGamePacket extends DataPacket{
$this->putBool($this->isWorldTemplateOptionLocked);
$this->putBool($this->onlySpawnV1Villagers);
$this->putString($this->vanillaVersion);
$this->putString($this->levelId);
$this->putString($this->worldName);
$this->putString($this->premiumWorldTemplateId);
$this->putBool($this->isTrial);
$this->putBool($this->isMovementServerAuthoritative);
$this->putLLong($this->currentTick);
$this->putVarInt($this->enchantmentSeed);
@ -274,11 +284,11 @@ class StartGamePacket extends DataPacket{
if($this->blockTable === null){
if(self::$blockTableCache === null){
//this is a really nasty hack, but it'll do for now
self::$blockTableCache = self::serializeBlockTable(RuntimeBlockMapping::getBedrockKnownStates());
self::$blockTableCache = (new NetworkLittleEndianNBTStream())->write(new ListTag("", RuntimeBlockMapping::getBedrockKnownStates()));
}
$this->put(self::$blockTableCache);
}else{
$this->put(self::serializeBlockTable($this->blockTable));
$this->put((new NetworkLittleEndianNBTStream())->write($this->blockTable));
}
if($this->itemTable === null){
if(self::$itemTableCache === null){
@ -292,17 +302,6 @@ class StartGamePacket extends DataPacket{
$this->putString($this->multiplayerCorrelationId);
}
private static function serializeBlockTable(array $table) : string{
$stream = new NetworkBinaryStream();
$stream->putUnsignedVarInt(count($table));
foreach($table as $v){
$stream->putString($v["name"]);
$stream->putLShort($v["data"]);
$stream->putLShort($v["legacy_id"]);
}
return $stream->getBuffer();
}
private static function serializeItemTable(array $table) : string{
$stream = new NetworkBinaryStream();
$stream->putUnsignedVarInt(count($table));

View File

@ -28,8 +28,8 @@ namespace pocketmine\network\mcpe\protocol;
use pocketmine\network\mcpe\NetworkSession;
use pocketmine\network\mcpe\protocol\types\StructureSettings;
class StructureTemplateDataExportRequestPacket extends DataPacket{
public const NETWORK_ID = ProtocolInfo::STRUCTURE_TEMPLATE_DATA_EXPORT_REQUEST_PACKET;
class StructureTemplateDataRequestPacket extends DataPacket{
public const NETWORK_ID = ProtocolInfo::STRUCTURE_TEMPLATE_DATA_REQUEST_PACKET;
public const TYPE_ALWAYS_LOAD = 1;
public const TYPE_CREATE_AND_LOAD = 2;
@ -62,6 +62,6 @@ class StructureTemplateDataExportRequestPacket extends DataPacket{
}
public function handle(NetworkSession $handler) : bool{
return $handler->handleStructureTemplateDataExportRequest($this);
return $handler->handleStructureTemplateDataRequest($this);
}
}

View File

@ -27,8 +27,8 @@ namespace pocketmine\network\mcpe\protocol;
use pocketmine\network\mcpe\NetworkSession;
class StructureTemplateDataExportResponsePacket extends DataPacket{
public const NETWORK_ID = ProtocolInfo::STRUCTURE_TEMPLATE_DATA_EXPORT_RESPONSE_PACKET;
class StructureTemplateDataResponsePacket extends DataPacket{
public const NETWORK_ID = ProtocolInfo::STRUCTURE_TEMPLATE_DATA_RESPONSE_PACKET;
/** @var string */
public $structureTemplateName;
@ -51,6 +51,6 @@ class StructureTemplateDataExportResponsePacket extends DataPacket{
}
public function handle(NetworkSession $handler) : bool{
return $handler->handleStructureTemplateDataExportResponse($this);
return $handler->handleStructureTemplateDataResponse($this);
}
}

View File

@ -0,0 +1,73 @@
<?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\network\mcpe\protocol;
#include <rules/DataPacket.h>
use pocketmine\network\mcpe\NetworkSession;
class TickSyncPacket extends DataPacket/* implements ClientboundPacket, ServerboundPacket*/{
public const NETWORK_ID = ProtocolInfo::TICK_SYNC_PACKET;
/** @var int */
private $clientSendTime;
/** @var int */
private $serverReceiveTime;
public static function request(int $clientTime) : self{
$result = new self;
$result->clientSendTime = $clientTime;
$result->serverReceiveTime = 0; //useless
return $result;
}
public static function response(int $clientSendTime, int $serverReceiveTime) : self{
$result = new self;
$result->clientSendTime = $clientSendTime;
$result->serverReceiveTime = $serverReceiveTime;
return $result;
}
public function getClientSendTime() : int{
return $this->clientSendTime;
}
public function getServerReceiveTime() : int{
return $this->serverReceiveTime;
}
protected function decodePayload() : void{
$this->clientSendTime = $this->getLLong();
$this->serverReceiveTime = $this->getLLong();
}
protected function encodePayload() : void{
$this->putLLong($this->clientSendTime);
$this->putLLong($this->serverReceiveTime);
}
public function handle(NetworkSession $handler) : bool{
return $handler->handleTickSync($this);
}
}

View File

@ -0,0 +1,67 @@
<?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\network\mcpe\protocol\types;
class CommandEnumConstraint{
/** @var CommandEnum */
private $enum;
/** @var int */
private $valueOffset;
/** @var int[] */
private $constraints; //TODO: find constants
/**
* @param CommandEnum $enum
* @param int $valueOffset
* @param int[] $constraints
*/
public function __construct(CommandEnum $enum, int $valueOffset, array $constraints){
(static function(int ...$_){})(...$constraints);
if(!isset($enum->enumValues[$valueOffset])){
throw new \InvalidArgumentException("Invalid enum value offset $valueOffset");
}
$this->enum = $enum;
$this->valueOffset = $valueOffset;
$this->constraints = $constraints;
}
public function getEnum() : CommandEnum{
return $this->enum;
}
public function getValueOffset() : int{
return $this->valueOffset;
}
public function getAffectedValue() : string{
return $this->enum->enumValues[$this->valueOffset];
}
/**
* @return int[]
*/
public function getConstraints() : array{
return $this->constraints;
}
}

View File

@ -24,6 +24,9 @@ declare(strict_types=1);
namespace pocketmine\network\mcpe\protocol\types;
class CommandParameter{
public const FLAG_FORCE_COLLAPSE_ENUM = 0x1;
public const FLAG_HAS_ENUM_CONSTRAINT = 0x2;
/** @var string */
public $paramName;
/** @var int */

View File

@ -34,6 +34,6 @@ interface ContainerIds{
public const CREATIVE = 121;
public const HOTBAR = 122;
public const FIXED_INVENTORY = 123;
public const CURSOR = 124;
public const UI = 124;
}

View File

@ -0,0 +1,36 @@
<?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\network\mcpe\protocol\types;
final class InputMode{
private function __construct(){
//NOOP
}
public const MOUSE_KEYBOARD = 1;
public const TOUCHSCREEN = 2;
public const GAME_PAD = 3;
public const MOTION_CONTROLLER = 4;
}

View File

@ -0,0 +1,63 @@
<?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\network\mcpe\protocol\types;
use pocketmine\entity\Skin;
use function is_array;
use function is_string;
class LegacySkinAdapter implements SkinAdapter{
public function toSkinData(Skin $skin) : SkinData{
$capeData = new SkinImage(32, 64, $skin->getCapeData());
if($skin->getCapeData() === ""){
$capeData = new SkinImage(0, 0, $skin->getCapeData());
}
return new SkinData(
$skin->getSkinId(),
json_encode(["geometry" => ["default" => $skin->getGeometryName()]]),
SkinImage::fromLegacy($skin->getSkinData()), [],
$capeData,
$skin->getGeometryData()
);
}
public function fromSkinData(SkinData $data) : Skin{
$capeData = $data->getCapeImage()->getData();
$geometryName = "";
$resourcePatch = json_decode($data->getResourcePatch(), true);
if(is_array($resourcePatch["geometry"]) && is_string($resourcePatch["geometry"]["default"])){
$geometryName = $resourcePatch["geometry"]["default"];
}else{
//TODO: Kick for invalid skin
}
if($data->isPersona()){
return new Skin("Standard_Custom", str_repeat(random_bytes(3) . "\xff", 2048), "", "geometry.humanoid.custom");
}elseif($data->isPersonaCapeOnClassic()){
$capeData = "";
}
return new Skin($data->getSkinId(), $data->getSkinImage()->getData(), $capeData, $geometryName, $data->getGeometryData());
}
}

View File

@ -23,6 +23,7 @@ declare(strict_types=1);
namespace pocketmine\network\mcpe\protocol\types;
use pocketmine\inventory\CraftingGrid;
use pocketmine\inventory\transaction\action\CreativeInventoryAction;
use pocketmine\inventory\transaction\action\DropItemAction;
use pocketmine\inventory\transaction\action\InventoryAction;
@ -36,7 +37,6 @@ class NetworkInventoryAction{
public const SOURCE_WORLD = 2; //drop/pickup item entity
public const SOURCE_CREATIVE = 3;
public const SOURCE_CRAFTING_GRID = 100;
public const SOURCE_TODO = 99999;
/**
@ -108,17 +108,8 @@ class NetworkInventoryAction{
break;
case self::SOURCE_CREATIVE:
break;
case self::SOURCE_CRAFTING_GRID:
case self::SOURCE_TODO:
$this->windowId = $packet->getVarInt();
switch($this->windowId){
/** @noinspection PhpMissingBreakStatementInspection */
case self::SOURCE_TYPE_CRAFTING_RESULT:
$packet->isFinalCraftingPart = true;
case self::SOURCE_TYPE_CRAFTING_USE_INGREDIENT:
$packet->isCraftingPart = true;
break;
}
break;
default:
throw new \UnexpectedValueException("Unknown inventory action source type $this->sourceType");
@ -146,7 +137,6 @@ class NetworkInventoryAction{
break;
case self::SOURCE_CREATIVE:
break;
case self::SOURCE_CRAFTING_GRID:
case self::SOURCE_TODO:
$packet->putVarInt($this->windowId);
break;
@ -167,11 +157,37 @@ class NetworkInventoryAction{
* @throws \UnexpectedValueException
*/
public function createInventoryAction(Player $player){
if($this->oldItem->equalsExact($this->newItem)){
//filter out useless noise in 1.13
return null;
}
switch($this->sourceType){
case self::SOURCE_CONTAINER:
$window = $player->getWindow($this->windowId);
if($this->windowId === ContainerIds::UI and $this->inventorySlot > 0){
if($this->inventorySlot === 50){
return null; //useless noise
}
if($this->inventorySlot >= 28 and $this->inventorySlot <= 31){
$window = $player->getCraftingGrid();
if($window->getGridWidth() !== CraftingGrid::SIZE_SMALL){
throw new \UnexpectedValueException("Expected small crafting grid");
}
$slot = $this->inventorySlot - 28;
}elseif($this->inventorySlot >= 32 and $this->inventorySlot <= 40){
$window = $player->getCraftingGrid();
if($window->getGridWidth() !== CraftingGrid::SIZE_BIG){
throw new \UnexpectedValueException("Expected big crafting grid");
}
$slot = $this->inventorySlot - 32;
}else{
throw new \UnexpectedValueException("Unhandled magic UI slot offset $this->inventorySlot");
}
}else{
$window = $player->getWindow($this->windowId);
$slot = $this->inventorySlot;
}
if($window !== null){
return new SlotChangeAction($window, $this->inventorySlot, $this->oldItem, $this->newItem);
return new SlotChangeAction($window, $slot, $this->oldItem, $this->newItem);
}
throw new \UnexpectedValueException("Player " . $player->getName() . " has no open container with window ID $this->windowId");
@ -195,7 +211,6 @@ class NetworkInventoryAction{
}
return new CreativeInventoryAction($this->oldItem, $this->newItem, $type);
case self::SOURCE_CRAFTING_GRID:
case self::SOURCE_TODO:
//These types need special handling.
switch($this->windowId){

View File

@ -0,0 +1,45 @@
<?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\network\mcpe\protocol\types;
/**
* Enum used by PlayerAuthInputPacket. Most of these names don't make any sense, but that isn't surprising.
*/
final class PlayMode{
private function __construct(){
//NOOP
}
public const NORMAL = 0;
public const TEASER = 1;
public const SCREEN = 2;
public const VIEWER = 3;
public const VR = 4;
public const PLACEMENT = 5;
public const LIVING_ROOM = 6;
public const EXIT_LEVEL = 7;
public const EXIT_LEVEL_LIVING_ROOM = 8;
}

View File

@ -34,12 +34,18 @@ class PlayerListEntry{
public $entityUniqueId;
/** @var string */
public $username;
/** @var Skin */
public $skin;
/** @var SkinData */
public $skinData;
/** @var string */
public $xboxUserId;
/** @var string */
public $platformChatId = "";
/** @var int */
public $buildPlatform = -1;
/** @var bool */
public $isTeacher = false;
/** @var bool */
public $isHost = false;
public static function createRemovalEntry(UUID $uuid) : PlayerListEntry{
$entry = new PlayerListEntry();
@ -48,14 +54,17 @@ class PlayerListEntry{
return $entry;
}
public static function createAdditionEntry(UUID $uuid, int $entityUniqueId, string $username, Skin $skin, string $xboxUserId = "", string $platformChatId = "") : PlayerListEntry{
public static function createAdditionEntry(UUID $uuid, int $entityUniqueId, string $username, SkinData $skinData, string $xboxUserId = "", string $platformChatId = "", int $buildPlatform = -1, bool $isTeacher = false, bool $isHost = false) : PlayerListEntry{
$entry = new PlayerListEntry();
$entry->uuid = $uuid;
$entry->entityUniqueId = $entityUniqueId;
$entry->username = $username;
$entry->skin = $skin;
$entry->skinData = $skinData;
$entry->xboxUserId = $xboxUserId;
$entry->platformChatId = $platformChatId;
$entry->buildPlatform = $buildPlatform;
$entry->isTeacher = $isTeacher;
$entry->isHost = $isHost;
return $entry;
}

View File

@ -0,0 +1,51 @@
<?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\network\mcpe\protocol\types;
class PotionContainerChangeRecipe{
/** @var int */
private $inputItemId;
/** @var int */
private $ingredientItemId;
/** @var int */
private $outputItemId;
public function __construct(int $inputItemId, int $ingredientItemId, int $outputItemId){
$this->inputItemId = $inputItemId;
$this->ingredientItemId = $ingredientItemId;
$this->outputItemId = $outputItemId;
}
public function getInputItemId() : int{
return $this->inputItemId;
}
public function getIngredientItemId() : int{
return $this->ingredientItemId;
}
public function getOutputItemId() : int{
return $this->outputItemId;
}
}

View File

@ -0,0 +1,51 @@
<?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\network\mcpe\protocol\types;
class PotionTypeRecipe{
/** @var int */
private $inputPotionType;
/** @var int */
private $ingredientItemId;
/** @var int */
private $outputPotionType;
public function __construct(int $inputPotionType, int $ingredientItemId, int $outputPotionType){
$this->inputPotionType = $inputPotionType;
$this->ingredientItemId = $ingredientItemId;
$this->outputPotionType = $outputPotionType;
}
public function getInputPotionType() : int{
return $this->inputPotionType;
}
public function getIngredientItemId() : int{
return $this->ingredientItemId;
}
public function getOutputPotionType() : int{
return $this->outputPotionType;
}
}

View File

@ -30,9 +30,12 @@ final class ResourcePackType{
}
public const INVALID = 0;
public const RESOURCES = 1;
public const BEHAVIORS = 2;
public const WORLD_TEMPLATE = 3;
public const ADDON = 4; //scripts?
public const SKINS = 5;
public const ADDON = 1;
public const CACHED = 2;
public const COPY_PROTECTED = 3;
public const BEHAVIORS = 4;
public const PERSONA_PIECE = 5;
public const RESOURCES = 6;
public const SKINS = 7;
public const WORLD_TEMPLATE = 8;
}

View File

@ -24,6 +24,12 @@ declare(strict_types=1);
namespace pocketmine\network\mcpe\protocol\types;
use pocketmine\block\BlockIds;
use pocketmine\nbt\NBT;
use pocketmine\nbt\NetworkLittleEndianNBTStream;
use pocketmine\nbt\tag\CompoundTag;
use pocketmine\nbt\tag\ListTag;
use pocketmine\nbt\tag\StringTag;
use pocketmine\utils\BinaryDataException;
use function file_get_contents;
use function getmypid;
use function json_decode;
@ -40,40 +46,71 @@ final class RuntimeBlockMapping{
private static $legacyToRuntimeMap = [];
/** @var int[] */
private static $runtimeToLegacyMap = [];
/** @var mixed[] */
private static $bedrockKnownStates;
/** @var CompoundTag[]|null */
private static $bedrockKnownStates = null;
private function __construct(){
//NOOP
}
public static function init() : void{
$legacyIdMap = json_decode(file_get_contents(\pocketmine\RESOURCE_PATH . "vanilla/block_id_map.json"), true);
$compressedTable = json_decode(file_get_contents(\pocketmine\RESOURCE_PATH . "vanilla/required_block_states.json"), true);
$decompressed = [];
foreach($compressedTable as $prefix => $entries){
foreach($entries as $shortStringId => $states){
foreach($states as $state){
$name = "$prefix:$shortStringId";
$decompressed[] = [
"name" => $name,
"data" => $state,
"legacy_id" => $legacyIdMap[$name]
];
}
}
$tag = (new NetworkLittleEndianNBTStream())->read(file_get_contents(\pocketmine\RESOURCE_PATH . "vanilla/required_block_states.nbt"));
if(!($tag instanceof ListTag) or $tag->getTagType() !== NBT::TAG_Compound){ //this is a little redundant currently, but good for auto complete and makes phpstan happy
throw new \RuntimeException("Invalid blockstates table, expected TAG_List<TAG_Compound> root");
}
self::$bedrockKnownStates = self::randomizeTable($decompressed);
foreach(self::$bedrockKnownStates as $k => $obj){
if($obj["data"] > 15){
//TODO: in 1.12 they started using data values bigger than 4 bits which we can't handle right now
/** @var CompoundTag[] $list */
$list = $tag->getValue();
self::$bedrockKnownStates = self::randomizeTable($list);
self::setupLegacyMappings();
}
private static function setupLegacyMappings() : void{
$legacyIdMap = json_decode(file_get_contents(\pocketmine\RESOURCE_PATH . "vanilla/block_id_map.json"), true);
$legacyStateMap = (new NetworkLittleEndianNBTStream())->read(file_get_contents(\pocketmine\RESOURCE_PATH . "vanilla/r12_to_current_block_map.nbt"));
if(!($legacyStateMap instanceof ListTag) or $legacyStateMap->getTagType() !== NBT::TAG_Compound){
throw new \RuntimeException("Invalid legacy states mapping table, expected TAG_List<TAG_Compound> root");
}
/**
* @var int[][] $idToStatesMap string id -> int[] list of candidate state indices
*/
$idToStatesMap = [];
foreach(self::$bedrockKnownStates as $k => $state){
$idToStatesMap[$state->getCompoundTag("block")->getString("name")][] = $k;
}
/** @var CompoundTag $pair */
foreach($legacyStateMap as $pair){
$oldState = $pair->getCompoundTag("old");
$id = $legacyIdMap[$oldState->getString("name")];
$data = $oldState->getShort("val");
if($data > 15){
//we can't handle metadata with more than 4 bits
continue;
}
//this has to use the json offset to make sure the mapping is consistent with what we send over network, even though we aren't using all the entries
self::registerMapping($k, $obj["legacy_id"], $obj["data"]);
$mappedState = $pair->getCompoundTag("new");
//TODO HACK: idiotic NBT compare behaviour on 3.x compares keys which are stored by values
$mappedState->setName("block");
$mappedName = $mappedState->getString("name");
if(!isset($idToStatesMap[$mappedName])){
throw new \RuntimeException("Mapped new state does not appear in network table");
}
foreach($idToStatesMap[$mappedName] as $k){
$networkState = self::$bedrockKnownStates[$k];
if($mappedState->equals($networkState->getCompoundTag("block"))){
self::registerMapping($k, $id, $data);
continue 2;
}
}
throw new \RuntimeException("Mapped new state does not appear in network table");
}
}
private static function lazyInit() : void{
if(self::$bedrockKnownStates === null){
self::init();
}
}
@ -82,9 +119,9 @@ final class RuntimeBlockMapping{
* Plugins shouldn't use this stuff anyway, but plugin devs have an irritating habit of ignoring what they
* aren't supposed to do, so we have to deliberately break it to make them stop.
*
* @param array $table
* @param CompoundTag[] $table
*
* @return array
* @return CompoundTag[]
*/
private static function randomizeTable(array $table) : array{
$postSeed = mt_rand(); //save a seed to set afterwards, to avoid poor quality randoms
@ -101,6 +138,7 @@ final class RuntimeBlockMapping{
* @return int
*/
public static function toStaticRuntimeId(int $id, int $meta = 0) : int{
self::lazyInit();
/*
* try id+meta first
* if not found, try id+0 (strip meta)
@ -115,6 +153,7 @@ final class RuntimeBlockMapping{
* @return int[] [id, meta]
*/
public static function fromStaticRuntimeId(int $runtimeId) : array{
self::lazyInit();
$v = self::$runtimeToLegacyMap[$runtimeId];
return [$v >> 4, $v & 0xf];
}
@ -125,10 +164,10 @@ final class RuntimeBlockMapping{
}
/**
* @return array
* @return CompoundTag[]
*/
public static function getBedrockKnownStates() : array{
self::lazyInit();
return self::$bedrockKnownStates;
}
}
RuntimeBlockMapping::init();

View File

@ -0,0 +1,48 @@
<?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\network\mcpe\protocol\types;
use pocketmine\entity\Skin;
/**
* Used to convert new skin data to the skin entity or old skin entity to skin data.
*/
interface SkinAdapter{
/**
* Allows you to convert a skin entity to skin data.
*
* @param Skin $skin
* @return SkinData
*/
public function toSkinData(Skin $skin) : SkinData;
/**
* Allows you to convert skin data to a skin entity.
*
* @param SkinData $data
* @return Skin
*/
public function fromSkinData(SkinData $data) : Skin;
}

View File

@ -0,0 +1,43 @@
<?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\network\mcpe\protocol\types;
/**
* Accessor for SkinAdapter
*/
class SkinAdapterSingleton{
/** @var SkinAdapter|null */
private static $skinAdapter = null;
public static function get() : SkinAdapter{
if(self::$skinAdapter === null){
self::$skinAdapter = new LegacySkinAdapter();
}
return self::$skinAdapter;
}
public static function set(SkinAdapter $adapter) : void{
self::$skinAdapter = $adapter;
}
}

View File

@ -0,0 +1,71 @@
<?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\network\mcpe\protocol\types;
class SkinAnimation{
public const TYPE_HEAD = 1;
public const TYPE_BODY_32 = 2;
public const TYPE_BODY_64 = 3;
/** @var SkinImage */
private $image;
/** @var int */
private $type;
/** @var float */
private $frames;
public function __construct(SkinImage $image, int $type, float $frames){
$this->image = $image;
$this->type = $type;
$this->frames = $frames;
}
/**
* Image of the animation.
*
* @return SkinImage
*/
public function getImage() : SkinImage{
return $this->image;
}
/**
* The type of animation you are applying.
*
* @return int
*/
public function getType() : int{
return $this->type;
}
/**
* The total amount of frames in an animation.
*
* @return float
*/
public function getFrames() : float{
return $this->frames;
}
}

View File

@ -0,0 +1,155 @@
<?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\network\mcpe\protocol\types;
class SkinData{
/** @var string */
private $skinId;
/** @var string */
private $resourcePatch;
/** @var SkinImage */
private $skinImage;
/** @var SkinAnimation[] */
private $animations;
/** @var SkinImage */
private $capeImage;
/** @var string */
private $geometryData;
/** @var string */
private $animationData;
/** @var bool */
private $persona;
/** @var bool */
private $premium;
/** @var bool */
private $personaCapeOnClassic;
/** @var string */
private $capeId;
/**
* @param string $skinId
* @param string $resourcePatch
* @param SkinImage $skinImage
* @param SkinAnimation[] $animations
* @param SkinImage|null $capeImage
* @param string $geometryData
* @param string $animationData
* @param bool $premium
* @param bool $persona
* @param bool $personaCapeOnClassic
* @param string $capeId
*/
public function __construct(string $skinId, string $resourcePatch, SkinImage $skinImage, array $animations = [], SkinImage $capeImage = null, string $geometryData = "", string $animationData = "", bool $premium = false, bool $persona = false, bool $personaCapeOnClassic = false, string $capeId = ""){
$this->skinId = $skinId;
$this->resourcePatch = $resourcePatch;
$this->skinImage = $skinImage;
$this->animations = $animations;
$this->capeImage = $capeImage;
$this->geometryData = $geometryData;
$this->animationData = $animationData;
$this->premium = $premium;
$this->persona = $persona;
$this->personaCapeOnClassic = $personaCapeOnClassic;
$this->capeId = $capeId;
}
/**
* @return string
*/
public function getSkinId() : string{
return $this->skinId;
}
/**
* @return string
*/
public function getResourcePatch() : string{
return $this->resourcePatch;
}
/**
* @return SkinImage
*/
public function getSkinImage() : SkinImage{
return $this->skinImage;
}
/**
* @return SkinAnimation[]
*/
public function getAnimations() : array{
return $this->animations;
}
/**
* @return SkinImage
*/
public function getCapeImage() : SkinImage{
return $this->capeImage;
}
/**
* @return string
*/
public function getGeometryData() : string{
return $this->geometryData;
}
/**
* @return string
*/
public function getAnimationData() : string{
return $this->animationData;
}
/**
* @return bool
*/
public function isPersona() : bool{
return $this->persona;
}
/**
* @return bool
*/
public function isPremium() : bool{
return $this->premium;
}
/**
* @return bool
*/
public function isPersonaCapeOnClassic() : bool{
return $this->personaCapeOnClassic;
}
/**
* @return string
*/
public function getCapeId() : string{
return $this->capeId;
}
}

View File

@ -0,0 +1,67 @@
<?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\network\mcpe\protocol\types;
class SkinImage{
/** @var int */
private $height;
/** @var int */
private $width;
/** @var string */
private $data;
public function __construct(int $height, int $width, string $data){
$this->height = $height;
$this->width = $width;
$this->data = $data;
}
public static function fromLegacy(string $data) : SkinImage{
switch(strlen($data)){
case 64 * 32 * 4:
return new self(64, 32, $data);
case 64 * 64 * 4:
return new self(64, 64, $data);
case 128 * 64 * 4:
return new self(128, 64, $data);
case 128 * 128 * 4:
return new self(128, 128, $data);
}
throw new \InvalidArgumentException("Unknown size");
}
public function getHeight() : int{
return $this->height;
}
public function getWidth() : int{
return $this->width;
}
public function getData() : string{
return $this->data;
}
}

View File

@ -50,7 +50,7 @@ abstract class UPnP{
$com = new \COM("HNetCfg.NATUPnP");
/** @noinspection PhpUndefinedFieldInspection */
if($com === false or !is_object($com->StaticPortMappingCollection)){
if(!is_object($com->StaticPortMappingCollection)){
throw new \RuntimeException("Failed to portforward using UPnP. Ensure that network discovery is enabled in Control Panel.");
}
@ -70,7 +70,7 @@ abstract class UPnP{
/** @noinspection PhpUndefinedClassInspection */
$com = new \COM("HNetCfg.NATUPnP");
/** @noinspection PhpUndefinedFieldInspection */
if($com === false or !is_object($com->StaticPortMappingCollection)){
if(!is_object($com->StaticPortMappingCollection)){
return false;
}
/** @noinspection PhpUndefinedFieldInspection */

View File

@ -733,7 +733,7 @@ class PluginManager{
$eventClass = $parameters[0]->getClass();
}catch(\ReflectionException $e){ //class doesn't exist
if(isset($tags["softDepend"]) && !isset($this->plugins[$tags["softDepend"]])){
$this->server->getLogger()->debug("Not registering @softDepend listener " . Utils::getNiceClosureName($handlerClosure) . "(" . $parameters[0]->getType()->getName() . ") because plugin \"" . $tags["softDepend"] . "\" not found");
$this->server->getLogger()->debug("Not registering @softDepend listener " . Utils::getNiceClosureName($handlerClosure) . "() because plugin \"" . $tags["softDepend"] . "\" not found");
continue;
}

View File

@ -263,6 +263,7 @@ class AsyncPool{
while(($task = $worker->unstack()) !== null){
//cancelRun() is not strictly necessary here, but it might be used to inform plugins of the task state
//(i.e. it never executed).
assert($task instanceof AsyncTask);
$task->cancelRun();
$this->removeTask($task, true);
}

View File

@ -64,7 +64,7 @@ class MainLogger extends \AttachableThreadedLogger{
protected $shutdown = false;
/** @var bool */
protected $logDebug;
/** @var MainLogger */
/** @var MainLogger|null */
public static $logger = null;
/** @var bool */
private $syncFlush = false;

View File

@ -0,0 +1,24 @@
<?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);
define('pocketmine\_PHPSTAN_ANALYSIS', true);

View File

@ -0,0 +1,80 @@
#cyclic refs in lots of objects prevent GC, causing increased memory pressure
#the proper fix is to not have cycles, but in the meantime we have these hacks
parameters:
ignoreErrors:
-
message: "#^Property pocketmine\\\\Player\\:\\:\\$sessionAdapter \\(pocketmine\\\\network\\\\mcpe\\\\PlayerNetworkSessionAdapter\\) does not accept null\\.$#"
count: 1
path: ../../../src/pocketmine/Player.php
-
message: "#^Property pocketmine\\\\Player\\:\\:\\$cursorInventory \\(pocketmine\\\\inventory\\\\PlayerCursorInventory\\) does not accept null\\.$#"
count: 1
path: ../../../src/pocketmine/Player.php
-
message: "#^Property pocketmine\\\\Player\\:\\:\\$craftingGrid \\(pocketmine\\\\inventory\\\\CraftingGrid\\) does not accept null\\.$#"
count: 1
path: ../../../src/pocketmine/Player.php
-
message: "#^Property pocketmine\\\\Player\\:\\:\\$perm \\(pocketmine\\\\permission\\\\PermissibleBase\\) does not accept null\\.$#"
count: 1
path: ../../../src/pocketmine/Player.php
-
message: "#^Property pocketmine\\\\entity\\\\Entity\\:\\:\\$namedtag \\(pocketmine\\\\nbt\\\\tag\\\\CompoundTag\\) does not accept null\\.$#"
count: 1
path: ../../../src/pocketmine/entity/Entity.php
-
message: "#^Property pocketmine\\\\entity\\\\Human\\:\\:\\$inventory \\(pocketmine\\\\inventory\\\\PlayerInventory\\) does not accept null\\.$#"
count: 1
path: ../../../src/pocketmine/entity/Human.php
-
message: "#^Property pocketmine\\\\entity\\\\Human\\:\\:\\$enderChestInventory \\(pocketmine\\\\inventory\\\\EnderChestInventory\\) does not accept null\\.$#"
count: 1
path: ../../../src/pocketmine/entity/Human.php
-
message: "#^Property pocketmine\\\\entity\\\\Living\\:\\:\\$armorInventory \\(pocketmine\\\\inventory\\\\ArmorInventory\\) does not accept null\\.$#"
count: 1
path: ../../../src/pocketmine/entity/Living.php
-
message: "#^Property pocketmine\\\\inventory\\\\DoubleChestInventory\\:\\:\\$left \\(pocketmine\\\\inventory\\\\ChestInventory\\) does not accept null\\.$#"
count: 1
path: ../../../src/pocketmine/inventory/DoubleChestInventory.php
-
message: "#^Property pocketmine\\\\inventory\\\\DoubleChestInventory\\:\\:\\$right \\(pocketmine\\\\inventory\\\\ChestInventory\\) does not accept null\\.$#"
count: 1
path: ../../../src/pocketmine/inventory/DoubleChestInventory.php
-
message: "#^Property pocketmine\\\\level\\\\Level\\:\\:\\$provider \\(pocketmine\\\\level\\\\format\\\\io\\\\LevelProvider\\) does not accept null\\.$#"
count: 1
path: ../../../src/pocketmine/level/Level.php
-
message: "#^Property pocketmine\\\\level\\\\Level\\:\\:\\$blockMetadata \\(pocketmine\\\\metadata\\\\BlockMetadataStore\\) does not accept null\\.$#"
count: 1
path: ../../../src/pocketmine/level/Level.php
-
message: "#^Property pocketmine\\\\level\\\\Level\\:\\:\\$temporalPosition \\(pocketmine\\\\level\\\\Position\\) does not accept null\\.$#"
count: 1
path: ../../../src/pocketmine/level/Level.php
-
message: "#^Property pocketmine\\\\tile\\\\Chest\\:\\:\\$inventory \\(pocketmine\\\\inventory\\\\ChestInventory\\) does not accept null\\.$#"
count: 1
path: ../../../src/pocketmine/tile/Chest.php
-
message: "#^Property pocketmine\\\\tile\\\\Furnace\\:\\:\\$inventory \\(pocketmine\\\\inventory\\\\FurnaceInventory\\) does not accept null\\.$#"
count: 1
path: ../../../src/pocketmine/tile/Furnace.php

View File

@ -0,0 +1,12 @@
parameters:
ignoreErrors:
-
message: "#^Instantiated class COM not found\\.$#"
count: 2
path: ../../../src/pocketmine/network/upnp/UPnP.php
-
message: "#^Access to property \\$StaticPortMappingCollection on an unknown class COM\\.$#"
count: 4
path: ../../../src/pocketmine/network/upnp/UPnP.php

View File

@ -0,0 +1,30 @@
parameters:
ignoreErrors:
-
message: "#^Used constant LEVELDB_ZLIB_RAW_COMPRESSION not found\\.$#"
path: ../../../src/pocketmine/level/format/io/leveldb/LevelDB.php
-
message: "#^Constant LEVELDB_ZLIB_RAW_COMPRESSION not found\\.$#"
path: ../../../src/pocketmine/level/format/io/leveldb/LevelDB.php
-
message: "#^Instantiated class LevelDB not found\\.$#"
path: ../../../src/pocketmine/level/format/io/leveldb/LevelDB.php
-
message: "#^Return typehint of method pocketmine\\\\level\\\\format\\\\io\\\\leveldb\\\\LevelDB\\:\\:createDB\\(\\) has invalid type LevelDB\\.$#"
path: ../../../src/pocketmine/level/format/io/leveldb/LevelDB.php
-
message: "#^Return typehint of method pocketmine\\\\level\\\\format\\\\io\\\\leveldb\\\\LevelDB\\:\\:getDatabase\\(\\) has invalid type LevelDB\\.$#"
path: ../../../src/pocketmine/level/format/io/leveldb/LevelDB.php
-
message: "#^Property pocketmine\\\\level\\\\format\\\\io\\\\leveldb\\\\LevelDB\\:\\:\\$db has unknown class LevelDB as its type\\.$#"
path: ../../../src/pocketmine/level/format/io/leveldb/LevelDB.php
-
message: "#^Call to method (get|put|delete|close)\\(\\) on an unknown class LevelDB\\.$#"
path: ../../../src/pocketmine/level/format/io/leveldb/LevelDB.php

View File

@ -0,0 +1,33 @@
parameters:
ignoreErrors:
-
message: "#^PHPDoc tag @param has invalid value \\(.+\\)\\: Unexpected token \"&\", expected variable at offset \\d+$#"
path: ../../../src
-
message: "#^Default value of the parameter \\#\\d+ \\$[A-Za-z\\d_]+ \\(\\-?\\d+\\) of method .+\\(\\) is incompatible with type float\\.$#"
path: ../../../src
-
message: "#^Cannot access an offset on Threaded\\.$#"
path: ../../../src
-
message: "#^Cannot assign new offset to Threaded\\.$#"
path: ../../../src
-
message: "#^Offset string does not exist on array\\(\\)\\.$#"
count: 3
path: ../../../src/pocketmine/MemoryManager.php
-
message: "#^Offset \\(int\\|string\\) does not exist on array\\(\\)\\.$#"
count: 1
path: ../../../src/pocketmine/MemoryManager.php
-
message: "#^Array \\(array\\) does not accept key int\\.$#"
count: 1
path: ../../../src/pocketmine/plugin/PluginDescription.php

View File

@ -0,0 +1,6 @@
parameters:
ignoreErrors:
-
message: "#^Variable \\$GLOBALS in isset\\(\\) always exists and is not nullable\\.$#"
path: ../../../src/pocketmine/MemoryManager.php

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