Compare commits

..

167 Commits

Author SHA1 Message Date
fd4ac885bb Release 3.18.1 2021-03-28 21:24:03 +01:00
f35886f18a Updated composer dependencies 2021-03-28 21:14:02 +01:00
a9eaa55427 actions: added a php-cs-fixer run 2021-03-28 20:38:56 +01:00
5c41f79be4 Added php-cs-fixer configuration
this is by no means a complete code style guide, but it fixes a lot of common issues that show up, particularly in PRs.
2021-03-28 19:21:41 +01:00
34c2b62ffe Remove unused import 2021-03-28 19:12:18 +01:00
e42a691da9 Strip trailing whitespace 2021-03-28 19:02:51 +01:00
Ali
3b3fb5e662 fix ItemFrames (#4101)
removing items from item frames was broken due to behavioural changes in 1.16.210.
2021-03-28 18:53:46 +01:00
01ffe8bf57 Updated build/php submodule to pmmp/php-build-scripts@c64baa0f1c 2021-03-28 18:14:40 +01:00
4abf4aecad MainLogger: fixed potential deadlock during syncFlushBuffer()
the notify() to flush the buffer might arrive in between the writeLogStream() and synchronized() calls in the thread body, resulting in a deadlock if the logger thread managed to call wait() before the main thread did.
2021-03-28 18:10:23 +01:00
b29f83ee99 Added preprocessor test build job to Actions
this should catch problems like the one that broke 3.17.6 at the root.
2021-03-25 01:25:04 +00:00
4bc57f00b8 Updated LevelSoundEventPacket constants 2021-03-23 23:36:48 +00:00
ff61e1e018 ClientCacheBlobStatusPacket: fixed field order
miss comes first, not hit.
2021-03-23 19:52:25 +00:00
fb20bb3832 Don't handle NAN/INF in movements 2021-03-23 14:54:39 +00:00
3333df31df Bump phpunit/phpunit from 9.5.3 to 9.5.4 (#4104)
Bumps [phpunit/phpunit](https://github.com/sebastianbergmann/phpunit) from 9.5.3 to 9.5.4.
- [Release notes](https://github.com/sebastianbergmann/phpunit/releases)
- [Changelog](https://github.com/sebastianbergmann/phpunit/blob/master/ChangeLog-9.5.md)
- [Commits](https://github.com/sebastianbergmann/phpunit/compare/9.5.3...9.5.4)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>

Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com>
2021-03-23 13:53:45 +00:00
c09fcb2df2 Merge branch 'stable' of github.com:pmmp/PocketMine-MP into stable 2021-03-22 21:22:56 +00:00
c7cdaeae85 Revert "Backport InventoryTransactionPacket impl from PM4"
This reverts commit cb06be615a.

we can't push this to stable because it would break plugins without any
way to know (no protocol or API change).

At most, this should have been wrapped into a protocol change.
2021-03-22 21:21:11 +00:00
4416cd5a28 Bump phpstan/phpstan from 0.12.81 to 0.12.82 (#4088)
Bumps [phpstan/phpstan](https://github.com/phpstan/phpstan) from 0.12.81 to 0.12.82.
- [Release notes](https://github.com/phpstan/phpstan/releases)
- [Commits](https://github.com/phpstan/phpstan/compare/0.12.81...0.12.82)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>

Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com>
2021-03-22 13:26:07 +00:00
cb93095857 [ci skip] readme: added link to devdoc.pmmp.io 2021-03-21 16:59:58 +00:00
c8f396ecbc [ci skip] doxygen: link to devdoc.pmmp.io instead of the github repo 2021-03-21 16:56:23 +00:00
cb06be615a Backport InventoryTransactionPacket impl from PM4
this version is far better, and we're going to need it to deal with the PlayerAuthInputPacket bullshit.
2021-03-19 22:16:30 +00:00
0d3c11699c Clean up PHPStan baselines 2021-03-19 22:14:07 +00:00
3667e95ff6 Added PlayerAuthInputFlags 2021-03-19 21:41:22 +00:00
0e2dc51ec8 added some missing things to the protocol 2021-03-19 21:09:53 +00:00
eaf85b028a fix prebuilt binaries link (#4090) 2021-03-19 20:42:21 +00:00
9479a1a0ab Bump phpunit/phpunit from 9.5.2 to 9.5.3 (#4084)
Bumps [phpunit/phpunit](https://github.com/sebastianbergmann/phpunit) from 9.5.2 to 9.5.3.
- [Release notes](https://github.com/sebastianbergmann/phpunit/releases)
- [Changelog](https://github.com/sebastianbergmann/phpunit/blob/master/ChangeLog-9.5.md)
- [Commits](https://github.com/sebastianbergmann/phpunit/compare/9.5.2...9.5.3)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>

Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com>
2021-03-17 14:08:44 +00:00
1bb2d162ab Simplify CommandReader
while stream_select() doesn't work on pipes, if it ever starts working properly in the future, we'll need this code. In the meantime, it's harmless (it just immediately returns 1 anyway).
2021-03-16 21:42:35 +00:00
ee868bcccc update argument type constants (#4082) 2021-03-15 18:22:01 +00:00
cbc8576d4a Implement UPnP support without dotNET (#3378)
UPnP forwarding is now available on all supported platforms.
com_dotnet is no longer required for UPnP forwarding to work.

Closes #3216 .
2021-03-14 22:50:33 +00:00
edcf296086 RakLibInterface: fixed server being unjoinable if gamemode is Spectator
closes #4069
this happens because the client bans any server that has an invalid pong, which is very stupid in this case because the gamemode isn't even shown on the UI anyway ...
2021-03-14 20:35:17 +00:00
9e27c47116 Merge branch 'stable' of github.com:pmmp/PocketMine-MP into stable 2021-03-12 22:08:20 +00:00
a0368a843e 3.18.1 is next 2021-03-12 22:07:01 +00:00
3f64906263 Release 3.18.0 2021-03-12 22:07:01 +00:00
19bb8a00df Updated PHPStan baselines 2021-03-12 22:05:15 +00:00
4816a66fb8 Baseline protocol changes for 1.16.210
this is not a complete changeset, but it's sufficient to get servers back online.
There are additional changes to PlayerAuthInputPacket which need to be reversed.
2021-03-12 21:41:48 +00:00
06f4e1e4c2 Bump phpstan/phpstan from 0.12.80 to 0.12.81 (#4063) 2021-03-11 00:33:05 +00:00
5b8166c1f0 3.17.8 is next 2021-03-11 00:22:17 +00:00
30c5cad5b3 Release 3.17.7 2021-03-11 00:22:17 +00:00
a7a7fe3895 Merge branch 'stable' of github.com:pmmp/PocketMine-MP into stable 2021-03-11 00:15:48 +00:00
55ac2f07dc Updated PreProcessor submodule to pmmp/PreProcessor@1b9304de61 2021-03-11 00:15:33 +00:00
0660888029 Updated NBT dependency (again) 2021-03-11 00:15:00 +00:00
0476e6bcfc Updated PreProcessor submodule to pmmp/PreProcessor@934f92d388 2021-03-10 23:33:45 +00:00
72bd37e442 Updated PreProcessor submodule to pmmp/PreProcessor@652c6d8b4c 2021-03-10 23:02:47 +00:00
f95fcecb5b 3.17.7 is next 2021-03-10 20:49:10 +00:00
61391b6e23 Release 3.17.6 2021-03-10 20:48:57 +00:00
fbb6f1f81c Workaround for cursor sync in 1.13+, closes #4059 2021-03-07 21:17:52 +00:00
712df04bc4 Updated NBT dependency to 0.2.17 2021-03-07 21:06:08 +00:00
1563e25378 Updated composer dependencies 2021-03-07 19:57:16 +00:00
ed84252942 Player: Improved XUID verification
we check if an existing player is online with a matching XUID first; if there isn't, we don't bother loading the playerdata, since that other player couldn't have joined unless they had a match or were allowed to bypass.
2021-03-07 19:53:19 +00:00
3d90625020 Revert "Revert "Use PHP 7.4.16 for Actions""
This reverts commit 9f6b914925.
2021-03-07 16:37:33 +00:00
9f6b914925 Revert "Use PHP 7.4.16 for Actions"
This reverts commit 0e614ea8fd.

apparently php-build doesn't have 7.4.16 yet ...
2021-03-06 00:41:19 +00:00
0e614ea8fd Use PHP 7.4.16 for Actions 2021-03-06 00:32:56 +00:00
401bd09d60 Bump phpstan/phpstan from 0.12.79 to 0.12.80 (#4054) 2021-03-01 16:56:23 +00:00
649671cc69 Bump phpstan/phpstan from 0.12.78 to 0.12.79 (#4051) 2021-02-27 17:42:19 +00:00
e755e1dc23 ResourcePackClientResponsePacket: fixed non-deterministic decoding 2021-02-27 01:08:18 +00:00
e34a444dde Bump phpstan/phpstan from 0.12.77 to 0.12.78 (#4046) 2021-02-26 00:34:38 +00:00
78f9985377 Player: fixed PlayerMoveEvent->getFrom() returning unexpected results on movement reversion
fixes #4043
2021-02-26 00:30:42 +00:00
fac2bd3379 Liquid: mark getSmallestFlowDecay() as impure
this fixes two bogus PHPStan warnings.
2021-02-25 22:41:07 +00:00
fcfd51dfc7 CrashDump: do not put FALSE into crashdumps in case file_get_contents() failed 2021-02-23 19:39:21 +00:00
ccc76cf338 Make less noise about XBL being enabled
this has been in force for years now, it's expected by now.
2021-02-23 19:25:22 +00:00
10a73488ed Merge branch 'stable' of https://github.com/pmmp/pocketmine-mp into stable 2021-02-22 16:43:51 +00:00
9c5114084b Updated Snooze to fix race conditions 2021-02-22 16:42:54 +00:00
11630ab1aa Bump phpstan/phpstan from 0.12.76 to 0.12.77 (#4041) 2021-02-18 11:34:42 +00:00
a3068b39a2 Update composer dependencies 2021-02-16 22:31:01 +00:00
edbc73a72c 3.17.6 is next 2021-02-16 22:13:05 +00:00
3a0c8dd594 Release 3.17.5 2021-02-16 22:13:05 +00:00
16fa26405a Remove remaining usages of LevelDB::close()
this is handled by the object destructor.

closes #4035
2021-02-15 20:10:11 +00:00
57423540f0 BUILDING.md: Document server-phar.php's compression bug (#4037)
This bug is not fixable on PM's side because the fault lies with php-src. It was fixed recently in 1bb2a4f91c.
2021-02-15 19:53:44 +00:00
8f8821c904 Bump phpstan/phpstan from 0.12.75 to 0.12.76 (#4038) 2021-02-15 11:25:36 +00:00
094102fe92 fopen() might return FALSE if permission was denied to read/write the file 2021-02-12 16:16:36 +00:00
2aef83e7d7 MainLogger: fix type ambiguity 2021-02-12 15:05:24 +00:00
5c3e78e1d3 Bump phpstan/phpstan from 0.12.74 to 0.12.75 (#4033) 2021-02-12 14:58:01 +00:00
18666e5a60 Be compatible with newest versions of php-leveldb 2021-02-11 22:33:29 +00:00
f72163c173 Fixed build not failing when PHP build gets borked 2021-02-11 17:06:03 +00:00
7407e504b6 actions: bump PHP versions to 7.3.27 and 7.4.15 2021-02-11 16:35:19 +00:00
0e396dc47d actions: update PHP extension versions 2021-02-11 16:24:09 +00:00
d2204da1d5 [ci skip] center the build badges 2021-02-11 16:05:55 +00:00
2a51269305 Merge branch 'stable' of https://github.com/pmmp/pocketmine-mp into stable 2021-02-11 16:05:24 +00:00
928041ddf1 Bump phpstan/phpstan from 0.12.71 to 0.12.74 (#4028)
Bumps [phpstan/phpstan](https://github.com/phpstan/phpstan) from 0.12.71 to 0.12.74.
- [Release notes](https://github.com/phpstan/phpstan/releases)
- [Commits](https://github.com/phpstan/phpstan/compare/0.12.71...0.12.74)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>

Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com>
2021-02-08 21:42:08 +00:00
007f4f9350 CraftingDataPacket: Remove useless @var comment 2021-02-08 11:53:50 +00:00
46e9f0cec6 Player: fixed verify-xuid not kicking in by default on old configs 2021-02-07 21:10:23 +00:00
606d56b55d Composer: lock in PHP at ^7.3 || ^8.0, don't leave it unbounded 2021-02-07 17:31:32 +00:00
78a62a8b27 Remember and verify player XUIDs (controlled by player.verify-xuid in pocketmine.yml) 2021-02-05 14:42:57 +00:00
c5bdd7dd64 Added a unit test to ensure valid format of MINECRAFT_VERSION_NETWORK 2021-02-04 22:36:40 +00:00
8ee37a3033 Bump phpunit/phpunit from 9.5.1 to 9.5.2 (#4023) 2021-02-04 16:46:22 +00:00
7e3e63f342 Fixed race condition in MainLogger shutdown
this resulted in a deadlock in https://github.com/pmmp/PocketMine-MP/runs/1831812620?check_suite_focus=true because the notify() arrived while writeLogStream() was executing.
This ensures that either:
- the notification will occur before the sleep, and therefore no sleeping will occur (this->shutdown = true before the wait)
- the notification will arrive during the sleep.
2021-02-04 16:40:10 +00:00
8ef1e54e20 MainLogger: fixing CPU waste on logger thread
this doesn't need to keep spinning every 25ms; it can just wake up when there's actually log messages to write into the buffer.
2021-02-04 15:07:40 +00:00
eaf3a86981 MainLogger: fixed UB in writeLogStream()
notify() has to be used inside a synchronized block.
2021-02-04 15:03:14 +00:00
317a48d9b0 ItemStackRequest: expose filterStrings 2021-02-03 23:40:34 +00:00
bc14660e55 Added missing ItemStackRequest protocol changes 2021-02-03 23:37:41 +00:00
b1bb9fbd1c Reinstall PHP deps on cache hit
the 20.04 actions image doesn't have libzip5 and who knows what else is missing ...
2021-02-03 17:42:11 +00:00
96181f8cf5 Version PHP build caches by image version
we can't safely use `ubuntu-latest` because the build caches will break if they were built for 18.04 and used on 20.04, or vice versa. Instead, we pin the images (and caches) to a specific version.
2021-02-03 17:24:50 +00:00
4771e3dc28 3.17.5 is next 2021-02-02 14:04:51 +00:00
2e9117d102 Release 3.17.4 2021-02-02 14:04:50 +00:00
06493da7d9 Imports cleanup 2021-02-02 13:58:07 +00:00
bd303b1062 RegionLoader: fixed flaky region header validation since 3.17.3 2021-02-02 13:43:52 +00:00
fe731b9018 Added failing test case for region header validation
fucking PHP... what genius thought it was a good idea to cache file stats without even an attempt at keeping the cache up to date on modifications?
2021-02-02 13:43:12 +00:00
1a24afc6d1 InventoryTransaction: Fixed indexes persisting from balance calculation in crafting input/outputs
fixes #4019
the order of the actual items may not be the same across runs, but index 0 will at least be sure to exist.
2021-02-02 00:13:58 +00:00
bef906b0f0 phpstan 0.12.71 2021-02-02 00:05:53 +00:00
37e8dd6444 Fix PHP 8 optional before required parameters deprecation warnings (#4016) 2021-01-31 12:08:47 +00:00
02ee0f23c0 Removed old support requests configuration 2021-01-27 22:53:37 +00:00
cda472333c Add workflow for dessant/support-requests
we're using the legacy github app right now.
2021-01-27 22:47:33 +00:00
47cf58be8a phpstan 0.12.70 2021-01-27 20:11:37 +00:00
ccf9691927 Bump phpunit/phpunit from 9.5.0 to 9.5.1 (#4010) 2021-01-27 19:28:36 +00:00
16fa958416 phpstan: better hack for any-callable parameters
variadics are a bad fit for this because what we really need is to accept callable with any number of arguments. LSP requires that the provided number of arguments must be >= than the required number of arguments.
2021-01-27 19:25:28 +00:00
bac57c159f Player: fix bridging, towering and various other fast building bugs
clickPos is relative to the base block position, so if you keep aiming at the same spot on the block and jump, it thinks you're still spamming.
closes #2730
2021-01-27 00:11:14 +00:00
38b2d83799 MemoryManager: fixed protected properties being dumped multiple times
we don't need to scan the parent classes for anything other than private properties, because protected and public properties will appear on the main reflection as if they were declared directly as such.
2021-01-26 20:32:23 +00:00
c134b1cd8a [ci skip] README: add some badges 2021-01-26 17:34:05 +00:00
62deafda48 CommandReader: removed readline support
readline has been borked for a long time and it's not thread safe.
2021-01-25 17:53:25 +00:00
31b6df4376 3.17.4 is next 2021-01-25 17:15:43 +00:00
b296ae1b87 Release 3.17.3 2021-01-25 17:15:31 +00:00
f9e42b716a Scrub PHPStan baselines
these are now always generated with level 8.
2021-01-24 20:31:22 +00:00
34c1d455a7 phpstan: enable checkMissingCallableSignature 2021-01-24 20:27:53 +00:00
af8936dba5 phpstan 0.12.69 2021-01-24 20:14:42 +00:00
e8ffab1787 RegionLoader: avoid hitting the disk twice during chunk reads
this provides some performance improvement (although it's difficult to measure because of cache).
this does mean that we read some garbage data during chunk reads, but it's less costly than hitting the disk twice.
2021-01-20 21:05:44 +00:00
ecc1e1f698 RegionLoader: improve performance of region header validation
I was unaware that fseek actually makes a syscall which is rather costly, which became painfully obvious during large world conversions on PM4.
On average this problem appeared to be adding about 5ms to the load time for a newly loaded region, which is insanely expensive.
2021-01-20 20:04:21 +00:00
ea5931e274 Updated build/php submodule to pmmp/php-build-scripts@60194e8b14 2021-01-16 19:34:06 +00:00
988cf7f535 Fixed PHP 8.0 deprecation error 2021-01-16 19:31:07 +00:00
e156fb47e8 Disable xdebug on Actions 2021-01-15 21:09:45 +00:00
efc5f34877 wrong place ... when shared defaults :( 2021-01-15 17:53:39 +00:00
dd0d8842d5 actions: disable fail-fast 2021-01-15 17:35:27 +00:00
7bdc564ccc Update first-party dependencies to PHP 8.0 compatible versions
all deps of PM3 are ready (at least as far as PHPStan can show).
2021-01-15 16:59:51 +00:00
69fff23f1a LevelProviderManager: removed bogus @var
I'm not sure why this wasn't detected until 0.12.67...
2021-01-15 16:53:49 +00:00
ae43698e88 phpstan 0.12.67
for some reason dependabot shit itself while trying to scan for updates and thought this wasn't updatable ...
2021-01-15 16:53:49 +00:00
0987e03c03 Bump phpstan/phpstan-strict-rules from 0.12.8 to 0.12.9 (#4003) 2021-01-13 10:55:54 +00:00
97c124edf9 thanks git, this just sneaked in without any questions ................ 2021-01-12 21:43:34 +00:00
56501178b7 Updated composer dependencies 2021-01-12 21:41:25 +00:00
da663deea1 Bump phpstan/phpstan from 0.12.65 to 0.12.66 (#4001) 2021-01-12 10:41:59 +00:00
972c911485 phpstan 0.12.65 2021-01-09 18:04:42 +00:00
0d8858f948 composer.json: sort packages automatically 2021-01-09 17:38:22 +00:00
da71540fce first shot building multi PHP versions on actions 2021-01-05 22:03:51 +00:00
ec9b39862b bootstrap: commit suicide if composer dependencies are not in sync 2020-12-29 17:47:32 +00:00
efca8077d5 3.17.3 is next 2020-12-28 23:03:37 +00:00
5066d5225b Release 3.17.2 2020-12-28 23:03:32 +00:00
aefaf73685 Living: extract an applyConsumptionResults() method from consumeObject()
inspired by #3592, which has gone stale
2020-12-28 22:27:29 +00:00
15401d740f RegionLoader: mark area as garbage in removeChunk() 2020-12-27 19:16:05 +00:00
5920b0ba40 Remove _PHPSTAN_ANALYSIS constant
we don't need this anymore since PHPStan is able to intelligently decide whether to autoload a file or not.
2020-12-27 19:10:40 +00:00
dea75a0687 RegionLoader: do not attempt to auto-repair chunks with oversized lengths
In the old days, we used to try to correct this problem by adjusting the region header to match the
length found at the start of the chunk payload. However, this has a very good chance to cause corruption
of other chunks, since we can't do any fast overlap checks (an upsize might cause the chunk's alloocated
area to overlap into another one, causing corruption when either chunk's space gets written to).

This corruption risk has become more problematic since the
introduction of region garbage sector reuse, since a broken location
header could cause chunks to trash each others' saved data.

In addition, if there is a length mismatch, there's a good chance that the oversized chunk itself will
already be corrupted, so we'd just fail trying to decompress it later on.

So, instead of trying to fix this automatically, we bail and hope this doesn't occur often enough for
users to get upset, and allow external offline tools to attempt to repair the mess instead.
2020-12-27 18:50:52 +00:00
873e8740e0 3.17.2 is next 2020-12-23 22:20:24 +00:00
260c55f23a Release 3.17.1 2020-12-23 22:20:19 +00:00
9ed430acb9 CrashDump: fixed a bug in crashdump generation 2020-12-23 21:53:12 +00:00
f0241043de CrashDump: add server uptime to crash information 2020-12-23 20:26:18 +00:00
135f1c95e4 phpstan 0.12.64 2020-12-23 20:04:40 +00:00
5431807e43 Split tests up into multiple jobs
this gives a more granular view of test failures and also allows independent steps to run in parallel.
2020-12-23 19:48:39 +00:00
d49ae832e8 actions: rename cache miss fallback build step 2020-12-21 21:32:27 +00:00
ff9d013005 build: hash composer cache by lockfile instead of composer.json
this ensures a cache refresh when transitive dependencies are updated.
2020-12-20 23:58:37 +00:00
b0e1317818 Merge branch 'stable' of https://github.com/pmmp/pocketmine-mp into stable 2020-12-20 23:53:26 +00:00
8653afb0fb Updated composer dependencies 2020-12-20 23:53:09 +00:00
995b56aaa0 Fixed Composer package cache 2020-12-20 23:49:28 +00:00
3ecddf312d build.sh: sort configure parameters 2020-12-20 22:49:39 +00:00
470243ca6f experimental: build PHP in a separate build job 2020-12-20 22:30:47 +00:00
3f21e59917 Bump phpstan/phpstan-strict-rules from 0.12.5 to 0.12.7 (#3976) 2020-12-18 13:44:19 +00:00
fdd74a4f46 Bump phpstan/phpstan-phpunit from 0.12.16 to 0.12.17 (#3975) 2020-12-18 13:15:05 +00:00
a43b46a93c Merge branch 'stable' of https://github.com/pmmp/pocketmine-mp into stable 2020-12-18 00:33:10 +00:00
0604dfc9e5 phpstan 0.12.63 2020-12-18 00:32:55 +00:00
dd2c3db285 Fixed a bucket of lava disappearing when used in a furnace (#3973)
fixes #2385
2020-12-17 23:57:34 +00:00
c95e283507 fix CXXFLAGS 2020-12-14 22:02:16 +00:00
6afbd1f55c Squashed commit of the following:
commit 1f42169f0f929958f7d68a68f194c6f3492b7eb4
Author: Dylan K. Taylor <odigiman@gmail.com>
Date:   Mon Dec 14 21:23:44 2020 +0000

    ... install it in the right fucking place

commit d2a88abeda5fa937d3f508c4e0300a949af97846
Author: Dylan K. Taylor <odigiman@gmail.com>
Date:   Mon Dec 14 21:14:21 2020 +0000

    Build PHP using system libraries to reduce rebuild time
2020-12-14 21:58:58 +00:00
0682c93f5a Drop bcmath dependency
we haven't used bcmath since the days of 32-bit.
2020-12-14 20:59:07 +00:00
da90ae85da Updated composer dependencies 2020-12-14 19:24:36 +00:00
e87127f309 readme: drop travis badge in favour of GH Actions badge 2020-12-11 22:38:14 +00:00
0237a50d90 thank you for your service travis 2020-12-11 22:26:53 +00:00
8b53e4150e Setup GitHub Actions (#3966) 2020-12-11 22:25:08 +00:00
1c43538238 Fix that a hoe gets damage applied to it, when it's used to break a block (#3967)
closes #3965
2020-12-11 21:14:52 +00:00
68887105b2 Utils::cleanPath(): drop the square braces
this looks ugly, as well as breaking plugin crash detection (which tbh is too fragile, but it is what it is ...)
2020-12-09 20:26:08 +00:00
104e90b794 CrashDump: more robust core crash detection 2020-12-08 23:27:03 +00:00
994062f6dc CrashDump: fixed plugin detection on eval()'d code
it's possible we could clean the path up to detect which plugin caused the crash, but for now I'll be happy to not have them showing up as core crashes ...
2020-12-08 23:11:29 +00:00
69a41a5ed4 3.17.1 is next 2020-12-08 21:02:14 +00:00
96 changed files with 1995 additions and 915 deletions

16
.github/support.yml vendored
View File

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

281
.github/workflows/main.yml vendored Normal file
View File

@ -0,0 +1,281 @@
name: CI
on:
push:
pull_request:
workflow_dispatch:
jobs:
build-php:
name: Prepare PHP
runs-on: ${{ matrix.image }}
strategy:
matrix:
image: [ubuntu-20.04]
php: [7.3.27, 7.4.16]
steps:
- uses: actions/checkout@v2 #needed for build.sh
- name: Check for PHP build cache
id: php-build-cache
uses: actions/cache@v2
with:
path: "./bin"
key: "php-build-generic-${{ matrix.php }}-${{ matrix.image }}-${{ hashFiles('./tests/gh-actions/build.sh') }}"
- name: Compile PHP
if: steps.php-build-cache.outputs.cache-hit != 'true'
run: ./tests/gh-actions/build.sh "${{ matrix.php }}"
phpstan:
name: PHPStan analysis
needs: build-php
runs-on: ${{ matrix.image }}
strategy:
fail-fast: false
matrix:
image: [ubuntu-20.04]
php: [7.3.27, 7.4.16]
steps:
- uses: actions/checkout@v2
- name: Restore PHP build cache
id: php-build-cache
uses: actions/cache@v2
with:
path: "./bin"
key: "php-build-generic-${{ matrix.php }}-${{ matrix.image }}-${{ hashFiles('./tests/gh-actions/build.sh') }}"
- name: Kill build on PHP build cache miss (should never happen)
if: steps.php-build-cache.outputs.cache-hit != 'true'
run: exit 1
- name: Install cached PHP's dependencies
if: steps.php-build-cache.outputs.cache-hit == 'true'
run: chmod +x ./bin/php7/install-dependencies.sh && ./bin/php7/install-dependencies.sh
- name: Prefix PHP to PATH
run: echo "$(pwd)/bin/php7/bin" >> $GITHUB_PATH
- name: Install Composer
run: curl -sS https://getcomposer.org/installer | php
- name: Restore Composer package cache
uses: actions/cache@v2
with:
path: |
~/.cache/composer/files
~/.cache/composer/vcs
key: "composer-v2-cache-${{ matrix.php }}-${{ hashFiles('./composer.lock') }}"
restore-keys: |
composer-v2-cache-
- name: Install Composer dependencies
run: php composer.phar install --prefer-dist --no-interaction
- name: Run PHPStan
run: ./vendor/bin/phpstan analyze --no-progress --memory-limit=2G
phpunit:
name: PHPUnit tests
needs: build-php
runs-on: ${{ matrix.image }}
strategy:
fail-fast: false
matrix:
image: [ubuntu-20.04]
php: [7.3.27, 7.4.16]
steps:
- uses: actions/checkout@v2
- name: Restore PHP build cache
id: php-build-cache
uses: actions/cache@v2
with:
path: "./bin"
key: "php-build-generic-${{ matrix.php }}-${{ matrix.image }}-${{ hashFiles('./tests/gh-actions/build.sh') }}"
- name: Kill build on PHP build cache miss (should never happen)
if: steps.php-build-cache.outputs.cache-hit != 'true'
run: exit 1
- name: Install cached PHP's dependencies
if: steps.php-build-cache.outputs.cache-hit == 'true'
run: chmod +x ./bin/php7/install-dependencies.sh && ./bin/php7/install-dependencies.sh
- name: Prefix PHP to PATH
run: echo "$(pwd)/bin/php7/bin" >> $GITHUB_PATH
- name: Install Composer
run: curl -sS https://getcomposer.org/installer | php
- name: Restore Composer package cache
uses: actions/cache@v2
with:
path: |
~/.cache/composer/files
~/.cache/composer/vcs
key: "composer-v2-cache-${{ matrix.php }}-${{ hashFiles('./composer.lock') }}"
restore-keys: |
composer-v2-cache-
- name: Install Composer dependencies
run: php composer.phar install --prefer-dist --no-interaction
- name: Run PHPUnit tests
run: ./vendor/bin/phpunit --bootstrap vendor/autoload.php --fail-on-warning tests/phpunit
integration:
name: Integration tests
needs: build-php
runs-on: ${{ matrix.image }}
strategy:
fail-fast: false
matrix:
image: [ubuntu-20.04]
php: [7.3.27, 7.4.16]
steps:
- uses: actions/checkout@v2
with:
submodules: true
- name: Restore PHP build cache
id: php-build-cache
uses: actions/cache@v2
with:
path: "./bin"
key: "php-build-generic-${{ matrix.php }}-${{ matrix.image }}-${{ hashFiles('./tests/gh-actions/build.sh') }}"
- name: Kill build on PHP build cache miss (should never happen)
if: steps.php-build-cache.outputs.cache-hit != 'true'
run: exit 1
- name: Install cached PHP's dependencies
if: steps.php-build-cache.outputs.cache-hit == 'true'
run: chmod +x ./bin/php7/install-dependencies.sh && ./bin/php7/install-dependencies.sh
- name: Prefix PHP to PATH
run: echo "$(pwd)/bin/php7/bin" >> $GITHUB_PATH
- name: Install Composer
run: curl -sS https://getcomposer.org/installer | php
- name: Restore Composer package cache
uses: actions/cache@v2
with:
path: |
~/.cache/composer/files
~/.cache/composer/vcs
key: "composer-v2-cache-${{ matrix.php }}-${{ hashFiles('./composer.lock') }}"
restore-keys: |
composer-v2-cache-
- name: Install Composer dependencies
run: php composer.phar install --no-dev --prefer-dist --no-interaction
- name: Run integration tests
run: ./tests/travis.sh -t4
preprocessor:
name: Preprocessor tests
needs: build-php
runs-on: ${{ matrix.image }}
strategy:
fail-fast: false
matrix:
image: [ubuntu-20.04]
php: [7.3.27, 7.4.16]
steps:
- uses: actions/checkout@v2
with:
submodules: true
- name: Restore PHP build cache
id: php-build-cache
uses: actions/cache@v2
with:
path: "./bin"
key: "php-build-generic-${{ matrix.php }}-${{ matrix.image }}-${{ hashFiles('./tests/gh-actions/build.sh') }}"
- name: Kill build on PHP build cache miss (should never happen)
if: steps.php-build-cache.outputs.cache-hit != 'true'
run: exit 1
- name: Install cached PHP's dependencies
if: steps.php-build-cache.outputs.cache-hit == 'true'
run: chmod +x ./bin/php7/install-dependencies.sh && ./bin/php7/install-dependencies.sh
- name: Prefix PHP to PATH
run: echo "$(pwd)/bin/php7/bin" >> $GITHUB_PATH
- name: Install Composer
run: curl -sS https://getcomposer.org/installer | php
- name: Restore Composer package cache
uses: actions/cache@v2
with:
path: |
~/.cache/composer/files
~/.cache/composer/vcs
key: "composer-v2-cache-${{ matrix.php }}-${{ hashFiles('./composer.lock') }}"
restore-keys: |
composer-v2-cache-
- name: Install Composer dependencies
run: php composer.phar install --no-dev --prefer-dist --no-interaction
- name: Run preprocessor
run: |
PM_PREPROCESSOR_PATH="$GITHUB_WORKSPACE/build/preprocessor"
php "$PM_PREPROCESSOR_PATH/PreProcessor.php" --path=src --multisize || (echo "Preprocessor exited with code $?" && exit 1)
#dump the diff of preprocessor replacements to a patch in case it has bugs
git diff > preprocessor_diff.patch
VENDOR_PM="$GITHUB_WORKSPACE/vendor"
VENDOR_PM_BACKUP="$GITHUB_WORKSPACE/vendor-before-preprocess"
cp -r "$VENDOR_PM" "$VENDOR_PM_BACKUP"
for f in $(ls $VENDOR_PM/pocketmine); do
echo "Processing directory \"$f\"..."
php "$PM_PREPROCESSOR_PATH/PreProcessor.php" --path="$VENDOR_PM/pocketmine/$f" --multisize || (echo "Preprocessor exited with code $?" && exit 1)
echo "Checking for changes in \"$f\"..."
DIFF=$(git diff --no-index "$VENDOR_PM_BACKUP/pocketmine/$f" "$VENDOR_PM/pocketmine/$f" || true)
if [ "$DIFF" != "" ]; then
PATCH="$GITHUB_WORKSPACE/preprocessor_diff_$f.patch"
echo "$DIFF" > "$PATCH"
echo "Generated patch file \"$PATCH\""
else
echo "No diff generated for \"$f\" (preprocessor made no changes)"
fi
done
- name: Upload preprocessor diffs
uses: actions/upload-artifact@v2
if: always()
with:
name: preprocessor_diffs_${{ matrix.php }}_${{ matrix.image }}
path: ${{ github.workspace }}/preprocessor_diff*.patch
codestyle:
name: Code Style checks
runs-on: ubuntu-20.04
strategy:
fail-fast: false
steps:
- uses: actions/checkout@v2
- name: Setup PHP and tools
uses: shivammathur/setup-php@2.9.0
with:
php-version: 7.4
tools: php-cs-fixer
- name: Run PHP-CS-Fixer
run: php-cs-fixer fix --dry-run --diff --diff-format=udiff

22
.github/workflows/support.yml vendored Normal file
View File

@ -0,0 +1,22 @@
name: 'Manage support request issues'
on:
issues:
types: [labeled, unlabeled, reopened]
jobs:
support:
runs-on: ubuntu-latest
steps:
- uses: dessant/support-requests@v2
with:
github-token: ${{ github.token }}
support-label: "Support request"
issue-comment: >
Thanks, but this issue tracker is not intended for support requests. Please read the guidelines on [submitting an issue](https://github.com/pmmp/PocketMine-MP/blob/master/CONTRIBUTING.md#creating-an-issue).
[Docs](https://pmmp.rtfd.io) | [Discord](https://discord.gg/bmSAZBG) | [Forums](https://forums.pmmp.io)
close-issue: true
lock-issue: false

71
.php_cs Normal file
View File

@ -0,0 +1,71 @@
<?php
$finder = PhpCsFixer\Finder::create()
->in(__DIR__ . '/src')
->in(__DIR__ . '/build')
->in(__DIR__ . '/tests')
->notPath('plugins/DevTools')
->notPath('preprocessor')
->notContains('#ifndef COMPILE') //preprocessor will break if these are changed
->notName('PocketMine.php');
return PhpCsFixer\Config::create()
->setRiskyAllowed(true)
->setRules([
'align_multiline_comment' => [
'comment_type' => 'phpdocs_only'
],
'array_indentation' => true,
'array_syntax' => [
'syntax' => 'short'
],
'blank_line_after_namespace' => true,
'blank_line_after_opening_tag' => true,
'blank_line_before_statement' => [
'statements' => [
'declare'
]
],
'cast_spaces' => [
'space' => 'single'
],
'concat_space' => [
'spacing' => 'one'
],
'declare_strict_types' => true,
'elseif' => true,
'global_namespace_import' => [
'import_constants' => true,
'import_functions' => true,
'import_classes' => null,
],
'indentation_type' => true,
'native_function_invocation' => [
'scope' => 'namespaced'
],
'no_closing_tag' => true,
'no_empty_phpdoc' => true,
'no_extra_blank_lines' => true,
'no_superfluous_phpdoc_tags' => [
'allow_mixed' => true,
],
'no_trailing_whitespace' => true,
'no_trailing_whitespace_in_comment' => true,
'no_whitespace_in_blank_line' => true,
'no_unused_imports' => true,
'ordered_imports' => [
'imports_order' => [
'class',
'function',
'const',
],
'sort_algorithm' => 'alpha'
],
'phpdoc_trim' => true,
'phpdoc_trim_consecutive_blank_line_separation' => true,
'single_import_per_statement' => true,
'strict_param' => true,
])
->setFinder($finder)
->setIndent("\t")
->setLineEnding("\n");

View File

@ -1,21 +0,0 @@
import:
source: ./tests/travis/setup-php.yml
script:
- composer install --prefer-dist
- ./vendor/bin/phpstan analyze --no-progress --memory-limit=2G
- ./vendor/bin/phpunit --bootstrap vendor/autoload.php --fail-on-warning tests/phpunit
- composer install --no-dev --prefer-dist
- ./tests/travis.sh -t4
cache:
directories:
- $HOME/.composer/cache/files
- $HOME/.composer/cache/vcs
notifications:
email:
recipients:
- team@pmmp.io
on_success: change
on_failure: always

View File

@ -8,7 +8,7 @@
## Custom PHP binaries
Because PocketMine-MP requires several non-standard PHP extensions and configuration, PMMP provides scripts to build custom binaries for running PocketMine-MP, as well as prebuilt binaries.
- [Prebuilt binaries](https://jenkins.pmmp.io/job/PHP-7.3-Aggregate)
- [Prebuilt binaries](https://jenkins.pmmp.io/job/PHP-7.4-Aggregate)
- [Compile scripts](https://github.com/pmmp/php-build-scripts) are provided as a submodule in the path `build/php`
If you use a custom binary, you'll need to replace `composer` usages in this guide with `path/to/your/php path/to/your/composer.phar`.
@ -34,5 +34,11 @@ Run `composer make-server` using your preferred PHP binary. It'll drop a `Pocket
You can also use the `--out` option to change the output filename.
There is a bug in PHP that might cause an error which looks like this:
```
Fatal error: Uncaught BadMethodCallException: unable to create temporary file in PocketMine-MP/build/server-phar.php:119
```
You can work around it by setting `ulimit -n` to some bigger number, e.g. `8192`, or by updating your PHP version to at least 7.4.16 or 8.0.3.
## Running PocketMine-MP from source code
Run `src/pocketmine/PocketMine.php` using your preferred PHP binary.

View File

@ -3,7 +3,12 @@
<b>A highly customisable, open source server software for Minecraft: Bedrock Edition written in PHP</b>
</p>
[![Build Status](https://travis-ci.com/pmmp/PocketMine-MP.svg?branch=master)](https://travis-ci.com/pmmp/PocketMine-MP)
<p align="center">
<img src="https://github.com/pmmp/PocketMine-MP/workflows/CI/badge.svg" alt="CI" />
<a href="https://github.com/pmmp/PocketMine-MP/releases"><img src="https://img.shields.io/github/v/tag/pmmp/PocketMine-MP?label=release&logo=github" alt="GitHub tag (latest semver)" /></a>
<a href="https://hub.docker.com/r/pmmp/pocketmine-mp"><img src="https://img.shields.io/docker/v/pmmp/pocketmine-mp?logo=docker&label=image" alt="Docker image version (latest semver)" /></a>
<a href="https://discord.gg/bmSAZBG"><img src="https://img.shields.io/discord/373199722573201408?label=discord&color=7289DA&logo=discord" alt="Discord" /></a>
</p>
## Getting started
- [Documentation](http://pmmp.readthedocs.org/)
@ -18,6 +23,7 @@
## For developers
* [Building and running from source](BUILDING.md)
* [Developer documentation](https://devdoc.pmmp.io) - General documentation for PocketMine-MP plugin developers
* [Latest API documentation](https://jenkins.pmmp.io/job/PocketMine-MP-doc/doxygen/) - Doxygen documentation generated from development
* [DevTools](https://github.com/pmmp/DevTools/) - Development tools plugin for creating plugins
* [ExamplePlugin](https://github.com/pmmp/ExamplePlugin/) - Example plugin demonstrating some basic API features

View File

@ -24,7 +24,6 @@ declare(strict_types=1);
namespace pocketmine\build\make_release;
use pocketmine\utils\VersionString;
use function defined;
use function dirname;
use function fgets;
use function file_get_contents;
@ -72,7 +71,7 @@ function main(array $argv) : void{
$versionInfoPath = dirname(__DIR__) . '/src/pocketmine/VersionInfo.php';
replaceVersion($versionInfoPath, $currentVer->getBaseVersion(), false);
echo "please add appropriate notes to the changelog and press enter...";
fgets(STDIN);
system('git add "' . dirname(__DIR__) . '/changelogs"');
@ -86,6 +85,4 @@ function main(array $argv) : void{
system('git push origin HEAD ' . $currentVer->getBaseVersion());
}
if(!defined('pocketmine\_PHPSTAN_ANALYSIS')){
main($argv);
}
main($argv);

View File

@ -26,7 +26,6 @@ namespace pocketmine\build\server_phar;
use pocketmine\utils\Git;
use function array_map;
use function count;
use function defined;
use function dirname;
use function file_exists;
use function getcwd;
@ -174,6 +173,4 @@ STUB
}
}
if(!defined('pocketmine\_PHPSTAN_ANALYSIS')){
main();
}
main();

View File

@ -15,3 +15,49 @@ Plugin developers should **only** update their required API to this version if y
- Pumpkin and melon stems may not connect to their corresponding pumpkin/melon
- New blocks, items & mobs aren't implemented
- Nether doesn't exist
# 3.17.1
- Fixed some instances of plugin-caused crashes not being detected (eval()'d code, custom plugin paths).
- Server uptime is now included in crash reports.
- Hoes now take damage when used to break sponges.
- Using lava as fuel in a furnace now leaves behind an empty bucket.
# 3.17.2
- Fixed region header corruption when chunks with larger-than-expected lengths are found. These chunks are now treated as corrupted, instead of automatically attempting to salvage them (which usually fails anyway).
- `RegionLoader->removeChunk()` now allows the space used by the removed chunk to be reused by future region saves.
- Extracted `Living->applyConsumptionResults()` from `Living->consumeObject()` (preparation for a future bug fix).
# 3.17.3
- Improved performance of chunk loading in Region-based worlds.
- Improved performance of region header validation in Region-based worlds (indirect improvement to chunk loading performance).
- Fixed some PHP 8.0 language-level compatibility issues.
- Source installations will now exit with an error when Composer dependencies are not in sync with the current Git revision. Now, it's required to run `composer install` after every git pull to make sure the correct dependency versions are installed.
# 3.17.4
- Removed `readline` support. This hasn't been maintained for many years, never worked correctly, and isn't thread-safe in any case.
- Fixed false-positives of region corruption in Region-based worlds (outdated file stat cache).
- Fixed more deprecation warnings on PHP 8.0 (optional parameter before required).
- `CraftItemEvent->getInputs()` now returns a list starting at offset 0, instead of random offsets. (Note that the contents still won't be ordered.)
- `CraftItemEvent->getOutputs()` now returns a list starting at offset 0, instead of random offsets. (Note that the contents still won't be ordered.)
- Fixed a bug that broke synchronized building, bridging, towering and more.
- Objects in memory dumps no longer show inherited properties multiple times.
# 3.17.5
- Reduced CPU wastage by the logger thread.
- Fixed LevelDB deprecation errors on PHP 8.0.
- Added some protocol changes for 1.16.200 which were previously overlooked.
- Player XUIDs are now tracked. If a player's XUID does not match the previously recorded XUID when they next join the server, they will be kicked. This can be disabled by the `player.verify-xuid` setting in `pocketmine.yml`.
- `BUILDING.md` now has a note about `build/server-phar.php`'s compression bug (a bug in PHP).
# 3.17.6
- Fixed core race conditions that could have led to server freezes (race conditions in pmmp/Snooze).
- The log message about Xbox Live authentication being enabled has been reduced to INFO, and the tip on how to turn it off removed (disabling it should usually only be done by power users anyway).
- Fixed `PlayerMoveEvent->getFrom()` returning incorrect results for players who experienced movement reversions.
- Fixed a bug in `ResourcePackClientResponsePacket` decoding that caused unexpected results when decoding the packet twice.
- XUID verification now compares XUIDs against players who are already on the server to detect mismatches to avoid unnecessary loading of playerdata.
- Fixed an inventory duplication bug which could occur when the same player joined with two devices at the same time.
- Fixed cursor item not being synced on inventory transaction rollbacks.
- Fixed items with TAG_Float in their NBT not being able to be moved around in the inventory.
# 3.17.7
- Fixed crash caused by preprocessor in 3.17.6.

26
changelogs/3.18.md Normal file
View File

@ -0,0 +1,26 @@
**For Minecraft: Bedrock Edition 1.16.210**
### 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.18.0
- Added support for Minecraft: Bedrock Edition 1.16.210.
- Removed compatibility with earlier versions.
## Known issues (please don't open issues for these)
- Walls don't connect to each other
- Pumpkin and melon stems may not connect to their corresponding pumpkin/melon
- New blocks, items & mobs aren't implemented
- Nether doesn't exist
- Items can't be removed from item frames in Survival mode
# 3.18.1
- UPnP is now supported on all platforms instead of just Windows. Note that it's still experimental. Please file issues for any bugs that you find.
- Fixed server joining when default game mode is set to Spectator mode.
- Fixed items not being able to be removed from item frames in Survival mode.
- Fixed field order in ClientCacheBlobStatusPacket (hits and misses were inverted).
- Fixed a deadlock that could occur when MainLogger->syncFlushBuffer() was used (usually only used during exception logging).
- Updated constants for various things in the protocol.

View File

@ -5,11 +5,10 @@
"homepage": "https://pmmp.io",
"license": "LGPL-3.0",
"require": {
"php": ">=7.3.0",
"php": "^7.3 || ^8.0",
"php-64bit": "*",
"ext-bcmath": "*",
"ext-curl": "*",
"ext-ctype": "*",
"ext-curl": "*",
"ext-date": "*",
"ext-hash": "*",
"ext-json": "*",
@ -19,26 +18,27 @@
"ext-phar": "*",
"ext-pthreads": "~3.2.0",
"ext-reflection": "*",
"ext-simplexml": "*",
"ext-sockets": "*",
"ext-spl": "*",
"ext-yaml": ">=2.0.0",
"ext-zip": "*",
"ext-zlib": ">=1.2.11",
"pocketmine/raklib": "^0.12.7",
"pocketmine/spl": "^0.4.0",
"composer-runtime-api": "^2.0",
"adhocore/json-comment": "^0.1.0",
"pocketmine/binaryutils": "^0.1.9",
"pocketmine/nbt": "^0.2.10",
"pocketmine/math": "^0.2.0",
"pocketmine/snooze": "^0.1.0",
"pocketmine/callback-validator": "^1.0.2",
"pocketmine/classloader": "^0.1.0",
"pocketmine/log": "^0.2.0",
"pocketmine/log-pthreads": "^0.1.0",
"pocketmine/callback-validator": "^1.0.2",
"adhocore/json-comment": "^0.1.0",
"composer-runtime-api": "^2.0"
"pocketmine/math": "^0.2.0",
"pocketmine/nbt": "^0.2.18",
"pocketmine/raklib": "^0.12.7",
"pocketmine/snooze": "^0.1.0",
"pocketmine/spl": "^0.4.0"
},
"require-dev": {
"phpstan/phpstan": "0.12.59",
"phpstan/phpstan": "0.12.82",
"phpstan/phpstan-phpunit": "^0.12.6",
"phpstan/phpstan-strict-rules": "^0.12.2",
"phpunit/phpunit": "^9.2"
@ -61,7 +61,8 @@
"config": {
"platform": {
"php": "7.3.0"
}
},
"sort-packages": true
},
"scripts": {
"make-devtools": "@php -dphar.readonly=0 tests/plugins/DevTools/src/DevTools/ConsoleScript.php --make tests/plugins/DevTools --out plugins/DevTools.phar",

340
composer.lock generated
View File

@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
"content-hash": "2c44138f2052c259a201871d4d423947",
"content-hash": "df0cb7c9eab4da5e693533deb010f9d1",
"packages": [
{
"name": "adhocore/json-comment",
@ -56,25 +56,25 @@
},
{
"name": "pocketmine/binaryutils",
"version": "0.1.12",
"version": "0.1.13",
"source": {
"type": "git",
"url": "https://github.com/pmmp/BinaryUtils.git",
"reference": "566fa87829e007eda0bd96e39fe20b9b0d638132"
"reference": "0abee38d4e2861621f262c79a2a3d699d8a697f4"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/pmmp/BinaryUtils/zipball/566fa87829e007eda0bd96e39fe20b9b0d638132",
"reference": "566fa87829e007eda0bd96e39fe20b9b0d638132",
"url": "https://api.github.com/repos/pmmp/BinaryUtils/zipball/0abee38d4e2861621f262c79a2a3d699d8a697f4",
"reference": "0abee38d4e2861621f262c79a2a3d699d8a697f4",
"shasum": ""
},
"require": {
"php": ">=7.2",
"php": "^7.2 || ^8.0",
"php-64bit": "*"
},
"require-dev": {
"phpstan/extension-installer": "^1.0",
"phpstan/phpstan": "0.12.40",
"phpstan/phpstan": "0.12.67",
"phpstan/phpstan-strict-rules": "^0.12.4"
},
"type": "library",
@ -90,34 +90,34 @@
"description": "Classes and methods for conveniently handling binary data",
"support": {
"issues": "https://github.com/pmmp/BinaryUtils/issues",
"source": "https://github.com/pmmp/BinaryUtils/tree/stable"
"source": "https://github.com/pmmp/BinaryUtils/tree/0.1.13"
},
"time": "2020-08-28T20:43:21+00:00"
"time": "2021-01-15T14:19:13+00:00"
},
{
"name": "pocketmine/callback-validator",
"version": "1.0.2",
"version": "1.0.3",
"source": {
"type": "git",
"url": "git@github.com:pmmp/CallbackValidator.git",
"reference": "8321aa3ccfe63639b0d08f0cbf270755cfc99fe2"
"url": "https://github.com/pmmp/CallbackValidator.git",
"reference": "64787469766bcaa7e5885242e85c23c25e8c55a2"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/pmmp/CallbackValidator/zipball/8321aa3ccfe63639b0d08f0cbf270755cfc99fe2",
"reference": "8321aa3ccfe63639b0d08f0cbf270755cfc99fe2",
"url": "https://api.github.com/repos/pmmp/CallbackValidator/zipball/64787469766bcaa7e5885242e85c23c25e8c55a2",
"reference": "64787469766bcaa7e5885242e85c23c25e8c55a2",
"shasum": ""
},
"require": {
"ext-reflection": "*",
"php": ">=7.1"
"php": "^7.1 || ^8.0"
},
"replace": {
"daverandom/callback-validator": "*"
},
"require-dev": {
"phpstan/extension-installer": "^1.0",
"phpstan/phpstan": "0.12.38",
"phpstan/phpstan": "0.12.59",
"phpstan/phpstan-strict-rules": "^0.12.4",
"phpunit/phpunit": "^7.5 || ^8.5 || ^9.0"
},
@ -138,33 +138,37 @@
}
],
"description": "Fork of daverandom/callback-validator - Tools for validating callback signatures",
"time": "2020-08-21T19:51:42+00:00"
"support": {
"issues": "https://github.com/pmmp/CallbackValidator/issues",
"source": "https://github.com/pmmp/CallbackValidator/tree/1.0.3"
},
"time": "2020-12-11T01:45:37+00:00"
},
{
"name": "pocketmine/classloader",
"version": "0.1.1",
"version": "0.1.2",
"source": {
"type": "git",
"url": "https://github.com/pmmp/ClassLoader.git",
"reference": "7c0363491d1ce8f914fe96d41a4338c982adedff"
"reference": "9757928424652393b178a3760073113aa7c9911b"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/pmmp/ClassLoader/zipball/7c0363491d1ce8f914fe96d41a4338c982adedff",
"reference": "7c0363491d1ce8f914fe96d41a4338c982adedff",
"url": "https://api.github.com/repos/pmmp/ClassLoader/zipball/9757928424652393b178a3760073113aa7c9911b",
"reference": "9757928424652393b178a3760073113aa7c9911b",
"shasum": ""
},
"require": {
"ext-pthreads": "~3.2.0",
"ext-reflection": "*",
"php": ">=7.2.0"
"php": "^7.2 || ^8.0"
},
"conflict": {
"pocketmine/spl": "<0.4"
},
"require-dev": {
"phpstan/extension-installer": "^1.0",
"phpstan/phpstan": "0.12.38",
"phpstan/phpstan": "0.12.66",
"phpstan/phpstan-strict-rules": "^0.12.4"
},
"type": "library",
@ -180,32 +184,32 @@
"description": "Ad-hoc autoloading components used by PocketMine-MP",
"support": {
"issues": "https://github.com/pmmp/ClassLoader/issues",
"source": "https://github.com/pmmp/ClassLoader/tree/stable"
"source": "https://github.com/pmmp/ClassLoader/tree/0.1.2"
},
"time": "2020-08-22T11:48:51+00:00"
"time": "2021-01-15T00:40:47+00:00"
},
{
"name": "pocketmine/log",
"version": "0.2.0",
"version": "0.2.1",
"source": {
"type": "git",
"url": "https://github.com/pmmp/Log.git",
"reference": "e59bedb5d4bbeb9a26647cb7c367cb2fa72addfa"
"reference": "830b44a2cf96ef703c550abe64302f230231ca49"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/pmmp/Log/zipball/e59bedb5d4bbeb9a26647cb7c367cb2fa72addfa",
"reference": "e59bedb5d4bbeb9a26647cb7c367cb2fa72addfa",
"url": "https://api.github.com/repos/pmmp/Log/zipball/830b44a2cf96ef703c550abe64302f230231ca49",
"reference": "830b44a2cf96ef703c550abe64302f230231ca49",
"shasum": ""
},
"require": {
"php": ">=7.2"
"php": "^7.2 || ^8.0"
},
"conflict": {
"pocketmine/spl": "<0.4"
},
"require-dev": {
"phpstan/phpstan": "^0.12.8",
"phpstan/phpstan": "0.12.67",
"phpstan/phpstan-strict-rules": "^0.12.2"
},
"type": "library",
@ -221,34 +225,36 @@
"description": "Logging components used by PocketMine-MP and related projects",
"support": {
"issues": "https://github.com/pmmp/Log/issues",
"source": "https://github.com/pmmp/Log/tree/0.2.0"
"source": "https://github.com/pmmp/Log/tree/0.2.1"
},
"time": "2020-03-31T15:43:47+00:00"
"time": "2021-01-15T14:32:41+00:00"
},
{
"name": "pocketmine/log-pthreads",
"version": "0.1.1",
"version": "0.1.3",
"source": {
"type": "git",
"url": "https://github.com/pmmp/LogPthreads.git",
"reference": "9bbcef398b01487ab47c234a6a7054722abbe067"
"reference": "e477ecf6ec214fdd4415ea1da3fdd9d73bf699ea"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/pmmp/LogPthreads/zipball/9bbcef398b01487ab47c234a6a7054722abbe067",
"reference": "9bbcef398b01487ab47c234a6a7054722abbe067",
"url": "https://api.github.com/repos/pmmp/LogPthreads/zipball/e477ecf6ec214fdd4415ea1da3fdd9d73bf699ea",
"reference": "e477ecf6ec214fdd4415ea1da3fdd9d73bf699ea",
"shasum": ""
},
"require": {
"ext-pthreads": "~3.2.0",
"php": ">=7.2",
"php": "^7.2 || ^8.0",
"pocketmine/log": "^0.2.0"
},
"conflict": {
"pocketmine/spl": "<0.4"
},
"require-dev": {
"phpstan/phpstan": "^0.12.18"
"phpstan/extension-installer": "^1.0",
"phpstan/phpstan": "0.12.66",
"phpstan/phpstan-strict-rules": "^0.12.4"
},
"type": "library",
"autoload": {
@ -263,31 +269,31 @@
"description": "Logging components specialized for pthreads used by PocketMine-MP and related projects",
"support": {
"issues": "https://github.com/pmmp/LogPthreads/issues",
"source": "https://github.com/pmmp/LogPthreads/tree/0.1.1"
"source": "https://github.com/pmmp/LogPthreads/tree/0.1.3"
},
"time": "2020-03-31T16:17:19+00:00"
"time": "2021-01-15T00:35:49+00:00"
},
{
"name": "pocketmine/math",
"version": "0.2.5",
"version": "0.2.6",
"source": {
"type": "git",
"url": "https://github.com/pmmp/Math.git",
"reference": "8c46cfa95351fb0b2b30739a381310941934b55f"
"reference": "43057cb8c179a9859677b496a788db922fd5cfc3"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/pmmp/Math/zipball/8c46cfa95351fb0b2b30739a381310941934b55f",
"reference": "8c46cfa95351fb0b2b30739a381310941934b55f",
"url": "https://api.github.com/repos/pmmp/Math/zipball/43057cb8c179a9859677b496a788db922fd5cfc3",
"reference": "43057cb8c179a9859677b496a788db922fd5cfc3",
"shasum": ""
},
"require": {
"php": ">=7.2.0",
"php": "^7.2 || ^8.0",
"php-64bit": "*"
},
"require-dev": {
"phpstan/extension-installer": "^1.0",
"phpstan/phpstan": "0.12.40",
"phpstan/phpstan": "0.12.67",
"phpstan/phpstan-strict-rules": "^0.12.4"
},
"type": "library",
@ -303,34 +309,34 @@
"description": "PHP library containing math related code used in PocketMine-MP",
"support": {
"issues": "https://github.com/pmmp/Math/issues",
"source": "https://github.com/pmmp/Math/tree/stable"
"source": "https://github.com/pmmp/Math/tree/0.2.6"
},
"time": "2020-08-27T11:45:40+00:00"
"time": "2021-01-15T14:25:11+00:00"
},
{
"name": "pocketmine/nbt",
"version": "0.2.15",
"version": "0.2.18",
"source": {
"type": "git",
"url": "https://github.com/pmmp/NBT.git",
"reference": "f8a81d37d24eb79fb77d985a52549d68955bc6a1"
"reference": "9f82ca4d7f97fcd9a566e44b63c4f18a7657ae82"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/pmmp/NBT/zipball/f8a81d37d24eb79fb77d985a52549d68955bc6a1",
"reference": "f8a81d37d24eb79fb77d985a52549d68955bc6a1",
"url": "https://api.github.com/repos/pmmp/NBT/zipball/9f82ca4d7f97fcd9a566e44b63c4f18a7657ae82",
"reference": "9f82ca4d7f97fcd9a566e44b63c4f18a7657ae82",
"shasum": ""
},
"require": {
"ext-zlib": "*",
"php": ">=7.2.0",
"php": "^7.2 || ^8.0",
"php-64bit": "*",
"pocketmine/binaryutils": "^0.1.9"
},
"require-dev": {
"irstea/phpunit-shim": "^7.5 || ^8.0",
"phpstan/extension-installer": "^1.0",
"phpstan/phpstan": "0.12.40",
"phpstan/phpstan": "0.12.80",
"phpstan/phpstan-strict-rules": "^0.12.4"
},
"type": "library",
@ -346,28 +352,28 @@
"description": "PHP library for working with Named Binary Tags",
"support": {
"issues": "https://github.com/pmmp/NBT/issues",
"source": "https://github.com/pmmp/NBT/tree/stable"
"source": "https://github.com/pmmp/NBT/tree/0.2.18"
},
"time": "2020-08-28T15:11:32+00:00"
"time": "2021-03-11T00:09:04+00:00"
},
{
"name": "pocketmine/raklib",
"version": "0.12.9",
"version": "0.12.11",
"source": {
"type": "git",
"url": "https://github.com/pmmp/RakLib.git",
"reference": "5f2a02009f486ca4d90892814570fa13ebdc078d"
"reference": "9cce458b8bfde3e4dfdbf70c659fc7b7fe26b5c4"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/pmmp/RakLib/zipball/5f2a02009f486ca4d90892814570fa13ebdc078d",
"reference": "5f2a02009f486ca4d90892814570fa13ebdc078d",
"url": "https://api.github.com/repos/pmmp/RakLib/zipball/9cce458b8bfde3e4dfdbf70c659fc7b7fe26b5c4",
"reference": "9cce458b8bfde3e4dfdbf70c659fc7b7fe26b5c4",
"shasum": ""
},
"require": {
"ext-pthreads": "~3.2.0",
"ext-sockets": "*",
"php": ">=7.2.0",
"php": "^7.2 || ^8.0",
"php-64bit": "*",
"php-ipv6": "*",
"pocketmine/binaryutils": "^0.1.9",
@ -376,7 +382,7 @@
"pocketmine/snooze": "^0.1.0"
},
"require-dev": {
"phpstan/phpstan": "0.12.40",
"phpstan/phpstan": "0.12.76",
"phpstan/phpstan-strict-rules": "^0.12.2"
},
"type": "library",
@ -392,31 +398,31 @@
"description": "A RakNet server implementation written in PHP",
"support": {
"issues": "https://github.com/pmmp/RakLib/issues",
"source": "https://github.com/pmmp/RakLib/tree/stable"
"source": "https://github.com/pmmp/RakLib/tree/0.12.11"
},
"time": "2020-08-28T15:22:57+00:00"
"time": "2021-02-15T11:21:05+00:00"
},
{
"name": "pocketmine/snooze",
"version": "0.1.3",
"version": "0.1.5",
"source": {
"type": "git",
"url": "https://github.com/pmmp/Snooze.git",
"reference": "849510fa62e57512b8467e3694e9b3add97038fd"
"reference": "70b5e7937a06878dd321a3182ceb76d56298f2cd"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/pmmp/Snooze/zipball/849510fa62e57512b8467e3694e9b3add97038fd",
"reference": "849510fa62e57512b8467e3694e9b3add97038fd",
"url": "https://api.github.com/repos/pmmp/Snooze/zipball/70b5e7937a06878dd321a3182ceb76d56298f2cd",
"reference": "70b5e7937a06878dd321a3182ceb76d56298f2cd",
"shasum": ""
},
"require": {
"ext-pthreads": ">=3.1.7dev",
"php-64bit": ">=7.2.0"
"php-64bit": "^7.2 || ^8.0"
},
"require-dev": {
"phpstan/extension-installer": "^1.0",
"phpstan/phpstan": "0.12.40",
"phpstan/phpstan": "0.12.76",
"phpstan/phpstan-strict-rules": "^0.12.4"
},
"type": "library",
@ -432,26 +438,26 @@
"description": "Thread notification management library for code using the pthreads extension",
"support": {
"issues": "https://github.com/pmmp/Snooze/issues",
"source": "https://github.com/pmmp/Snooze/tree/0.1.3"
"source": "https://github.com/pmmp/Snooze/tree/0.1.5"
},
"time": "2020-08-28T22:19:21+00:00"
"time": "2021-02-22T16:16:12+00:00"
},
{
"name": "pocketmine/spl",
"version": "0.4.1",
"version": "0.4.2",
"source": {
"type": "git",
"url": "https://github.com/pmmp/SPL.git",
"reference": "ff0579a0be41bbe65d3637607715c0f87728a838"
"reference": "6b08b7cf8c4afa17139c9a1b3bf1b408531de161"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/pmmp/SPL/zipball/ff0579a0be41bbe65d3637607715c0f87728a838",
"reference": "ff0579a0be41bbe65d3637607715c0f87728a838",
"url": "https://api.github.com/repos/pmmp/SPL/zipball/6b08b7cf8c4afa17139c9a1b3bf1b408531de161",
"reference": "6b08b7cf8c4afa17139c9a1b3bf1b408531de161",
"shasum": ""
},
"require": {
"php": ">=7.2"
"php": "^7.2 || ^8.0"
},
"require-dev": {
"phpstan/phpstan": "^0.12.8"
@ -469,9 +475,9 @@
"description": "Standard library files required by PocketMine-MP and related projects",
"support": {
"issues": "https://github.com/pmmp/SPL/issues",
"source": "https://github.com/pmmp/SPL/tree/0.4.1"
"source": "https://github.com/pmmp/SPL/tree/0.4.2"
},
"time": "2020-01-31T16:18:03+00:00"
"time": "2021-01-15T15:15:23+00:00"
}
],
"packages-dev": [
@ -604,16 +610,16 @@
},
{
"name": "nikic/php-parser",
"version": "v4.10.3",
"version": "v4.10.4",
"source": {
"type": "git",
"url": "https://github.com/nikic/PHP-Parser.git",
"reference": "dbe56d23de8fcb157bbc0cfb3ad7c7de0cfb0984"
"reference": "c6d052fc58cb876152f89f532b95a8d7907e7f0e"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/dbe56d23de8fcb157bbc0cfb3ad7c7de0cfb0984",
"reference": "dbe56d23de8fcb157bbc0cfb3ad7c7de0cfb0984",
"url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/c6d052fc58cb876152f89f532b95a8d7907e7f0e",
"reference": "c6d052fc58cb876152f89f532b95a8d7907e7f0e",
"shasum": ""
},
"require": {
@ -654,9 +660,9 @@
],
"support": {
"issues": "https://github.com/nikic/PHP-Parser/issues",
"source": "https://github.com/nikic/PHP-Parser/tree/v4.10.3"
"source": "https://github.com/nikic/PHP-Parser/tree/v4.10.4"
},
"time": "2020-12-03T17:45:45+00:00"
"time": "2020-12-20T10:01:03+00:00"
},
{
"name": "phar-io/manifest",
@ -720,16 +726,16 @@
},
{
"name": "phar-io/version",
"version": "3.0.3",
"version": "3.1.0",
"source": {
"type": "git",
"url": "https://github.com/phar-io/version.git",
"reference": "726c026815142e4f8677b7cb7f2249c9ffb7ecae"
"reference": "bae7c545bef187884426f042434e561ab1ddb182"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/phar-io/version/zipball/726c026815142e4f8677b7cb7f2249c9ffb7ecae",
"reference": "726c026815142e4f8677b7cb7f2249c9ffb7ecae",
"url": "https://api.github.com/repos/phar-io/version/zipball/bae7c545bef187884426f042434e561ab1ddb182",
"reference": "bae7c545bef187884426f042434e561ab1ddb182",
"shasum": ""
},
"require": {
@ -765,9 +771,9 @@
"description": "Library for handling version information and constraints",
"support": {
"issues": "https://github.com/phar-io/version/issues",
"source": "https://github.com/phar-io/version/tree/3.0.3"
"source": "https://github.com/phar-io/version/tree/3.1.0"
},
"time": "2020-11-30T09:21:21+00:00"
"time": "2021-02-23T14:00:09+00:00"
},
{
"name": "phpdocumentor/reflection-common",
@ -929,16 +935,16 @@
},
{
"name": "phpspec/prophecy",
"version": "1.12.1",
"version": "1.13.0",
"source": {
"type": "git",
"url": "https://github.com/phpspec/prophecy.git",
"reference": "8ce87516be71aae9b956f81906aaf0338e0d8a2d"
"reference": "be1996ed8adc35c3fd795488a653f4b518be70ea"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/phpspec/prophecy/zipball/8ce87516be71aae9b956f81906aaf0338e0d8a2d",
"reference": "8ce87516be71aae9b956f81906aaf0338e0d8a2d",
"url": "https://api.github.com/repos/phpspec/prophecy/zipball/be1996ed8adc35c3fd795488a653f4b518be70ea",
"reference": "be1996ed8adc35c3fd795488a653f4b518be70ea",
"shasum": ""
},
"require": {
@ -950,7 +956,7 @@
},
"require-dev": {
"phpspec/phpspec": "^6.0",
"phpunit/phpunit": "^8.0 || ^9.0 <9.3"
"phpunit/phpunit": "^8.0 || ^9.0"
},
"type": "library",
"extra": {
@ -990,22 +996,22 @@
],
"support": {
"issues": "https://github.com/phpspec/prophecy/issues",
"source": "https://github.com/phpspec/prophecy/tree/1.12.1"
"source": "https://github.com/phpspec/prophecy/tree/1.13.0"
},
"time": "2020-09-29T09:10:42+00:00"
"time": "2021-03-17T13:42:18+00:00"
},
{
"name": "phpstan/phpstan",
"version": "0.12.59",
"version": "0.12.82",
"source": {
"type": "git",
"url": "https://github.com/phpstan/phpstan.git",
"reference": "cf4107257c8ca2ad967efdd6a00f12b21acbb779"
"reference": "3920f0fb0aff39263d3a4cb0bca120a67a1a6a11"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/phpstan/phpstan/zipball/cf4107257c8ca2ad967efdd6a00f12b21acbb779",
"reference": "cf4107257c8ca2ad967efdd6a00f12b21acbb779",
"url": "https://api.github.com/repos/phpstan/phpstan/zipball/3920f0fb0aff39263d3a4cb0bca120a67a1a6a11",
"reference": "3920f0fb0aff39263d3a4cb0bca120a67a1a6a11",
"shasum": ""
},
"require": {
@ -1036,7 +1042,7 @@
"description": "PHPStan - PHP Static Analysis Tool",
"support": {
"issues": "https://github.com/phpstan/phpstan/issues",
"source": "https://github.com/phpstan/phpstan/tree/0.12.59"
"source": "https://github.com/phpstan/phpstan/tree/0.12.82"
},
"funding": [
{
@ -1052,39 +1058,34 @@
"type": "tidelift"
}
],
"time": "2020-12-07T14:46:03+00:00"
"time": "2021-03-19T06:08:17+00:00"
},
{
"name": "phpstan/phpstan-phpunit",
"version": "0.12.16",
"version": "0.12.18",
"source": {
"type": "git",
"url": "https://github.com/phpstan/phpstan-phpunit.git",
"reference": "1dd916d181b0539dea5cd37e91546afb8b107e17"
"reference": "ab44aec7cfb5cb267b8bc30a8caea86dd50d1f72"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/phpstan/phpstan-phpunit/zipball/1dd916d181b0539dea5cd37e91546afb8b107e17",
"reference": "1dd916d181b0539dea5cd37e91546afb8b107e17",
"url": "https://api.github.com/repos/phpstan/phpstan-phpunit/zipball/ab44aec7cfb5cb267b8bc30a8caea86dd50d1f72",
"reference": "ab44aec7cfb5cb267b8bc30a8caea86dd50d1f72",
"shasum": ""
},
"require": {
"php": "^7.1 || ^8.0",
"phpstan/phpstan": "^0.12.33"
"phpstan/phpstan": "^0.12.60"
},
"conflict": {
"phpunit/phpunit": "<7.0"
},
"require-dev": {
"consistence/coding-standard": "^3.5",
"dealerdirect/phpcodesniffer-composer-installer": "^0.7.0",
"ergebnis/composer-normalize": "^2.0.2",
"jakub-onderka/php-parallel-lint": "^1.0",
"phing/phing": "^2.16.0",
"phpstan/phpstan-strict-rules": "^0.12",
"phpunit/phpunit": "^7.0 || ^8.0 || ^9.0",
"satooshi/php-coveralls": "^1.0",
"slevomat/coding-standard": "^4.7.2"
"phing/phing": "^2.16.3",
"php-parallel-lint/php-parallel-lint": "^1.2",
"phpstan/phpstan-strict-rules": "^0.12.6",
"phpunit/phpunit": "^7.5.20"
},
"type": "phpstan-extension",
"extra": {
@ -1110,37 +1111,33 @@
"description": "PHPUnit extensions and rules for PHPStan",
"support": {
"issues": "https://github.com/phpstan/phpstan-phpunit/issues",
"source": "https://github.com/phpstan/phpstan-phpunit/tree/0.12.16"
"source": "https://github.com/phpstan/phpstan-phpunit/tree/0.12.18"
},
"time": "2020-08-05T13:28:50+00:00"
"time": "2021-03-06T11:51:27+00:00"
},
{
"name": "phpstan/phpstan-strict-rules",
"version": "0.12.5",
"version": "0.12.9",
"source": {
"type": "git",
"url": "https://github.com/phpstan/phpstan-strict-rules.git",
"reference": "334898a32217e4605e0f9cfa3d3fc3101bda26be"
"reference": "0705fefc7c9168529fd130e341428f5f10f4f01d"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/phpstan/phpstan-strict-rules/zipball/334898a32217e4605e0f9cfa3d3fc3101bda26be",
"reference": "334898a32217e4605e0f9cfa3d3fc3101bda26be",
"url": "https://api.github.com/repos/phpstan/phpstan-strict-rules/zipball/0705fefc7c9168529fd130e341428f5f10f4f01d",
"reference": "0705fefc7c9168529fd130e341428f5f10f4f01d",
"shasum": ""
},
"require": {
"php": "^7.1 || ^8.0",
"phpstan/phpstan": "^0.12.33"
"phpstan/phpstan": "^0.12.66"
},
"require-dev": {
"consistence/coding-standard": "^3.0.1",
"dealerdirect/phpcodesniffer-composer-installer": "^0.7.0",
"ergebnis/composer-normalize": "^2.0.2",
"jakub-onderka/php-parallel-lint": "^1.0",
"phing/phing": "^2.16.0",
"phpstan/phpstan-phpunit": "^0.12",
"phpunit/phpunit": "^7.0",
"slevomat/coding-standard": "^4.5.2"
"phing/phing": "^2.16.3",
"php-parallel-lint/php-parallel-lint": "^1.2",
"phpstan/phpstan-phpunit": "^0.12.16",
"phpunit/phpunit": "^7.5.20"
},
"type": "phpstan-extension",
"extra": {
@ -1165,22 +1162,22 @@
"description": "Extra strict and opinionated rules for PHPStan",
"support": {
"issues": "https://github.com/phpstan/phpstan-strict-rules/issues",
"source": "https://github.com/phpstan/phpstan-strict-rules/tree/master"
"source": "https://github.com/phpstan/phpstan-strict-rules/tree/0.12.9"
},
"time": "2020-08-30T15:42:06+00:00"
"time": "2021-01-13T08:50:28+00:00"
},
{
"name": "phpunit/php-code-coverage",
"version": "9.2.5",
"version": "9.2.6",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/php-code-coverage.git",
"reference": "f3e026641cc91909d421802dd3ac7827ebfd97e1"
"reference": "f6293e1b30a2354e8428e004689671b83871edde"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/f3e026641cc91909d421802dd3ac7827ebfd97e1",
"reference": "f3e026641cc91909d421802dd3ac7827ebfd97e1",
"url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/f6293e1b30a2354e8428e004689671b83871edde",
"reference": "f6293e1b30a2354e8428e004689671b83871edde",
"shasum": ""
},
"require": {
@ -1236,7 +1233,7 @@
],
"support": {
"issues": "https://github.com/sebastianbergmann/php-code-coverage/issues",
"source": "https://github.com/sebastianbergmann/php-code-coverage/tree/9.2.5"
"source": "https://github.com/sebastianbergmann/php-code-coverage/tree/9.2.6"
},
"funding": [
{
@ -1244,7 +1241,7 @@
"type": "github"
}
],
"time": "2020-11-28T06:44:49+00:00"
"time": "2021-03-28T07:26:59+00:00"
},
{
"name": "phpunit/php-file-iterator",
@ -1489,16 +1486,16 @@
},
{
"name": "phpunit/phpunit",
"version": "9.5.0",
"version": "9.5.4",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/phpunit.git",
"reference": "8e16c225d57c3d6808014df6b1dd7598d0a5bbbe"
"reference": "c73c6737305e779771147af66c96ca6a7ed8a741"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/8e16c225d57c3d6808014df6b1dd7598d0a5bbbe",
"reference": "8e16c225d57c3d6808014df6b1dd7598d0a5bbbe",
"url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/c73c6737305e779771147af66c96ca6a7ed8a741",
"reference": "c73c6737305e779771147af66c96ca6a7ed8a741",
"shasum": ""
},
"require": {
@ -1576,7 +1573,7 @@
],
"support": {
"issues": "https://github.com/sebastianbergmann/phpunit/issues",
"source": "https://github.com/sebastianbergmann/phpunit/tree/9.5.0"
"source": "https://github.com/sebastianbergmann/phpunit/tree/9.5.4"
},
"funding": [
{
@ -1588,7 +1585,7 @@
"type": "github"
}
],
"time": "2020-12-04T05:05:53+00:00"
"time": "2021-03-23T07:16:29+00:00"
},
{
"name": "sebastian/cli-parser",
@ -2556,16 +2553,16 @@
},
{
"name": "symfony/polyfill-ctype",
"version": "v1.20.0",
"version": "v1.22.1",
"source": {
"type": "git",
"url": "https://github.com/symfony/polyfill-ctype.git",
"reference": "f4ba089a5b6366e453971d3aad5fe8e897b37f41"
"reference": "c6c942b1ac76c82448322025e084cadc56048b4e"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/f4ba089a5b6366e453971d3aad5fe8e897b37f41",
"reference": "f4ba089a5b6366e453971d3aad5fe8e897b37f41",
"url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/c6c942b1ac76c82448322025e084cadc56048b4e",
"reference": "c6c942b1ac76c82448322025e084cadc56048b4e",
"shasum": ""
},
"require": {
@ -2577,7 +2574,7 @@
"type": "library",
"extra": {
"branch-alias": {
"dev-main": "1.20-dev"
"dev-main": "1.22-dev"
},
"thanks": {
"name": "symfony/polyfill",
@ -2615,7 +2612,7 @@
"portable"
],
"support": {
"source": "https://github.com/symfony/polyfill-ctype/tree/v1.20.0"
"source": "https://github.com/symfony/polyfill-ctype/tree/v1.22.1"
},
"funding": [
{
@ -2631,7 +2628,7 @@
"type": "tidelift"
}
],
"time": "2020-10-23T14:02:19+00:00"
"time": "2021-01-07T16:49:33+00:00"
},
{
"name": "theseer/tokenizer",
@ -2685,30 +2682,35 @@
},
{
"name": "webmozart/assert",
"version": "1.9.1",
"version": "1.10.0",
"source": {
"type": "git",
"url": "https://github.com/webmozart/assert.git",
"reference": "bafc69caeb4d49c39fd0779086c03a3738cbb389"
"url": "https://github.com/webmozarts/assert.git",
"reference": "6964c76c7804814a842473e0c8fd15bab0f18e25"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/webmozart/assert/zipball/bafc69caeb4d49c39fd0779086c03a3738cbb389",
"reference": "bafc69caeb4d49c39fd0779086c03a3738cbb389",
"url": "https://api.github.com/repos/webmozarts/assert/zipball/6964c76c7804814a842473e0c8fd15bab0f18e25",
"reference": "6964c76c7804814a842473e0c8fd15bab0f18e25",
"shasum": ""
},
"require": {
"php": "^5.3.3 || ^7.0 || ^8.0",
"php": "^7.2 || ^8.0",
"symfony/polyfill-ctype": "^1.8"
},
"conflict": {
"phpstan/phpstan": "<0.12.20",
"vimeo/psalm": "<3.9.1"
"vimeo/psalm": "<4.6.1 || 4.6.2"
},
"require-dev": {
"phpunit/phpunit": "^4.8.36 || ^7.5.13"
"phpunit/phpunit": "^8.5.13"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.10-dev"
}
},
"autoload": {
"psr-4": {
"Webmozart\\Assert\\": "src/"
@ -2731,10 +2733,10 @@
"validate"
],
"support": {
"issues": "https://github.com/webmozart/assert/issues",
"source": "https://github.com/webmozart/assert/tree/master"
"issues": "https://github.com/webmozarts/assert/issues",
"source": "https://github.com/webmozarts/assert/tree/1.10.0"
},
"time": "2020-07-08T17:02:28+00:00"
"time": "2021-03-09T10:59:23+00:00"
}
],
"aliases": [],
@ -2743,11 +2745,10 @@
"prefer-stable": false,
"prefer-lowest": false,
"platform": {
"php": ">=7.3.0",
"php": "^7.3 || ^8.0",
"php-64bit": "*",
"ext-bcmath": "*",
"ext-curl": "*",
"ext-ctype": "*",
"ext-curl": "*",
"ext-date": "*",
"ext-hash": "*",
"ext-json": "*",
@ -2757,6 +2758,7 @@
"ext-phar": "*",
"ext-pthreads": "~3.2.0",
"ext-reflection": "*",
"ext-simplexml": "*",
"ext-sockets": "*",
"ext-spl": "*",
"ext-yaml": ">=2.0.0",

View File

@ -7,4 +7,4 @@ This site can be accessed via https://apidoc.pmmp.io.
### Additional developer resources
- [DevTools](https://github.com/pmmp/DevTools/) - Development tools plugin for creating plugins
- [ExamplePlugin](https://github.com/pmmp/ExamplePlugin/) - Example plugin demonstrating some basic API features
- [DeveloperDocs](https://github.com/pmmp/DeveloperDocs/) - Reference, guides and specifications for the PocketMine-MP API
- [DeveloperDocs](https://devdoc.pmmp.io) - General documentation for PocketMine-MP plugin developers

View File

@ -1,7 +1,6 @@
includes:
- tests/phpstan/configs/actual-problems.neon
- tests/phpstan/configs/check-explicit-mixed-baseline.neon
- tests/phpstan/configs/com-dotnet-magic.neon
- tests/phpstan/configs/gc-hacks.neon
- tests/phpstan/configs/l7-baseline.neon
- tests/phpstan/configs/l8-baseline.neon
@ -17,6 +16,7 @@ includes:
parameters:
level: 8
checkExplicitMixed: true
checkMissingCallableSignature: true
bootstrapFiles:
- tests/phpstan/bootstrap.php
scanDirectories:
@ -41,3 +41,9 @@ parameters:
reportUnmatchedIgnoredErrors: false #no other way to silence platform-specific non-warnings
staticReflectionClassNamePatterns:
- "#^COM$#"
typeAliases:
#variadics don't work for this - mixed probably shouldn't work either, but for now it does
#what we actually need is something that accepts an infinite number of parameters, but in the absence of that,
#we'll just fill it with 10 - it's very unlikely to encounter a callable with 10 parameters anyway.
anyCallable: 'callable(mixed, mixed, mixed, mixed, mixed, mixed, mixed, mixed, mixed, mixed) : mixed'
anyClosure: '\Closure(mixed, mixed, mixed, mixed, mixed, mixed, mixed, mixed, mixed, mixed) : mixed'

View File

@ -28,6 +28,7 @@ use pocketmine\network\mcpe\protocol\ProtocolInfo;
use pocketmine\plugin\PluginBase;
use pocketmine\plugin\PluginLoadOrder;
use pocketmine\plugin\PluginManager;
use pocketmine\utils\AssumptionFailedError;
use pocketmine\utils\Utils;
use pocketmine\utils\VersionString;
use function base64_encode;
@ -46,6 +47,7 @@ use function is_resource;
use function json_encode;
use function json_last_error_msg;
use function max;
use function microtime;
use function mkdir;
use function ob_end_clean;
use function ob_get_contents;
@ -58,7 +60,6 @@ use function sprintf;
use function str_split;
use function strpos;
use function substr;
use function time;
use function zend_version;
use function zlib_encode;
use const E_COMPILE_ERROR;
@ -89,7 +90,7 @@ class CrashDump{
* having their content changed, version format changing, etc.
* It is not necessary to increase this when adding new fields.
*/
private const FORMAT_VERSION = 3;
private const FORMAT_VERSION = 4;
private const PLUGIN_INVOLVEMENT_NONE = "none";
private const PLUGIN_INVOLVEMENT_DIRECT = "direct";
@ -99,7 +100,7 @@ class CrashDump{
private $server;
/** @var resource */
private $fp;
/** @var int */
/** @var float */
private $time;
/**
* @var mixed[]
@ -112,12 +113,12 @@ class CrashDump{
private $path;
public function __construct(Server $server){
$this->time = time();
$this->time = microtime(true);
$this->server = $server;
if(!is_dir($this->server->getDataPath() . "crashdumps")){
mkdir($this->server->getDataPath() . "crashdumps");
}
$this->path = $this->server->getDataPath() . "crashdumps/" . date("D_M_j-H.i.s-T_Y", $this->time) . ".log";
$this->path = $this->server->getDataPath() . "crashdumps/" . date("D_M_j-H.i.s-T_Y", (int) $this->time) . ".log";
$fp = @fopen($this->path, "wb");
if(!is_resource($fp)){
throw new \RuntimeException("Could not create Crash Dump");
@ -125,7 +126,8 @@ class CrashDump{
$this->fp = $fp;
$this->data["format_version"] = self::FORMAT_VERSION;
$this->data["time"] = $this->time;
$this->addLine($this->server->getName() . " Crash Dump " . date("D M j H:i:s T Y", $this->time));
$this->data["uptime"] = $this->time - \pocketmine\START_TIME;
$this->addLine($this->server->getName() . " Crash Dump " . date("D M j H:i:s T Y", (int) $this->time));
$this->addLine();
$this->baseCrash();
$this->generalData();
@ -166,7 +168,9 @@ class CrashDump{
if($json === false){
throw new \RuntimeException("Failed to encode crashdump JSON: " . json_last_error_msg());
}
$this->encodedData = zlib_encode($json, ZLIB_ENCODING_DEFLATE, 9);
$zlibEncoded = zlib_encode($json, ZLIB_ENCODING_DEFLATE, 9);
if($zlibEncoded === false) throw new AssumptionFailedError("ZLIB compression failed");
$this->encodedData = $zlibEncoded;
foreach(str_split(base64_encode($this->encodedData), 76) as $line){
$this->addLine($line);
}
@ -202,9 +206,16 @@ class CrashDump{
if($this->server->getProperty("auto-report.send-settings", true) !== false){
$this->data["parameters"] = (array) $argv;
$this->data["server.properties"] = @file_get_contents($this->server->getDataPath() . "server.properties");
$this->data["server.properties"] = preg_replace("#^rcon\\.password=(.*)$#m", "rcon.password=******", $this->data["server.properties"]);
$this->data["pocketmine.yml"] = @file_get_contents($this->server->getDataPath() . "pocketmine.yml");
if(($serverDotProperties = @file_get_contents($this->server->getDataPath() . "server.properties")) !== false){
$this->data["server.properties"] = preg_replace("#^rcon\\.password=(.*)$#m", "rcon.password=******", $serverDotProperties);
}else{
$this->data["server.properties"] = $serverDotProperties;
}
if(($pocketmineDotYml = @file_get_contents($this->server->getDataPath() . "pocketmine.yml")) !== false){
$this->data["pocketmine.yml"] = $pocketmineDotYml;
}else{
$this->data["pocketmine.yml"] = "";
}
}else{
$this->data["pocketmine.yml"] = "";
$this->data["server.properties"] = "";
@ -310,8 +321,8 @@ class CrashDump{
}
private function determinePluginFromFile(string $filePath, bool $crashFrame) : bool{
$frameCleanPath = Utils::cleanPath($filePath); //this will be empty in phar stub
if(strpos($frameCleanPath, "plugins") === 0 and file_exists($filePath)){
$frameCleanPath = Utils::cleanPath($filePath);
if(strpos($frameCleanPath, Utils::CLEAN_PATH_SRC_PREFIX) !== 0){
$this->addLine();
if($crashFrame){
$this->addLine("THIS CRASH WAS CAUSED BY A PLUGIN");
@ -321,15 +332,17 @@ class CrashDump{
$this->data["plugin_involvement"] = self::PLUGIN_INVOLVEMENT_INDIRECT;
}
$reflection = new \ReflectionClass(PluginBase::class);
$file = $reflection->getProperty("file");
$file->setAccessible(true);
foreach($this->server->getPluginManager()->getPlugins() as $plugin){
$filePath = Utils::cleanPath($file->getValue($plugin));
if(strpos($frameCleanPath, $filePath) === 0){
$this->data["plugin"] = $plugin->getName();
$this->addLine("BAD PLUGIN: " . $plugin->getDescription()->getFullName());
break;
if(file_exists($filePath)){
$reflection = new \ReflectionClass(PluginBase::class);
$file = $reflection->getProperty("file");
$file->setAccessible(true);
foreach($this->server->getPluginManager()->getPlugins() as $plugin){
$filePath = Utils::cleanPath($file->getValue($plugin));
if(strpos($frameCleanPath, $filePath) === 0){
$this->data["plugin"] = $plugin->getName();
$this->addLine("BAD PLUGIN: " . $plugin->getDescription()->getFullName());
break;
}
}
}
return true;

View File

@ -423,8 +423,12 @@ class MemoryManager{
}
$name = $property->getName();
if($reflection !== $original and !$property->isPublic()){
$name = $reflection->getName() . ":" . $name;
if($reflection !== $original){
if($property->isPrivate()){
$name = $reflection->getName() . ":" . $name;
}else{
continue;
}
}
if(!$property->isPublic()){
$property->setAccessible(true);

View File

@ -100,6 +100,7 @@ use pocketmine\nbt\tag\ByteTag;
use pocketmine\nbt\tag\CompoundTag;
use pocketmine\nbt\tag\DoubleTag;
use pocketmine\nbt\tag\ListTag;
use pocketmine\nbt\tag\StringTag;
use pocketmine\network\mcpe\convert\ItemTypeDictionary;
use pocketmine\network\mcpe\PlayerNetworkSessionAdapter;
use pocketmine\network\mcpe\protocol\ActorEventPacket;
@ -155,6 +156,8 @@ use pocketmine\network\mcpe\protocol\types\inventory\UIInventorySlotOffset;
use pocketmine\network\mcpe\protocol\types\NetworkInventoryAction;
use pocketmine\network\mcpe\protocol\types\PersonaPieceTintColor;
use pocketmine\network\mcpe\protocol\types\PersonaSkinPiece;
use pocketmine\network\mcpe\protocol\types\PlayerMovementSettings;
use pocketmine\network\mcpe\protocol\types\PlayerMovementType;
use pocketmine\network\mcpe\protocol\types\PlayerPermissions;
use pocketmine\network\mcpe\protocol\types\SkinAdapterSingleton;
use pocketmine\network\mcpe\protocol\types\SkinAnimation;
@ -193,7 +196,9 @@ use function get_class;
use function gettype;
use function implode;
use function in_array;
use function is_infinite;
use function is_int;
use function is_nan;
use function is_object;
use function is_string;
use function json_encode;
@ -408,8 +413,8 @@ class Player extends Human implements CommandSender, ChunkLoader, IPlayer{
/** @var float */
protected $lastRightClickTime = 0.0;
/** @var Vector3|null */
protected $lastRightClickPos = null;
/** @var \stdClass|null */
protected $lastRightClickData = null;
/**
* @return TranslationContainer|string
@ -1652,13 +1657,6 @@ class Player extends Human implements CommandSender, ChunkLoader, IPlayer{
$deltaAngle = abs($this->lastYaw - $to->yaw) + abs($this->lastPitch - $to->pitch);
if($delta > 0.0001 or $deltaAngle > 1.0){
$this->lastX = $to->x;
$this->lastY = $to->y;
$this->lastZ = $to->z;
$this->lastYaw = $to->yaw;
$this->lastPitch = $to->pitch;
$ev = new PlayerMoveEvent($this, $from, $to);
$ev->call();
@ -1673,6 +1671,12 @@ class Player extends Human implements CommandSender, ChunkLoader, IPlayer{
return;
}
$this->lastX = $to->x;
$this->lastY = $to->y;
$this->lastZ = $to->z;
$this->lastYaw = $to->yaw;
$this->lastPitch = $to->pitch;
$this->broadcastMovement();
$distance = sqrt((($from->x - $to->x) ** 2) + (($from->z - $to->z) ** 2));
@ -1695,13 +1699,6 @@ class Player extends Human implements CommandSender, ChunkLoader, IPlayer{
}
protected function revertMovement(Location $from) : void{
$this->lastX = $from->x;
$this->lastY = $from->y;
$this->lastZ = $from->z;
$this->lastYaw = $from->yaw;
$this->lastPitch = $from->pitch;
$this->setPosition($from);
$this->sendPosition($from, $from->yaw, $from->pitch, MovePlayerPacket::MODE_RESET);
}
@ -1964,6 +1961,7 @@ class Player extends Human implements CommandSender, ChunkLoader, IPlayer{
$skinData = new SkinData(
$packet->clientData["SkinId"],
$packet->clientData["PlayFabId"],
base64_decode($packet->clientData["SkinResourcePatch"] ?? "", true),
new SkinImage(
$packet->clientData["SkinImageHeight"],
@ -2080,17 +2078,42 @@ class Player extends Human implements CommandSender, ChunkLoader, IPlayer{
* @return void
*/
protected function processLogin(){
$checkXUID = (bool) $this->server->getProperty("player.verify-xuid", true);
$kickForXUIDMismatch = function(string $xuid) use ($checkXUID) : bool{
if($checkXUID && $this->xuid !== $xuid){
if($this->kick("XUID does not match (possible impersonation attempt)", false)){
//TODO: Longer term, we should be identifying playerdata using something more reliable, like XUID or UUID.
//However, that would be a very disruptive change, so this will serve as a stopgap for now.
//Side note: this will also prevent offline players hijacking XBL playerdata on online servers, since their
//XUID will always be empty.
return true;
}
$this->server->getLogger()->debug("XUID mismatch for " . $this->getName() . ", but plugin cancelled event allowing them to join anyway");
}
return false;
};
foreach($this->server->getLoggedInPlayers() as $p){
if($p !== $this and ($p->iusername === $this->iusername or $this->getUniqueId()->equals($p->getUniqueId()))){
if($kickForXUIDMismatch($p->getXuid())){
return;
}
if(!$p->kick("logged in from another location")){
$this->close($this->getLeaveMessage(), "Logged in from another location");
return;
}
}
}
$this->namedtag = $this->server->getOfflinePlayerData($this->username);
if($checkXUID){
$recordedXUID = $this->namedtag->getTag("LastKnownXUID");
if(!($recordedXUID instanceof StringTag)){
$this->server->getLogger()->debug("No previous XUID recorded for " . $this->getName() . ", no choice but to trust this player");
}elseif(!$kickForXUIDMismatch($recordedXUID->getValue())){
$this->server->getLogger()->debug("XUID match for " . $this->getName());
}
}
$this->playedBefore = ($this->getLastPlayed() - $this->getFirstPlayed()) > 1; // microtime(true) - microtime(true) may have less than one millisecond difference
$this->namedtag->setString("NameTag", $this->username);
@ -2250,6 +2273,7 @@ class Player extends Human implements CommandSender, ChunkLoader, IPlayer{
$pk->worldName = $this->server->getMotd();
$pk->experiments = new Experiments([], false);
$pk->itemTable = ItemTypeDictionary::getInstance()->getEntries();
$pk->playerMovementSettings = new PlayerMovementSettings(PlayerMovementType::LEGACY, 0, false);
$this->dataPacket($pk);
$this->sendDataPacket(new AvailableActorIdentifiersPacket());
@ -2335,8 +2359,15 @@ class Player extends Human implements CommandSender, ChunkLoader, IPlayer{
}
public function handleMovePlayer(MovePlayerPacket $packet) : bool{
$newPos = $packet->position->round(4)->subtract(0, $this->baseOffset, 0);
$rawPos = $packet->position;
foreach([$rawPos->x, $rawPos->y, $rawPos->z, $packet->yaw, $packet->headYaw, $packet->pitch] as $float){
if(is_infinite($float) || is_nan($float)){
$this->server->getLogger()->debug("Invalid movement from " . $this->getName() . ", contains NAN/INF components");
return false;
}
}
$newPos = $rawPos->round(4)->subtract(0, $this->baseOffset, 0);
if($this->forceMoveSync !== null and $newPos->distanceSquared($this->forceMoveSync) > 1){ //Tolerate up to 1 block to avoid problems with client-sided physics when spawning in blocks
$this->server->getLogger()->debug("Got outdated pre-teleport movement from " . $this->getName() . ", received " . $newPos . ", expected " . $this->asVector3());
//Still getting movements from before teleport, ignore them
@ -2495,12 +2526,16 @@ class Player extends Human implements CommandSender, ChunkLoader, IPlayer{
switch($type){
case InventoryTransactionPacket::USE_ITEM_ACTION_CLICK_BLOCK:
//TODO: start hack for client spam bug
$spamBug = ($this->lastRightClickPos !== null and
$spamBug = ($this->lastRightClickData !== null and
microtime(true) - $this->lastRightClickTime < 0.1 and //100ms
$this->lastRightClickPos->distanceSquared($packet->trData->clickPos) < 0.00001 //signature spam bug has 0 distance, but allow some error
$this->lastRightClickData->playerPos->distanceSquared($packet->trData->playerPos) < 0.00001 and
$this->lastRightClickData->x === $packet->trData->x and
$this->lastRightClickData->y === $packet->trData->y and
$this->lastRightClickData->z === $packet->trData->z and
$this->lastRightClickData->clickPos->distanceSquared($packet->trData->clickPos) < 0.00001 //signature spam bug has 0 distance, but allow some error
);
//get rid of continued spam if the player clicks and holds right-click
$this->lastRightClickPos = clone $packet->trData->clickPos;
$this->lastRightClickData = $packet->trData;
$this->lastRightClickTime = microtime(true);
if($spamBug){
return true;
@ -2902,6 +2937,16 @@ class Player extends Human implements CommandSender, ChunkLoader, IPlayer{
break;
}
$tile = $this->level->getTile($pos);
if($tile instanceof ItemFrame and $tile->hasItem()){
if (lcg_value() <= $tile->getItemDropChance()){
$this->level->dropItem($tile->getBlock(), $tile->getItem());
}
$tile->setItem(null);
$tile->setItemRotation(0);
break;
}
$block = $target->getSide($packet->face);
if($block->getId() === Block::FIRE){
$this->level->setBlock($block, BlockFactory::get(Block::AIR));
@ -2953,7 +2998,7 @@ class Player extends Human implements CommandSender, ChunkLoader, IPlayer{
case PlayerActionPacket::ACTION_START_GLIDE:
case PlayerActionPacket::ACTION_STOP_GLIDE:
break; //TODO
case PlayerActionPacket::ACTION_CONTINUE_BREAK:
case PlayerActionPacket::ACTION_CRACK_BREAK:
$block = $this->level->getBlock($pos);
$this->level->broadcastLevelEvent($pos, LevelEventPacket::EVENT_PARTICLE_PUNCH_BLOCK, $block->getRuntimeId() | ($packet->face << 24));
//TODO: destroy-progress level event
@ -3752,6 +3797,8 @@ class Player extends Human implements CommandSender, ChunkLoader, IPlayer{
parent::saveNBT();
$this->namedtag->setString("LastKnownXUID", $this->xuid);
if($this->isValid()){
$this->namedtag->setString("Level", $this->level->getFolderName());
}

View File

@ -23,6 +23,7 @@ declare(strict_types=1);
namespace pocketmine {
use Composer\InstalledVersions;
use pocketmine\utils\Git;
use pocketmine\utils\MainLogger;
use pocketmine\utils\Process;
@ -73,7 +74,6 @@ namespace pocketmine {
}
$extensions = [
"bcmath" => "BC Math",
"curl" => "cURL",
"ctype" => "ctype",
"date" => "Date",
@ -206,6 +206,19 @@ namespace pocketmine {
define('pocketmine\GIT_COMMIT', $gitHash);
$composerGitHash = InstalledVersions::getReference('pocketmine/pocketmine-mp');
if($composerGitHash !== null){
$currentGitHash = explode("-", \pocketmine\GIT_COMMIT)[0];
if($currentGitHash !== $composerGitHash){
critical_error("Composer dependencies and/or autoloader are out of sync.");
critical_error("- Current revision is $currentGitHash");
critical_error("- Composer dependencies were last synchronized for revision $composerGitHash");
critical_error("Out-of-sync Composer dependencies may result in crashes and classes not being found.");
critical_error("Please synchronize Composer dependencies before running the server.");
exit(1);
}
}
$opts = getopt("", ["data:", "plugins:", "no-wizard", "enable-ansi", "disable-ansi"]);
define('pocketmine\DATA', isset($opts["data"]) ? $opts["data"] . DIRECTORY_SEPARATOR : realpath(getcwd()) . DIRECTORY_SEPARATOR);
@ -215,7 +228,12 @@ namespace pocketmine {
mkdir(\pocketmine\DATA, 0777, true);
}
define('pocketmine\LOCK_FILE', fopen(\pocketmine\DATA . 'server.lock', "a+b"));
$lockFile = fopen(\pocketmine\DATA . 'server.lock', "a+b");
if($lockFile === false){
critical_error("Unable to open server.lock file. Please check that the current user has read/write permissions to it.");
exit(1);
}
define('pocketmine\LOCK_FILE', $lockFile);
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
@ -280,7 +298,7 @@ namespace pocketmine {
if(ThreadManager::getInstance()->stopAll() > 0){
$logger->debug("Some threads could not be stopped, performing a force-kill");
Process::kill(getmypid());
Process::kill(Process::pid());
}
}while(false);
@ -300,7 +318,5 @@ namespace pocketmine {
exit($exitCode);
}
if(!defined('pocketmine\_PHPSTAN_ANALYSIS')){
\pocketmine\server();
}
\pocketmine\server();
}

View File

@ -126,7 +126,6 @@ use function file_put_contents;
use function filemtime;
use function function_exists;
use function get_class;
use function getmypid;
use function getopt;
use function gettype;
use function implode;
@ -1462,8 +1461,7 @@ class Server{
$this->onlineMode = $this->getConfigBool("xbox-auth", true);
if($this->onlineMode){
$this->logger->notice($this->getLanguage()->translateString("pocketmine.server.auth.enabled"));
$this->logger->notice($this->getLanguage()->translateString("pocketmine.server.authProperty.enabled"));
$this->logger->info($this->getLanguage()->translateString("pocketmine.server.auth.enabled"));
}else{
$this->logger->warning($this->getLanguage()->translateString("pocketmine.server.auth.disabled"));
$this->logger->warning($this->getLanguage()->translateString("pocketmine.server.authWarning"));
@ -1939,7 +1937,7 @@ class Server{
}catch(\Throwable $e){
$this->logger->logException($e);
$this->logger->emergency("Crashed while crashing, killing process");
@Process::kill(getmypid());
@Process::kill(Process::pid());
}
}
@ -2132,7 +2130,7 @@ class Server{
echo "--- Waiting $spacing seconds to throttle automatic restart (you can kill the process safely now) ---" . PHP_EOL;
sleep($spacing);
}
@Process::kill(getmypid());
@Process::kill(Process::pid());
exit(1);
}

View File

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

View File

@ -35,5 +35,6 @@ interface BlockToolType{
public const TYPE_PICKAXE = 1 << 2;
public const TYPE_AXE = 1 << 3;
public const TYPE_SHEARS = 1 << 4;
public const TYPE_HOE = 1 << 5;
}

View File

@ -418,6 +418,9 @@ abstract class Liquid extends Transparent{
return $isOptimalFlowDirection;
}
/**
* @phpstan-impure This function modifies the adjacent sources count (premature optimisation)
*/
private function getSmallestFlowDecay(Block $block, int $decay) : int{
$blockDecay = $this->getFlowDecay($block);

View File

@ -31,6 +31,10 @@ class Sponge extends Solid{
$this->meta = $meta;
}
public function getToolType() : int{
return BlockToolType::TYPE_HOE;
}
public function getHardness() : float{
return 0.6;
}

View File

@ -25,23 +25,18 @@ namespace pocketmine\command;
use pocketmine\snooze\SleeperNotifier;
use pocketmine\Thread;
use pocketmine\utils\Utils;
use function extension_loaded;
use function fclose;
use function fgets;
use function fopen;
use function fstat;
use function getopt;
use function is_resource;
use function microtime;
use function preg_replace;
use function readline;
use function readline_add_history;
use function stream_isatty;
use function stream_select;
use function trim;
use function usleep;
use const STDIN;
class CommandReader extends Thread{
@ -65,12 +60,6 @@ class CommandReader extends Thread{
public function __construct(?SleeperNotifier $notifier = null){
$this->buffer = new \Threaded;
$this->notifier = $notifier;
$opts = getopt("", ["disable-readline", "enable-readline"]);
if(extension_loaded("readline") and (Utils::getOS() === Utils::OS_WINDOWS ? isset($opts["enable-readline"]) : !isset($opts["disable-readline"])) and !$this->isPipe(STDIN)){
$this->type = self::TYPE_READLINE;
}
}
/**
@ -127,44 +116,28 @@ class CommandReader extends Thread{
* @return bool if the main execution should continue reading lines
*/
private function readLine() : bool{
$line = "";
if($this->type === self::TYPE_READLINE){
if(($raw = readline("> ")) !== false and ($line = trim($raw)) !== ""){
readline_add_history($line);
}else{
return true;
}
}else{
if(!is_resource(self::$stdin)){
$this->initStdin();
}
switch($this->type){
/** @noinspection PhpMissingBreakStatementInspection */
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
$this->initStdin();
}
case self::TYPE_PIPED:
if(($raw = fgets(self::$stdin)) === false){ //broken pipe or EOF
$this->initStdin();
$this->synchronized(function() : void{
$this->wait(200000);
}); //prevent CPU waste if it's end of pipe
return true; //loop back round
}
$line = trim($raw);
break;
}
if(!is_resource(self::$stdin)){
$this->initStdin();
}
$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
$this->initStdin();
}
if(($raw = fgets(self::$stdin)) === false){ //broken pipe or EOF
$this->initStdin();
$this->synchronized(function() : void{
$this->wait(200000);
}); //prevent CPU waste if it's end of pipe
return true; //loop back round
}
$line = trim($raw);
if($line !== ""){
$this->buffer[] = preg_replace("#\\x1b\\x5b([^\\x1b]*\\x7e|[\\x40-\\x50])#", "", $line);
if($this->notifier !== null){
@ -193,17 +166,11 @@ class CommandReader extends Thread{
*/
public function run(){
$this->registerClassLoader();
if($this->type !== self::TYPE_READLINE){
$this->initStdin();
}
$this->initStdin();
while(!$this->shutdown and $this->readLine());
if($this->type !== self::TYPE_READLINE){
fclose(self::$stdin);
}
fclose(self::$stdin);
}
public function getThreadName() : string{

View File

@ -175,56 +175,56 @@ abstract class Entity extends Location implements Metadatable, EntityIds{
public const DATA_RIDER_ROTATION_LOCKED = 57; //byte
public const DATA_RIDER_MAX_ROTATION = 58; //float
public const DATA_RIDER_MIN_ROTATION = 59; //float
public const DATA_AREA_EFFECT_CLOUD_RADIUS = 60; //float
public const DATA_AREA_EFFECT_CLOUD_WAITING = 61; //int
public const DATA_AREA_EFFECT_CLOUD_PARTICLE_ID = 62; //int
/* 63 (int) shulker-related */
public const DATA_SHULKER_ATTACH_FACE = 64; //byte
/* 65 (short) shulker-related */
public const DATA_SHULKER_ATTACH_POS = 66; //block coords
public const DATA_TRADING_PLAYER_EID = 67; //long
public const DATA_AREA_EFFECT_CLOUD_RADIUS = 61; //float
public const DATA_AREA_EFFECT_CLOUD_WAITING = 62; //int
public const DATA_AREA_EFFECT_CLOUD_PARTICLE_ID = 63; //int
/* 64 (int) shulker-related */
public const DATA_SHULKER_ATTACH_FACE = 65; //byte
/* 66 (short) shulker-related */
public const DATA_SHULKER_ATTACH_POS = 67; //block coords
public const DATA_TRADING_PLAYER_EID = 68; //long
/* 69 (byte) command-block */
public const DATA_COMMAND_BLOCK_COMMAND = 70; //string
public const DATA_COMMAND_BLOCK_LAST_OUTPUT = 71; //string
public const DATA_COMMAND_BLOCK_TRACK_OUTPUT = 72; //byte
public const DATA_CONTROLLING_RIDER_SEAT_NUMBER = 73; //byte
public const DATA_STRENGTH = 74; //int
public const DATA_MAX_STRENGTH = 75; //int
/* 76 (int) */
public const DATA_LIMITED_LIFE = 77;
public const DATA_ARMOR_STAND_POSE_INDEX = 78; //int
public const DATA_ENDER_CRYSTAL_TIME_OFFSET = 79; //int
public const DATA_ALWAYS_SHOW_NAMETAG = 80; //byte: -1 = default, 0 = only when looked at, 1 = always
public const DATA_COLOR_2 = 81; //byte
/* 82 (unknown) */
public const DATA_SCORE_TAG = 83; //string
public const DATA_BALLOON_ATTACHED_ENTITY = 84; //int64, entity unique ID of owner
public const DATA_PUFFERFISH_SIZE = 85; //byte
public const DATA_BOAT_BUBBLE_TIME = 86; //int (time in bubble column)
public const DATA_PLAYER_AGENT_EID = 87; //long
/* 88 (float) related to panda sitting
* 89 (float) related to panda sitting */
public const DATA_EAT_COUNTER = 90; //int (used by pandas)
public const DATA_FLAGS2 = 91; //long (extended data flags)
/* 92 (float) related to panda lying down
* 93 (float) related to panda lying down */
public const DATA_AREA_EFFECT_CLOUD_DURATION = 94; //int
public const DATA_AREA_EFFECT_CLOUD_SPAWN_TIME = 95; //int
public const DATA_AREA_EFFECT_CLOUD_RADIUS_PER_TICK = 96; //float, usually negative
public const DATA_AREA_EFFECT_CLOUD_RADIUS_CHANGE_ON_PICKUP = 97; //float
public const DATA_AREA_EFFECT_CLOUD_PICKUP_COUNT = 98; //int
public const DATA_INTERACTIVE_TAG = 99; //string (button text)
public const DATA_TRADE_TIER = 100; //int
public const DATA_MAX_TRADE_TIER = 101; //int
public const DATA_TRADE_XP = 102; //int
public const DATA_SKIN_ID = 103; //int ???
/* 104 (int) related to wither */
public const DATA_COMMAND_BLOCK_TICK_DELAY = 105; //int
public const DATA_COMMAND_BLOCK_EXECUTE_ON_FIRST_TICK = 106; //byte
public const DATA_AMBIENT_SOUND_INTERVAL_MIN = 107; //float
public const DATA_AMBIENT_SOUND_INTERVAL_RANGE = 108; //float
public const DATA_AMBIENT_SOUND_EVENT = 109; //string
/* 70 (byte) command-block */
public const DATA_COMMAND_BLOCK_COMMAND = 71; //string
public const DATA_COMMAND_BLOCK_LAST_OUTPUT = 72; //string
public const DATA_COMMAND_BLOCK_TRACK_OUTPUT = 73; //byte
public const DATA_CONTROLLING_RIDER_SEAT_NUMBER = 74; //byte
public const DATA_STRENGTH = 75; //int
public const DATA_MAX_STRENGTH = 76; //int
/* 77 (int) */
public const DATA_LIMITED_LIFE = 78;
public const DATA_ARMOR_STAND_POSE_INDEX = 79; //int
public const DATA_ENDER_CRYSTAL_TIME_OFFSET = 80; //int
public const DATA_ALWAYS_SHOW_NAMETAG = 81; //byte: -1 = default, 0 = only when looked at, 1 = always
public const DATA_COLOR_2 = 82; //byte
/* 83 (unknown) */
public const DATA_SCORE_TAG = 84; //string
public const DATA_BALLOON_ATTACHED_ENTITY = 85; //int64, entity unique ID of owner
public const DATA_PUFFERFISH_SIZE = 86; //byte
public const DATA_BOAT_BUBBLE_TIME = 87; //int (time in bubble column)
public const DATA_PLAYER_AGENT_EID = 88; //long
/* 89 (float) related to panda sitting
* 90 (float) related to panda sitting */
public const DATA_EAT_COUNTER = 91; //int (used by pandas)
public const DATA_FLAGS2 = 92; //long (extended data flags)
/* 93 (float) related to panda lying down
* 94 (float) related to panda lying down */
public const DATA_AREA_EFFECT_CLOUD_DURATION = 95; //int
public const DATA_AREA_EFFECT_CLOUD_SPAWN_TIME = 96; //int
public const DATA_AREA_EFFECT_CLOUD_RADIUS_PER_TICK = 97; //float, usually negative
public const DATA_AREA_EFFECT_CLOUD_RADIUS_CHANGE_ON_PICKUP = 98; //float
public const DATA_AREA_EFFECT_CLOUD_PICKUP_COUNT = 99; //int
public const DATA_INTERACTIVE_TAG = 100; //string (button text)
public const DATA_TRADE_TIER = 101; //int
public const DATA_MAX_TRADE_TIER = 102; //int
public const DATA_TRADE_XP = 103; //int
public const DATA_SKIN_ID = 104; //int ???
/* 105 (int) related to wither */
public const DATA_COMMAND_BLOCK_TICK_DELAY = 106; //int
public const DATA_COMMAND_BLOCK_EXECUTE_ON_FIRST_TICK = 107; //byte
public const DATA_AMBIENT_SOUND_INTERVAL_MIN = 108; //float
public const DATA_AMBIENT_SOUND_INTERVAL_RANGE = 109; //float
public const DATA_AMBIENT_SOUND_EVENT = 110; //string
public const DATA_FLAG_ONFIRE = 0;
public const DATA_FLAG_SNEAKING = 1;

View File

@ -300,17 +300,20 @@ class Human extends Creature implements ProjectileSource, InventoryHolder{
if($consumable instanceof MaybeConsumable and !$consumable->canBeConsumed()){
return false;
}
if($consumable instanceof FoodSource && $consumable->requiresHunger() and !$this->isHungry()){
return false;
}
return parent::consumeObject($consumable);
}
protected function applyConsumptionResults(Consumable $consumable) : void{
if($consumable instanceof FoodSource){
if($consumable->requiresHunger() and !$this->isHungry()){
return false;
}
$this->addFood($consumable->getFoodRestore());
$this->addSaturation($consumable->getSaturationRestore());
}
return parent::consumeObject($consumable);
parent::applyConsumptionResults($consumable);
}
/**

View File

@ -363,13 +363,20 @@ abstract class Living extends Entity implements Damageable{
return false;
}
$this->applyConsumptionResults($consumable);
return true;
}
/**
* Applies effects from consuming the object. This shouldn't do any can-consume checks (those are expected to be
* handled by the caller).
*/
protected function applyConsumptionResults(Consumable $consumable) : void{
foreach($consumable->getAdditionalEffects() as $effect){
$this->addEffect($effect);
}
$consumable->onConsume($this);
return true;
}
/**

View File

@ -48,7 +48,7 @@ class BlockBreakEvent extends BlockEvent implements Cancellable{
/**
* @param Item[] $drops
*/
public function __construct(Player $player, Block $block, Item $item, bool $instaBreak = false, array $drops, int $xpDrops = 0){
public function __construct(Player $player, Block $block, Item $item, bool $instaBreak = false, array $drops = [], int $xpDrops = 0){
parent::__construct($block);
$this->item = $item;
$this->player = $player;

View File

@ -53,4 +53,13 @@ class PlayerCursorInventory extends BaseInventory{
public function getHolder(){
return $this->holder;
}
public function sendContents($target) : void{
//TODO: HACK!
//Since 1.13, this is now part of a larger "UI inventory", and sending contents for this larger inventory does
//not work the way it's intended to. Even if it did, it would be necessary to send all 51 slots just to update
//this one, which is just not worth it.
//This workaround isn't great, but it's at least simple.
$this->sendSlot(0, $target);
}
}

View File

@ -30,6 +30,7 @@ use pocketmine\inventory\transaction\action\SlotChangeAction;
use pocketmine\item\Item;
use pocketmine\Player;
use function array_keys;
use function array_values;
use function assert;
use function count;
use function get_class;
@ -168,6 +169,8 @@ class InventoryTransaction{
}
}
}
$needItems = array_values($needItems);
$haveItems = array_values($haveItems);
}
/**

View File

@ -50,6 +50,14 @@ class Bucket extends Item implements MaybeConsumable{
return 0;
}
public function getFuelResidue() : Item{
if($this->meta === Block::LAVA or $this->meta === Block::FLOWING_LAVA){
return ItemFactory::get(Item::BUCKET);
}
return parent::getFuelResidue();
}
public function onActivate(Player $player, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector) : bool{
$resultBlock = BlockFactory::get($this->meta);

View File

@ -23,11 +23,24 @@ declare(strict_types=1);
namespace pocketmine\item;
use pocketmine\block\Block;
use pocketmine\block\BlockToolType;
use pocketmine\entity\Entity;
class Hoe extends TieredTool{
public function getBlockToolType() : int{
return BlockToolType::TYPE_HOE;
}
public function onAttackEntity(Entity $victim) : bool{
return $this->applyDamage(1);
}
public function onDestroyBlock(Block $block) : bool{
if($block->getHardness() > 0){
return $this->applyDamage(1);
}
return false;
}
}

View File

@ -655,6 +655,16 @@ class Item implements ItemIds, \JsonSerializable{
return 0;
}
/**
* Returns an item after burning fuel
*/
public function getFuelResidue() : Item{
$item = clone $this;
$item->pop();
return $item;
}
/**
* Returns how many points of damage this item will deal to an entity when used as a weapon.
*/

View File

@ -921,7 +921,9 @@ class Chunk{
$biomeIds = $stream->get(256);
if($lightPopulated){
$heightMap = array_values(unpack("v*", $stream->get(512)));
/** @var int[] $unpackedHeightMap */
$unpackedHeightMap = unpack("v*", $stream->get(512)); //unpack() will never fail here
$heightMap = array_values($unpackedHeightMap);
}
}

View File

@ -63,7 +63,6 @@ abstract class LevelProviderManager{
throw new \InvalidArgumentException("Class $class cannot be constructed");
}
/** @var LevelProvider $class */
self::$providers[strtolower($class::getProviderName())] = $class;
}

View File

@ -183,8 +183,6 @@ class LevelDB extends BaseLevelProvider{
if(!$this->levelData->hasTag("generatorOptions", StringTag::class)){
$this->levelData->setString("generatorOptions", "");
}
$db->close();
}
public static function getProviderName() : string{
@ -269,9 +267,6 @@ class LevelDB extends BaseLevelProvider{
$db->put(self::ENTRY_FLAT_WORLD_LAYERS, $out); //Add vanilla flatworld layers to allow terrain generation by MCPE to continue seamlessly
}
}
$db->close();
}
public function saveLevelData(){
@ -368,7 +363,9 @@ class LevelDB extends BaseLevelProvider{
if(($maps2d = $this->db->get($index . self::TAG_DATA_2D)) !== false){
$binaryStream->setBuffer($maps2d, 0);
$heightMap = array_values(unpack("v*", $binaryStream->get(512)));
/** @var int[] $unpackedHeightMap */
$unpackedHeightMap = unpack("v*", $binaryStream->get(512)); //unpack() will never fail here
$heightMap = array_values($unpackedHeightMap);
$biomeIds = $binaryStream->get(256);
}
break;
@ -411,8 +408,13 @@ class LevelDB extends BaseLevelProvider{
$subChunks[$yy] = new SubChunk($ids, $data, $skyLight, $blockLight);
}
$heightMap = array_values(unpack("C*", $binaryStream->get(256)));
$biomeIds = ChunkUtils::convertBiomeColors(array_values(unpack("N*", $binaryStream->get(1024))));
/** @var int[] $unpackedHeightMap */
$unpackedHeightMap = unpack("C*", $binaryStream->get(256)); //unpack() will never fail here, but static analysers don't know that
$heightMap = array_values($unpackedHeightMap);
/** @var int[] $unpackedBiomeIds */
$unpackedBiomeIds = unpack("N*", $binaryStream->get(1024)); //nor here
$biomeIds = ChunkUtils::convertBiomeColors(array_values($unpackedBiomeIds));
break;
default:
//TODO: set chunks read-only so the version on disk doesn't get overwritten
@ -548,6 +550,6 @@ class LevelDB extends BaseLevelProvider{
}
public function close(){
$this->db->close();
unset($this->db);
}
}

View File

@ -182,7 +182,9 @@ class McRegion extends BaseLevelProvider{
$heightMap = [];
if($chunk->hasTag("HeightMap", ByteArrayTag::class)){
$heightMap = array_values(unpack("C*", $chunk->getByteArray("HeightMap")));
/** @var int[] $unpackedHeightMap */
$unpackedHeightMap = unpack("C*", $chunk->getByteArray("HeightMap")); //unpack() will never fail here
$heightMap = array_values($unpackedHeightMap);
}elseif($chunk->hasTag("HeightMap", IntArrayTag::class)){
$heightMap = $chunk->getIntArray("HeightMap"); #blameshoghicp
}

View File

@ -27,12 +27,13 @@ use pocketmine\level\format\ChunkException;
use pocketmine\level\format\io\exception\CorruptedChunkException;
use pocketmine\utils\AssumptionFailedError;
use pocketmine\utils\Binary;
use pocketmine\utils\MainLogger;
use pocketmine\utils\BinaryDataException;
use pocketmine\utils\BinaryStream;
use function assert;
use function ceil;
use function chr;
use function clearstatcache;
use function fclose;
use function feof;
use function file_exists;
use function filesize;
use function fopen;
@ -43,14 +44,12 @@ use function fwrite;
use function is_resource;
use function ksort;
use function max;
use function ord;
use function pack;
use function str_pad;
use function str_repeat;
use function stream_set_read_buffer;
use function stream_set_write_buffer;
use function strlen;
use function substr;
use function time;
use function touch;
use function unpack;
@ -99,6 +98,7 @@ class RegionLoader{
* @throws CorruptedRegionException
*/
public function open(){
clearstatcache(false, $this->filePath);
$exists = file_exists($this->filePath);
if(!$exists){
touch($this->filePath);
@ -146,37 +146,34 @@ class RegionLoader{
fseek($this->filePointer, $this->locationTable[$index]->getFirstSector() << 12);
$prefix = fread($this->filePointer, 4);
if($prefix === false or strlen($prefix) !== 4){
throw new CorruptedChunkException("Corrupted chunk header detected (unexpected end of file reading length prefix)");
}
$length = Binary::readInt($prefix);
/*
* this might cause us to read some junk, but under normal circumstances it won't be any more than 4096 bytes wasted.
* doing this in a single call is faster than making two seeks and reads to fetch the chunk.
* this relies on the assumption that the end of the file is always padded to a multiple of 4096 bytes.
*/
$bytesToRead = $this->locationTable[$index]->getSectorCount() << 12;
$payload = fread($this->filePointer, $bytesToRead);
if($length <= 0){ //TODO: if we reached here, the locationTable probably needs updating
return null;
}
if($length > self::MAX_SECTOR_LENGTH){ //corrupted
throw new CorruptedChunkException("Length for chunk x=$x,z=$z ($length) is larger than maximum " . self::MAX_SECTOR_LENGTH);
if($payload === false || strlen($payload) !== $bytesToRead){
throw new CorruptedChunkException("Corrupted chunk detected (unexpected EOF, truncated or non-padded chunk found)");
}
$stream = new BinaryStream($payload);
if($length > ($this->locationTable[$index]->getSectorCount() << 12)){ //Invalid chunk, bigger than defined number of sectors
MainLogger::getLogger()->error("Chunk x=$x,z=$z length mismatch (expected " . ($this->locationTable[$index]->getSectorCount() << 12) . " sectors, got $length sectors)");
$old = $this->locationTable[$index];
$this->locationTable[$index] = new RegionLocationTableEntry($old->getFirstSector(), $length >> 12, time());
$this->writeLocationIndex($index);
}
try{
$length = $stream->getInt();
if($length <= 0){ //TODO: if we reached here, the locationTable probably needs updating
return null;
}
$chunkData = fread($this->filePointer, $length);
if($chunkData === false or strlen($chunkData) !== $length){
throw new CorruptedChunkException("Corrupted chunk detected (unexpected end of file reading chunk data)");
}
$compression = $stream->getByte();
if($compression !== self::COMPRESSION_ZLIB and $compression !== self::COMPRESSION_GZIP){
throw new CorruptedChunkException("Invalid compression type (got $compression, expected " . self::COMPRESSION_ZLIB . " or " . self::COMPRESSION_GZIP . ")");
}
$compression = ord($chunkData[0]);
if($compression !== self::COMPRESSION_ZLIB and $compression !== self::COMPRESSION_GZIP){
throw new CorruptedChunkException("Invalid compression type (got $compression, expected " . self::COMPRESSION_ZLIB . " or " . self::COMPRESSION_GZIP . ")");
return $stream->get($length - 1); //length prefix includes the compression byte
}catch(BinaryDataException $e){
throw new CorruptedChunkException("Corrupted chunk detected: " . $e->getMessage(), 0, $e);
}
return substr($chunkData, 1);
}
/**
@ -186,6 +183,23 @@ class RegionLoader{
return $this->isChunkGenerated(self::getChunkOffset($x, $z));
}
private function disposeGarbageArea(RegionLocationTableEntry $oldLocation) : void{
/* release the area containing the old copy to the garbage pool */
$this->garbageTable->add($oldLocation);
$endGarbage = $this->garbageTable->end();
$nextSector = $this->nextSector;
for(; $endGarbage !== null and $endGarbage->getLastSector() + 1 === $nextSector; $endGarbage = $this->garbageTable->end()){
$nextSector = $endGarbage->getFirstSector();
$this->garbageTable->remove($endGarbage);
}
if($nextSector !== $this->nextSector){
$this->nextSector = $nextSector;
ftruncate($this->filePointer, $this->nextSector << 12);
}
}
/**
* @return void
* @throws ChunkException
@ -230,20 +244,7 @@ class RegionLoader{
$this->writeLocationIndex($index);
if($oldLocation !== null){
/* release the area containing the old copy to the garbage pool */
$this->garbageTable->add($oldLocation);
$endGarbage = $this->garbageTable->end();
$nextSector = $this->nextSector;
for(; $endGarbage !== null and $endGarbage->getLastSector() + 1 === $nextSector; $endGarbage = $this->garbageTable->end()){
$nextSector = $endGarbage->getFirstSector();
$this->garbageTable->remove($endGarbage);
}
if($nextSector !== $this->nextSector){
$this->nextSector = $nextSector;
ftruncate($this->filePointer, $this->nextSector << 12);
}
$this->disposeGarbageArea($oldLocation);
}
}
@ -253,8 +254,12 @@ class RegionLoader{
*/
public function removeChunk(int $x, int $z){
$index = self::getChunkOffset($x, $z);
$oldLocation = $this->locationTable[$index];
$this->locationTable[$index] = null;
$this->writeLocationIndex($index);
if($oldLocation !== null){
$this->disposeGarbageArea($oldLocation);
}
}
/**
@ -336,6 +341,8 @@ class RegionLoader{
/** @var int[] $usedOffsets */
$usedOffsets = [];
$fileSize = filesize($this->filePath);
if($fileSize === false) throw new AssumptionFailedError("filesize() should not return false here");
for($i = 0; $i < 1024; ++$i){
$entry = $this->locationTable[$i];
if($entry === null){
@ -348,8 +355,7 @@ class RegionLoader{
//TODO: more validity checks
fseek($this->filePointer, $fileOffset);
if(feof($this->filePointer)){
if($fileOffset >= $fileSize){
throw new CorruptedRegionException("Region file location offset x=$x,z=$z points to invalid file location $fileOffset");
}
if(isset($usedOffsets[$offset])){
@ -402,6 +408,7 @@ class RegionLoader{
fwrite($this->filePointer, Binary::writeInt($entry !== null ? ($entry->getFirstSector() << 8) | $entry->getSectorCount() : 0), 4);
fseek($this->filePointer, 4096 + ($index << 2));
fwrite($this->filePointer, Binary::writeInt($entry !== null ? $entry->getTimestamp() : 0), 4);
clearstatcache(false, $this->filePath);
}
/**

View File

@ -29,7 +29,10 @@ namespace pocketmine\metadata;
use pocketmine\plugin\Plugin;
abstract class MetadataStore{
/** @var \SplObjectStorage[]|MetadataValue[][] */
/**
* @var \SplObjectStorage[]|MetadataValue[][]
* @phpstan-var array<string, \SplObjectStorage<Plugin, MetadataValue>>
*/
private $metadataMap;
/**
@ -41,6 +44,7 @@ abstract class MetadataStore{
$owningPlugin = $newMetadataValue->getOwningPlugin();
if(!isset($this->metadataMap[$key])){
/** @phpstan-var \SplObjectStorage<Plugin, MetadataValue> $entry */
$entry = new \SplObjectStorage();
$this->metadataMap[$key] = $entry;
}else{
@ -92,7 +96,6 @@ abstract class MetadataStore{
* @return void
*/
public function invalidateAll(Plugin $owningPlugin){
/** @var \SplObjectStorage|MetadataValue[] $values */
foreach($this->metadataMap as $values){
if(isset($values[$owningPlugin])){
$values[$owningPlugin]->invalidate();

View File

@ -87,6 +87,7 @@ class NetworkBinaryStream extends BinaryStream{
public function getSkin() : SkinData{
$skinId = $this->getString();
$skinPlayFabId = $this->getString();
$skinResourcePatch = $this->getString();
$skinData = $this->getSkinImage();
$animationCount = $this->getLInt();
@ -133,7 +134,7 @@ class NetworkBinaryStream extends BinaryStream{
);
}
return new SkinData($skinId, $skinResourcePatch, $skinData, $animations, $capeData, $geometryData, $animationData, $premium, $persona, $capeOnClassic, $capeId, $fullSkinId, $armSize, $skinColor, $personaPieces, $pieceTintColors);
return new SkinData($skinId, $skinPlayFabId, $skinResourcePatch, $skinData, $animations, $capeData, $geometryData, $animationData, $premium, $persona, $capeOnClassic, $capeId, $fullSkinId, $armSize, $skinColor, $personaPieces, $pieceTintColors);
}
/**
@ -141,6 +142,7 @@ class NetworkBinaryStream extends BinaryStream{
*/
public function putSkin(SkinData $skin){
$this->putString($skin->getSkinId());
$this->putString($skin->getPlayFabId());
$this->putString($skin->getResourcePatch());
$this->putSkinImage($skin->getSkinImage());
$this->putLInt(count($skin->getAnimations()));

View File

@ -48,6 +48,7 @@ use pocketmine\network\mcpe\protocol\CameraPacket;
use pocketmine\network\mcpe\protocol\CameraShakePacket;
use pocketmine\network\mcpe\protocol\ChangeDimensionPacket;
use pocketmine\network\mcpe\protocol\ChunkRadiusUpdatedPacket;
use pocketmine\network\mcpe\protocol\ClientboundDebugRendererPacket;
use pocketmine\network\mcpe\protocol\ClientboundMapItemDataPacket;
use pocketmine\network\mcpe\protocol\ClientCacheBlobStatusPacket;
use pocketmine\network\mcpe\protocol\ClientCacheMissResponsePacket;
@ -821,4 +822,8 @@ abstract class NetworkSession{
public function handleFilterText(FilterTextPacket $packet) : bool{
return false;
}
public function handleClientboundDebugRenderer(ClientboundDebugRendererPacket $packet) : bool{
return false;
}
}

View File

@ -212,7 +212,7 @@ class RakLibInterface implements ServerInstance, AdvancedSourceInterface{
$info->getMaxPlayerCount(),
$this->rakLib->getServerId(),
$this->server->getName(),
Server::getGamemodeName($this->server->getGamemode())
Server::getGamemodeName(Player::getClientFriendlyGamemode($this->server->getGamemode()))
]) . ";"
);
}

View File

@ -54,13 +54,15 @@ class AdventureSettingsPacket extends DataPacket{
public const FLYING = 0x200;
public const MUTED = 0x400;
public const BUILD_AND_MINE = 0x01 | self::BITFLAG_SECOND_SET;
public const MINE = 0x01 | self::BITFLAG_SECOND_SET;
public const DOORS_AND_SWITCHES = 0x02 | self::BITFLAG_SECOND_SET;
public const OPEN_CONTAINERS = 0x04 | self::BITFLAG_SECOND_SET;
public const ATTACK_PLAYERS = 0x08 | self::BITFLAG_SECOND_SET;
public const ATTACK_MOBS = 0x10 | self::BITFLAG_SECOND_SET;
public const OPERATOR = 0x20 | self::BITFLAG_SECOND_SET;
public const TELEPORT = 0x80 | self::BITFLAG_SECOND_SET;
public const BUILD = 0x100 | self::BITFLAG_SECOND_SET;
public const DEFAULT = 0x200 | self::BITFLAG_SECOND_SET;
/** @var int */
public $flags = 0;

View File

@ -49,25 +49,26 @@ class AvailableCommandsPacket extends DataPacket{
* ARG_FLAG_VALID | (type const)
*/
public const ARG_TYPE_INT = 0x01;
public const ARG_TYPE_FLOAT = 0x02;
public const ARG_TYPE_VALUE = 0x03;
public const ARG_TYPE_WILDCARD_INT = 0x04;
public const ARG_TYPE_OPERATOR = 0x05;
public const ARG_TYPE_TARGET = 0x06;
public const ARG_TYPE_FLOAT = 0x03;
public const ARG_TYPE_VALUE = 0x04;
public const ARG_TYPE_WILDCARD_INT = 0x05;
public const ARG_TYPE_OPERATOR = 0x06;
public const ARG_TYPE_TARGET = 0x07;
public const ARG_TYPE_WILDCARD_TARGET = 0x08;
public const ARG_TYPE_FILEPATH = 0x0e;
public const ARG_TYPE_FILEPATH = 0x10;
public const ARG_TYPE_STRING = 0x1d;
public const ARG_TYPE_STRING = 0x20;
public const ARG_TYPE_POSITION = 0x25;
public const ARG_TYPE_POSITION = 0x28;
public const ARG_TYPE_MESSAGE = 0x29;
public const ARG_TYPE_MESSAGE = 0x2c;
public const ARG_TYPE_RAWTEXT = 0x2b;
public const ARG_TYPE_RAWTEXT = 0x2e;
public const ARG_TYPE_JSON = 0x2f;
public const ARG_TYPE_JSON = 0x32;
public const ARG_TYPE_COMMAND = 0x36;
public const ARG_TYPE_COMMAND = 0x3f;
/**
* Enums are a little different: they are composed as follows:

View File

@ -27,6 +27,7 @@ namespace pocketmine\network\mcpe\protocol;
use pocketmine\network\mcpe\NetworkBinaryStream;
use pocketmine\network\mcpe\NetworkSession;
use pocketmine\utils\AssumptionFailedError;
use function assert;
use function get_class;
use function strlen;
@ -72,7 +73,9 @@ class BatchPacket extends DataPacket{
}
protected function encodePayload(){
$this->put(zlib_encode($this->payload, ZLIB_ENCODING_RAW, $this->compressionLevel));
$encoded = zlib_encode($this->payload, ZLIB_ENCODING_RAW, $this->compressionLevel);
if($encoded === false) throw new AssumptionFailedError("ZLIB compression failed");
$this->put($encoded);
}
/**

View File

@ -33,18 +33,24 @@ class CameraShakePacket extends DataPacket/* implements ClientboundPacket*/{
public const TYPE_POSITIONAL = 0;
public const TYPE_ROTATIONAL = 1;
public const ACTION_ADD = 0;
public const ACTION_STOP = 1;
/** @var float */
private $intensity;
/** @var float */
private $duration;
/** @var int */
private $shakeType;
/** @var int */
private $shakeAction;
public static function create(float $intensity, float $duration, int $shakeType) : self{
public static function create(float $intensity, float $duration, int $shakeType, int $shakeAction) : self{
$result = new self;
$result->intensity = $intensity;
$result->duration = $duration;
$result->shakeType = $shakeType;
$result->shakeAction = $shakeAction;
return $result;
}
@ -54,16 +60,20 @@ class CameraShakePacket extends DataPacket/* implements ClientboundPacket*/{
public function getShakeType() : int{ return $this->shakeType; }
public function getShakeAction() : int{ return $this->shakeAction; }
protected function decodePayload() : void{
$this->intensity = $this->getLFloat();
$this->duration = $this->getLFloat();
$this->shakeType = $this->getByte();
$this->shakeAction = $this->getByte();
}
protected function encodePayload() : void{
$this->putLFloat($this->intensity);
$this->putLFloat($this->duration);
$this->putByte($this->shakeType);
$this->putByte($this->shakeAction);
}
public function handle(NetworkSession $handler) : bool{

View File

@ -66,23 +66,23 @@ class ClientCacheBlobStatusPacket extends DataPacket/* implements ServerboundPac
}
protected function decodePayload() : void{
$hitCount = $this->getUnsignedVarInt();
$missCount = $this->getUnsignedVarInt();
for($i = 0; $i < $hitCount; ++$i){
$this->hitHashes[] = $this->getLLong();
}
$hitCount = $this->getUnsignedVarInt();
for($i = 0; $i < $missCount; ++$i){
$this->missHashes[] = $this->getLLong();
}
for($i = 0; $i < $hitCount; ++$i){
$this->hitHashes[] = $this->getLLong();
}
}
protected function encodePayload() : void{
$this->putUnsignedVarInt(count($this->hitHashes));
$this->putUnsignedVarInt(count($this->missHashes));
foreach($this->hitHashes as $hash){
$this->putUnsignedVarInt(count($this->hitHashes));
foreach($this->missHashes as $hash){
$this->putLLong($hash);
}
foreach($this->missHashes as $hash){
foreach($this->hitHashes as $hash){
$this->putLLong($hash);
}
}

View File

@ -0,0 +1,137 @@
<?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;
class ClientboundDebugRendererPacket extends DataPacket/* implements ClientboundPacket*/{
public const NETWORK_ID = ProtocolInfo::CLIENTBOUND_DEBUG_RENDERER_PACKET;
public const TYPE_CLEAR = 1;
public const TYPE_ADD_CUBE = 2;
/** @var int */
private $type;
//TODO: if more types are added, we'll probably want to make a separate data type and interfaces
/** @var string */
private $text;
/** @var Vector3 */
private $position;
/** @var float */
private $red;
/** @var float */
private $green;
/** @var float */
private $blue;
/** @var float */
private $alpha;
/** @var int */
private $durationMillis;
private static function base(int $type) : self{
$result = new self;
$result->type = $type;
return $result;
}
public static function clear() : self{ return self::base(self::TYPE_CLEAR); }
public static function addCube(string $text, Vector3 $position, float $red, float $green, float $blue, float $alpha, int $durationMillis) : self{
$result = self::base(self::TYPE_ADD_CUBE);
$result->text = $text;
$result->position = $position;
$result->red = $red;
$result->green = $green;
$result->blue = $blue;
$result->alpha = $alpha;
$result->durationMillis = $durationMillis;
return $result;
}
public function getType() : int{ return $this->type; }
public function getText() : string{ return $this->text; }
public function getPosition() : Vector3{ return $this->position; }
public function getRed() : float{ return $this->red; }
public function getGreen() : float{ return $this->green; }
public function getBlue() : float{ return $this->blue; }
public function getAlpha() : float{ return $this->alpha; }
public function getDurationMillis() : int{ return $this->durationMillis; }
protected function decodePayload() : void{
$this->type = $this->getLInt();
switch($this->type){
case self::TYPE_CLEAR:
//NOOP
break;
case self::TYPE_ADD_CUBE:
$this->text = $this->getString();
$this->position = $this->getVector3();
$this->red = $this->getLFloat();
$this->green = $this->getLFloat();
$this->blue = $this->getLFloat();
$this->alpha = $this->getLFloat();
$this->durationMillis = $this->getLLong();
break;
default:
throw new \UnexpectedValueException("Unknown type " . $this->type);
}
}
protected function encodePayload() : void{
$this->putLInt($this->type);
switch($this->type){
case self::TYPE_CLEAR:
//NOOP
break;
case self::TYPE_ADD_CUBE:
$this->putString($this->text);
$this->putVector3($this->position);
$this->putLFloat($this->red);
$this->putLFloat($this->green);
$this->putLFloat($this->blue);
$this->putLFloat($this->alpha);
$this->putLLong($this->durationMillis);
break;
default:
throw new \InvalidArgumentException("Unknown type " . $this->type);
}
}
public function handle(NetworkSession $session) : bool{
return $session->handleClientboundDebugRenderer($this);
}
}

View File

@ -33,6 +33,11 @@ use function count;
class CommandOutputPacket extends DataPacket{
public const NETWORK_ID = ProtocolInfo::COMMAND_OUTPUT_PACKET;
public const TYPE_LAST = 1;
public const TYPE_SILENT = 2;
public const TYPE_ALL = 3;
public const TYPE_DATA_SET = 4;
/** @var CommandOriginData */
public $originData;
/** @var int */
@ -53,7 +58,7 @@ class CommandOutputPacket extends DataPacket{
$this->messages[] = $this->getCommandMessage();
}
if($this->outputType === 4){
if($this->outputType === self::TYPE_DATA_SET){
$this->unknownString = $this->getString();
}
}
@ -81,7 +86,7 @@ class CommandOutputPacket extends DataPacket{
$this->putCommandMessage($message);
}
if($this->outputType === 4){
if($this->outputType === self::TYPE_DATA_SET){
$this->putString($this->unknownString);
}
}

View File

@ -28,7 +28,6 @@ namespace pocketmine\network\mcpe\protocol;
use pocketmine\inventory\FurnaceRecipe;
use pocketmine\inventory\ShapedRecipe;
use pocketmine\inventory\ShapelessRecipe;
use pocketmine\item\Item;
use pocketmine\item\ItemFactory;
use pocketmine\network\mcpe\convert\ItemTranslator;
use pocketmine\network\mcpe\NetworkBinaryStream;
@ -84,7 +83,6 @@ class CraftingDataPacket extends DataPacket{
case self::ENTRY_SHAPELESS_CHEMISTRY:
$entry["recipe_id"] = $this->getString();
$ingredientCount = $this->getUnsignedVarInt();
/** @var Item */
$entry["input"] = [];
for($j = 0; $j < $ingredientCount; ++$j){
$entry["input"][] = $in = $this->getRecipeIngredient();

View File

@ -174,7 +174,7 @@ abstract class DataPacket extends NetworkBinaryStream{
public function __debugInfo(){
$data = [];
foreach((array) $this as $k => $v){
if($k === "buffer" and is_string($v)){
if($k === "buffer"){
$data[$k] = bin2hex($v);
}elseif(is_string($v) or (is_object($v) and method_exists($v, "__toString"))){
$data[$k] = Utils::printable((string) $v);

View File

@ -48,6 +48,13 @@ class EventPacket extends DataPacket{
public const TYPE_CAULDRON_BLOCK_USED = 15;
public const TYPE_COMPOSTER_BLOCK_USED = 16;
public const TYPE_BELL_BLOCK_USED = 17;
public const TYPE_ACTOR_DEFINITION = 18;
public const TYPE_RAID_UPDATE = 19;
public const TYPE_PLAYER_MOVEMENT_ANOMALY = 20; //anti cheat
public const TYPE_PLAYER_MOVEMENT_CORRECTED = 21;
public const TYPE_HONEY_HARVESTED = 22;
public const TYPE_TARGET_BLOCK_HIT = 23;
public const TYPE_PIGLIN_BARTER = 24;
/** @var int */
public $playerRuntimeId;

View File

@ -255,7 +255,7 @@ class LevelSoundEventPacket extends DataPacket{
public const SOUND_BLOCK_TURTLE_EGG_BREAK = 224;
public const SOUND_BLOCK_TURTLE_EGG_CRACK = 225;
public const SOUND_BLOCK_TURTLE_EGG_HATCH = 226;
public const SOUND_LAY_EGG = 227;
public const SOUND_BLOCK_TURTLE_EGG_ATTACK = 228;
public const SOUND_BEACON_ACTIVATE = 229;
public const SOUND_BEACON_AMBIENT = 230;
@ -309,7 +309,56 @@ class LevelSoundEventPacket extends DataPacket{
public const SOUND_BLOCK_SMOKER_SMOKE = 278;
public const SOUND_BLOCK_BLASTFURNACE_FIRE_CRACKLE = 279;
public const SOUND_BLOCK_SMITHING_TABLE_USE = 280;
public const SOUND_UNDEFINED = 281;
public const SOUND_SCREECH = 281;
public const SOUND_SLEEP = 282;
public const SOUND_BLOCK_FURNACE_LIT = 283;
public const SOUND_CONVERT_MOOSHROOM = 284;
public const SOUND_MILK_SUSPICIOUSLY = 285;
public const SOUND_CELEBRATE = 286;
public const SOUND_JUMP_PREVENT = 287;
public const SOUND_AMBIENT_POLLINATE = 288;
public const SOUND_BLOCK_BEEHIVE_DRIP = 289;
public const SOUND_BLOCK_BEEHIVE_ENTER = 290;
public const SOUND_BLOCK_BEEHIVE_EXIT = 291;
public const SOUND_BLOCK_BEEHIVE_WORK = 292;
public const SOUND_BLOCK_BEEHIVE_SHEAR = 293;
public const SOUND_DRINK_HONEY = 294;
public const SOUND_AMBIENT_CAVE = 295;
public const SOUND_RETREAT = 296;
public const SOUND_CONVERTED_TO_ZOMBIFIED = 297;
public const SOUND_ADMIRE = 298;
public const SOUND_STEP_LAVA = 299;
public const SOUND_TEMPT = 300;
public const SOUND_PANIC = 301;
public const SOUND_ANGRY = 302;
public const SOUND_AMBIENT_WARPED_FOREST_MOOD = 303;
public const SOUND_AMBIENT_SOULSAND_VALLEY_MOOD = 304;
public const SOUND_AMBIENT_NETHER_WASTES_MOOD = 305;
public const SOUND_RESPAWN_ANCHOR_BASALT_DELTAS_MOOD = 306;
public const SOUND_AMBIENT_CRIMSON_FOREST_MOOD = 307;
public const SOUND_RESPAWN_ANCHOR_CHARGE = 308;
public const SOUND_RESPAWN_ANCHOR_DEPLETE = 309;
public const SOUND_RESPAWN_ANCHOR_SET_SPAWN = 310;
public const SOUND_RESPAWN_ANCHOR_AMBIENT = 311;
public const SOUND_PARTICLE_SOUL_ESCAPE_QUIET = 312;
public const SOUND_PARTICLE_SOUL_ESCAPE_LOUD = 313;
public const SOUND_RECORD_PIGSTEP = 314;
public const SOUND_LODESTONE_COMPASS_LINK_COMPASS_TO_LODESTONE = 315;
public const SOUND_SMITHING_TABLE_USE = 316;
public const SOUND_ARMOR_EQUIP_NETHERITE = 317;
public const SOUND_AMBIENT_WARPED_FOREST_LOOP = 318;
public const SOUND_AMBIENT_SOULSAND_VALLEY_LOOP = 319;
public const SOUND_AMBIENT_NETHER_WASTES_LOOP = 320;
public const SOUND_AMBIENT_BASALT_DELTAS_LOOP = 321;
public const SOUND_AMBIENT_CRIMSON_FOREST_LOOP = 322;
public const SOUND_AMBIENT_WARPED_FOREST_ADDITIONS = 323;
public const SOUND_AMBIENT_SOULSAND_VALLEY_ADDITIONS = 324;
public const SOUND_AMBIENT_NETHER_WASTES_ADDITIONS = 325;
public const SOUND_AMBIENT_BASALT_DELTAS_ADDITIONS = 326;
public const SOUND_AMBIENT_CRIMSON_FOREST_ADDITIONS = 327;
public const SOUND_BUCKET_FILL_POWDER_SNOW = 328;
public const SOUND_BUCKET_EMPTY_POWDER_SNOW = 329;
public const SOUND_UNDEFINED = 330;
/** @var int */
public $sound;

View File

@ -194,6 +194,7 @@ class PacketPool{
static::registerPacket(new CorrectPlayerMovePredictionPacket());
static::registerPacket(new ItemComponentPacket());
static::registerPacket(new FilterTextPacket());
static::registerPacket(new ClientboundDebugRendererPacket());
}
/**

View File

@ -48,7 +48,7 @@ class PlayerActionPacket extends DataPacket{
public const ACTION_START_GLIDE = 15;
public const ACTION_STOP_GLIDE = 16;
public const ACTION_BUILD_DENIED = 17;
public const ACTION_CONTINUE_BREAK = 18;
public const ACTION_CRACK_BREAK = 18;
public const ACTION_CHANGE_SKIN = 19;
public const ACTION_SET_ENCHANTMENT_SEED = 20; //no longer used
public const ACTION_START_SWIMMING = 21;
@ -56,6 +56,8 @@ class PlayerActionPacket extends DataPacket{
public const ACTION_START_SPIN_ATTACK = 23;
public const ACTION_STOP_SPIN_ATTACK = 24;
public const ACTION_INTERACT_BLOCK = 25;
public const ACTION_PREDICT_DESTROY_BLOCK = 26;
public const ACTION_CONTINUE_DESTROY_BLOCK = 27;
/** @var int */
public $entityRuntimeId;

View File

@ -28,6 +28,7 @@ namespace pocketmine\network\mcpe\protocol;
use pocketmine\math\Vector3;
use pocketmine\network\mcpe\NetworkSession;
use pocketmine\network\mcpe\protocol\types\InputMode;
use pocketmine\network\mcpe\protocol\types\PlayerAuthInputFlags;
use pocketmine\network\mcpe\protocol\types\PlayMode;
use function assert;
@ -60,6 +61,7 @@ class PlayerAuthInputPacket extends DataPacket/* implements ServerboundPacket*/{
private $delta;
/**
* @param int $inputFlags @see InputFlags
* @param int $inputMode @see InputMode
* @param int $playMode @see PlayMode
* @param Vector3|null $vrGazeDirection only used when PlayMode::VR
@ -111,6 +113,9 @@ class PlayerAuthInputPacket extends DataPacket/* implements ServerboundPacket*/{
return $this->moveVecZ;
}
/**
* @see PlayerAuthInputFlags
*/
public function getInputFlags() : int{
return $this->inputFlags;
}

View File

@ -37,11 +37,11 @@ interface ProtocolInfo{
*/
/** Actual Minecraft: PE protocol version */
public const CURRENT_PROTOCOL = 422;
public const CURRENT_PROTOCOL = 428;
/** Current Minecraft PE version reported by the server. This is usually the earliest currently supported version. */
public const MINECRAFT_VERSION = 'v1.16.200';
public const MINECRAFT_VERSION = 'v1.16.210';
/** Version number sent to clients in ping responses. */
public const MINECRAFT_VERSION_NETWORK = '1.16.200';
public const MINECRAFT_VERSION_NETWORK = '1.16.210';
public const LOGIN_PACKET = 0x01;
public const PLAY_STATUS_PACKET = 0x02;
@ -206,5 +206,6 @@ interface ProtocolInfo{
public const CORRECT_PLAYER_MOVE_PREDICTION_PACKET = 0xa1;
public const ITEM_COMPONENT_PACKET = 0xa2;
public const FILTER_TEXT_PACKET = 0xa3;
public const CLIENTBOUND_DEBUG_RENDERER_PACKET = 0xa4;
}

View File

@ -44,6 +44,7 @@ class ResourcePackClientResponsePacket extends DataPacket{
protected function decodePayload(){
$this->status = $this->getByte();
$entryCount = $this->getLShort();
$this->packIds = [];
while($entryCount-- > 0){
$this->packIds[] = $this->getString();
}

View File

@ -36,6 +36,9 @@ class SetTitlePacket extends DataPacket{
public const TYPE_SET_SUBTITLE = 3;
public const TYPE_SET_ACTIONBAR_MESSAGE = 4;
public const TYPE_SET_ANIMATION_TIMES = 5;
public const TYPE_SET_TITLE_JSON = 6;
public const TYPE_SET_SUBTITLE_JSON = 7;
public const TYPE_SET_ACTIONBAR_MESSAGE_JSON = 8;
/** @var int */
public $type;

View File

@ -35,7 +35,7 @@ use pocketmine\network\mcpe\protocol\types\GameRuleType;
use pocketmine\network\mcpe\protocol\types\GeneratorType;
use pocketmine\network\mcpe\protocol\types\ItemTypeEntry;
use pocketmine\network\mcpe\protocol\types\MultiplayerGameVisibility;
use pocketmine\network\mcpe\protocol\types\PlayerMovementType;
use pocketmine\network\mcpe\protocol\types\PlayerMovementSettings;
use pocketmine\network\mcpe\protocol\types\PlayerPermissions;
use pocketmine\network\mcpe\protocol\types\SpawnSettings;
use function count;
@ -154,8 +154,8 @@ class StartGamePacket extends DataPacket{
public $premiumWorldTemplateId = "";
/** @var bool */
public $isTrial = false;
/** @var int */
public $playerMovementType = PlayerMovementType::LEGACY;
/** @var PlayerMovementSettings */
public $playerMovementSettings;
/** @var int */
public $currentTick = 0; //only used if isTrial is true
/** @var int */
@ -235,7 +235,7 @@ class StartGamePacket extends DataPacket{
$this->worldName = $this->getString();
$this->premiumWorldTemplateId = $this->getString();
$this->isTrial = $this->getBool();
$this->playerMovementType = $this->getVarInt();
$this->playerMovementSettings = PlayerMovementSettings::read($this);
$this->currentTick = $this->getLLong();
$this->enchantmentSeed = $this->getVarInt();
@ -317,7 +317,7 @@ class StartGamePacket extends DataPacket{
$this->putString($this->worldName);
$this->putString($this->premiumWorldTemplateId);
$this->putBool($this->isTrial);
$this->putVarInt($this->playerMovementType);
$this->playerMovementSettings->write($this);
$this->putLLong($this->currentTick);
$this->putVarInt($this->enchantmentSeed);

View File

@ -44,6 +44,7 @@ class LegacySkinAdapter implements SkinAdapter{
}
return new SkinData(
$skin->getSkinId(),
"", //TODO: playfab ID
json_encode(["geometry" => ["default" => $geometryName]]),
SkinImage::fromLegacy($skin->getSkinData()), [],
$capeImage,

View File

@ -0,0 +1,75 @@
<?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\network\mcpe\protocol\PlayerAuthInputPacket;
/**
* These flags are used in PlayerAuthInputPacket's inputFlags field.
* The flags should be written as
* `flags |= (1 << flag)`
* and read as
* `(flags & (1 & flag)) !== 0`
*
* @see PlayerAuthInputPacket
*/
final class PlayerAuthInputFlags{
public const ASCEND = 0;
public const DESCEND = 1;
public const NORTH_JUMP = 2;
public const JUMP_DOWN = 3;
public const SPRINT_DOWN = 4;
public const CHANGE_HEIGHT = 5;
public const JUMPING = 6;
public const AUTO_JUMPING_IN_WATER = 7;
public const SNEAKING = 8;
public const SNEAK_DOWN = 9;
public const UP = 10;
public const DOWN = 11;
public const LEFT = 12;
public const RIGHT = 13;
public const UP_LEFT = 14;
public const UP_RIGHT = 15;
public const WANT_UP = 16;
public const WANT_DOWN = 17;
public const WANT_DOWN_SLOW = 18;
public const WANT_UP_SLOW = 19;
public const SPRINTING = 20;
public const ASCEND_SCAFFOLDING = 21;
public const DESCEND_SCAFFOLDING = 22;
public const SNEAK_TOGGLE_DOWN = 23;
public const PERSIST_SNEAK = 24;
public const START_SPRINTING = 25;
public const STOP_SPRINTING = 26;
public const START_SNEAKING = 27;
public const STOP_SNEAKING = 28;
public const START_SWIMMING = 29;
public const STOP_SWIMMING = 30;
public const START_JUMPING = 31;
public const START_GLIDING = 32;
public const STOP_GLIDING = 33;
public const PERFORM_ITEM_INTERACTION = 34;
public const PERFORM_BLOCK_ACTIONS = 35;
public const PERFORM_ITEM_STACK_REQUEST = 36;
}

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\types;
use pocketmine\network\mcpe\NetworkBinaryStream;
final class PlayerMovementSettings{
/** @var int */
private $movementType;
/** @var int */
private $rewindHistorySize;
/** @var bool */
private $serverAuthoritativeBlockBreaking;
public function __construct(int $movementType, int $rewindHistorySize, bool $serverAuthoritativeBlockBreaking){
$this->movementType = $movementType;
$this->rewindHistorySize = $rewindHistorySize;
//do not ask me what the F this is doing here
$this->serverAuthoritativeBlockBreaking = $serverAuthoritativeBlockBreaking;
}
public function getMovementType() : int{ return $this->movementType; }
public function getRewindHistorySize() : int{ return $this->rewindHistorySize; }
public function isServerAuthoritativeBlockBreaking() : bool{ return $this->serverAuthoritativeBlockBreaking; }
public static function read(NetworkBinaryStream $in) : self{
$movementType = $in->getVarInt();
$rewindHistorySize = $in->getVarInt();
$serverAuthBlockBreaking = $in->getBool();
return new self($movementType, $rewindHistorySize, $serverAuthBlockBreaking);
}
public function write(NetworkBinaryStream $out) : void{
$out->putVarInt($this->movementType);
$out->putVarInt($this->rewindHistorySize);
$out->putBool($this->serverAuthoritativeBlockBreaking);
}
}

View File

@ -33,6 +33,8 @@ class SkinData{
/** @var string */
private $skinId;
/** @var string */
private $playFabId;
/** @var string */
private $resourcePatch;
/** @var SkinImage */
private $skinImage;
@ -70,8 +72,9 @@ class SkinData{
* @param PersonaSkinPiece[] $personaPieces
* @param PersonaPieceTintColor[] $pieceTintColors
*/
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 = "", ?string $fullSkinId = null, string $armSize = self::ARM_SIZE_WIDE, string $skinColor = "", array $personaPieces = [], array $pieceTintColors = [], bool $isVerified = true){
public function __construct(string $skinId, string $playFabId, string $resourcePatch, SkinImage $skinImage, array $animations = [], SkinImage $capeImage = null, string $geometryData = "", string $animationData = "", bool $premium = false, bool $persona = false, bool $personaCapeOnClassic = false, string $capeId = "", ?string $fullSkinId = null, string $armSize = self::ARM_SIZE_WIDE, string $skinColor = "", array $personaPieces = [], array $pieceTintColors = [], bool $isVerified = true){
$this->skinId = $skinId;
$this->playFabId = $playFabId;
$this->resourcePatch = $resourcePatch;
$this->skinImage = $skinImage;
$this->animations = $animations;
@ -95,6 +98,8 @@ class SkinData{
return $this->skinId;
}
public function getPlayFabId() : string{ return $this->playFabId; }
public function getResourcePatch() : string{
return $this->resourcePatch;
}

View File

@ -0,0 +1,59 @@
<?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\inventory\stackrequest;
use pocketmine\network\mcpe\NetworkBinaryStream;
/**
* Renames an item in an anvil, or map on a cartography table.
*/
final class CraftRecipeOptionalStackRequestAction extends ItemStackRequestAction{
/** @var int */
private $recipeId;
/** @var int */
private $filterStringIndex;
public function __construct(int $type, int $filterStringIndex){
$this->recipeId = $type;
$this->filterStringIndex = $filterStringIndex;
}
public function getRecipeId() : int{ return $this->recipeId; }
public function getFilterStringIndex() : int{ return $this->filterStringIndex; }
public static function getTypeId() : int{ return ItemStackRequestActionType::CRAFTING_RECIPE_OPTIONAL; }
public static function read(NetworkBinaryStream $in) : self{
$recipeId = $in->readGenericTypeNetworkId();
$filterStringIndex = $in->getLInt();
return new self($recipeId, $filterStringIndex);
}
public function write(NetworkBinaryStream $out) : void{
$out->writeGenericTypeNetworkId($this->recipeId);
$out->putLInt($this->filterStringIndex);
}
}

View File

@ -32,13 +32,21 @@ final class ItemStackRequest{
private $requestId;
/** @var ItemStackRequestAction[] */
private $actions;
/**
* @var string[]
* @phpstan-var list<string>
*/
private $filterStrings;
/**
* @param ItemStackRequestAction[] $actions
* @param string[] $filterStrings
* @phpstan-param list<string> $filterStrings
*/
public function __construct(int $requestId, array $actions){
public function __construct(int $requestId, array $actions, array $filterStrings){
$this->requestId = $requestId;
$this->actions = $actions;
$this->filterStrings = $filterStrings;
}
public function getRequestId() : int{ return $this->requestId; }
@ -46,6 +54,12 @@ final class ItemStackRequest{
/** @return ItemStackRequestAction[] */
public function getActions() : array{ return $this->actions; }
/**
* @return string[]
* @phpstan-return list<string>
*/
public function getFilterStrings() : array{ return $this->filterStrings; }
private static function readAction(NetworkBinaryStream $in, int $typeId) : ItemStackRequestAction{
switch($typeId){
case TakeStackRequestAction::getTypeId(): return TakeStackRequestAction::read($in);
@ -57,9 +71,11 @@ final class ItemStackRequest{
case CraftingMarkSecondaryResultStackRequestAction::getTypeId(): return CraftingMarkSecondaryResultStackRequestAction::read($in);
case LabTableCombineStackRequestAction::getTypeId(): return LabTableCombineStackRequestAction::read($in);
case BeaconPaymentStackRequestAction::getTypeId(): return BeaconPaymentStackRequestAction::read($in);
case MineBlockStackRequestAction::getTypeId(): return MineBlockStackRequestAction::read($in);
case CraftRecipeStackRequestAction::getTypeId(): return CraftRecipeStackRequestAction::read($in);
case CraftRecipeAutoStackRequestAction::getTypeId(): return CraftRecipeAutoStackRequestAction::read($in);
case CreativeCreateStackRequestAction::getTypeId(): return CreativeCreateStackRequestAction::read($in);
case CraftRecipeOptionalStackRequestAction::getTypeId(): return CraftRecipeOptionalStackRequestAction::read($in);
case DeprecatedCraftingNonImplementedStackRequestAction::getTypeId(): return DeprecatedCraftingNonImplementedStackRequestAction::read($in);
case DeprecatedCraftingResultsStackRequestAction::getTypeId(): return DeprecatedCraftingResultsStackRequestAction::read($in);
}
@ -73,7 +89,11 @@ final class ItemStackRequest{
$typeId = $in->getByte();
$actions[] = self::readAction($in, $typeId);
}
return new self($requestId, $actions);
$filterStrings = [];
for($i = 0, $len = $in->getUnsignedVarInt(); $i < $len; ++$i){
$filterStrings[] = $in->getString();
}
return new self($requestId, $actions, $filterStrings);
}
public function write(NetworkBinaryStream $out) : void{
@ -83,5 +103,9 @@ final class ItemStackRequest{
$out->putByte($action::getTypeId());
$action->write($out);
}
$out->putUnsignedVarInt(count($this->filterStrings));
foreach($this->filterStrings as $string){
$out->putString($string);
}
}
}

View File

@ -38,9 +38,11 @@ final class ItemStackRequestActionType{
public const CRAFTING_MARK_SECONDARY_RESULT_SLOT = 6;
public const LAB_TABLE_COMBINE = 7;
public const BEACON_PAYMENT = 8;
public const CRAFTING_RECIPE = 9;
public const CRAFTING_RECIPE_AUTO = 10; //recipe book?
public const CREATIVE_CREATE = 11;
public const CRAFTING_NON_IMPLEMENTED_DEPRECATED_ASK_TY_LAING = 12; //anvils aren't fully implemented yet
public const CRAFTING_RESULTS_DEPRECATED_ASK_TY_LAING = 13; //no idea what this is for
public const MINE_BLOCK = 9;
public const CRAFTING_RECIPE = 10;
public const CRAFTING_RECIPE_AUTO = 11; //recipe book?
public const CREATIVE_CREATE = 12;
public const CRAFTING_RECIPE_OPTIONAL = 13; //anvil/cartography table rename
public const CRAFTING_NON_IMPLEMENTED_DEPRECATED_ASK_TY_LAING = 14;
public const CRAFTING_RESULTS_DEPRECATED_ASK_TY_LAING = 15; //no idea what this is for
}

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\inventory\stackrequest;
use pocketmine\network\mcpe\NetworkBinaryStream;
final class MineBlockStackRequestAction extends ItemStackRequestAction{
/** @var int */
private $unknown1;
/** @var int */
private $predictedDurability;
/** @var int */
private $stackId;
public function __construct(int $unknown1, int $predictedDurability, int $stackId){
$this->unknown1 = $unknown1;
$this->predictedDurability = $predictedDurability;
$this->stackId = $stackId;
}
public function getUnknown1() : int{ return $this->unknown1; }
public function getPredictedDurability() : int{ return $this->predictedDurability; }
public function getStackId() : int{ return $this->stackId; }
public static function getTypeId() : int{ return ItemStackRequestActionType::MINE_BLOCK; }
public static function read(NetworkBinaryStream $in) : self{
$unknown1 = $in->getVarInt();
$predictedDurability = $in->getVarInt();
$stackId = $in->readGenericTypeNetworkId();
return new self($unknown1, $predictedDurability, $stackId);
}
public function write(NetworkBinaryStream $out) : void{
$out->putVarInt($this->unknown1);
$out->putVarInt($this->predictedDurability);
$out->writeGenericTypeNetworkId($this->stackId);
}
}

View File

@ -37,13 +37,16 @@ final class ItemStackResponseSlotInfo{
private $itemStackId;
/** @var string */
private $customName;
/** @var int */
private $durabilityCorrection;
public function __construct(int $slot, int $hotbarSlot, int $count, int $itemStackId, string $customName){
public function __construct(int $slot, int $hotbarSlot, int $count, int $itemStackId, string $customName, int $durabilityCorrection){
$this->slot = $slot;
$this->hotbarSlot = $hotbarSlot;
$this->count = $count;
$this->itemStackId = $itemStackId;
$this->customName = $customName;
$this->durabilityCorrection = $durabilityCorrection;
}
public function getSlot() : int{ return $this->slot; }
@ -56,13 +59,16 @@ final class ItemStackResponseSlotInfo{
public function getCustomName() : string{ return $this->customName; }
public function getDurabilityCorrection() : int{ return $this->durabilityCorrection; }
public static function read(NetworkBinaryStream $in) : self{
$slot = $in->getByte();
$hotbarSlot = $in->getByte();
$count = $in->getByte();
$itemStackId = $in->readGenericTypeNetworkId();
$customName = $in->getString();
return new self($slot, $hotbarSlot, $count, $itemStackId, $customName);
$durabilityCorrection = $in->getVarInt();
return new self($slot, $hotbarSlot, $count, $itemStackId, $customName, $durabilityCorrection);
}
public function write(NetworkBinaryStream $out) : void{
@ -71,5 +77,6 @@ final class ItemStackResponseSlotInfo{
$out->putByte($this->count);
$out->writeGenericTypeNetworkId($this->itemStackId);
$out->putString($this->customName);
$out->putVarInt($this->durabilityCorrection);
}
}

View File

@ -77,7 +77,7 @@ class RCONInstance extends Thread{
* @param resource $socket
* @param resource $ipcSocket
*/
public function __construct($socket, string $password, int $maxClients = 50, \ThreadedLogger $logger, $ipcSocket, ?SleeperNotifier $notifier){
public function __construct($socket, string $password, int $maxClients, \ThreadedLogger $logger, $ipcSocket, ?SleeperNotifier $notifier){
$this->stop = false;
$this->cmd = "";
$this->response = "";

View File

@ -19,63 +19,238 @@
*
*/
// This code is based on a Go implementation and its license is below:
// Copyright (c) 2010 Jack Palevich. All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
declare(strict_types=1);
/**
* UPnP port forwarding support. Only for Windows
* UPnP port forwarding support.
*/
namespace pocketmine\network\upnp;
use pocketmine\utils\AssumptionFailedError;
use pocketmine\utils\Internet;
use pocketmine\utils\Utils;
use function class_exists;
use function is_object;
use function count;
use function libxml_use_internal_errors;
use function parse_url;
use function preg_last_error;
use function preg_match;
use function socket_close;
use function socket_create;
use function socket_last_error;
use function socket_recvfrom;
use function socket_sendto;
use function socket_set_option;
use function socket_strerror;
use function sprintf;
use function strlen;
use function trim;
use const AF_INET;
use const SO_RCVTIMEO;
use const SOCK_DGRAM;
use const SOCKET_ETIMEDOUT;
use const SOL_SOCKET;
use const SOL_UDP;
abstract class UPnP{
private const MAX_DISCOVERY_ATTEMPTS = 3;
/** @var string|null */
private static $serviceURL = null;
private static function makePcreError() : \RuntimeException{
$errorCode = preg_last_error();
$message = [
PREG_INTERNAL_ERROR => "Internal error",
PREG_BACKTRACK_LIMIT_ERROR => "Backtrack limit reached",
PREG_RECURSION_LIMIT_ERROR => "Recursion limit reached",
PREG_BAD_UTF8_ERROR => "Malformed UTF-8",
PREG_BAD_UTF8_OFFSET_ERROR => "Bad UTF-8 offset",
PREG_JIT_STACKLIMIT_ERROR => "PCRE JIT stack limit reached"
][$errorCode] ?? "Unknown (code $errorCode)";
throw new \RuntimeException("PCRE error: $message");
}
public static function getServiceUrl() : string{
$socket = @socket_create(AF_INET, SOCK_DGRAM, SOL_UDP);
if($socket === false){
throw new \RuntimeException("Socket error: " . trim(socket_strerror(socket_last_error())));
}
if(!@socket_set_option($socket, SOL_SOCKET, SO_RCVTIMEO, ["sec" => 3, "usec" => 0])){
throw new \RuntimeException("Socket error: " . trim(socket_strerror(socket_last_error($socket))));
}
$contents =
"M-SEARCH * HTTP/1.1\r\n" .
"MX: 2\r\n" .
"HOST: 239.255.255.250:1900\r\n" .
"MAN: \"ssdp:discover\"\r\n" .
"ST: upnp:rootdevice\r\n\r\n";
$location = null;
for($i = 0; $i < self::MAX_DISCOVERY_ATTEMPTS; ++$i){
$sendbyte = @socket_sendto($socket, $contents, strlen($contents), 0, "239.255.255.250", 1900);
if($sendbyte === false){
throw new \RuntimeException("Socket error: " . trim(socket_strerror(socket_last_error($socket))));
}
if($sendbyte !== strlen($contents)){
throw new \RuntimeException("Socket error: Unable to send the entire contents.");
}
while(true){
if(@socket_recvfrom($socket, $buffer, 1024, 0, $responseHost, $responsePort) === false){
if(socket_last_error($socket) === SOCKET_ETIMEDOUT){
continue 2;
}
throw new \RuntimeException("Socket error: " . trim(socket_strerror(socket_last_error($socket))));
}
$pregResult = preg_match('/location\s*:\s*(.+)\n/i', $buffer, $matches);
if($pregResult === false){
//TODO: replace with preg_last_error_msg() in PHP 8.
throw self::makePcreError();
}
if($pregResult !== 0){ //this might be garbage from somewhere other than the router
$location = trim($matches[1]);
break 2;
}
}
}
socket_close($socket);
if($location === null){
throw new \RuntimeException("Unable to find the router. Ensure that network discovery is enabled in Control Panel.");
}
$url = parse_url($location);
if($url === false){
throw new \RuntimeException("Failed to parse the router's url: {$location}");
}
if(!isset($url['host'])){
throw new \RuntimeException("Failed to recognize the host name from the router's url: {$location}");
}
$urlHost = $url['host'];
if(!isset($url['port'])){
throw new \RuntimeException("Failed to recognize the port number from the router's url: {$location}");
}
$urlPort = $url['port'];
$response = Internet::getURL($location, 3, [], $err, $headers, $httpCode);
if($response === false){
throw new \RuntimeException("Unable to access XML: {$err}");
}
if($httpCode !== 200){
throw new \RuntimeException("Unable to access XML: {$response}");
}
$defaultInternalError = libxml_use_internal_errors(true);
try{
$root = new \SimpleXMLElement($response);
}catch(\Exception $e){
throw new \RuntimeException("Broken XML.");
}
libxml_use_internal_errors($defaultInternalError);
$root->registerXPathNamespace("upnp", "urn:schemas-upnp-org:device-1-0");
$xpathResult = $root->xpath(
'//upnp:device[upnp:deviceType="urn:schemas-upnp-org:device:InternetGatewayDevice:1"]' .
'/upnp:deviceList/upnp:device[upnp:deviceType="urn:schemas-upnp-org:device:WANDevice:1"]' .
'/upnp:deviceList/upnp:device[upnp:deviceType="urn:schemas-upnp-org:device:WANConnectionDevice:1"]' .
'/upnp:serviceList/upnp:service[upnp:serviceType="urn:schemas-upnp-org:service:WANIPConnection:1"]' .
'/upnp:controlURL'
);
if($xpathResult === false){
//this should be an array of 0 if there is no matching elements; false indicates a problem with the query itself
throw new AssumptionFailedError("xpath query should not error here");
}
if(count($xpathResult) === 0){
throw new \RuntimeException("Your router does not support portforwarding");
}
$controlURL = (string) $xpathResult[0];
$serviceURL = sprintf("%s:%d/%s", $urlHost, $urlPort, $controlURL);
return $serviceURL;
}
public static function PortForward(int $port) : void{
if(!Internet::$online){
throw new \RuntimeException("Server is offline");
}
if(Utils::getOS() !== Utils::OS_WINDOWS){
throw new \RuntimeException("UPnP is only supported on Windows");
if(self::$serviceURL === null){
self::$serviceURL = self::getServiceUrl();
}
if(!class_exists("COM")){
throw new \RuntimeException("UPnP requires the com_dotnet extension");
$body =
'<u:AddPortMapping xmlns:u="urn:schemas-upnp-org:service:WANIPConnection:1">' .
'<NewRemoteHost></NewRemoteHost>' .
'<NewExternalPort>' . $port . '</NewExternalPort>' .
'<NewProtocol>UDP</NewProtocol>' .
'<NewInternalPort>' . $port . '</NewInternalPort>' .
'<NewInternalClient>' . Internet::getInternalIP() . '</NewInternalClient>' .
'<NewEnabled>1</NewEnabled>' .
'<NewPortMappingDescription>PocketMine-MP</NewPortMappingDescription>' .
'<NewLeaseDuration>0</NewLeaseDuration>' .
'</u:AddPortMapping>';
$contents =
'<?xml version="1.0"?>' .
'<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/" s:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">' .
'<s:Body>' . $body . '</s:Body></s:Envelope>';
$headers = [
'Content-Type: text/xml',
'SOAPAction: "urn:schemas-upnp-org:service:WANIPConnection:1#AddPortMapping"'
];
if(Internet::postURL(self::$serviceURL, $contents, 3, $headers, $err) === false){
throw new \RuntimeException("Failed to portforward using UPnP: " . $err);
}
$myLocalIP = Internet::getInternalIP();
/** @noinspection PhpUndefinedClassInspection */
$com = new \COM("HNetCfg.NATUPnP");
/** @noinspection PhpUndefinedFieldInspection */
if(!is_object($com->StaticPortMappingCollection)){
throw new \RuntimeException("Failed to portforward using UPnP. Ensure that network discovery is enabled in Control Panel.");
}
/** @noinspection PhpUndefinedFieldInspection */
$com->StaticPortMappingCollection->Add($port, "UDP", $port, $myLocalIP, true, "PocketMine-MP");
}
public static function RemovePortForward(int $port) : bool{
if(!Internet::$online){
return false;
}
if(Utils::getOS() !== Utils::OS_WINDOWS or !class_exists("COM")){
if(self::$serviceURL === null){
return false;
}
try{
/** @noinspection PhpUndefinedClassInspection */
$com = new \COM("HNetCfg.NATUPnP");
/** @noinspection PhpUndefinedFieldInspection */
if(!is_object($com->StaticPortMappingCollection)){
return false;
}
/** @noinspection PhpUndefinedFieldInspection */
$com->StaticPortMappingCollection->Remove($port, "UDP");
}catch(\Throwable $e){
$body =
'<u:DeletePortMapping xmlns:u="urn:schemas-upnp-org:service:WANIPConnection:1">' .
'<NewRemoteHost></NewRemoteHost>' .
'<NewExternalPort>' . $port . '</NewExternalPort>' .
'<NewProtocol>UDP</NewProtocol>' .
'</u:DeletePortMapping>';
$contents =
'<?xml version="1.0"?>' .
'<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/" s:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">' .
'<s:Body>' . $body . '</s:Body></s:Envelope>';
$headers = [
'Content-Type: text/xml',
'SOAPAction: "urn:schemas-upnp-org:service:WANIPConnection:1#DeletePortMapping"'
];
if(Internet::postURL(self::$serviceURL, $contents, 3, $headers) === false){
return false;
}

View File

@ -701,9 +701,18 @@ class PluginManager{
}
$handlerClosure = $method->getClosure($listener);
if($handlerClosure === null) throw new AssumptionFailedError("This should never happen");
try{
$eventClass = $parameters[0]->getClass();
$paramType = $parameters[0]->getType();
//isBuiltin() returns false for builtin classes ..................
if($paramType instanceof \ReflectionNamedType && !$paramType->isBuiltin()){
/** @phpstan-var class-string $paramClass */
$paramClass = $paramType->getName();
$eventClass = new \ReflectionClass($paramClass);
}else{
$eventClass = null;
}
}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) . "() because plugin \"" . $tags["softDepend"] . "\" not found");

View File

@ -87,7 +87,7 @@ network:
compression-level: 6
#Use AsyncTasks for compression. Adds half/one tick delay, less CPU load on main thread
async-compression: false
#Experimental, only for Windows. Tries to use UPnP to automatically port forward
#Experimental. Use UPnP to automatically port forward
upnp-forwarding: false
#Maximum size in bytes of packets sent over the network (default 1492 bytes). Packets larger than this will be
#fragmented or split into smaller parts. Clients can request MTU sizes up to but not more than this number.
@ -100,6 +100,9 @@ debug:
player:
#Choose whether to enable player data saving.
save-player-data: true
#If true, checks that joining players' Xbox user ID (XUID) match what was previously recorded.
#This also prevents non-XBL players using XBL players' usernames to steal their data on servers with xbox-auth=off.
verify-xuid: true
anti-cheat:
#If false, will try to prevent speed and noclip cheats. May cause movement issues.
allow-movement-cheats: true

View File

@ -51,6 +51,7 @@ use function unserialize;
abstract class AsyncTask extends Collectable{
/**
* @var \SplObjectStorage|null
* @phpstan-var \SplObjectStorage<AsyncTask, mixed>
* Used to store objects on the main thread which should not be serialized.
*/
private static $threadLocalStorage;
@ -258,7 +259,9 @@ abstract class AsyncTask extends Collectable{
}
if(self::$threadLocalStorage === null){
self::$threadLocalStorage = new \SplObjectStorage(); //lazy init
/** @phpstan-var \SplObjectStorage<AsyncTask, mixed> $storage */
$storage = new \SplObjectStorage();
self::$threadLocalStorage = $storage; //lazy init
}
if(isset(self::$threadLocalStorage[$this])){

View File

@ -152,8 +152,7 @@ class Furnace extends Spawnable implements InventoryHolder, Container, Nameable{
}
if($this->burnTime > 0 and $ev->isBurning()){
$fuel->pop();
$this->inventory->setFuel($fuel);
$this->inventory->setFuel($fuel->getFuelResidue());
}
}

View File

@ -278,8 +278,10 @@ class MainLogger extends \AttachableThreadedLogger{
* @return void
*/
public function shutdown(){
$this->shutdown = true;
$this->notify();
$this->synchronized(function() : void{
$this->shutdown = true;
$this->notify();
});
}
/**
@ -321,6 +323,7 @@ class MainLogger extends \AttachableThreadedLogger{
}
$this->logStream[] = $time->format("Y-m-d") . " " . TextFormat::clean($message) . PHP_EOL;
$this->notify();
});
}
@ -328,10 +331,11 @@ class MainLogger extends \AttachableThreadedLogger{
* @return void
*/
public function syncFlushBuffer(){
$this->syncFlush = true;
$this->synchronized(function() : void{
$this->syncFlush = true;
$this->notify(); //write immediately
});
$this->synchronized(function() : void{
while($this->syncFlush){
$this->wait(); //block until it's all been written to disk
}
@ -343,14 +347,17 @@ class MainLogger extends \AttachableThreadedLogger{
*/
private function writeLogStream($logResource) : void{
while($this->logStream->count() > 0){
/** @var string $chunk */
$chunk = $this->logStream->shift();
fwrite($logResource, $chunk);
}
if($this->syncFlush){
$this->syncFlush = false;
$this->notify(); //if this was due to a sync flush, tell the caller to stop waiting
}
$this->synchronized(function() : void{
if($this->syncFlush){
$this->syncFlush = false;
$this->notify(); //if this was due to a sync flush, tell the caller to stop waiting
}
});
}
/**
@ -365,7 +372,9 @@ class MainLogger extends \AttachableThreadedLogger{
while(!$this->shutdown){
$this->writeLogStream($logResource);
$this->synchronized(function() : void{
$this->wait(25000);
if(!$this->shutdown && !$this->syncFlush){
$this->wait();
}
});
}

View File

@ -30,6 +30,8 @@ use function fclose;
use function file;
use function file_get_contents;
use function function_exists;
use function getmypid;
use function getmyuid;
use function hexdec;
use function memory_get_usage;
use function posix_kill;
@ -175,4 +177,20 @@ final class Process{
return proc_close($process);
}
public static function pid() : int{
$result = getmypid();
if($result === false){
throw new \LogicException("getmypid() doesn't work on this platform");
}
return $result;
}
public static function uid() : int{
$result = getmyuid();
if($result === false){
throw new \LogicException("getmyuid() doesn't work on this platform");
}
return $result;
}
}

View File

@ -24,7 +24,6 @@ declare(strict_types=1);
namespace pocketmine\utils;
use pocketmine\Thread;
use function getmypid;
use function time;
class ServerKiller extends Thread{
@ -55,7 +54,7 @@ class ServerKiller extends Thread{
});
if(time() - $start >= $this->time){
echo "\nTook too long to stop, server was killed forcefully!\n";
@Process::kill(getmypid());
@Process::kill(Process::pid());
}
}

View File

@ -94,7 +94,7 @@ class UUID{
}
public static function fromRandom() : UUID{
return self::fromData(Binary::writeInt(time()), Binary::writeShort(getmypid()), Binary::writeShort(getmyuid()), Binary::writeInt(mt_rand(-0x7fffffff, 0x7fffffff)), Binary::writeInt(mt_rand(-0x7fffffff, 0x7fffffff)));
return self::fromData(Binary::writeInt(time()), Binary::writeShort(($pid = getmypid()) !== false ? $pid : 0), Binary::writeShort(($uid = getmyuid()) !== false ? $uid : 0), Binary::writeInt(mt_rand(-0x7fffffff, 0x7fffffff)), Binary::writeInt(mt_rand(-0x7fffffff, 0x7fffffff)));
}
public function toBinary() : string{

View File

@ -106,6 +106,9 @@ class Utils{
public const OS_BSD = "bsd";
public const OS_UNKNOWN = "other";
public const CLEAN_PATH_SRC_PREFIX = "pmsrc";
public const CLEAN_PATH_PLUGINS_PREFIX = "plugins";
/** @var string|null */
public static $os;
/** @var UUID|null */
@ -114,6 +117,8 @@ class Utils{
/**
* Generates an unique identifier to a callable
*
* @phpstan-param anyCallable $variable
*
* @return string
*/
public static function getCallableIdentifier(callable $variable){
@ -129,6 +134,7 @@ class Utils{
/**
* Returns a readable identifier for the given Closure, including file and line.
*
* @phpstan-param anyClosure $closure
* @throws \ReflectionException
*/
public static function getNiceClosureName(\Closure $closure) : string{
@ -189,7 +195,14 @@ class Utils{
}
$machine = php_uname("a");
$machine .= ($cpuinfo = @file("/proc/cpuinfo")) !== false ? implode(preg_grep("/(model name|Processor|Serial)/", $cpuinfo)) : "";
$cpuinfo = @file("/proc/cpuinfo");
if($cpuinfo !== false){
$cpuinfoLines = preg_grep("/(model name|Processor|Serial)/", $cpuinfo);
if($cpuinfoLines === false){
throw new AssumptionFailedError("Pattern is valid, so this shouldn't fail ...");
}
$machine .= implode("", $cpuinfoLines);
}
$machine .= sys_get_temp_dir();
$machine .= $extra;
$os = Utils::getOS();
@ -604,8 +617,8 @@ class Utils{
//remove relative paths
//TODO: make these paths dynamic so they can be unit-tested against
static $cleanPaths = [
\pocketmine\PLUGIN_PATH => "plugins", //this has to come BEFORE \pocketmine\PATH because it's inside that by default on src installations
\pocketmine\PATH => ""
\pocketmine\PLUGIN_PATH => self::CLEAN_PATH_PLUGINS_PREFIX, //this has to come BEFORE \pocketmine\PATH because it's inside that by default on src installations
\pocketmine\PATH => self::CLEAN_PATH_SRC_PREFIX
];
foreach($cleanPaths as $cleanPath => $replacement){
$cleanPath = rtrim(str_replace([DIRECTORY_SEPARATOR, "phar://"], ["/", ""], $cleanPath), "/");
@ -675,6 +688,8 @@ class Utils{
*
* @param callable $signature Dummy callable with the required parameters and return type
* @param callable $subject Callable to check the signature of
* @phpstan-param anyCallable $signature
* @phpstan-param anyCallable $subject
*
* @throws \DaveRandom\CallbackValidator\InvalidCallbackException
* @throws \TypeError

View File

@ -221,7 +221,7 @@ LICENSE;
$config->save();
}
private function printIpDetails() : void{
$this->message($this->lang->get("ip_get"));

26
tests/gh-actions/build.sh Executable file
View File

@ -0,0 +1,26 @@
VERSION="$1"
sudo apt update && sudo apt install -y \
re2c \
libtool \
libtool-bin \
zlib1g-dev \
libcurl4-openssl-dev \
libxml2-dev \
libyaml-dev \
libgmp-dev \
libzip-dev \
libssl-dev
INSTALL_DIR="$(pwd)/bin/php7"
export CFLAGS="$CFLAGS -march=x86-64"
export CXXFLAGS="$CXXFLAGS -march=x86-64"
git clone https://github.com/php-build/php-build.git
cd php-build
./install-dependencies.sh
echo '"pthreads",,"https://github.com/pmmp/pthreads.git",,,"extension",' >> share/php-build/extension/definition
PHP_BUILD_INSTALL_EXTENSION='pthreads=@acc6e52b2144c61c434b62a3cb680d537e06828e yaml=2.2.1' PHP_BUILD_ZTS_ENABLE=on ./bin/php-build "$VERSION" "$INSTALL_DIR" || exit 1
rm "$INSTALL_DIR/etc/conf.d/xdebug.ini" || true
cp install-dependencies.sh "$INSTALL_DIR"

View File

@ -21,8 +21,6 @@
declare(strict_types=1);
define('pocketmine\_PHPSTAN_ANALYSIS', true);
if(!defined('LEVELDB_ZLIB_RAW_COMPRESSION')){
//leveldb might not be loaded
define('LEVELDB_ZLIB_RAW_COMPRESSION', 4);

View File

@ -10,11 +10,6 @@ parameters:
count: 1
path: ../../../src/pocketmine/Player.php
-
message: "#^Cannot instantiate interface pocketmine\\\\level\\\\format\\\\io\\\\LevelProvider\\.$#"
count: 1
path: ../../../src/pocketmine/Server.php
-
message: "#^Instanceof between pocketmine\\\\plugin\\\\PluginManager and pocketmine\\\\plugin\\\\PluginManager will always evaluate to true\\.$#"
count: 1
@ -745,6 +740,11 @@ parameters:
count: 1
path: ../../../src/pocketmine/level/generator/normal/Normal.php
-
message: "#^Method pocketmine\\\\metadata\\\\MetadataStore\\:\\:getMetadataInternal\\(\\) should return array\\<pocketmine\\\\metadata\\\\MetadataValue\\> but returns SplObjectStorage\\<pocketmine\\\\plugin\\\\Plugin, pocketmine\\\\metadata\\\\MetadataValue\\>\\.$#"
count: 1
path: ../../../src/pocketmine/metadata/MetadataStore.php
-
message: "#^Variable method call on pocketmine\\\\event\\\\Listener\\.$#"
count: 1

View File

@ -5,11 +5,6 @@ parameters:
count: 1
path: ../../../src/pocketmine/CrashDump.php
-
message: "#^Parameter \\#3 \\$subject of function preg_replace expects array\\|string, mixed given\\.$#"
count: 1
path: ../../../src/pocketmine/CrashDump.php
-
message: "#^Cannot access offset float\\|int on mixed\\.$#"
count: 1
@ -20,11 +15,6 @@ parameters:
count: 1
path: ../../../src/pocketmine/CrashDump.php
-
message: "#^Cannot access offset 'name' on mixed\\.$#"
count: 1
path: ../../../src/pocketmine/CrashDump.php
-
message: "#^Cannot cast mixed to int\\.$#"
count: 7
@ -46,32 +36,7 @@ parameters:
path: ../../../src/pocketmine/Player.php
-
message: "#^Parameter \\#10 \\$personaCapeOnClassic of class pocketmine\\\\network\\\\mcpe\\\\protocol\\\\types\\\\SkinData constructor expects bool, mixed given\\.$#"
count: 1
path: ../../../src/pocketmine/Player.php
-
message: "#^Parameter \\#11 \\$capeId of class pocketmine\\\\network\\\\mcpe\\\\protocol\\\\types\\\\SkinData constructor expects string, mixed given\\.$#"
count: 1
path: ../../../src/pocketmine/Player.php
-
message: "#^Parameter \\#13 \\$armSize of class pocketmine\\\\network\\\\mcpe\\\\protocol\\\\types\\\\SkinData constructor expects string, mixed given\\.$#"
count: 1
path: ../../../src/pocketmine/Player.php
-
message: "#^Parameter \\#14 \\$skinColor of class pocketmine\\\\network\\\\mcpe\\\\protocol\\\\types\\\\SkinData constructor expects string, mixed given\\.$#"
count: 1
path: ../../../src/pocketmine/Player.php
-
message: "#^Parameter \\#8 \\$premium of class pocketmine\\\\network\\\\mcpe\\\\protocol\\\\types\\\\SkinData constructor expects bool, mixed given\\.$#"
count: 1
path: ../../../src/pocketmine/Player.php
-
message: "#^Parameter \\#9 \\$persona of class pocketmine\\\\network\\\\mcpe\\\\protocol\\\\types\\\\SkinData constructor expects bool, mixed given\\.$#"
message: "#^Parameter \\#2 \\$playFabId of class pocketmine\\\\network\\\\mcpe\\\\protocol\\\\types\\\\SkinData constructor expects string, mixed given\\.$#"
count: 1
path: ../../../src/pocketmine/Player.php
@ -90,6 +55,36 @@ parameters:
count: 2
path: ../../../src/pocketmine/Player.php
-
message: "#^Parameter \\#9 \\$premium of class pocketmine\\\\network\\\\mcpe\\\\protocol\\\\types\\\\SkinData constructor expects bool, mixed given\\.$#"
count: 1
path: ../../../src/pocketmine/Player.php
-
message: "#^Parameter \\#10 \\$persona of class pocketmine\\\\network\\\\mcpe\\\\protocol\\\\types\\\\SkinData constructor expects bool, mixed given\\.$#"
count: 1
path: ../../../src/pocketmine/Player.php
-
message: "#^Parameter \\#11 \\$personaCapeOnClassic of class pocketmine\\\\network\\\\mcpe\\\\protocol\\\\types\\\\SkinData constructor expects bool, mixed given\\.$#"
count: 1
path: ../../../src/pocketmine/Player.php
-
message: "#^Parameter \\#12 \\$capeId of class pocketmine\\\\network\\\\mcpe\\\\protocol\\\\types\\\\SkinData constructor expects string, mixed given\\.$#"
count: 1
path: ../../../src/pocketmine/Player.php
-
message: "#^Parameter \\#14 \\$armSize of class pocketmine\\\\network\\\\mcpe\\\\protocol\\\\types\\\\SkinData constructor expects string, mixed given\\.$#"
count: 1
path: ../../../src/pocketmine/Player.php
-
message: "#^Parameter \\#15 \\$skinColor of class pocketmine\\\\network\\\\mcpe\\\\protocol\\\\types\\\\SkinData constructor expects string, mixed given\\.$#"
count: 1
path: ../../../src/pocketmine/Player.php
-
message: "#^Parameter \\#1 \\.\\.\\.\\$slots of method pocketmine\\\\inventory\\\\BaseInventory\\:\\:addItem\\(\\) expects pocketmine\\\\item\\\\Item, mixed given\\.$#"
count: 1
@ -260,26 +255,6 @@ parameters:
count: 1
path: ../../../src/pocketmine/level/generator/Flat.php
-
message: "#^Parameter \\#4 \\$q0 of static method pocketmine\\\\level\\\\generator\\\\noise\\\\Noise\\:\\:linearLerp\\(\\) expects float, mixed given\\.$#"
count: 1
path: ../../../src/pocketmine/level/generator/noise/Noise.php
-
message: "#^Parameter \\#5 \\$q1 of static method pocketmine\\\\level\\\\generator\\\\noise\\\\Noise\\:\\:linearLerp\\(\\) expects float, mixed given\\.$#"
count: 1
path: ../../../src/pocketmine/level/generator/noise/Noise.php
-
message: "#^Cannot access offset int on mixed\\.$#"
count: 6
path: ../../../src/pocketmine/level/generator/noise/Noise.php
-
message: "#^Cannot call method invalidate\\(\\) on mixed\\.$#"
count: 1
path: ../../../src/pocketmine/metadata/MetadataStore.php
-
message: "#^Parameter \\#1 \\$buffer of class pocketmine\\\\network\\\\mcpe\\\\protocol\\\\BatchPacket constructor expects string, mixed given\\.$#"
count: 1
@ -450,11 +425,6 @@ parameters:
count: 1
path: ../../../src/pocketmine/network/mcpe/protocol/SetActorDataPacket.php
-
message: "#^Parameter \\#1 \\$table of static method pocketmine\\\\network\\\\mcpe\\\\protocol\\\\StartGamePacket\\:\\:serializeItemTable\\(\\) expects array\\<string, int\\>, mixed given\\.$#"
count: 1
path: ../../../src/pocketmine/network/mcpe/protocol/StartGamePacket.php
-
message: "#^Parameter \\#1 \\$value of static method pocketmine\\\\permission\\\\Permission\\:\\:getByName\\(\\) expects bool\\|string, mixed given\\.$#"
count: 1
@ -590,11 +560,6 @@ parameters:
count: 1
path: ../../../src/pocketmine/utils/Internet.php
-
message: "#^Parameter \\#2 \\$str of function fwrite expects string, mixed given\\.$#"
count: 1
path: ../../../src/pocketmine/utils/MainLogger.php
-
message: "#^Cannot access offset 'status' on mixed\\.$#"
count: 1

View File

@ -1,7 +0,0 @@
parameters:
ignoreErrors:
-
message: "#^Access to an undefined property COM\\:\\:\\$StaticPortMappingCollection\\.$#"
count: 2
path: ../../../src/pocketmine/network/upnp/UPnP.php

View File

@ -31,17 +31,17 @@ parameters:
path: ../../../src/pocketmine/Player.php
-
message: "#^Parameter \\#2 \\$resourcePatch of class pocketmine\\\\network\\\\mcpe\\\\protocol\\\\types\\\\SkinData constructor expects string, string\\|false given\\.$#"
message: "#^Parameter \\#3 \\$resourcePatch of class pocketmine\\\\network\\\\mcpe\\\\protocol\\\\types\\\\SkinData constructor expects string, string\\|false given\\.$#"
count: 1
path: ../../../src/pocketmine/Player.php
-
message: "#^Parameter \\#6 \\$geometryData of class pocketmine\\\\network\\\\mcpe\\\\protocol\\\\types\\\\SkinData constructor expects string, string\\|false given\\.$#"
message: "#^Parameter \\#7 \\$geometryData of class pocketmine\\\\network\\\\mcpe\\\\protocol\\\\types\\\\SkinData constructor expects string, string\\|false given\\.$#"
count: 1
path: ../../../src/pocketmine/Player.php
-
message: "#^Parameter \\#7 \\$animationData of class pocketmine\\\\network\\\\mcpe\\\\protocol\\\\types\\\\SkinData constructor expects string, string\\|false given\\.$#"
message: "#^Parameter \\#8 \\$animationData of class pocketmine\\\\network\\\\mcpe\\\\protocol\\\\types\\\\SkinData constructor expects string, string\\|false given\\.$#"
count: 1
path: ../../../src/pocketmine/Player.php
@ -60,16 +60,6 @@ parameters:
count: 1
path: ../../../src/pocketmine/PocketMine.php
-
message: "#^Parameter \\#1 \\$filename of function is_file expects string, array\\<int, mixed\\>\\|string given\\.$#"
count: 1
path: ../../../src/pocketmine/PocketMine.php
-
message: "#^Binary operation \"\\.\" between 'Composer autoloader…' and array\\<int, mixed\\>\\|string\\|false results in an error\\.$#"
count: 1
path: ../../../src/pocketmine/PocketMine.php
-
message: "#^Binary operation \"\\.\" between array\\<int, mixed\\>\\|string\\|false and '/'\\|'\\\\\\\\' results in an error\\.$#"
count: 2
@ -80,36 +70,6 @@ parameters:
count: 2
path: ../../../src/pocketmine/PocketMine.php
-
message: "#^Parameter \\#1 \\$fp of function flock expects resource, resource\\|false given\\.$#"
count: 4
path: ../../../src/pocketmine/PocketMine.php
-
message: "#^Parameter \\#1 \\$source of function stream_get_contents expects resource, resource\\|false given\\.$#"
count: 1
path: ../../../src/pocketmine/PocketMine.php
-
message: "#^Parameter \\#1 \\$fp of function ftruncate expects resource, resource\\|false given\\.$#"
count: 1
path: ../../../src/pocketmine/PocketMine.php
-
message: "#^Parameter \\#1 \\$fp of function fwrite expects resource, resource\\|false given\\.$#"
count: 1
path: ../../../src/pocketmine/PocketMine.php
-
message: "#^Parameter \\#1 \\$fp of function fflush expects resource, resource\\|false given\\.$#"
count: 1
path: ../../../src/pocketmine/PocketMine.php
-
message: "#^Parameter \\#1 \\$fp of function fclose expects resource, resource\\|false given\\.$#"
count: 1
path: ../../../src/pocketmine/PocketMine.php
-
message: "#^Parameter \\#1 \\$buffer of method pocketmine\\\\nbt\\\\NBTStream\\:\\:readCompressed\\(\\) expects string, string\\|false given\\.$#"
count: 1
@ -155,51 +115,6 @@ parameters:
count: 1
path: ../../../src/pocketmine/block/Cactus.php
-
message: "#^Parameter \\#1 \\$x of method pocketmine\\\\level\\\\Level\\:\\:getBlockIdAt\\(\\) expects int, float\\|int given\\.$#"
count: 1
path: ../../../src/pocketmine/block/Farmland.php
-
message: "#^Parameter \\#2 \\$y of method pocketmine\\\\level\\\\Level\\:\\:getBlockIdAt\\(\\) expects int, float\\|int given\\.$#"
count: 1
path: ../../../src/pocketmine/block/Farmland.php
-
message: "#^Parameter \\#3 \\$z of method pocketmine\\\\level\\\\Level\\:\\:getBlockIdAt\\(\\) expects int, float\\|int given\\.$#"
count: 1
path: ../../../src/pocketmine/block/Farmland.php
-
message: "#^Parameter \\#1 \\$x of method pocketmine\\\\level\\\\Level\\:\\:getFullLightAt\\(\\) expects int, float\\|int given\\.$#"
count: 1
path: ../../../src/pocketmine/block/Grass.php
-
message: "#^Parameter \\#2 \\$y of method pocketmine\\\\level\\\\Level\\:\\:getFullLightAt\\(\\) expects int, float\\|int given\\.$#"
count: 1
path: ../../../src/pocketmine/block/Grass.php
-
message: "#^Parameter \\#3 \\$z of method pocketmine\\\\level\\\\Level\\:\\:getFullLightAt\\(\\) expects int, float\\|int given\\.$#"
count: 1
path: ../../../src/pocketmine/block/Grass.php
-
message: "#^Parameter \\#1 \\$x of method pocketmine\\\\level\\\\Level\\:\\:getBlockIdAt\\(\\) expects int, float\\|int given\\.$#"
count: 1
path: ../../../src/pocketmine/block/Grass.php
-
message: "#^Parameter \\#2 \\$y of method pocketmine\\\\level\\\\Level\\:\\:getBlockIdAt\\(\\) expects int, float\\|int given\\.$#"
count: 1
path: ../../../src/pocketmine/block/Grass.php
-
message: "#^Parameter \\#3 \\$z of method pocketmine\\\\level\\\\Level\\:\\:getBlockIdAt\\(\\) expects int, float\\|int given\\.$#"
count: 1
path: ../../../src/pocketmine/block/Grass.php
-
message: "#^Parameter \\#1 \\$min of function mt_rand expects int, float\\|int given\\.$#"
count: 3
@ -210,36 +125,6 @@ parameters:
count: 3
path: ../../../src/pocketmine/block/Grass.php
-
message: "#^Parameter \\#1 \\$x of method pocketmine\\\\level\\\\Level\\:\\:getHighestAdjacentBlockLight\\(\\) expects int, float\\|int given\\.$#"
count: 1
path: ../../../src/pocketmine/block/Ice.php
-
message: "#^Parameter \\#2 \\$y of method pocketmine\\\\level\\\\Level\\:\\:getHighestAdjacentBlockLight\\(\\) expects int, float\\|int given\\.$#"
count: 1
path: ../../../src/pocketmine/block/Ice.php
-
message: "#^Parameter \\#3 \\$z of method pocketmine\\\\level\\\\Level\\:\\:getHighestAdjacentBlockLight\\(\\) expects int, float\\|int given\\.$#"
count: 1
path: ../../../src/pocketmine/block/Ice.php
-
message: "#^Parameter \\#1 \\$x of method pocketmine\\\\level\\\\Level\\:\\:getBlockAt\\(\\) expects int, float\\|int given\\.$#"
count: 23
path: ../../../src/pocketmine/block/Liquid.php
-
message: "#^Parameter \\#2 \\$y of method pocketmine\\\\level\\\\Level\\:\\:getBlockAt\\(\\) expects int, float\\|int given\\.$#"
count: 23
path: ../../../src/pocketmine/block/Liquid.php
-
message: "#^Parameter \\#3 \\$z of method pocketmine\\\\level\\\\Level\\:\\:getBlockAt\\(\\) expects int, float\\|int given\\.$#"
count: 23
path: ../../../src/pocketmine/block/Liquid.php
-
message: "#^Parameter \\#1 \\$x of static method pocketmine\\\\level\\\\Level\\:\\:blockHash\\(\\) expects int, float\\|int given\\.$#"
count: 3
@ -295,36 +180,6 @@ parameters:
count: 2
path: ../../../src/pocketmine/block/Sapling.php
-
message: "#^Parameter \\#1 \\$x of method pocketmine\\\\level\\\\Level\\:\\:getFullLightAt\\(\\) expects int, float\\|int given\\.$#"
count: 1
path: ../../../src/pocketmine/block/Sapling.php
-
message: "#^Parameter \\#2 \\$y of method pocketmine\\\\level\\\\Level\\:\\:getFullLightAt\\(\\) expects int, float\\|int given\\.$#"
count: 1
path: ../../../src/pocketmine/block/Sapling.php
-
message: "#^Parameter \\#3 \\$z of method pocketmine\\\\level\\\\Level\\:\\:getFullLightAt\\(\\) expects int, float\\|int given\\.$#"
count: 1
path: ../../../src/pocketmine/block/Sapling.php
-
message: "#^Parameter \\#1 \\$x of method pocketmine\\\\level\\\\Level\\:\\:getBlockLightAt\\(\\) expects int, float\\|int given\\.$#"
count: 1
path: ../../../src/pocketmine/block/SnowLayer.php
-
message: "#^Parameter \\#2 \\$y of method pocketmine\\\\level\\\\Level\\:\\:getBlockLightAt\\(\\) expects int, float\\|int given\\.$#"
count: 1
path: ../../../src/pocketmine/block/SnowLayer.php
-
message: "#^Parameter \\#3 \\$z of method pocketmine\\\\level\\\\Level\\:\\:getBlockLightAt\\(\\) expects int, float\\|int given\\.$#"
count: 1
path: ../../../src/pocketmine/block/SnowLayer.php
-
message: "#^Parameter \\#1 \\$x of method pocketmine\\\\level\\\\Level\\:\\:getBlockAt\\(\\) expects int, float\\|int given\\.$#"
count: 2
@ -400,21 +255,6 @@ parameters:
count: 1
path: ../../../src/pocketmine/entity/Human.php
-
message: "#^Parameter \\#1 \\$x of method pocketmine\\\\level\\\\Level\\:\\:getBlockAt\\(\\) expects int, float\\|int given\\.$#"
count: 1
path: ../../../src/pocketmine/entity/Living.php
-
message: "#^Parameter \\#2 \\$y of method pocketmine\\\\level\\\\Level\\:\\:getBlockAt\\(\\) expects int, float\\|int given\\.$#"
count: 1
path: ../../../src/pocketmine/entity/Living.php
-
message: "#^Parameter \\#3 \\$z of method pocketmine\\\\level\\\\Level\\:\\:getBlockAt\\(\\) expects int, float\\|int given\\.$#"
count: 1
path: ../../../src/pocketmine/entity/Living.php
-
message: "#^Parameter \\#1 \\$x of method pocketmine\\\\level\\\\Level\\:\\:getBlockAt\\(\\) expects int, float\\|int given\\.$#"
count: 1
@ -435,21 +275,6 @@ parameters:
count: 3
path: ../../../src/pocketmine/entity/projectile/Projectile.php
-
message: "#^Parameter \\#1 \\$x of method pocketmine\\\\level\\\\Level\\:\\:getBlockAt\\(\\) expects int, float\\|int given\\.$#"
count: 2
path: ../../../src/pocketmine/entity/projectile/Projectile.php
-
message: "#^Parameter \\#2 \\$y of method pocketmine\\\\level\\\\Level\\:\\:getBlockAt\\(\\) expects int, float\\|int given\\.$#"
count: 2
path: ../../../src/pocketmine/entity/projectile/Projectile.php
-
message: "#^Parameter \\#3 \\$z of method pocketmine\\\\level\\\\Level\\:\\:getBlockAt\\(\\) expects int, float\\|int given\\.$#"
count: 2
path: ../../../src/pocketmine/entity/projectile/Projectile.php
-
message: "#^Parameter \\#1 \\$argument of class ReflectionClass constructor expects class\\-string\\<T of object\\>\\|T of object, string given\\.$#"
count: 1
@ -685,11 +510,6 @@ parameters:
count: 1
path: ../../../src/pocketmine/level/Level.php
-
message: "#^Parameter \\#2 \\$y of method pocketmine\\\\level\\\\format\\\\Chunk\\:\\:setBlock\\(\\) expects int, float\\|int given\\.$#"
count: 1
path: ../../../src/pocketmine/level/Level.php
-
message: "#^Parameter \\#1 \\$x of static method pocketmine\\\\level\\\\Level\\:\\:chunkBlockHash\\(\\) expects int, float\\|int given\\.$#"
count: 1
@ -770,16 +590,6 @@ parameters:
count: 1
path: ../../../src/pocketmine/level/generator/object/TallGrass.php
-
message: "#^Method pocketmine\\\\metadata\\\\MetadataStore\\:\\:getMetadataInternal\\(\\) should return array\\<pocketmine\\\\metadata\\\\MetadataValue\\> but returns array\\<pocketmine\\\\metadata\\\\MetadataValue\\>\\|SplObjectStorage\\.$#"
count: 1
path: ../../../src/pocketmine/metadata/MetadataStore.php
-
message: "#^Cannot call method count\\(\\) on array\\<pocketmine\\\\metadata\\\\MetadataValue\\>\\|SplObjectStorage\\.$#"
count: 1
path: ../../../src/pocketmine/metadata/MetadataStore.php
-
message: "#^Parameter \\#1 \\$str of method pocketmine\\\\utils\\\\BinaryStream\\:\\:put\\(\\) expects string, string\\|false given\\.$#"
count: 2
@ -881,25 +691,10 @@ parameters:
path: ../../../src/pocketmine/network/mcpe/protocol/StartGamePacket.php
-
message: "#^Parameter \\#2 \\$resourcePatch of class pocketmine\\\\network\\\\mcpe\\\\protocol\\\\types\\\\SkinData constructor expects string, string\\|false given\\.$#"
message: "#^Parameter \\#3 \\$resourcePatch of class pocketmine\\\\network\\\\mcpe\\\\protocol\\\\types\\\\SkinData constructor expects string, string\\|false given\\.$#"
count: 1
path: ../../../src/pocketmine/network/mcpe/protocol/types/LegacySkinAdapter.php
-
message: "#^Call to an undefined method object\\:\\:Add\\(\\)\\.$#"
count: 1
path: ../../../src/pocketmine/network/upnp/UPnP.php
-
message: "#^Call to an undefined method object\\:\\:Remove\\(\\)\\.$#"
count: 1
path: ../../../src/pocketmine/network/upnp/UPnP.php
-
message: "#^Parameter \\#1 \\$event of method pocketmine\\\\plugin\\\\PluginManager\\:\\:registerEvent\\(\\) expects class\\-string\\<pocketmine\\\\event\\\\Event\\>, class\\-string\\<object\\> given\\.$#"
count: 1
path: ../../../src/pocketmine/plugin/PluginManager.php
-
message: "#^Parameter \\#1 \\$string of function strlen expects string, string\\|false given\\.$#"
count: 2
@ -985,18 +780,3 @@ parameters:
count: 3
path: ../../../src/pocketmine/tile/Tile.php
-
message: "#^Parameter \\#1 \\$x of method pocketmine\\\\level\\\\Level\\:\\:getBlockAt\\(\\) expects int, float\\|int given\\.$#"
count: 1
path: ../../../src/pocketmine/tile/Tile.php
-
message: "#^Parameter \\#2 \\$y of method pocketmine\\\\level\\\\Level\\:\\:getBlockAt\\(\\) expects int, float\\|int given\\.$#"
count: 1
path: ../../../src/pocketmine/tile/Tile.php
-
message: "#^Parameter \\#3 \\$z of method pocketmine\\\\level\\\\Level\\:\\:getBlockAt\\(\\) expects int, float\\|int given\\.$#"
count: 1
path: ../../../src/pocketmine/tile/Tile.php

View File

@ -147,7 +147,7 @@ parameters:
-
message: "#^Cannot call method getTile\\(\\) on pocketmine\\\\level\\\\Level\\|null\\.$#"
count: 2
count: 3
path: ../../../src/pocketmine/Player.php
-
@ -165,6 +165,11 @@ parameters:
count: 3
path: ../../../src/pocketmine/Player.php
-
message: "#^Cannot call method dropItem\\(\\) on pocketmine\\\\level\\\\Level\\|null\\.$#"
count: 4
path: ../../../src/pocketmine/Player.php
-
message: "#^Cannot call method setBlock\\(\\) on pocketmine\\\\level\\\\Level\\|null\\.$#"
count: 1
@ -175,11 +180,6 @@ parameters:
count: 3
path: ../../../src/pocketmine/Player.php
-
message: "#^Cannot call method dropItem\\(\\) on pocketmine\\\\level\\\\Level\\|null\\.$#"
count: 3
path: ../../../src/pocketmine/Player.php
-
message: "#^Cannot call method getTileAt\\(\\) on pocketmine\\\\level\\\\Level\\|null\\.$#"
count: 1
@ -1445,11 +1445,6 @@ parameters:
count: 1
path: ../../../src/pocketmine/network/mcpe/convert/RuntimeBlockMapping.php
-
message: "#^Parameter \\#1 \\$that of method pocketmine\\\\nbt\\\\tag\\\\NamedTag\\:\\:equals\\(\\) expects pocketmine\\\\nbt\\\\tag\\\\NamedTag, pocketmine\\\\nbt\\\\tag\\\\CompoundTag\\|null given\\.$#"
count: 1
path: ../../../src/pocketmine/network/mcpe/convert/RuntimeBlockMapping.php
-
message: "#^Method pocketmine\\\\network\\\\mcpe\\\\convert\\\\RuntimeBlockMapping\\:\\:getBedrockKnownStates\\(\\) should return array\\<pocketmine\\\\nbt\\\\tag\\\\CompoundTag\\> but returns array\\<pocketmine\\\\nbt\\\\tag\\\\CompoundTag\\>\\|null\\.$#"
count: 1
@ -1485,11 +1480,6 @@ parameters:
count: 1
path: ../../../src/pocketmine/plugin/PluginBase.php
-
message: "#^Parameter \\#1 \\$closure of static method pocketmine\\\\utils\\\\Utils\\:\\:getNiceClosureName\\(\\) expects Closure, Closure\\|null given\\.$#"
count: 3
path: ../../../src/pocketmine/plugin/PluginManager.php
-
message: "#^Cannot call method handleException\\(\\) on pocketmine\\\\scheduler\\\\AsyncWorker\\|null\\.$#"
count: 1

View File

@ -1,15 +1,5 @@
parameters:
ignoreErrors:
-
message: "#^Comparison operation \"\\>\\=\" between 0 and 2 is always false\\.$#"
count: 1
path: ../../../src/pocketmine/block/Liquid.php
-
message: "#^If condition is always false\\.$#"
count: 1
path: ../../../src/pocketmine/block/Liquid.php
-
message: "#^Call to function is_resource\\(\\) with resource will always evaluate to true\\.$#"
count: 3

View File

@ -115,4 +115,19 @@ class RegionLoaderTest extends TestCase{
$this->expectException(\InvalidArgumentException::class);
$this->region->readChunk($x, $z);
}
/**
* Test that cached filesize() values don't break validation of region headers
*/
public function testRegionHeaderCachedFilesizeRegression() : void{
$this->region->close();
$region = new RegionLoader($this->regionPath, 0, 0); //now we have a region, so the header will be verified, triggering two filesize() calls
$region->open();
$data = str_repeat("hello", 2000);
$region->writeChunk(0, 0, $data); //add some data to the end of the file, to make the cached filesize invalid
$region->close();
$region = new RegionLoader($this->regionPath, 0, 0);
$region->open();
self::assertSame($data, $region->readChunk(0, 0));
}
}

View File

@ -0,0 +1,37 @@
<?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 PHPUnit\Framework\TestCase;
final class ProtocolInfoTest extends TestCase{
public function testMinecraftVersionNetwork() : void{
self::assertMatchesRegularExpression(
'/^(?:\d+\.)?(?:\d+\.)?(?:\d+\.)?\d+$/',
ProtocolInfo::MINECRAFT_VERSION_NETWORK,
"Network version should only contain 0-9 and \".\", and no more than 4 groups of digits"
);
}
}

View File

@ -1,18 +0,0 @@
language: php
php:
- 7.3
- 7.4
before_script:
- phpenv config-rm xdebug.ini
- echo | pecl install channel://pecl.php.net/yaml-2.1.0
- git clone https://github.com/pmmp/pthreads.git
- cd pthreads
- git checkout b81ab29df58fa0fb239a9d5ca1c2380a0d087feb
- phpize
- ./configure
- make
- make install
- cd ..
- echo "extension=pthreads.so" >> ~/.phpenv/versions/$(phpenv version-name)/etc/php.ini
- composer self-update --2