Compare commits

..

406 Commits

Author SHA1 Message Date
6d62b06ce6 Release 4.0.0-BETA14 2021-11-30 01:26:07 +00:00
8be92d16fe Merge branch 'stable' 2021-11-30 01:19:54 +00:00
8079ae341a Updated build/php submodule to pmmp/php-build-scripts@bd329dba08 2021-11-30 01:19:14 +00:00
ba295dc7dc Always use LF in .neon files 2021-11-30 01:16:28 +00:00
38325c8573 Updated translations 2021-11-30 01:14:21 +00:00
f239b077b9 Fixed PHPStan complaints 2021-11-30 00:36:38 +00:00
6f8f460a6c Partially revert "ConsoleReaderChildProcess: Commit suicide in more cases"
This reverts commit cbe0f44c4f.

This achieves the same result as the reverted commit wrt. process in the
same manner (writing a keepalive into the socket and checking if it
failed to send). However, it does _not_ allow the process to die on
reaching pipe EOF, since this can cause many spams of subprocesses when
stdin is actually not a tty (e.g. in a Docker container).
2021-11-30 00:27:52 +00:00
882df94bcb ConsoleReaderThread: fixed zombie process leak 2021-11-29 23:45:10 +00:00
4a8ca603a1 Log a message when forceShutdown() is called for anything other than a graceful shutdown 2021-11-28 18:53:34 +00:00
52f0c4f3ed Removed dodgy test using invalid block metadata 2021-11-27 22:51:14 +00:00
e2815eed60 BlockFactory: remap a bunch more invalid states 2021-11-27 20:07:58 +00:00
932a88764c composer commands suck 2021-11-27 04:07:25 +00:00
9540193766 Fixed everything lighting on fire 2021-11-27 03:54:30 +00:00
cc23e0b7a1 Updated DevTools submodule to pmmp/DevTools@6af57741e6 2021-11-27 03:52:32 +00:00
1f9400f901 World: automatically remap invalid blockstates on chunk load
this fixes a wide range of blocks with invalid blockstates becoming update! blocks on the client.

The most common occurrence of this was air with nonzero metadata left behind by world editors which set blockIDs but not block metadata. This caused large ghost structures of update! blocks to appear from nowhere.

The performance impact of this is very minimal (20 microseconds per chunk load in timings, compared to average 660 microseconds to load tiles).
2021-11-27 01:12:30 +00:00
e5149756a8 WorldTimings: fixed merge error introduced by 3bf87378ef 2021-11-27 00:06:09 +00:00
bc18969a09 Merge branch 'stable' 2021-11-26 23:45:09 +00:00
c19174a174 3.25.7 is next 2021-11-26 23:37:47 +00:00
f95142f6b6 Release 3.25.6 2021-11-26 23:37:46 +00:00
7ace24caab Fixed borked build number
this was a problem before the recent clean-up; the only reason it just decided to show now is because 2000+25 is valid PHP code, so PHP saved our asses.
2021-11-26 23:36:19 +00:00
32f619ac49 3.25.6 is next 2021-11-26 23:20:48 +00:00
1bb6ac4fb6 Release 3.25.5 2021-11-26 23:20:40 +00:00
533d3aae8b Merge branch 'stable' 2021-11-26 22:41:18 +00:00
52a891ba73 shut 2021-11-26 22:32:25 +00:00
71b813d4f9 Define pocketmine\BUILD_NUMBER from phar metadata
this way we don't have to patch the code (no idea why we were doing that anyway).
2021-11-26 22:27:58 +00:00
f2540a72ad Backport improved make-release.php from PM4 2021-11-26 22:10:46 +00:00
03f13495b7 Merge branch 'stable' 2021-11-26 21:59:55 +00:00
7e0f6c02a1 Updated build/php submodule to pmmp/php-build-scripts@a59722c676 2021-11-26 21:59:39 +00:00
1bc7869f6e Added remapping for almost 4000 invalid blockstates
when a block has sole ownership of an ID, the state bitmask can be ignored and we can just claim the whole metadata range for that single block.
This fixes a large number of issues with unknown blocks on older worlds where world editors did not remove the metadata, although update blocks will currently still appear on initial chunk send due to lack of AOT conversion (TODO).
2021-11-26 01:58:52 +00:00
5556861000 ItemFactory: move SweetBerries registration to the correct place 2021-11-26 00:46:35 +00:00
7dd5d0b593 4.0.0-BETA14 is next 2021-11-25 00:40:43 +00:00
9338d42742 Release 4.0.0-BETA13 2021-11-25 00:40:40 +00:00
9346ecdc39 Merge branch 'stable' 2021-11-25 00:01:48 +00:00
c023c02b6c MemoryManager: Removed obsolete workaround for $GLOBALS not being defined on threads
this was long since fixed, and everyone has since been forced to upgrade to pthreads 4.0.0, which definitely has the fix.
2021-11-24 23:57:55 +00:00
bb7683158f Remove dead ignoreErrors patterns 2021-11-24 23:52:51 +00:00
fad96b77ce stfu 2021-11-24 23:49:56 +00:00
40575a6dcf Merge branch 'master' of github.com:pmmp/PocketMine-MP 2021-11-24 23:43:03 +00:00
40f8f042da Merge branch 'stable' 2021-11-24 23:42:53 +00:00
0fe6038c41 Merge branch 'stable' 2021-11-24 23:41:40 +00:00
adff561483 phpstan: go nuclear on OPcache
when using dynamic reflection (which is the default), any time static reflection comes into play, bad shit starts to happen because of FileReadTrapStreamWrapper.
I attempted to fix these issues (phpstan/phpstan-src#801) and failed miserably.
So, to save the hassle, it's time to just remove OPcache from the picture (which, unfortunately, also means that PHPStan will not benefit from JIT).
2021-11-24 23:40:54 +00:00
ad56392d95 Skull: fixed calculation of collision boxes (#4591) 2021-11-24 21:42:51 +00:00
472ffb28ff ScriptPluginLoader: use parseDocComment() instead of reinventing the wheel 2021-11-24 17:22:49 +00:00
726c5652f7 ScriptPluginLoader: fixed reading @tags from non-docblock lines preceding the first docblock 2021-11-24 17:07:34 +00:00
b784a04e08 Utils: fixed parseDocComment() ignoring tags containing hyphens 2021-11-24 16:38:37 +00:00
5c7125f190 Improved error handling for loading broken entity / tile data 2021-11-23 17:41:26 +00:00
eb0cf52d81 Remove useless code (#4590) 2021-11-23 17:09:33 +00:00
d8f0fd0a7e McRegion: skip chunks with TerrainGenerated=false
legacy PM used to save even ungenerated chunks, and omitted some tags when doing so which we expect to always be present.
2021-11-23 01:49:48 +00:00
fb0eebc0dc RegionWorldProvider: Show a more specific message on missing required ByteArrayTags 2021-11-23 01:39:35 +00:00
020cd7b966 CrashDump: fixed encodedData being uninitialized before getEncodedData() is called 2021-11-22 22:31:07 +00:00
c37c261c0f Separate crashdump file generation from crashdump data collection
this allows CrashDump to be used just to generate data, which will come in useful for non-crash error reporting in the future (e.g. packet decoding errors).
2021-11-22 22:19:40 +00:00
2bb97d8904 Be quiet CS 2021-11-22 15:40:47 +00:00
d3878b2d57 fixed spam 2021-11-22 15:37:33 +00:00
cbe0f44c4f ConsoleReaderChildProcess: Commit suicide in more cases
this makes it slightly less annoying to get rid of as an orphan process, though it still won't immediately die.
2021-11-22 14:58:45 +00:00
37622e02b8 Updated translations 2021-11-21 21:11:39 +00:00
ed8b4950a3 Updated BedrockProtocol 2021-11-21 21:10:58 +00:00
fc7d297f60 Added missing fields of StructureSettings 2021-11-21 20:51:35 +00:00
7b4ef293bd NetworkBinaryStream: fixed incorrect field types for StructureSettings 2021-11-21 20:49:00 +00:00
c72d66f370 Merge branch 'stable' 2021-11-20 18:28:55 +00:00
3683884b9c Updated build/php submodule to pmmp/php-build-scripts@7a2ab5b922 2021-11-20 18:27:43 +00:00
37e8b1ee8c Merge branch 'master' of github.com:pmmp/PocketMine-MP 2021-11-20 18:25:45 +00:00
046dafc34f Merge branch 'stable' 2021-11-20 18:25:30 +00:00
db135788b9 Updated transient dependencies 2021-11-20 18:19:27 +00:00
b34e6f53eb Changed visibility of Projectile->move to Protected. (#4585) 2021-11-19 23:21:10 +00:00
b4b954cc5f build/generate-registry-annotations: accommodate code with CRLF 2021-11-19 21:38:43 +00:00
7210db25b0 Bump phpstan/phpstan from 1.1.2 to 1.2.0 (#4583)
Bumps [phpstan/phpstan](https://github.com/phpstan/phpstan) from 1.1.2 to 1.2.0.
- [Release notes](https://github.com/phpstan/phpstan/releases)
- [Changelog](https://github.com/phpstan/phpstan/blob/master/CHANGELOG.md)
- [Commits](https://github.com/phpstan/phpstan/compare/1.1.2...1.2.0)

---
updated-dependencies:
- dependency-name: phpstan/phpstan
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

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

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2021-11-19 14:42:01 +00:00
4599913034 Separate crashdump rendering from crashdump data collection
this allows this code to be reused for reproducing crashdumps based on the original data.
2021-11-18 00:58:20 +00:00
c48aa274e7 Merge branch 'master' of github.com:pmmp/PocketMine-MP 2021-11-15 22:52:47 +00:00
269231c228 Ban foreach(arrayWithStringKeys as k => v)
this is not as good as phpstan/phpstan-src#769 (e.g. array_key_first()/array_key_last() aren't covered by this, nor is array_rand()) but it does eliminate the most infuriating cases where this usually crops up.
2021-11-15 22:52:05 +00:00
4cad552909 Allow input of relative coordinates to setworldspawn command (#4575) 2021-11-14 20:07:37 +00:00
f2d5455c5e changelog: mention that armor right-click equipping is now supported
[ci skip]
closes #4570
2021-11-14 16:42:35 +00:00
65247b7248 changelog: add notes about ender inventory
closes #4569
2021-11-14 16:41:57 +00:00
2f408708f0 Explosion: fixed blocks with tiles not using said tiles for drop info
closes #4571
2021-11-14 16:27:47 +00:00
3dd03075cb StringToItemParser: added some quality-of-life aliases 2021-11-14 15:52:50 +00:00
82b5bca83e Merge branch 'master' of github.com:pmmp/PocketMine-MP 2021-11-14 15:52:05 +00:00
639867a640 Added missing aliases for wooden items 2021-11-14 15:51:41 +00:00
d4a382d568 Fix position of setworldspawn command (#4574)
* The world spawn position is no longer rounded

* Remove round() since the position is always int
2021-11-14 15:40:20 +00:00
399824c31c Add correct drop for Podzol (#4573) 2021-11-14 14:15:36 +00:00
ada469bc45 README: do not show beta releases on badge
[ci skip]
2021-11-12 01:35:39 +00:00
dc8243f88b Bump phpstan/phpstan from 1.1.1 to 1.1.2 (#4564)
Bumps [phpstan/phpstan](https://github.com/phpstan/phpstan) from 1.1.1 to 1.1.2.
- [Release notes](https://github.com/phpstan/phpstan/releases)
- [Commits](https://github.com/phpstan/phpstan/compare/1.1.1...1.1.2)

---
updated-dependencies:
- dependency-name: phpstan/phpstan
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

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

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2021-11-12 00:24:23 +00:00
7668171c56 Merge branch 'master' of github.com:pmmp/PocketMine-MP 2021-11-12 00:17:07 +00:00
e4754ab029 PluginBase: Improved error messages for commands containing illegal characters 2021-11-12 00:16:53 +00:00
3276047497 Updated composer dependencies 2021-11-12 00:13:22 +00:00
49a8eff11e BUILDING: submodules are no longer required
submodules are useful (e.g. devtools, build/php) but they are not required to build a server phar.
2021-11-11 14:29:56 +00:00
73592349cd 4.0.0-BETA13 is next 2021-11-09 16:50:46 +00:00
635a9143de Release 4.0.0-BETA12 2021-11-09 16:50:42 +00:00
c3ec9c0948 Effect default duration is once again NOT hardcoded, like PM3
I have no fucking idea why I hardcoded this to begin with. Not one of my better ideas ...
2021-11-09 01:52:47 +00:00
09a2e006a8 CS AGAIN 2021-11-09 00:20:06 +00:00
fed59d3ebe added missing file 2021-11-09 00:11:39 +00:00
c7beb0a702 Clean up inventory auto close mess from PM3
on PM3 there was no concept of 'current window', we had no idea which window the player was actually looking at.
2021-11-08 23:51:25 +00:00
5be429a8c4 Ensure inventories get evacuated on server-side window close 2021-11-08 23:48:05 +00:00
ab002ca06d Improved handling of temporary inventory windows
evacuation behaviour is now consistent regardless of who is doing it
2021-11-08 23:36:58 +00:00
6efb1db107 Fixed inventories not working after dying with inventory open
closes #4185
closes #4177
2021-11-08 23:04:00 +00:00
6fdcfb01c8 Seal up main inventory open/close logic inside InventoryManager where it belongs 2021-11-08 22:58:06 +00:00
1beec348f9 3.25.5 is next 2021-11-08 22:33:09 +00:00
7306a2d939 Release 3.25.4 2021-11-08 22:33:08 +00:00
4bf338f783 Player: fixed removeWindow() causing all other inventories to be unopenable 2021-11-08 22:29:14 +00:00
255ff63fda 3.25.4 is next 2021-11-08 20:35:15 +00:00
d72f6a3ac6 Release 3.25.3 2021-11-08 20:35:14 +00:00
93a1e84ad9 TypeConverter: further simplification 2021-11-08 20:27:53 +00:00
c33f97ae41 TypeConverter: clean up absurdly overcomplicated bullshit in createInventoryAction() 2021-11-08 20:18:19 +00:00
cc4bb91fcb Implemented IPv6 support (#4554) 2021-11-08 20:03:28 +00:00
eb9012401b Merge branch 'stable' 2021-11-08 19:53:56 +00:00
3b34268ed6 Human: try to trap this stupid float cast bug in the wild 2021-11-08 19:48:39 +00:00
4c07078586 Merge branch 'stable' 2021-11-08 19:01:08 +00:00
19a3efe893 ....... 2021-11-08 18:57:14 +00:00
a1ecdc27e5 Removed Vanilla*::fromString()
these were misbegotten and should never have existed.
If someone really needs these for some reason, they can use getAll()[name].
2021-11-08 18:52:14 +00:00
f93b5be789 Added new dynamic StringToEffectParser 2021-11-08 18:49:28 +00:00
1fb60b5b3a CS fix again 2021-11-08 18:45:05 +00:00
08420c2556 Added new dynamic StringToEnchantmentParser
this should be used instead of VanillaEnchantments::fromString(), because it allows registering custom aliases.
2021-11-08 18:44:15 +00:00
18f5fb66bb Abstract the base functionality of StringToItemParser 2021-11-08 18:37:05 +00:00
a6f6b60bed fix CS again 2021-11-08 18:02:24 +00:00
c6c992a1f0 Preparations for negative Y support 2021-11-08 17:28:22 +00:00
df39a1ca07 TeleportCommand: do not hardcode world bounds 2021-11-08 17:22:01 +00:00
be6d1843de Merge branch 'master' of github.com:pmmp/PocketMine-MP 2021-11-08 17:17:20 +00:00
2b0b9bd8ed Update composer dependencies 2021-11-08 17:16:57 +00:00
76dad46e13 Bump phpstan/phpstan from 1.0.2 to 1.1.1 (#4560)
Bumps [phpstan/phpstan](https://github.com/phpstan/phpstan) from 1.0.2 to 1.1.1.
- [Release notes](https://github.com/phpstan/phpstan/releases)
- [Commits](https://github.com/phpstan/phpstan/compare/1.0.2...1.1.1)

---
updated-dependencies:
- dependency-name: phpstan/phpstan
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

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

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2021-11-08 13:36:06 +00:00
eb3530b6e6 Use pmmp/setup-php-action to compile PHP 2021-11-07 23:13:56 +00:00
4131bcef08 Changed "Level" string to "World" in Position::__toString() method. (#4559) 2021-11-07 21:11:55 +00:00
b84f7c18ec Install ext/crypto from PECL 2021-11-07 19:18:09 +00:00
45edb94607 Crafting tables now work the same way as anvils and enchanting tables
Removing almost all special-case logic for crafting tables.
2021-11-07 16:20:07 +00:00
6b316dc29a PluginManager: Make declaration of duplicate permissions a load error 2021-11-06 17:05:37 +00:00
d9d37f7fa6 ResourcePacksPacketHandler: fixed a mistake from c773e43eda
fixes #4557

Note: you may need to clear your local pack cache in order to get it working again.
2021-11-06 16:45:14 +00:00
4cb6c7dc1e PluginManager: fixed plugins being able to alter groups of other plugins' permissions
this could happen if a plugin declared a permission already declared by another plugin, and then declared a different default for it (e.g. true instead of op).
2021-11-06 16:32:19 +00:00
b392651354 pocketmine.yml: always refer to worlds as worlds in config comments, not levels 2021-11-06 02:22:14 +00:00
f81c55ce6c 4.0.0-BETA12 is next 2021-11-06 01:17:03 +00:00
002feacf8e Release 4.0.0-BETA11 2021-11-06 01:16:58 +00:00
b8523f7a18 Player: fix the fix which just degraded performance
if a chunk was requested for generation, count++ and count(activeRequests)++, which means that we would only get to submit half as many generation requests as we're allowed to.
Calculate the limit at the start and remember it instead.
2021-11-06 01:00:35 +00:00
640e88009b Player: fixed a mistake in generation rate limit
we don't want to allow sending further chunks when we haven't generated near ones, because we won't be able to see them anyway, and we might end up not needing them.
This now fully matches the results of PM3.
2021-11-06 00:57:37 +00:00
6cd272c9e1 Update transient composer dependencies 2021-11-06 00:55:13 +00:00
566c57bcd3 we no longer need submodules for these jobs 2021-11-06 00:35:39 +00:00
3c754b079c Move resources/locale to Composer dependency
all remaining submodules are now non-essential to running a server.
They are also versioned and updates can be done automatically using 'composer update'.

Finally, we can also put an end to the issue of translations being rendered incorrectly or being missing due to outdated submodules.
2021-11-06 00:32:58 +00:00
dbf9a33160 ChunkSelector: Improve algorithm to send chunks in proper circles, instead of squares
this ensures that the edge of loaded terain is always the same distance
away in any direction. This also means that when flying parallel to X or
Z axes, you now have about 12% more chunks directly in front of you,
instead of to your left and right, which gives the impression that
chunks are loading faster (they aren't, they are just being ordered in a
more sensible way).
2021-11-06 00:15:04 +00:00
07b1cff306 Bonemeal is no longer consumed when cancelling plant growth events (#4551) 2021-11-05 16:15:55 +00:00
0989c77037 Player: check that horizontal distance travelled is > 0 before adding exhaustion, or triggering a new chunk order
closes #4548
2021-11-05 15:46:55 +00:00
5107d0df4e Player: cap maximum number of active generation requests
this fixes the horrible spotty chunk loading seen in https://twitter.com/dktapps/status/1456397007946461190?s=20.
In practice, this made chunks invisible on teleport for several tens of seconds after teleporting. Having a larger chunks-per-tick with large render distance compounded to worsen the problem.
It wasn't really noticeable on small render distances, but very obvious on large ones with fast chunk sending and slow generation.

This also fixes #4187 (at least to the extent that it works on PM3, anyway).
2021-11-05 15:09:42 +00:00
579ef63663 EntityDataHelper: accept FloatTag for vector3 as well as Double
MCPE uses Float for entity positions.
2021-11-04 20:46:34 +00:00
8abc952c74 simulate-chunk-selector: do not reallocate colours on every frame 2021-11-04 19:38:40 +00:00
4c3a5fdd73 Clean PHPStan baselines from 1.0.2 2021-11-04 19:28:52 +00:00
54f287feb6 Merge branch 'stable' 2021-11-04 19:27:41 +00:00
84f8b3eb2d Move CrashDump to pocketmine\crash namespace 2021-11-04 19:23:45 +00:00
15fca84f3b remove some PHPStan error patterns 2021-11-04 19:22:49 +00:00
c60144210f Regenerate PHPStan bugs baseline 2021-11-04 19:18:29 +00:00
8ac999cbd4 Use object models for crashdump generation 2021-11-04 16:55:04 +00:00
4f8501ff34 Added a tool to visualise behaviour of ChunkSelector
I actually intended to write a tool for debugging generation, but it turns out this, as an intermediary step, is also useful and a whole bunch of fun to play with.
2021-11-04 14:14:55 +00:00
2405e45b35 Player: mark as not using item when held item slot is changed
closes #4538
2021-11-03 21:26:20 +00:00
e0b07ff308 Human: do not add more XP if totalXp limit was already reached
this matches the vanilla behaviour. For some reason it doesn't consider levels (so you can have a level higher or lower than this without actually having that amount of XP), but this matches Java behaviour as of 1.10.

fixes #4543
2021-11-03 20:45:55 +00:00
729f831b8f PHPStan 1.0.2 2021-11-03 20:26:32 +00:00
0356716e8e PopulationTask: do not expose internal fields as public
this code dates back to pthreads v2, when visibility on Threaded object fields meant different things (wtf, krakjoe??)
2021-11-03 15:23:43 +00:00
5c81b04813 PopulationTask: use typed properties 2021-11-03 15:22:49 +00:00
1ebb206762 World: fixed yet another edge case in drainPopulationRequestQueue() leading to assertion failure
really had to go fucking nuclear on it :(
2021-11-03 14:58:58 +00:00
29e2d92098 Bump phpstan/phpstan from 1.0.0 to 1.0.1 (#4541)
Bumps [phpstan/phpstan](https://github.com/phpstan/phpstan) from 1.0.0 to 1.0.1.
- [Release notes](https://github.com/phpstan/phpstan/releases)
- [Commits](https://github.com/phpstan/phpstan/compare/1.0.0...1.0.1)

---
updated-dependencies:
- dependency-name: phpstan/phpstan
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

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

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2021-11-03 11:27:42 +00:00
ef82a2cd79 Fixed PlayerEmoteEvent::setEmoteId() being useless 2021-11-02 23:10:26 +00:00
87031627bf Do not call PlayerEmoteEvent if rate limit was reached 2021-11-02 23:09:43 +00:00
f066199971 Implement emote support (#4523) 2021-11-02 23:04:55 +00:00
a0e9eec652 4.0.0-BETA11 is next 2021-11-02 19:18:20 +00:00
fa6a432d58 Release 4.0.0-BETA10 2021-11-02 19:18:19 +00:00
102277c636 draft-release: fixed BedrockData JSON minification 2021-11-02 19:16:36 +00:00
f50f26d52e 4.0.0-BETA10 is next 2021-11-02 19:14:15 +00:00
4ca7c29cde Release 4.0.0-BETA9 2021-11-02 19:14:12 +00:00
9f64bc8180 Merge branch 'stable' 2021-11-02 17:30:36 +00:00
f75a05d7fa 3.25.3 is next 2021-11-02 17:21:49 +00:00
3dae873731 Release 3.25.2 2021-11-02 17:21:44 +00:00
aa0dc60c32 Merge branch 'master' of github.com:pmmp/PocketMine-MP 2021-11-02 17:10:19 +00:00
d184838ba0 Move Promise classes to their own namespace 2021-11-02 17:10:07 +00:00
ead8ccf08d CocoaBlock: call BlockGrowEvent when growing for any reason (#4536) 2021-11-02 17:05:07 +00:00
38f97bed52 World: fixed PopulationTask failed assumption that generator is always registered
if the worker selected previously had a generator registered, but has since been shutdown, the workerStartHook that cleans up generatorRegisteredWorkers won't yet have been called.
This results in the worker being started by the submission of PopulationTask, and the generator doesn't get preemptively registered.
2021-11-02 16:58:14 +00:00
275f145418 BedrockData is now a Composer dependency
this should put a stop to people nagging me about incorrect blocks (we have a check to make sure composer dependencies are up to date).
2021-11-02 16:45:45 +00:00
6b07f7a5ec pmmp/BedrockProtocol@5.0.0+bedrock-1.17.40 2021-11-02 16:22:56 +00:00
e131c2cefa Drop pocketmine/spl 2021-11-02 16:08:29 +00:00
e34364412b Replace InvalidStateException usages with InvalidArgument or LogicException 2021-11-02 16:05:54 +00:00
4eef458d29 Config: throw AssumptionFailedError if config type is invalid or DETECT during save()
this should never happen ... it was already checked in load()
2021-11-02 16:03:43 +00:00
8b3565b75d PopulationTask no longer depends on a World object
this means it's now possible to test generation offline without too much hassle.
World::generateChunkCallback() has been removed from public API.
2021-11-02 15:40:51 +00:00
facfd7c04a sanity check 2021-11-02 15:26:54 +00:00
65ef9f786a Use standard chunkHash() to index population chunks 2021-11-02 15:25:03 +00:00
4dc13ab3da ConsoleReaderThread: strip control characters
this fixes a bug I encountered when accidentally pressing ctrl+a+d (which inserts a chr(1) character), because it made the server unable to find the command - but still reported an error containing what looked like a valid command (character isn't printable).
2021-11-02 15:11:23 +00:00
ede4157814 Check to see if the player can start using the Releasable item. (#4532) 2021-11-02 14:36:16 +00:00
34ea199fb0 World: fixed additional edge case - population promise rejected before task completion
if this happened, the index would stay set in activeChunkPopulationTasks, eventually causing the generation queue to jam up completely and non-forced generation to come to a standstill.
2021-11-02 14:30:23 +00:00
1775699f05 World: make sure that chunks locked by PopulationTask always get unlocked, no matter what
fixes #4527
2021-11-02 14:20:42 +00:00
32a857b8b4 fix CS 2021-11-02 14:09:16 +00:00
7e4be29fc4 Gracefully force-shutdown on failure to start RakLib
this now won't generate a crashdump.
2021-11-02 13:51:01 +00:00
c17587d436 World: use new Vector3() instead of Block->getPosition()
When profiling this, I noticed that we spend a stupidly large amount of time creating useless Position objects in the case of update=true, because Vector3->sides() calls Position->getSide(), which calls Position::fromObject(parent::getSide()). This is stupid because the update logic doesn't require Positions anywhere (as evidenced by this change needing no other alterations.

A rough profile shows that this improves setBlock() performance by about 25% in the update=true case, which is a pretty big margin.
As an added bonus, it gets rid of some unrealized cyclic dependencies in World->changedBlocks.
2021-11-02 03:00:00 +00:00
0f6b7e48cb Updated BedrockProtocol:
it's weirdly satisfying that LevelChunkPacket::create() with the extra parameter turns out to be exactly the same length as the old way.
2021-11-02 01:37:56 +00:00
f2912fcdd8 Updated pocketmine/log and pocketmine/log-pthreads (BC breaks included)
AttachableLogger deals with Closures now instead of LoggerAttachment objects
ThreadedLoggerAttachment no longer implements LoggerAttachment
2021-11-01 22:22:22 +00:00
f6cb4f9597 Updated BedrockProtocol 2021-11-01 21:32:02 +00:00
54442f7e4b Merge branch 'stable' 2021-11-01 21:18:35 +00:00
5257755dc5 shut 2021-11-01 21:15:58 +00:00
8c16ecaa5b Merge branch 'stable' 2021-11-01 21:08:32 +00:00
3214da8642 pthreads 4.0.0 2021-11-01 21:01:59 +00:00
f827a555d5 Merge branch 'stable' 2021-11-01 18:13:24 +00:00
61145baded Merge commit 27ae959e8 2021-11-01 17:42:31 +00:00
4d54d6c552 Merge commit f8f39687e2 2021-11-01 17:41:47 +00:00
485bc2c565 Merge commit 94737934de 2021-11-01 17:41:10 +00:00
07b4f844a9 Merge commit debb469de1 2021-11-01 17:40:40 +00:00
19e5775f6b Merge commit 73dc0598e4 2021-11-01 17:40:06 +00:00
804fb3f603 Merge commit 141fbde660 2021-11-01 17:39:40 +00:00
6175b03433 Merge commit 69952ae2af 2021-11-01 17:36:34 +00:00
a78248a19c Merge commit '71f2a34616961d6328f06fd911b6d4450a61643e' 2021-11-01 17:33:02 +00:00
414ccb9f10 Merge commit 'd17cd658030e66009c0bb32941387c7444d3ffe0' 2021-11-01 17:31:05 +00:00
794142fe49 Merge l7/l8/l9 baselines into actual-problems
it doesn't serve any practical purpose to keep these separated, particularly since it's getting so difficult to figure out which errors are coming from which levels (since we always use 9, it doesn't really make any difference).
2021-11-01 17:27:31 +00:00
ff27c5f7db PHPStan 1.0.0 2021-11-01 17:24:20 +00:00
4d4362801f AvailableCommandsPacket: remove dead code 2021-11-01 17:01:26 +00:00
0babe0a1ab LevelDB: remove unused private method 2021-11-01 16:55:05 +00:00
d696ebcda3 Level: do not use static:: to access levelIdCounter
the field is private.
2021-11-01 16:52:27 +00:00
c3768b997a Updated to pmmp/BedrockProtocol@146498c279 2021-11-01 16:13:33 +00:00
f6480017ce Update PHPUnit dependency junk 2021-11-01 16:12:37 +00:00
9f5c16bc46 Projectile: use closure instead of do/while for reading id/data of block
not ideal, but whatever I guess... this at least provides scope isolation
2021-11-01 15:56:28 +00:00
8865bb73ba BanEntry: remove useless do/while 2021-11-01 15:52:55 +00:00
2dee1dbc28 Remove ridiculous code in ResourcePackManager 2021-11-01 15:41:21 +00:00
0f0b6f0efa Utils: eliminate usages of backtick operator 2021-11-01 15:25:56 +00:00
d5f13d8be2 Timezone: make PHPStan 1.0 happy 2021-11-01 15:24:16 +00:00
27ae959e89 Terminal: backport shell_exec() code from PM4 to make PHPStan 1.0 happy 2021-11-01 15:23:36 +00:00
f8f39687e2 Achievement: declare proper type for $list static property 2021-11-01 15:22:33 +00:00
94737934de PlayerDeathEvent: fixed LSP violation reported by PHPStan 1.0 2021-11-01 14:17:54 +00:00
debb469de1 Updated PHPUnit dependency junk 2021-11-01 13:54:04 +00:00
616eb0050d World: remove premature optimisation of setBlockAt() introduced by ece28e5d7b
closes #4531
it turns out that letting the light updates themselves handle this is faster than trying to get in the way.
2021-11-01 02:34:44 +00:00
9d30bc8b95 World: fixed assertion failure when requesting, cancelling, and then re-requesting chunks via requestChunkPopulation()
if the request/cancel/re-request happens all in the time before the queue gets drained, chunk hashes may appear multiple times in the queue. We don't want to process them twice if this happens (although it's mostly harmless anyway).
2021-11-01 02:17:11 +00:00
46b7d35cd3 Player: return from callback if used chunk status is not REQUESTED_GENERATION()
this can happen especially on large render distances when flying fast and changing direction - we decide we don't want the chunk, then, after changing direction and re-ordering chunks, we decide we do want it again, and end up registering a second callback. In this case, we need to ensure that only one of the callbacks gets executed (it doesn't matter which one).
2021-11-01 01:45:49 +00:00
c781efcf90 World: avoid calling the same logic twice in requestChunkPopulation()
orderChunkPopulation() checks the preconditions too. Have them both call an internal function that doesn't.
2021-11-01 00:36:57 +00:00
e4a54f5b6a World: deduplicate code in request/orderChunkPopulation 2021-11-01 00:33:18 +00:00
afb54f1ae4 World: flip orderChunkPopulation() condition around
this makes it more obvious that the code is similar to requestChunkPopulation() barring one distinct difference.
2021-11-01 00:25:30 +00:00
8f803df511 World: check population locks _after_ checking if the chunk is already populated, not before
this led to another case where a population request would be queued up for an already-populated chunk for no reason.
2021-10-31 23:54:27 +00:00
f4a3c40b5c World: use better variable names in orderChunkPopulation() 2021-10-31 23:48:00 +00:00
9dec82cdbc World: fixed requestChunkPopulation() queuing requests for chunks which are already populated
this led to chunk sending getting bogged down if there were more than population-queue-size chunks waiting to be generated.
2021-10-31 23:40:34 +00:00
74031d2fbe World: remove the fulfilled promise from the population request map
fixes crash when unregistering chunk loaders
2021-10-31 23:05:12 +00:00
bd60e41268 Revert "Revert "Player: do not re-request the same ungenerated chunks multiple times""
This reverts commit 3265d3f6b4.
2021-10-31 22:57:56 +00:00
96cfdc79b8 World: fixed original promise not getting fulfilled if the chunk became populated=true after a promise was already made (but not fulfilled) to populate it
this could happen if a plugin calls setPopulated(true) on a chunk after a request for its population landed in the queue, but before it actually got processed. In that case, the promise would never get fulfilled.
2021-10-31 22:54:37 +00:00
2fa0a914ff World::orderChunkPopulation() may return a pre-resolved promise
this does not indicate a failure; it indicates that the chunk has already been successfully populated.
In this case, we shouldn't be putting the task back on the queue.

This is skirting around the real bug, which is that requestChunkPopulation() doesn't check if the target chunk is already populated before it creates a new promise that it will be.
2021-10-31 22:51:37 +00:00
08636d079d Promise: expose isResolved() 2021-10-31 22:48:52 +00:00
3265d3f6b4 Revert "Player: do not re-request the same ungenerated chunks multiple times"
This reverts commit 866020dfdb.

For some fucking reason this broke resending chunks in some cases (and
sending chunks at all in others). I don't have time to debug this right
now, so it's going to have to remain broken, infuriatingly enough.
2021-10-31 21:25:21 +00:00
0f78a2b5ef Advisory chunk locking for chunk population (#4513)
this allows chunks locked for population to be modified. If the PopulationTask detects that the chunk was modified during the onCompletion(), the result of the population will be discarded and rescheduled, so that it includes user modifications.
2021-10-31 21:11:20 +00:00
f1a791ef75 Improved Promise API - separate resolver and consumer APIs
this makes creating a promise slightly more cumbersome, but I'm more concerned about people who might try to call 'new Promise' directly.
2021-10-31 19:49:57 +00:00
866020dfdb Player: do not re-request the same ungenerated chunks multiple times
this doesn't affect chunk resends, since they'll be kicked back to NEEDED, which is detected by orderChunks().
2021-10-31 18:52:37 +00:00
c580bb2434 InGamePacketHandler: mark player as not using item in more cases
fixes #4355
2021-10-31 14:41:31 +00:00
4fe3f69702 World: eliminate final remaining 'no loaders attached' debug message on player creation 2021-10-31 14:33:27 +00:00
018006541e changelog: mention block-picking changes
[ci skip]
2021-10-31 14:12:12 +00:00
fbb91d123d World::unregisterChunkListenerFromAll(): go through unregisterChunkListener()
this ensures that everything gets cleaned up properly (e.g. player chunk listeners).
2021-10-31 14:03:40 +00:00
3dc75644d9 World: avoid duplicated logger code in initChunk() 2021-10-31 14:02:25 +00:00
1cabe4baf3 World: do not crash on duplicate tiles loaded from disk
closes #4049
2021-10-31 13:58:32 +00:00
73dc0598e4 CrashDump: remove derp space 2021-10-30 23:22:37 +01:00
faad2365e2 World: Register a temporary chunk loader on chunks used by PopulationTask
fixes #3839
2021-10-30 22:17:06 +01:00
4f816d03a7 SurvivalBlockBreakHandler: remove useless code 2021-10-30 21:35:58 +01:00
1d22761d27 Remove useless newline 2021-10-30 21:25:47 +01:00
5b8ce7e3e2 Cake: fixed desync on cancellation of eating
closes #3591
we don't support eating in creative right now, but the cake shouldn't appear to be eaten when it's not.
2021-10-30 21:02:24 +01:00
08f3c18de9 Arrow: do not add pickups to creative players' inventories
closes #2932
2021-10-30 17:16:46 +01:00
141fbde660 Player: fixed getting re-banned on rejoin after unban from hardcore death
closes #2175
2021-10-30 16:58:03 +01:00
465a509858 World: remove spammy debug message 2021-10-30 16:13:01 +01:00
69952ae2af Human: limit lifetime total XP range to INT32_MAX
closes #4484
2021-10-30 16:05:10 +01:00
71f2a34616 Entity: spawnTo() must silently swallow errors
Player->showPlayer() assumes that spawnTo() will take care of all the checks necessary to ensure we don't actually spawn a player to someone it shouldn't be able to see. In PM3, there's nothing we can do about that.
This could be a problem if anything decides to override spawnTo() to do additional stuff and assumes that the function will always succeed; however, there's not much reason to do that (plugins sending packets should override sendSpawnPacket() instead).
2021-10-30 15:38:27 +01:00
63dfcc60c3 4.0.0-BETA9 is next 2021-10-29 22:35:23 +01:00
428bd5ae91 Release 4.0.0-BETA8 2021-10-29 22:35:15 +01:00
d17cd65803 3.25.2 is next 2021-10-29 22:23:28 +01:00
a8d5e8c5f6 Release 3.25.1 2021-10-29 22:23:22 +01:00
19f448d074 pocketmine/math 0.4.0 2021-10-29 21:56:56 +01:00
1c18c731ef bootstrap: check for zlib raw support in leveldb 2021-10-29 19:15:12 +01:00
8a2ecfe1d4 Merge branch 'stable' 2021-10-29 19:04:01 +01:00
089e62b44e Entity::spawnTo(): verify that the target player belongs to the same world as the entity
this should never be hit in the PM case, but it's an InvalidArgument rather than AssumptionFailedError because plugins can and do call this with bad things.
2021-10-29 18:54:00 +01:00
32a34d2494 Location: change order of constructor parameters
to be consistent with Position::__construct() and Location::fromObject() (although Location::fromObject() has no choice, thanks to the anti-feature known as late static binding ...)
2021-10-29 15:43:09 +01:00
ee9f5e0044 Location: make __construct() parameters mandatory
I did consider allowing yaw/pitch to remain optional, but considering the implicit immutability of Location, it really doesn't make any sense to create a Location with default yaw/pitch - just create a Position in that case instead.
2021-10-29 15:40:58 +01:00
88b7389080 InventoryManager: reduce code duplication 2021-10-29 15:37:52 +01:00
f1cc168d26 phpstan: exclude a couple of files from analysis temporarily
close #4472
2021-10-29 00:23:13 +01:00
fb5543a2ad Updated BedrockProtocol dependency 2021-10-29 00:16:11 +01:00
a4eda9a8f5 World: call nearby entities' onNearbyBlockChange() in setChunk()
fixes #2779 in all known cases.
2021-10-28 23:59:32 +01:00
eb75df6f8e World: Intelligently perform automatic transfer or deletion of tiles in setChunk(), depending on the context
tiles may be deleted in the following circumstances:
1) the target block in the new chunk doesn't expect a tile
2) the target block in the new chunk expects a different type of tile (responsibility of the plugin developer to create the new tile)
3) there's already a tile in the target chunk which conflicts with the old one

In all other cases, the tile will be transferred.

This resolves a large number of unintentional bugs caused by world editors replacing chunks without setting the deleteTilesAndEntities parameter to false (even the core itself does it).

closes #4520
2021-10-28 23:48:17 +01:00
c66790b6a6 World: never delete entities in setChunk()
entities exist completely independently from chunks now, so there is no need to interact with them whatsoever.
As I wrote in #4520, there's no sense in deleting entities here, since a chunk replacement is essentially just a mass block update.

On that theme, it might be a good idea to call Entity->onNearbyBlockChange() for all entities in the target and adjacent chunks when replacing a chunk, to ensure that they get the proper movement updates.
2021-10-28 23:42:28 +01:00
d78801b9d5 World: fixed tiles and entities getting deleted when adjacent chunks are modified during population 2021-10-28 22:24:47 +01:00
d410db4302 Chunk: rename DIRTY_FLAG_TERRAIN to DIRTY_FLAG_BLOCKS
we use the word 'terrain' elsewhere to refer to the combination of blocks and biomes, so using TERRAIN here is misleading.
2021-10-28 22:11:07 +01:00
a62ce64fdd Revert "Chunk: added modification counter"
This reverts commit a5418a019d.

The more I assessed this, the more I realized that this implementation
doesn't actually offer any value. Since modcounters don't persist after
chunk unload + reload, they can't be reliably used to detect changes in
chunks without additional event subscriptions.
For the purpose I actually intended to use them for (population task
cancellation) there's a) another solution, and b) modcounts are
unreliable for that too, because of the aforementioned potential for
chunks to get unloaded and reloaded.
For the case of detecting dirty chunks within PopulationTask itself,
they are also unnecessary, since the dirty flags are sufficient within
there, since FastChunkSerializer doesn't copy dirty flags.

In conclusion, this was a misbegotten addition with little real value,
but does impact performance in hot paths.
2021-10-28 21:02:04 +01:00
5db3915aad Make MemoryManager aware of ChunkCache 2021-10-28 20:28:00 +01:00
eb40b741ae StandardPacketBroadcaster now splits broadcasts by session-specific PacketSerializerContext
in the normal case, all sessions will share the same PacketSerializerContext and Compressor, so this code will be the same as before
However, for the multi-protocol hackers out there, this should reduce the maintenance burden (@Driesboy) since now only the PacketSerializerContext needs to be maintained. I recommend a separate PacketSerializerContext for each protocol (perhaps put the protocol version in the serializer context too, if you need it for some reason).
2021-10-28 20:15:37 +01:00
b3720b3f17 4.0.0-BETA8 is next 2021-10-28 17:28:53 +01:00
7effa03ba4 Release 4.0.0-BETA7 2021-10-28 17:28:48 +01:00
d0474ccd92 make-release: note which channel the build will be released into 2021-10-28 16:29:20 +01:00
2b0768f720 make-release: fixed retention of +dev on release versions 2021-10-28 16:26:56 +01:00
dba148cfaa build/make-release: make arg parsing use getopt 2021-10-28 16:25:18 +01:00
48f77abe7e Leave channel ID in VersionInfo
so that I don't have to type it out every time I make a new release. Most of the time it's going to be posted to the same channel as before anyway.
2021-10-28 16:03:43 +01:00
bb05af103d PluginManager: fixed crash when using a plugin-loader plugin (read: devtools)
closes #4518
2021-10-28 15:55:05 +01:00
0ef5c67b9b Use static constructor for MovePlayerPacket
this marks the last of the packets created using the old way.
2021-10-27 21:10:16 +01:00
6d89265510 Player: reduce code duplication
back when this was just hardcoded >> 4 everywhere, nobody thought anything of it, but now it uses constants, it's easy to cross-reference and see where the duplicates are.
2021-10-26 23:02:50 +01:00
a7d8a598e1 World: reduce code duplication for chunk coordinate calculation 2021-10-26 22:58:17 +01:00
51fbff204b World: make PhpStorm understand return type of getAdjacentChunks() 2021-10-26 20:32:09 +01:00
1873457840 PopulationTask: stop using dynamic properties 2021-10-26 20:21:58 +01:00
fca70efbb1 World: move chunk population related methods to be in the same overall place 2021-10-26 16:44:08 +01:00
8f88393184 World: Specialize generateChunkCallback() for PopulationTask
this allows us to also set the adjacent chunks before calling ChunkPopulateEvent, to give a more accurate picture of what changed.
2021-10-26 15:28:00 +01:00
b9d9b69bbe ConsoleReaderThread: trim the string before returning it
it will have a newline at the end that was added by the subprocess when posting it to the main process.
2021-10-26 01:07:14 +01:00
1d99cd329a CS again 2021-10-26 00:50:43 +01:00
bd8cba1a7f Added unit tests for Utils::testValidInstance() 2021-10-26 00:49:41 +01:00
24d4daec90 Utils::testValidInstance() now accepts interfaces for the baseName 2021-10-26 00:32:32 +01:00
4178c81209 Utils: fixed testValidInstance() not accepting the same valid class for both className and baseName
this caused problems in PlayerCreationEvent because plugins set the base class and then set the player class to the same thing.
2021-10-26 00:31:30 +01:00
94f4ef5862 PopulationTask: Throw AssumptionFailedError if center chunk is null for some reason 2021-10-25 21:07:03 +01:00
2e2515354c PopulationTask: fixed undefined method call
fuck you PhpStorm! fuck you PhpStorm! fuck you PhpStorm!
2021-10-25 20:57:43 +01:00
359d0835f3 CS 2021-10-25 20:54:39 +01:00
d4cbde6f10 PopulationTask: use modification counters to detect changed chunks
instead of using terrain dirty flags, which aren't suitable for this purpose
2021-10-25 20:53:50 +01:00
a5418a019d Chunk: added modification counter
this is independent from the terrain dirty flags (which are specifically used to track state of chunks needing to be saved).
2021-10-25 20:53:11 +01:00
baba25953f Chunk: make all parameters of __construct() mandatory and non-nullable
having the constructor fill in defaults for these invariably causes bugs.
2021-10-25 20:22:50 +01:00
d53347454b Chunk: use HeightArray::fill() 2021-10-25 20:17:30 +01:00
401e8d117b Flat: use a less dumb way to build biome array 2021-10-25 20:15:33 +01:00
9835d75f65 Chunk: removed heighArray parameter from constructor
we don't pass this anywhere, and really it should be dynamically initialized anyway, just like light.
2021-10-25 20:13:50 +01:00
b8519d1af4 World: fixed every chunk having terrain saved at least once, even if unmodified
setPopulated() sets dirty flags on the chunk, causing the autosave sweep
to think they've been changed when they haven't. We now pass
terrainPopulated to the constructor to avoid this ambiguity recurring in
the future.
2021-10-25 19:53:47 +01:00
f6e53f826b Fixed Anvil/McRegion chunks getting autosaved on first time, even when unchanged
setGenerated/setPopulated and friends set hasChanged = true, which causes the world to autosave them the first time around, even though they weren't modified.
2021-10-25 19:52:44 +01:00
42ede30e77 ... 2021-10-23 23:57:28 +01:00
04aedc6494 Updated BedrockProtocol 2021-10-23 23:54:49 +01:00
701a71a4ee Sound::encode() position is no longer nullable
making this nullable was based on the invalid assumption that global sounds have no position, but it turns out they _do_ still use the position to make the sound come from the correct direction.
2021-10-23 02:01:26 +01:00
e50072dc27 Clean PHPStan baselines 2021-10-23 01:55:10 +01:00
c77829f4ad Migrate packet creation to use ::create() methods in all but one case
MovePlayerPacket doesn't yet have a ::create() due to a complication with fields that aren't always present.
2021-10-23 01:46:01 +01:00
c773e43eda Updated BedrockProtocol to pmmp/BedrockProtocol@97fa88e9ef 2021-10-23 01:16:45 +01:00
c262c2e726 Updated composer dependencies 2021-10-23 01:14:54 +01:00
a4b65d6a3f PlayerCreationEvent: verify that the class actually exists and is instantiable
this ensures that crashdumps blame the plugin instead of the core on bad classes, such as in this case: https://crash.pmmp.io/view/5331225
2021-10-21 20:37:45 +01:00
986b4e0651 Enforce single-line PhpDoc for properties where possible 2021-10-21 20:32:37 +01:00
2971bf30a5 actions: combine code verify into one step
this way the diff takes one less click to get to.
2021-10-21 00:30:19 +01:00
4f2bcb61d6 Fixed crashdump generation when crashing before PluginManager was created 2021-10-20 23:35:04 +01:00
e2275cc8ec PluginManager: Prevent infinite recursion in loadPlugins()
if a plugin calls loadPlugins(server->getPluginPath()) during its onLoad(), and it itself is in that plugin path, an infinite recursion will occur.
2021-10-20 23:10:18 +01:00
620874d902 PluginManager: Extract checkPluginLoadability() to a PluginLoadabilityChecker unit
this can be more easily unit-tested.
2021-10-20 22:31:56 +01:00
44508a138f Moved plugin extension requirement checks to PluginManager::checkPluginLoadability()
these don't really belong in PluginDescription.
2021-10-20 22:13:30 +01:00
aa408c9a97 Fixed 9646128d01 2021-10-20 21:54:57 +01:00
6d78a0b435 CS 2021-10-20 21:52:42 +01:00
76b4b23d98 PluginManager: remove loadPlugin()
loadPlugins() is now the preferred option, since it does all the proper checks.
In addition, the server now acknowledges that loading a single plugin may cause multiple plugins to be loaded, so returning only a single Plugin is not representative of what's actually happening.
2021-10-20 21:52:19 +01:00
03fcd844eb PluginManager::loadPlugins() now accepts files as well as directories
loadPlugins() is now a superior option to loadPlugin(), since it enforces dependency checks and also supports automatic loading of plugins when new loaders are installed.
2021-10-20 21:36:14 +01:00
fecc13f362 Merge branch 'master' of github.com:pmmp/PocketMine-MP 2021-10-20 21:23:14 +01:00
9646128d01 Updated resources/locale submodule to pmmp/Language@09c709f242 2021-10-20 21:22:56 +01:00
a788954551 Fixed dependency handling across plugin loaders (#3971) 2021-10-20 20:22:00 +01:00
dc07ac33d3 protocol: fixed missing field of CraftRecipeAuto 2021-10-20 19:47:32 +01:00
ec3986827c Update BedrockProtocol to 3.0.1, widen constraint to allow newer patch versions 2021-10-20 16:20:10 +01:00
09c840b66a Update transient composer dependencies 2021-10-20 16:19:20 +01:00
80b402e529 ItemTranslator: throw the proper exceptions when failing to map network IDs 2021-10-20 14:01:39 +01:00
a3f8546ac4 4.0.0-BETA7 is next 2021-10-19 19:13:43 +01:00
46920818b5 Release 4.0.0-BETA6 2021-10-19 19:13:43 +01:00
69cb575789 Merge branch 'stable' 2021-10-19 19:05:25 +01:00
fee6478cbe Updated BedrockData and BedrockProtocol for 1.17.40 support 2021-10-19 19:00:29 +01:00
9c5cec77b1 3.25.1 is next 2021-10-19 18:27:30 +01:00
f48b703533 Release 3.25.0 2021-10-19 18:27:26 +01:00
70636f6eb4 Protocol changes for 1.17.40 2021-10-19 18:00:34 +01:00
c70b80c273 ItemEntity: implement partial itemstack pickups in the dumbest way possible
Given the various limitations and flexibilities posed by EntityItemPickupEvent, I settled on this as the simplest way to deal with the problem.

- EntityItemPickupEvent may have its destination inventory changed, so we can't cache the result of getAddableItemQuantity() to use after the event.
- The item itself may have changed, so even if we thought we could add some items before the change, we might not be able to afterwards.

Considering the above facts, it's better to just give the whole itemstack to EntityItemPickupEvent, and let plugins use getAddableItemQuantity() on their own to decide if their chosen inventory can accommodate the item or not.
If it can't, then we'll just drop it on the ground.
This also fixes a potential issue where plugins changing the item to a custom one might end up with their items and the actual items both just vanishing if the target inventory was full.
closes #4499
2021-10-17 22:37:49 +01:00
a794d24c81 Added a tool to generate a Markdown document of all core permissions 2021-10-17 17:02:18 +01:00
8db5732b44 Drop respect/validation
it's not worth this turning into compatibility baggage just so that we can parse plugin_list.yml, especially when we have new ways to handle data parsing coming in the pipeline.
For something as small as plugin_list.yml, it's easier (and in this case better too) to just validate it manually (respect/validation was anyway too strict considering it's YAML we're dealing with).
2021-10-15 17:15:46 +01:00
48f809d3fa Removed another dead PHPStan error pattern
this was actually a PHPStan bug fixed in 0.12.99.
2021-10-15 17:01:09 +01:00
0348236860 fucking CS again 2021-10-14 15:56:50 +01:00
8c07748100 RakLibInterface: print packet exception info as a block using Utils::printableExceptionInfo() 2021-10-14 15:55:08 +01:00
06e7338ff9 Move exception printing utilities from MainLogger to Utils
where they can be useful to other stuff apart from just the logger
2021-10-14 15:54:20 +01:00
bdbfa70558 Server: break some isolated stuff out of Server::__construct() 2021-10-14 15:44:18 +01:00
7a4af7a0bc SignalHandler: fix CS
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
2021-10-14 15:14:27 +01:00
34b1392598 Cross-platform signal handler 2021-10-14 15:03:11 +01:00
321345fcc8 Sapling: simplify condition 2021-10-13 23:00:38 +01:00
0ac9f4fe61 BlockFactory: move SweetBerryBush to its proper place 2021-10-13 22:26:51 +01:00
2db53775e0 Sort item_from_string_bc_map using SORT_NATURAL 2021-10-13 21:01:59 +01:00
8523f0fb0b CS fix 2021-10-13 20:31:24 +01:00
b570324288 LegacyStringToItemParser: rely exclusively on item_from_string_bc_map.json, do not interpret integers given as strings
fixes #4507
2021-10-13 20:29:18 +01:00
6284cd14c7 LegacyStringToItemParser: added getMappings() 2021-10-13 20:19:44 +01:00
ce8af4e3bc 4.0.0-BETA6 is next 2021-10-13 00:02:01 +01:00
b65e89b605 Release 4.0.0-BETA5 2021-10-13 00:01:56 +01:00
d3f74d6ce1 Merge branch 'stable' 2021-10-12 23:32:43 +01:00
bbd925abc4 Merge commit '974d08efd62c52c1c8ac92cb1b67ac157908fd71' 2021-10-12 23:31:50 +01:00
4bf6205a6c Merge commit '289553fa46fc26b03db73db23481a98d6ddb12a5' 2021-10-12 23:28:35 +01:00
b5699679ef Merge commit 'e38866c4ba90f8efd5630dbe674fd7ca15f586ff' 2021-10-12 23:23:27 +01:00
824a89edfe Merge commit 'e032b8fe208a053441c9fbd377209740008cddb8' 2021-10-12 23:12:17 +01:00
ead9aae23c Updated build/php submodule to pmmp/php-build-scripts@fab0cbeaae 2021-10-12 23:10:06 +01:00
aefa0afd7c DefaultPermissions: Order registrations alphabetically 2021-10-12 22:17:46 +01:00
ec2699ffee DefaultPermissions: fix description of timings command permission 2021-10-12 22:16:20 +01:00
49c1e4c06e Implement fletching table (#4501) 2021-10-12 21:21:05 +01:00
9b94a4661b ItemTranslator: Use LegacyItemIdToStringMap instead of reading files directly 2021-10-11 22:17:40 +01:00
62f11360ee Added unit tests for getAddableItemQuantity() 2021-10-11 21:52:27 +01:00
a5833327f0 Inventory: added getAddableItemQuantity()
this mostly reuses the code from canAddItem().
2021-10-11 21:46:27 +01:00
d73ea8efe4 FlatGeneratorOptions: Do not hardcode biome ID 2021-10-11 21:32:20 +01:00
835e18ce6e Changelog: Changed utils\Color to color\Color (#4502)
[ci skip]
2021-10-11 20:15:44 +01:00
01c0602043 Server: do not attempt to generate a new world if it already exists 2021-10-11 17:48:08 +01:00
8fd475f87b WorldManager: Check generator options of worlds before loading them, too 2021-10-11 17:44:38 +01:00
34f54750c8 Added support for creation-time validation of generator options, closes #2717 2021-10-11 17:37:47 +01:00
092aabeb97 fix CS 2021-10-11 17:21:19 +01:00
89d7b7198f Server: drop support for tagging generator options onto the 'generator' key in pocketmine.yml
the 'preset' key should be used for this purpose instead.

This couldn't be dropped until now due to the shitty handling of unknown generators.
2021-10-11 17:20:49 +01:00
70deea0ef9 Flat: Move preset handling to a FlatGeneratorOptions unit 2021-10-11 16:53:08 +01:00
859cdfa5d2 GeneratorManager: removed unused parameter from getGenerator() 2021-10-11 16:18:38 +01:00
fa93a8d78f Server: Error on unknown generators when generating new worlds from config, instead of silently using DEFAULT
this is consistent with the behaviour of loading worlds.
2021-10-11 16:13:32 +01:00
7b6632941d GeneratorManager::getGenerator() now returns null for unknown generator aliases
instead of returning Normal::class (indistinguishable from successful match) or throwing an exception (pain in the ass to handle).
2021-10-11 16:04:36 +01:00
e62794e4cf TypeConverter: fixed PHPStan errors 2021-10-11 15:17:32 +01:00
500c298aaf Disallow the use of @handleCancelled on non-cancellable events
closes #3464
2021-10-11 15:12:16 +01:00
8ac16345a3 TypeConverter: account for items without properly mapped IDs
fixes #4459
2021-10-11 15:05:08 +01:00
19a66a8d03 committing the new strings would have helped ... 2021-10-11 01:14:00 +01:00
6d728e8d98 PluginManager: Improved startup performance when loading many plugins
for some reason we were reading and parsing the plugin.yml at least twice for every plugin loaded.
We were repeating work already done by the initial loadPlugins() triage (discovering correct loader, loading plugin.yml from disk, parsing plugin.yml, validating plugin.yml) every time loadPlugin() was called with that plugin.
2021-10-11 01:11:59 +01:00
e1ee320c8d PluginManager: Localize plugin loading error messages 2021-10-11 00:58:33 +01:00
965a16d19d PluginManager: Extract deterministic plugin loadability checks into a separate method 2021-10-11 00:49:32 +01:00
5bae458a91 changelog: mention that Entity->setPosition(AndRotation)() are now protected 2021-10-10 23:32:40 +01:00
2696698926 ClosureTask: relax closure checks to allow arrow functions without return typehints
nobody uses return typehints on arrow functions anyway .. they just waste space.
2021-10-10 23:31:57 +01:00
912e612743 Utils: allow validateCallableSignature() to accept a manually constructed CallbackType instead of a closure
this allows more fine-grained control without PHPStan yelling at us.
2021-10-10 23:27:09 +01:00
fd2df637b6 Block: rename getPositionOffset() -> getModelPositionOffset()
this gives a better idea of what the function does, and is also much less annoying for auto complete.
2021-10-10 22:35:38 +01:00
aa53dc6709 Entity: fixed network properties not updating when fireTicks changes
another bug that LBSG knew about, but didn't report. :/
2021-10-09 23:57:37 +01:00
c1f843a42c GarbageCollectorCommand: fixed duplicate MB suffix 2021-10-09 23:57:36 +01:00
09715906c8 StructureGrowEvent: added API to get the player who caused the growth (#4445) 2021-10-09 22:51:46 +01:00
13068ba3a7 3.24.1 is next 2021-10-09 20:20:41 +01:00
b54854529f Release 3.24.0 2021-10-09 20:20:37 +01:00
974d08efd6 Bump PHP minimum requirement to 8.0
PHPStan failed on 7.4 after updating to 0.12.99, and I figured it was less hassle to just do this than fix the build. In any case, we stopped shipping 7.4 months ago, and warned at 3.22 release that 7.4 support would soon be dropped.
2021-10-09 20:09:42 +01:00
289553fa46 CS again 2021-10-09 19:50:07 +01:00
e38866c4ba phpstan 0.12.99 2021-10-09 19:33:43 +01:00
58a95f8836 Updated transitive composer dependencies 2021-10-09 19:18:32 +01:00
ccc881ee58 Switch to custom permission denied message
closes #4494
2021-10-09 00:57:15 +01:00
308d7c126a Fixed world data ::generate() functions putting level.dat in the wrong place if the world path didn't end with a / 2021-10-08 23:39:25 +01:00
4910250a81 Config: fixed writeList() 2021-10-07 21:47:09 +01:00
e0d2e24698 fix CS (again\!) 2021-10-07 21:19:44 +01:00
d5f02a0bf8 Config: expose APIs to parse/emit list configs 2021-10-07 21:18:42 +01:00
2a3a57c519 Enable parsing/emitting .properties without creating a Config object
this is useful when the contents are just going to get passed straight into a model, making Config object redundant anyway.
2021-10-07 20:53:15 +01:00
5115387feb fix CS (again) 2021-10-07 20:43:55 +01:00
dd0aaf59b5 MainLogger: Log exceptions as a single block message 2021-10-07 20:40:20 +01:00
a555f21b18 MainLogger: write messages before calling logger attachments 2021-10-07 20:32:02 +01:00
1be9b2f037 Config: drop packing of arrays
we don't handle arrays on decode, so there's no reason to support them on encode either.
2021-10-07 20:30:56 +01:00
32fd9879e5 fix CS 2021-10-07 20:16:54 +01:00
dc2e8e7e8f ServerConfigGroup: do not assume that values are always bool|string 2021-10-07 20:02:21 +01:00
847e24fc41 4.0.0-BETA5 is next 2021-10-06 23:49:30 +01:00
e032b8fe20 Server: fixed stats reporting checking a nonexistent pocketmine.yml property
this was originally worked around by 47f7af6739. However, that commit was just duct tape, and I never bothered to investigate if the config was being checked somewhere else.
Here's to a years-old bug finally getting fixed.
2021-10-06 22:23:41 +01:00
295 changed files with 8078 additions and 4734 deletions

1
.gitattributes vendored
View File

@ -4,6 +4,7 @@
*.sh text eol=lf
*.txt text eol=lf
*.properties text eol=lf
*.neon text eol=lf
*.bat text eol=crlf
*.cmd text eol=crlf
*.ps1 text eol=crlf

View File

@ -35,17 +35,18 @@ jobs:
- name: Install Composer dependencies
run: composer install --no-dev --prefer-dist --no-interaction --ignore-platform-reqs
- name: Patch VersionInfo
- name: Calculate build number
id: build-number
run: |
BUILD_NUMBER=2000+$GITHUB_RUN_NUMBER #to stay above jenkins
BUILD_NUMBER=$((2000+$GITHUB_RUN_NUMBER)) #to stay above jenkins
echo "Build number: $BUILD_NUMBER"
sed -i "s/const BUILD_NUMBER = 0/const BUILD_NUMBER = ${BUILD_NUMBER}/" src/VersionInfo.php
echo ::set-output name=BUILD_NUMBER::$BUILD_NUMBER
- name: Minify BedrockData JSON files
run: php resources/vanilla/.minify_json.php
run: php vendor/pocketmine/bedrock-data/.minify_json.php
- name: Build PocketMine-MP.phar
run: php -dphar.readonly=0 build/server-phar.php --git ${{ github.sha }}
run: php -dphar.readonly=0 build/server-phar.php --git ${{ github.sha }} --build ${{ steps.build-number.outputs.BUILD_NUMBER }}
- name: Get PocketMine-MP release version
id: get-pm-version
@ -56,7 +57,7 @@ jobs:
echo ::set-output name=PM_VERSION_MD::$(php -r 'require "vendor/autoload.php"; echo str_replace(".", "", \pocketmine\VersionInfo::BASE_VERSION);')
- name: Generate build info
run: php build/generate-build-info-json.php ${{ github.sha }} ${{ steps.get-pm-version.outputs.PM_VERSION }} ${{ github.repository }} > build_info.json
run: php build/generate-build-info-json.php ${{ github.sha }} ${{ steps.get-pm-version.outputs.PM_VERSION }} ${{ github.repository }} ${{ steps.build-number.outputs.BUILD_NUMBER }} > build_info.json
- name: Upload release artifacts
uses: actions/upload-artifact@v2

View File

@ -16,17 +16,11 @@ jobs:
php: [8.0.11]
steps:
- uses: actions/checkout@v2 #needed for build.sh
- name: Check for PHP build cache
id: php-build-cache
uses: actions/cache@v2
- name: Build and prepare PHP cache
uses: pmmp/setup-php-action@e232f72a4330a07aae8418e8aa56b64efcdda636
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 }}"
php-version: ${{ matrix.php }}
install-path: "./bin"
phpstan:
name: PHPStan analysis
@ -42,23 +36,11 @@ jobs:
steps:
- uses: actions/checkout@v2
- name: Restore PHP build cache
id: php-build-cache
uses: actions/cache@v2
- name: Setup PHP
uses: pmmp/setup-php-action@e232f72a4330a07aae8418e8aa56b64efcdda636
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: ./tests/gh-actions/install-dependencies.sh
- name: Prefix PHP to PATH
run: echo "$(pwd)/bin/php7/bin" >> $GITHUB_PATH
php-version: ${{ matrix.php }}
install-path: "./bin"
- name: Install Composer
run: curl -sS https://getcomposer.org/installer | php
@ -91,26 +73,12 @@ jobs:
steps:
- uses: actions/checkout@v2
- name: Setup PHP
uses: pmmp/setup-php-action@e232f72a4330a07aae8418e8aa56b64efcdda636
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: ./tests/gh-actions/install-dependencies.sh
- name: Prefix PHP to PATH
run: echo "$(pwd)/bin/php7/bin" >> $GITHUB_PATH
php-version: ${{ matrix.php }}
install-path: "./bin"
- name: Install Composer
run: curl -sS https://getcomposer.org/installer | php
@ -146,23 +114,11 @@ jobs:
with:
submodules: true
- name: Restore PHP build cache
id: php-build-cache
uses: actions/cache@v2
- name: Setup PHP
uses: pmmp/setup-php-action@e232f72a4330a07aae8418e8aa56b64efcdda636
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: ./tests/gh-actions/install-dependencies.sh
- name: Prefix PHP to PATH
run: echo "$(pwd)/bin/php7/bin" >> $GITHUB_PATH
php-version: ${{ matrix.php }}
install-path: "./bin"
- name: Install Composer
run: curl -sS https://getcomposer.org/installer | php
@ -195,26 +151,12 @@ jobs:
steps:
- uses: actions/checkout@v2
- name: Setup PHP
uses: pmmp/setup-php-action@e232f72a4330a07aae8418e8aa56b64efcdda636
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: ./tests/gh-actions/install-dependencies.sh
- name: Prefix PHP to PATH
run: echo "$(pwd)/bin/php7/bin" >> $GITHUB_PATH
php-version: ${{ matrix.php }}
install-path: "./bin"
- name: Install Composer
run: curl -sS https://getcomposer.org/installer | php
@ -238,11 +180,10 @@ jobs:
- name: Regenerate KnownTranslation APIs
run: php build/generate-known-translation-apis.php
- name: Run git diff
run: git diff
- name: Fail job if changes were made
run: git diff --quiet
- name: Verify code is unchanged
run: |
git diff
git diff --quiet
codestyle:
name: Code Style checks
@ -254,10 +195,10 @@ jobs:
- uses: actions/checkout@v2
- name: Setup PHP and tools
uses: shivammathur/setup-php@2.9.0
uses: shivammathur/setup-php@2.15.0
with:
php-version: 8.0
tools: php-cs-fixer
tools: php-cs-fixer:3.2
- name: Run PHP-CS-Fixer
run: php-cs-fixer fix --dry-run --diff

View File

@ -22,8 +22,6 @@
declare(strict_types=1);
const VERSIONS = [
"7.3",
"7.4",
"8.0"
];

6
.gitmodules vendored
View File

@ -1,12 +1,6 @@
[submodule "resources/locale"]
path = resources/locale
url = https://github.com/pmmp/Language.git
[submodule "tests/plugins/DevTools"]
path = tests/plugins/DevTools
url = https://github.com/pmmp/DevTools.git
[submodule "build/php"]
path = build/php
url = https://github.com/pmmp/php-build-scripts.git
[submodule "resources/vanilla"]
path = resources/vanilla
url = https://github.com/pmmp/BedrockData.git

View File

@ -61,6 +61,11 @@ return (new PhpCsFixer\Config)
],
'sort_algorithm' => 'alpha'
],
'phpdoc_line_span' => [
'property' => 'single',
'method' => null,
'const' => null
],
'phpdoc_trim' => true,
'phpdoc_trim_consecutive_blank_line_separation' => true,
'single_import_per_statement' => true,

View File

@ -2,25 +2,24 @@
## Pre-requisites
- A bash shell (git bash is sufficient for Windows)
- [`git`](https://git-scm.com) available in your shell
- PHP 7.4 or newer available in your shell
- PHP 8.0 or newer available in your shell
- [`composer`](https://getcomposer.org) available in your shell
## 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.4-Aggregate)
- [Prebuilt binaries](https://jenkins.pmmp.io/job/PHP-8.0-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`.
## Setting up environment
1. `git clone --recursive https://github.com/pmmp/PocketMine-MP.git`
1. `git clone https://github.com/pmmp/PocketMine-MP.git`
2. `composer install`
## Checking out a different branch to build
1. `git checkout <branch to checkout>`
2. `git submodule update --init`
3. Re-run `composer install` to synchronize dependencies.
2. Re-run `composer install` to synchronize dependencies.
## Optimizing for release builds
1. Add the flags `--no-dev --classmap-authoritative` to your `composer install` command. This will reduce build size and improve autoloading speed.
@ -34,7 +33,7 @@ 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.
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 8.0.3.
## Running PocketMine-MP from source code
Run `src/PocketMine.php` using your preferred PHP binary.

View File

@ -5,7 +5,7 @@
<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>
<img alt="GitHub release (latest SemVer)" src="https://img.shields.io/github/v/release/pmmp/PocketMine-MP?label=release&sort=semver">
<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>

View File

@ -23,15 +23,15 @@ declare(strict_types=1);
require dirname(__DIR__) . '/vendor/autoload.php';
if(count($argv) !== 4){
fwrite(STDERR, "required args: <git hash> <tag name> <github repo (owner/name)>");
if(count($argv) !== 5){
fwrite(STDERR, "required args: <git hash> <tag name> <github repo (owner/name)> <build number>");
exit(1);
}
echo json_encode([
"php_version" => sprintf("%d.%d", PHP_MAJOR_VERSION, PHP_MINOR_VERSION),
"base_version" => \pocketmine\VersionInfo::BASE_VERSION,
"build" => \pocketmine\VersionInfo::BUILD_NUMBER,
"build" => (int) $argv[4],
"is_dev" => \pocketmine\VersionInfo::IS_DEVELOPMENT_BUILD,
"channel" => \pocketmine\VersionInfo::BUILD_CHANNEL,
"git_commit" => $argv[1],

View File

@ -24,6 +24,7 @@ declare(strict_types=1);
namespace pocketmine\build\generate_known_translation_apis;
use pocketmine\lang\Translatable;
use pocketmine\utils\Utils;
use Webmozart\PathUtil\Path;
use function array_map;
use function count;
@ -100,7 +101,7 @@ final class KnownTranslationKeys{
HEADER;
ksort($languageDefinitions, SORT_STRING);
foreach($languageDefinitions as $k => $_){
foreach(Utils::stringifyKeys($languageDefinitions) as $k => $_){
echo "\tpublic const ";
echo constantify($k);
echo " = \"" . $k . "\";\n";
@ -135,7 +136,7 @@ HEADER;
$parameterRegex = '/{%(.+?)}/';
$translationContainerClass = (new \ReflectionClass(Translatable::class))->getShortName();
foreach($languageDefinitions as $key => $value){
foreach(Utils::stringifyKeys($languageDefinitions) as $key => $value){
$parameters = [];
if(preg_match_all($parameterRegex, $value, $matches) > 0){
foreach($matches[1] as $parameterName){
@ -172,7 +173,7 @@ HEADER;
echo "Done generating KnownTranslationFactory.\n";
}
$lang = parse_ini_file(Path::join(\pocketmine\RESOURCE_PATH, "locale", "eng.ini"), false, INI_SCANNER_RAW);
$lang = parse_ini_file(Path::join(\pocketmine\LOCALE_DATA_PATH, "eng.ini"), false, INI_SCANNER_RAW);
if($lang === false){
fwrite(STDERR, "Missing language files!\n");
exit(1);

View File

@ -91,7 +91,7 @@ foreach(new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator($argv[1],
throw new \RuntimeException("Failed to get contents of $file");
}
if(preg_match("/^namespace (.+);$/m", $contents, $matches) !== 1 || preg_match('/^((final|abstract)\s+)?class /m', $contents) !== 1){
if(preg_match("/(*ANYCRLF)^namespace (.+);$/m", $contents, $matches) !== 1 || preg_match('/(*ANYCRLF)^((final|abstract)\s+)?class /m', $contents) !== 1){
continue;
}
$shortClassName = basename($file, ".php");
@ -101,7 +101,7 @@ foreach(new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator($argv[1],
}
$reflect = new \ReflectionClass($className);
$docComment = $reflect->getDocComment();
if($docComment === false || preg_match("/^\s*\*\s*@generate-registry-docblock$/m", $docComment) !== 1){
if($docComment === false || preg_match("/(*ANYCRLF)^\s*\*\s*@generate-registry-docblock$/m", $docComment) !== 1){
continue;
}
echo "Found registry in $file\n";

View File

@ -23,20 +23,29 @@ declare(strict_types=1);
namespace pocketmine\build\make_release;
use pocketmine\utils\Utils;
use pocketmine\utils\VersionString;
use pocketmine\VersionInfo;
use function count;
use function array_keys;
use function array_map;
use function dirname;
use function fgets;
use function file_get_contents;
use function file_put_contents;
use function fwrite;
use function getopt;
use function is_string;
use function max;
use function preg_replace;
use function sleep;
use function sprintf;
use function str_pad;
use function strlen;
use function system;
use const STDERR;
use const STDIN;
use const STDOUT;
use const STR_PAD_LEFT;
require_once dirname(__DIR__) . '/vendor/autoload.php';
@ -60,22 +69,38 @@ function replaceVersion(string $versionInfoPath, string $newVersion, bool $isDev
file_put_contents($versionInfoPath, $versionInfo);
}
/**
* @param string[] $argv
* @phpstan-param list<string> $argv
*/
function main(array $argv) : void{
if(count($argv) < 2){
fwrite(STDERR, "Arguments: <channel> [release version] [next version]\n");
exit(1);
const ACCEPTED_OPTS = [
"current" => "Version to insert and tag",
"next" => "Version to put in the file after tagging",
"channel" => "Release channel to post this build into"
];
function main() : void{
$filteredOpts = [];
foreach(Utils::stringifyKeys(getopt("", ["current:", "next:", "channel:", "help"])) as $optName => $optValue){
if($optName === "help"){
fwrite(STDOUT, "Options:\n");
$maxLength = max(array_map(fn(string $str) => strlen($str), array_keys(ACCEPTED_OPTS)));
foreach(ACCEPTED_OPTS as $acceptedName => $description){
fwrite(STDOUT, str_pad("--$acceptedName", $maxLength + 4, " ", STR_PAD_LEFT) . ": $description\n");
}
exit(0);
}
if(!is_string($optValue)){
fwrite(STDERR, "--$optName expects exactly 1 value\n");
exit(1);
}
$filteredOpts[$optName] = $optValue;
}
if(isset($argv[2])){
$currentVer = new VersionString($argv[2]);
if(isset($filteredOpts["current"])){
$currentVer = new VersionString($filteredOpts["current"]);
}else{
$currentVer = VersionInfo::VERSION();
$currentVer = new VersionString(VersionInfo::BASE_VERSION);
}
if(isset($argv[3])){
$nextVer = new VersionString($argv[3]);
if(isset($filteredOpts["next"])){
$nextVer = new VersionString($filteredOpts["next"]);
}else{
$nextVer = new VersionString(sprintf(
"%u.%u.%u",
@ -84,8 +109,10 @@ function main(array $argv) : void{
$currentVer->getPatch() + 1
));
}
$channel = $filteredOpts["channel"] ?? VersionInfo::BUILD_CHANNEL;
echo "About to tag version $currentVer. Next version will be $nextVer.\n";
echo "$currentVer will be published on release channel \"$channel\".\n";
echo "please add appropriate notes to the changelog and press enter...";
fgets(STDIN);
system('git add "' . dirname(__DIR__) . '/changelogs"');
@ -95,10 +122,10 @@ function main(array $argv) : void{
exit(1);
}
$versionInfoPath = dirname(__DIR__) . '/src/VersionInfo.php';
replaceVersion($versionInfoPath, $currentVer->getBaseVersion(), false, $argv[1]);
replaceVersion($versionInfoPath, $currentVer->getBaseVersion(), false, $channel);
system('git commit -m "Release ' . $currentVer->getBaseVersion() . '" --include "' . $versionInfoPath . '"');
system('git tag ' . $currentVer->getBaseVersion());
replaceVersion($versionInfoPath, $nextVer->getBaseVersion(), true, "");
replaceVersion($versionInfoPath, $nextVer->getBaseVersion(), true, $channel);
system('git add "' . $versionInfoPath . '"');
system('git commit -m "' . $nextVer->getBaseVersion() . ' is next" --include "' . $versionInfoPath . '"');
echo "pushing changes in 5 seconds\n";
@ -106,4 +133,4 @@ function main(array $argv) : void{
system('git push origin HEAD ' . $currentVer->getBaseVersion());
}
main($argv);
main();

View File

@ -134,13 +134,18 @@ function main() : void{
exit(1);
}
$opts = getopt("", ["out:", "git:"]);
$opts = getopt("", ["out:", "git:", "build:"]);
if(isset($opts["git"])){
$gitHash = $opts["git"];
}else{
$gitHash = Git::getRepositoryStatePretty(dirname(__DIR__));
echo "Git hash detected as $gitHash" . PHP_EOL;
}
if(isset($opts["build"])){
$build = (int) $opts["build"];
}else{
$build = 0;
}
foreach(buildPhar(
$opts["out"] ?? getcwd() . DIRECTORY_SEPARATOR . "PocketMine-MP.phar",
dirname(__DIR__) . DIRECTORY_SEPARATOR,
@ -150,7 +155,8 @@ function main() : void{
'vendor'
],
[
'git' => $gitHash
'git' => $gitHash,
'build' => $build
],
<<<'STUB'
<?php

12
changelogs/3.24.md Normal file
View File

@ -0,0 +1,12 @@
**For Minecraft: Bedrock Edition 1.17.30**
### 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.24.0
- PHP 8.0 is now required as a minimum.
- Fixed stats reporting checking the wrong `pocketmine.yml` property.
- Fixed `Projectile->move()` not respecting the given `dx`/`dy`/`dz` and using its own motion instead.

38
changelogs/3.25.md Normal file
View File

@ -0,0 +1,38 @@
**For Minecraft: Bedrock Edition 1.17.40**
### 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.25.0
- Added support for Minecraft: Bedrock Edition 1.17.40.
- Removed compatibility with earlier versions.
# 3.25.1
- Fixed autosave bug that caused unmodified chunks to be saved at least once (during the first autosave after they were loaded).
- `Entity->spawnTo()` now has an additional sanity check for matching worlds (might expose a few new errors in plugins).
- Fixed a missing field in `CraftRecipeAuto` item stack request type.
# 3.25.2
- Now analysed using level 9 on PHPStan 1.0.0.
- `ext-pthreads` v4.0.0 or newer is now required.
- Fixed crash in `Player->showPlayer()` when the target is not in the same world.
- `Human->setLifetimeTotalXp()` now limits the maximum value to 2^31.
- Fixed players, who died in hardcore mode and were unbanned, getting re-banned on next server join.
# 3.25.3
- Fixed crash when players try to pickup XP while already having max XP.
- Added a sanity check to `Human->setCurrentTotalXp()` to try and catch an elusive bug that's been appearing in the wild - please get in touch if you know how to reproduce it!
# 3.25.4
- Fixed a long-standing issue with `Player->removeWindow()` breaking inventory UIs on the client.
# 3.25.5
- Protocol: Fixed incorrect encoding in `StructureSettings`
- Fixed reading tags from non-docblock comments in script plugins.
- Build number is now defined in phar metadata instead of being patched into the source code directly.
# 3.25.6
- Fixed borked build number in release build of 3.25.5.

View File

@ -313,6 +313,10 @@ However, if we add `src-namespace-prefix: pmmp\TesterPlugin` to the `plugin.yml`
### Entity
#### General
- `Entity` no longer extends from `Location`. `Entity->getLocation()` and `Entity->getPosition()` should be used instead.
- Ender inventory has been refactored. It's now split into two parts:
- `EnderChestInventory` is a temporary gateway "inventory" that acts as a proxy to the player's ender inventory. It has a `Position` for holder. This is discarded when the player closes the inventory window.
- `PlayerEnderInventory` is the storage part. This is stored in `Human` and does not contain any block info.
- To open the player's ender inventory, use `Player->setCurrentWindow(new EnderChestInventory($blockPos, $player->getEnderInventory()))`.
- The following public fields have been removed:
- `Entity->chunk`: Entities no longer know which chunk they are in (the `World` now manages this instead).
- `Entity->height`: moved to `EntitySizeInfo`; use `Entity->size` instead
@ -329,6 +333,8 @@ However, if we add `src-namespace-prefix: pmmp\TesterPlugin` to the `plugin.yml`
- The following methods have signature changes:
- `Entity->entityBaseTick()` is now `protected`.
- `Entity->move()` is now `protected`.
- `Entity->setPosition()` is now `protected` (use `Entity->teleport()` instead).
- `Entity->setPositionAndRotation()` is now `protected` (use `Entity->teleport()` instead).
- `Living->knockBack()` now accepts `float, float, float` (the first two parameters have been removed).
- `Living->getEffects()` now returns `EffectManager` instead of `Effect[]`.
- The following classes have been added:
@ -349,6 +355,7 @@ However, if we add `src-namespace-prefix: pmmp\TesterPlugin` to the `plugin.yml`
- `Human->getMaxFood()` -> `HungerManager->getMaxFood()`
- `Human->addFood()` -> `HungerManager->addFood()`
- `Human->isHungry()` -> `HungerManager->isHungry()`
- `Human->getEnderChestInventory()` -> `Human->getEnderInventory()`
- `Human->getSaturation()` -> `HungerManager->getSaturation()`
- `Human->setSaturation()` -> `HungerManager->setSaturation()`
- `Human->addSaturation()` -> `HungerManager->addSaturation()`
@ -562,6 +569,7 @@ However, if we add `src-namespace-prefix: pmmp\TesterPlugin` to the `plugin.yml`
- `CallbackInventoryChangeListener`
- `CreativeInventory`: contains the creative functionality previously embedded in `pocketmine\item\Item`, see Item changes for details
- `InventoryChangeListener`: allows listening (but not interfering with) events in an inventory.
- `PlayerEnderInventory`: represents the pure storage part of the player's ender inventory, without any block information
- `transaction\CreateItemAction`
- `transaction\DestroyItemAction`
- The following classes have been renamed / moved:
@ -586,6 +594,7 @@ However, if we add `src-namespace-prefix: pmmp\TesterPlugin` to the `plugin.yml`
- The following API methods have been removed:
- `BaseInventory->getDefaultSize()`
- `BaseInventory->setSize()`
- `EnderChestInventory->setHolderPosition()`
- `Inventory->close()`
- `Inventory->dropContents()`
- `Inventory->getName()`
@ -1145,7 +1154,7 @@ However, if we add `src-namespace-prefix: pmmp\TesterPlugin` to the `plugin.yml`
#### Particles
- `DestroyBlockParticle` has been renamed to `BlockBreakParticle` for consistency.
- `DustParticle->__construct()` now accepts a `pocketmine\utils\Color` object instead of `r, g, b, a`.
- `DustParticle->__construct()` now accepts a `pocketmine\color\Color` object instead of `r, g, b, a`.
- `pocketmine\world\particle\Particle` no longer extends `pocketmine\math\Vector3`, and has been converted to an interface.
- Added the following `Particle` classes:
- `DragonEggTeleportParticle`
@ -1272,6 +1281,9 @@ However, if we add `src-namespace-prefix: pmmp\TesterPlugin` to the `plugin.yml`
### Inventory
- Implemented offhand inventory.
- Block-picking is now supported in survival mode.
- Block picking behaviour now matches vanilla (no longer overwrites held item, jumps to existing item where possible).
- Armor can now be equipped by right-clicking while holding it.
# 4.0.0-BETA2
Released 10th September 2021.
@ -1391,3 +1403,358 @@ Released 6th October 2021.
### Utils
- The following API methods have signature changes:
- `Process::kill()` now requires an additional `bool $subprocesses` parameter.
# 4.0.0-BETA5
Released 12th October 2021.
## General
- Exception log format has been changed. Now, exception info is logged in one big block message. This saves space on the console and improves readability, as well as reducing the ability for bad `ThreadedLoggerAttachment`s to break exception output.
- Log messages are now pushed to `server.log` before calling logger attachment, instead of after. This fixes messages not being written to disk when an error occurs in a logger attachment.
- Improved startup performance when loading many plugins.
- The `worlds` config in `pocketmine.yml` no longer supports attaching the generator settings to the `generator` key (use the `preset` key instead).
- Using an unknown generator in `server.properties` or `pocketmine.yml` will now cause a failure to generate the world.
- Using invalid/incorrect world generator options (presets) in `server.properties` or `pocketmine.yml` will now cause a failure to generate the world.
- Generator options of existing worlds are now validated before loading them. If they are invalid, the server will fail to load them.
- Several more log messages have been localized, including plugin loading errors.
## Fixes
- Fixed server crash when using `/give` to give an item by ID which doesn't exist in Minecraft.
- Fixed server crash when boolean `server.properties` options were given an integer value (e.g. `0` or `1` instead of `false` or `true`).
- Fixed stats reporting checking for a nonexistent `pocketmine.yml` setting.
- Fixed use of commands without the proper permission sending a message `commands.generic.permission` instead of the proper message.
- Fixed entities set on fire appearing to stay on fire, although not taking any damage.
- Fixed a duplicate `MB` suffix on the `Memory freed` output of `/gc`.
- Fixed the server attempting to generate a world if it failed to load.
## API
### Block
- The following API methods have been renamed:
- `Block->getPositionOffset()` -> `Block->getModelPositionOffset()`.
### Event
- `@handleCancelled` PhpDoc annotation can no longer be used on event handlers for non-cancellable events.
- The following API methods have been added:
- `StructureGrowEvent->getPlayer()`
### Inventory
- The following API methods have been added:
- `Inventory->getAddableItemQuantity()`
### Scheduler
- `ClosureTask` now permits closures without an explicit return type (useful for arrow functions).
### Utils
- The following API methods have been added:
- `Config::parseProperties()`
- `Config::writeProperties()`
- `Config::parseList()`
- `Config::writeList()`
### World
- The following API methods have signature changes:
- `GeneratorManager->registerGenerator()` now requires a `\Closure $presetValidator` parameter. This is used to check generator options of worlds and configs before attempting to use them.
# 4.0.0-BETA6
Released 19th October 2021.
## General
- Added support for Minecraft: Bedrock Edition 1.17.40.
- Removed support for earlier versions.
- CTRL+C signal handling has been restored, and is now supported on Windows. Pressing CTRL+C while the server is running will behave as if the `/stop` command was invoked.
- Added a script `tools/generate-permission-doc.php` to generate a Markdown file with a list of all permissions and their relationships. In the future, this will be used to maintain the official documentation, but plugin developers might find it useful for their own purposes too.
- [`respect/validation`](https://packagist.org/packages/respect/validation) is no longer a core dependency.
## Fixes
- Fixed server crash when using `/give` to give an item with a too-large item ID, or `/clear` to clear an item that does not exist.
- Now, `LegacyStringToItemParser` is used exclusively, and numeric IDs are no longer parsed.
## Gameplay
- Picking up some items from a dropped stack of items is now supported. This fixes various bugs with being unable to pick up items with an almost-full inventory.
# 4.0.0-BETA7
Released 28th October 2021.
## General
- Phar plugins are now able to depend on folder plugins loaded by DevTools.
- Now uses [`pocketmine/bedrock-protocol@58c53a259e819a076bf8fe875d2a012da7d19d65`](https://github.com/pmmp/BedrockProtocol/tree/58c53a259e819a076bf8fe875d2a012da7d19d65). This version features significant changes, including:
- Standardisation of various field names (e.g. `eid` -> `actorRuntimeId`, `evid` -> `eventId`)
- Rename of `entity` related fields to `actor` where appropriate (e.g. `entityRuntimeId` -> `actorRuntimeId`)
- Block position `x`/`y`/`z` fields replaced by `BlockPosition`
- Static `::create()` functions for all packets, which ensure that fields can't be forgotten
## Fixes
- Fixed server crash when clients send itemstacks with unmappable dynamic item IDs.
- Fixed server crash on invalid ItemStackRequest action types.
- Fixed autosave bug that caused unmodified chunks to be saved at least once (during the first autosave after they were loaded).
- Fixed `ConsoleReaderThread` returning strings with newlines still on the end.
- Fixed changes made to adjacent chunks in `ChunkPopulateEvent` (e.g. setting blocks) sometimes getting overwritten.
## API
### Event
- `PlayerCreationEvent` now verifies that the player class set is instantiable - this ensures that plugins get properly blamed for breaking things.
### World
- `World->generateChunkCallback()` has been specialized for use by `PopulationTask`. This allows fixing various inconsistencies involving `ChunkPopulateEvent` (e.g. modifications to adjacent chunks in `ChunkPopulationEvent` might be wiped out, if the population of the target chunk modified the adjacent chunk).
- It now accepts `Chunk $centerChunk, array<int, Chunk> $adjacentChunks` (instead of `?Chunk $chunk`).
- It's no longer expected to be used by plugins - plugins should be using `World->setChunk()` anyway.
- `Chunk->getModificationCounter()` has been added. This is a number starting from `0` when the `Chunk` object is first created (unless overridden by the constructor). It's incremented every time blocks or biomes are changed in the chunk. It resets after the chunk is unloaded and reloaded.
- The following API methods have changed signatures:
- `Sound->encode()` no longer accepts `null` for the position.
- `Chunk->__construct()`: removed `HeightArray $heightMap` parameter, added `bool $terrainPopulated` and `int $modificationCounter` parameters.
### Plugin
- `PluginManager->loadPlugins()` now accepts paths to files as well as directories, in which case it will load only the plugin found in the target file.
- The following API methods have been removed:
- `PluginManager->loadPlugin()`: use `PluginManager->loadPlugins()` instead
# 4.0.0-BETA8
Released 29th October 2021.
## General
- Chunk packet caches are now cleared by the memory manager on low memory.
- `Entity->spawnTo()` now has an additional sanity check for matching worlds (might expose a few new errors in plugins).
- [`pocketmine/math` 0.4.0](https://github.com/pmmp/Math/releases/tag/0.4.0) is now used. Please see its release notes for changes.
## Fixes
- Zlib raw check for LevelDB is now done directly on startup, avoiding crashes when later trying to load worlds.
- Fixed tiles and entities getting deleted from adjacent chunks during chunk population.
- Fixed players being unable to open their inventories more than once.
- Fixed entities not getting updated when a nearby chunk is replaced (e.g. dropped items would float in midair if the ground was lower than before)
## API
### World
- `World::setChunk()` has the following changes:
- `$deleteEntitiesAndTiles` parameter has been removed.
- Entities are no longer deleted on chunk replacement.
- Tiles are no longer deleted on chunk replacement, unless one of the following conditions is met:
- the target block in the new chunk doesn't expect a tile
- the target block in the new chunk expects a different type of tile (responsibility of the plugin developer to create the new tile)
- there's already a tile in the target chunk which conflicts with the old one
- `Location::__construct()` has the following changes:
- `world` parameter is now 4th instead of last.
- All parameters are now mandatory.
- Reverted addition of chunk modification counters in previous beta.
- `Chunk::DIRTY_FLAG_TERRAIN` has been renamed to `Chunk::DIRTY_FLAG_BLOCKS`.
# 4.0.0-BETA9
Released 2nd November 2021.
## General
- Now analysed using level 9 on PHPStan 1.0.0.
- `ext-pthreads` v4.0.0 or newer is now required.
- `resources/vanilla` submodule has been removed. BedrockData is now included via Composer dependency [`pocketmine/bedrock-data`](https://packagist.org/packages/pocketmine/bedrock-data).
- `pocketmine/spl` Composer dependency has been dropped.
- The following Composer dependency versions are now required:
- [`pocketmine/bedrock-protocol` v5.0.0](https://github.com/pmmp/BedrockProtocol/tree/5.0.0+bedrock-1.17.40) features substantial changes to its API compared to 3.0.1, which was used in 4.0.0-BETA8. Please see its [release notes](https://github.com/pmmp/BedrockData/releases/tag/5.0.0+bedrock-1.17.40).
- [`pocketmine/log` v0.4.0](https://github.com/pmmp/Log/tree/0.4.0) removes the `LoggerAttachment` interface and replaces logger attachment objects with closures.
- [`pocketmine/log-pthreads` v0.4.0](https://github.com/pmmp/LogPthreads/tree/0.4.0)
- [`pocketmine/classloader` v0.2.0](https://github.com/pmmp/ClassLoader/tree/0.2.0)
- A noisy debug message in `World->updateAllLight()` has been removed.
## API
### Entity
- `Human->setLifetimeTotalXp()` now limits the maximum value to 2^31.
### Event
- `BlockGrowEvent` is now called when cocoa pods grow.
### Item
- Added `Releasable->canStartUsingItem()`.
### Network
- Added `NetworkInterfaceStartException`, which may be thrown by `Network->registerInterface()` and `NetworkInterface->start()`.
### Player
- `SurvivalBlockBreakHandler::createIfNecessary()` has been removed.
- `SurvivalBlockBreakHandler->__construct()` is now public.
- `UsedChunkStatus::REQUESTED()` has been renamed to `REQUESTED_SENDING`.
- `UsedChunkStatus::REQUESTED_GENERATION()` has been added.
### Utils
- `Promise` API has changed:
- Promise-related classes have been moved to `pocketmine\promise` namespace.
- It's now split into `Promise` and `PromiseResolver`.
- `PromiseResolver` provides only `resolve()` and `reject()`. It should be used by callbacks to resolve a promise.
- `Promise` now provides only `onCompletion()` and `isResolved()` APIs. This should be given to consumers to allow them to handle the result of the async operation.
- `PromiseResolver` must not be created directly. Use `new PromiseResolver` and `PromiseResolver->getPromise()`.
### World
- Improved performance of `setBlock()` by around 35% when the `$update` parameter is set to `true`.
- Improved performance of `setBlock()` by around 30% when the `$update` parameter is set to `false`.
- `World->generateChunkCallback()` is no longer exposed to public API.
- `World->getAdjacentChunks()` now returns an array indexed using `World::chunkHash()`, where the `x` and `z` components are the relative offsets from the target chunk (range -1 to +1).
- `World->lockChunk()` now requires `ChunkLockId $lockId` parameter.
- `World->unlockChunk()` now requires a `?ChunkLockId $lockId` parameter. If a non-null lockID is given, the lock on the chunk will only be removed if it matches the given lockID.
- `World->unlockChunk()` now returns `bool` instead of `void` (to signal whether unlocking succeded or not).
- Added `ChunkLockId` class.
## Fixes
### World
- Fixed server crash when tiles with colliding positions are loaded from saved data. Now, an error is logged, but the server won't crash.
- Fixed server crash when liquids and other items flow into terrain locked for population. Now, an advisory locking mechanism is used, and population results will be discarded and recalculated if modifications are detected.
- Fixed various crashes that could occur if a chunk was flagged with `setPopulated(true)` after a promise had already been created for its population.
- Fixed `AssumptionFailedError` in `PopulationTask` when workers previously used for generation are shutdown, and then restarted on the fly by a generation request.
- Fixed assertion failure in `World->drainPopulationRequestQueue()` when requesting, cancelling and then re-requesting generation of a chunk while the generator was busy.
- Fixed generation potentially getting stuck if a population request was cancelled while the population task was running (failure to remove locks from used chunks).
- Fixed `World->requestChunkPopulation()` not taking into account that the target chunk may already be populated. This caused a variety of strange bugs and performance issues.
- Fixed potential memory leak caused by `World->unregisterChunkListenerFromAll()` not taking players into account.
- Fixed debug spam of `chunk has no loaders registered` messages during chunk generation.
### Other fixes
- Fixed server crash when unable to bind to the desired port. Now, the server will show an error and gracefully stop without a crashdump instead.
- Fixed server crash in `Player->showPlayer()` when the target is not in the same world.
- Fixed players, who died in hardcore mode and were unbanned, getting re-banned on next server join.
- Fixed cake block desync when attempting to eat in creative (eating in creative is not yet supported, but the block rollback was missing).
- Fixed players being able to eat items more quickly by dropping them while eating.
- Fixed arrows getting added to creative players' inventories when picked up.
- Fixed players re-requesting the same ungenerated chunks multiple times before they were sent.
- Fixed commands not working in some cases after using some control sequences on the console.
# 4.0.0-BETA10
Released 2nd November 2021.
## Fixes
- Fixed an issue with BedrockData JSON minification which broke the release build of 4.0.0-BETA9.
# 4.0.0-BETA11
Released 6th November 2021.
## General
- `resources/locale` submodule has been removed. Language files are now included via Composer dependency [`pocketmine/locale-data`](https://packagist.org/packages/pocketmine/locale-data).
- This means it's now possible to run a server from git sources without cloning submodules :)
- All remaining submodules (DevTools, build/php) are non-essential for building and running a server.
- Added a tool `tools/simulate-chunk-sending.php` to visualise the behaviour of `ChunkSelector`.
## Fixes
- Fixed server crash on saving when player XP has reached int32 max (XP is now capped, similar to Java Edition).
- Fixed another edge case in chunk generation that led to assertion failures.
- Fixed server crash when finding a list of `TAG_Float` for entity positions instead of `TAG_Double`.
- Fixed fast eating when picking up items.
- Fixed terrain being invisible for a long time when teleporting into ungenerated terrain.
- Fixed weird chunk loading when teleporting into ungenerated terrain (sometimes farther chunks would render before closer ones, leaving holes in the map temporarily).
- Fixed players re-requesting chunks when turning their heads or jumping.
- Fixed bonemeal sometimes being consumed even when cancelling `BlockGrowEvent` and `StructureGrowEvent`.
## API
### Event
- Added `PlayerEmoteEvent`.
### Gameplay
- Chunks are now sent in proper circles. This improves the experience when flying quickly parallel to X or Z axis, since now more chunks in front of the player will load sooner.
- Added support for emotes.
# 4.0.0-BETA12
Released 9th November 2021.
## General
- Introduced support for connecting via IPv6.
- PHP binary used must now always be built with IPv6 support, even if IPv6 is disabled. This is because RakNet may still send link-local IPv6 loopback addresses in connection packets even when only using IPv4.
- The default port for IPv6 is `19133` (similar to Bedrock Dedicated Server).
- Port `19133` is used by default so that Minecraft Bedrock can detect IPv6 servers on LAN.
- GS4 Query is supported on both IPv4 and IPv6 according to `server.properties` settings.
- The following `server.properties` settings are influential:
- `enable-ipv6`: `on` by default. Disabling this completely disables IPv6 support.
- `server-ipv6`: `::` by default (equivalent to "any IP", like `0.0.0.0` for IPv4). Most users shouldn't need to change this setting, and it doesn't appear in `server.properties` by default.
- `server-portv6`: `19133` by default. You may run both IPv4 and IPv6 on the same port.
- Various internal changes have been made to prepare for negative Y axis support (upcoming 1.18).
## Fixes
- Fixed resource packs not applying.
- Fixed inventory windows being unopenable after dying with inventory windows open.
- Fixed plugins being able to alter other plugins' permission defaults by redeclaring them in the `plugin.yml`.
## API
### Block
- `VanillaBlocks::fromString()` has been removed.
- Added `CraftingTableInventory`. This exclusively represents a crafting table's 3x3 crafting grid.
### Crafting
- `CraftingGrid` is now abstract.
- Removed `CraftingGrid->getHolder()`.
- The constructor of `CraftingGrid` no longer accepts a `Player` parameter.
### Entity
#### Effect
- `Effect->__construct()` once again accepts an `int $defaultDuration` parameter.
- Removed `VanillaEffects::fromString()`.
- Added `StringToEffectParser`
- Supports custom aliases!
- This is used by `/effect` to provide name support.
### Event
- `InventoryOpenEvent` is now fired when a player opens a crafting table's UI.
- `InventoryCloseEvent` is now fired when a player closes a crafting table's UI.
- `PlayerDropItemEvent` will now prevent the drops from force-closing of the following inventories:
- anvil
- enchanting table
- loom
### Inventory
- Added `TemporaryInventory`. This should be implemented by any inventory whose contents should be evacuated when closing.
- Added `PlayerCraftingInventory`. This exclusively represents the player's own 2x2 crafting grid.
### Item
- Removed `VanillaItems::fromString()`
- Obsoleted by the far superior, much more dynamic, and plugin-customizable `StringToItemParser`.
- `StringToItemParser` allows mapping strings to closure callbacks, allowing you to create aliases for `/give` for any item, including custom ones.
#### Enchantment
- Removed `VanillaEnchantments::fromString()`.
- Added `StringToEnchantmentParser`
- Supports custom aliases!
- This is used by `/enchant` to provide name support.
### Player
- Removed `Player->setCraftingGrid()`. To open a 3x3 crafting grid to a player, use `setCurrentWindow(new CraftingTableInventory)`.
### Server
- Added the following API methods:
- `Server->getIpV6()`
- `Server->getPortV6()`
# 4.0.0-BETA13
Released 25th November 2021.
## General
- Improved error messages when a plugin command name or alias contains an illegal character.
- Fixed script plugins reading tags from non-docblocks before the actual docblock.
- Added a sanity check to `Human->setCurrentTotalXp()` to try and catch an elusive bug that's been appearing in the wild - please get in touch if you know how to reproduce it!
- Updated `BUILDING.md` to reflect the fact that submodules are no longer required to build or run the server.
## Internals
- Crashdump rendering has been separated from crashdump data generation. This allows rendering crashdumps from existing JSON data.
- Direct iteration of arrays with string keys is now disallowed by a custom PHPStan rule. This is because numeric strings are casted to integers when used as array keys, which produces a variety of unexpected behaviour particularly for iteration.
- To iterate on arrays with string keys, `Utils::stringifyKeys()` must now be used.
## Fixes
- Fixed various crashes involving bad entity data saved on disk (e.g. an item entity with invalid item would crash the server).
- Fixed various crashes involving arrays with numeric string keys.
- Fixed crash when players try to pickup XP while already having max XP.
- Fixed ungenerated chunks saved on disk by old versions of PocketMine-MP (before 3.0.0) being treated as corrupted during world conversion (they are now ignored instead).
- Fixed misleading corruption error message when saved chunks have missing NBT tags.
## Gameplay
- Fixed `/setworldspawn` setting incorrect positions based on player position when in negative coordinates.
- `/setworldspawn` now accepts relative coordinates when used as a player.
- Added some extra aliases for `/give` and `/clear`: `chipped_anvil`, `coarse_dirt`, `damaged_anvil`, `dark_oak_standing_sign`, `jungle_wood_stairs`, `jungle_wooden_stairs` and `oak_standing_sign`.
- Some of these were added for quality-of-life, others were added just to be consistent.
- Fixed explosions dropping incorrect items when destroying blocks with tile data (e.g. banners, beds).
- Fixed the bounding box of skulls when mounted on a wall.
- Fixed podzol dropping itself when mined (instead of dirt).
## API
### Entity
- `Projectile->move()` is now protected, like its parent.
### Utils
- `Utils::parseDocComment()` now allows `-` in tag names.
# 4.0.0-BETA14
Released 30th November 2021.
## General
- The server will now log an EMERGENCY-level message when `forceShutdown()` is used for any other reason than a graceful shutdown.
- The server will now attempt to translate invalid blocks to valid equivalents when loading chunks. This fixes many issues with `update!` blocks appearing in worlds, particularly ghost structures (these would appear when world editors previously erased some blocks by setting their IDs but not metadata).
## Fixes
- Fixed `ConsoleReaderThread` spawning many zombie processes when running a server inside a Docker container.

View File

@ -22,7 +22,7 @@
"ext-openssl": "*",
"ext-pcre": "*",
"ext-phar": "*",
"ext-pthreads": "~3.2.0",
"ext-pthreads": "^4.0",
"ext-reflection": "*",
"ext-simplexml": "*",
"ext-sockets": "*",
@ -34,28 +34,28 @@
"adhocore/json-comment": "^1.1",
"fgrosse/phpasn1": "^2.3",
"netresearch/jsonmapper": "^4.0",
"pocketmine/bedrock-protocol": "2.0.0+bedrock1.17.30",
"pocketmine/bedrock-data": "^1.4.0+bedrock-1.17.40",
"pocketmine/bedrock-protocol": "^6.0.0+bedrock-1.17.40",
"pocketmine/binaryutils": "^0.2.1",
"pocketmine/callback-validator": "^1.0.2",
"pocketmine/classloader": "dev-master",
"pocketmine/classloader": "^0.2.0",
"pocketmine/color": "^0.2.0",
"pocketmine/errorhandler": "^0.3.0",
"pocketmine/log": "^0.3.0",
"pocketmine/log-pthreads": "^0.2.0",
"pocketmine/math": "^0.3.0",
"pocketmine/locale-data": "^2.0.16",
"pocketmine/log": "^0.4.0",
"pocketmine/log-pthreads": "^0.4.0",
"pocketmine/math": "^0.4.0",
"pocketmine/nbt": "^0.3.0",
"pocketmine/raklib": "^0.14.2",
"pocketmine/raklib-ipc": "^0.1.0",
"pocketmine/snooze": "^0.3.0",
"pocketmine/spl": "dev-master",
"ramsey/uuid": "^4.1",
"respect/validation": "^2.0",
"webmozart/path-util": "^2.3"
},
"require-dev": {
"phpstan/phpstan": "0.12.98",
"phpstan/phpstan-phpunit": "^0.12.6",
"phpstan/phpstan-strict-rules": "^0.12.2",
"phpstan/phpstan": "1.2.0",
"phpstan/phpstan-phpunit": "^1.0.0",
"phpstan/phpstan-strict-rules": "^1.0.0",
"phpunit/phpunit": "^9.2"
},
"autoload": {
@ -79,7 +79,7 @@
"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",
"make-devtools": "@php -dphar.readonly=0 tests/plugins/DevTools/src/ConsoleScript.php --make tests/plugins/DevTools --out plugins/DevTools.phar",
"make-server": [
"@composer install --no-dev --classmap-authoritative --ignore-platform-reqs",
"@php -dphar.readonly=0 build/server-phar.php"

557
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": "77f899b35819bca38246a665fd0233f3",
"content-hash": "fb545e4c8e17b0b07e8e20986b64e5a6",
"packages": [
{
"name": "adhocore/json-comment",
@ -248,33 +248,59 @@
"time": "2020-12-01T19:48:11+00:00"
},
{
"name": "pocketmine/bedrock-protocol",
"version": "2.0.0+bedrock1.17.30",
"name": "pocketmine/bedrock-data",
"version": "1.4.0+bedrock-1.17.40",
"source": {
"type": "git",
"url": "https://github.com/pmmp/BedrockProtocol.git",
"reference": "faff7da904e68f69b1a9128956dac3122e87308a"
"url": "https://github.com/pmmp/BedrockData.git",
"reference": "f29b7be8fa3046d2ee4c6421485b97b3f5b07774"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/pmmp/BedrockProtocol/zipball/faff7da904e68f69b1a9128956dac3122e87308a",
"reference": "faff7da904e68f69b1a9128956dac3122e87308a",
"url": "https://api.github.com/repos/pmmp/BedrockData/zipball/f29b7be8fa3046d2ee4c6421485b97b3f5b07774",
"reference": "f29b7be8fa3046d2ee4c6421485b97b3f5b07774",
"shasum": ""
},
"type": "library",
"notification-url": "https://packagist.org/downloads/",
"license": [
"LGPL-3.0"
],
"description": "Blobs of data generated from Minecraft: Bedrock Edition, used by PocketMine-MP",
"support": {
"issues": "https://github.com/pmmp/BedrockData/issues",
"source": "https://github.com/pmmp/BedrockData/tree/bedrock-1.17.40"
},
"time": "2021-10-19T16:55:41+00:00"
},
{
"name": "pocketmine/bedrock-protocol",
"version": "6.0.0+bedrock-1.17.40",
"source": {
"type": "git",
"url": "https://github.com/pmmp/BedrockProtocol.git",
"reference": "906bafec4fc41f548749ce01d120902b25c1bbfe"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/pmmp/BedrockProtocol/zipball/906bafec4fc41f548749ce01d120902b25c1bbfe",
"reference": "906bafec4fc41f548749ce01d120902b25c1bbfe",
"shasum": ""
},
"require": {
"ext-json": "*",
"netresearch/jsonmapper": "^4.0",
"php": "^7.4 || ^8.0",
"php": "^8.0",
"pocketmine/binaryutils": "^0.2.0",
"pocketmine/color": "^0.2.0",
"pocketmine/math": "^0.3.0",
"pocketmine/math": "^0.3.0 || ^0.4.0",
"pocketmine/nbt": "^0.3.0",
"ramsey/uuid": "^4.1"
},
"require-dev": {
"phpstan/phpstan": "0.12.99",
"phpstan/phpstan-phpunit": "^0.12.21",
"phpstan/phpstan-strict-rules": "^0.12.10",
"phpstan/phpstan": "1.2.0",
"phpstan/phpstan-phpunit": "^1.0.0",
"phpstan/phpstan-strict-rules": "^1.0.0",
"phpunit/phpunit": "^9.5"
},
"type": "library",
@ -290,22 +316,22 @@
"description": "An implementation of the Minecraft: Bedrock Edition protocol in PHP",
"support": {
"issues": "https://github.com/pmmp/BedrockProtocol/issues",
"source": "https://github.com/pmmp/BedrockProtocol/tree/bedrock-1.17.30"
"source": "https://github.com/pmmp/BedrockProtocol/tree/6.0.0+bedrock-1.17.40"
},
"time": "2021-09-21T23:25:51+00:00"
"time": "2021-11-21T20:56:18+00:00"
},
{
"name": "pocketmine/binaryutils",
"version": "0.2.1",
"version": "0.2.2",
"source": {
"type": "git",
"url": "https://github.com/pmmp/BinaryUtils.git",
"reference": "8cd078e2426f8100331f2d73bef10f481dad6cde"
"reference": "f883e1cf9099ed6a757a10a2f75b3333eeb2cdf9"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/pmmp/BinaryUtils/zipball/8cd078e2426f8100331f2d73bef10f481dad6cde",
"reference": "8cd078e2426f8100331f2d73bef10f481dad6cde",
"url": "https://api.github.com/repos/pmmp/BinaryUtils/zipball/f883e1cf9099ed6a757a10a2f75b3333eeb2cdf9",
"reference": "f883e1cf9099ed6a757a10a2f75b3333eeb2cdf9",
"shasum": ""
},
"require": {
@ -314,7 +340,7 @@
},
"require-dev": {
"phpstan/extension-installer": "^1.0",
"phpstan/phpstan": "0.12.85",
"phpstan/phpstan": "0.12.99",
"phpstan/phpstan-strict-rules": "^0.12.4"
},
"type": "library",
@ -330,9 +356,9 @@
"description": "Classes and methods for conveniently handling binary data",
"support": {
"issues": "https://github.com/pmmp/BinaryUtils/issues",
"source": "https://github.com/pmmp/BinaryUtils/tree/0.2.1"
"source": "https://github.com/pmmp/BinaryUtils/tree/0.2.2"
},
"time": "2021-05-30T19:42:57+00:00"
"time": "2021-10-22T19:54:16+00:00"
},
{
"name": "pocketmine/callback-validator",
@ -386,31 +412,31 @@
},
{
"name": "pocketmine/classloader",
"version": "dev-master",
"version": "0.2.0",
"source": {
"type": "git",
"url": "https://github.com/pmmp/ClassLoader.git",
"reference": "80226e0917be79ac3230606113e25134a31e6a85"
"reference": "49ea303993efdfb39cd302e2156d50aa78209e78"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/pmmp/ClassLoader/zipball/80226e0917be79ac3230606113e25134a31e6a85",
"reference": "80226e0917be79ac3230606113e25134a31e6a85",
"url": "https://api.github.com/repos/pmmp/ClassLoader/zipball/49ea303993efdfb39cd302e2156d50aa78209e78",
"reference": "49ea303993efdfb39cd302e2156d50aa78209e78",
"shasum": ""
},
"require": {
"ext-pthreads": "~3.2.0",
"ext-pthreads": "~3.2.0 || ^4.0",
"ext-reflection": "*",
"php": "^7.2 || ^8.0"
"php": "^8.0"
},
"conflict": {
"pocketmine/spl": "<0.4"
},
"require-dev": {
"phpstan/extension-installer": "^1.0",
"phpstan/phpstan": "0.12.80",
"phpstan/phpstan": "0.12.99",
"phpstan/phpstan-strict-rules": "^0.12.4",
"phpunit/phpunit": "^8.5 || ^9.5"
"phpunit/phpunit": "^9.5"
},
"type": "library",
"autoload": {
@ -425,9 +451,9 @@
"description": "Ad-hoc autoloading components used by PocketMine-MP",
"support": {
"issues": "https://github.com/pmmp/ClassLoader/issues",
"source": "https://github.com/pmmp/ClassLoader/tree/master"
"source": "https://github.com/pmmp/ClassLoader/tree/0.2.0"
},
"time": "2021-05-29T23:09:32+00:00"
"time": "2021-11-01T20:17:27+00:00"
},
{
"name": "pocketmine/color",
@ -506,17 +532,40 @@
"time": "2021-02-12T18:56:22+00:00"
},
{
"name": "pocketmine/log",
"version": "0.3.0",
"name": "pocketmine/locale-data",
"version": "2.0.20",
"source": {
"type": "git",
"url": "https://github.com/pmmp/Log.git",
"reference": "03ab1316da0b1978a7a1c8dd73e1c2a973cb62ec"
"url": "https://github.com/pmmp/Language.git",
"reference": "a6e4eb22587e0014f6d658732cf633262723f8d3"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/pmmp/Log/zipball/03ab1316da0b1978a7a1c8dd73e1c2a973cb62ec",
"reference": "03ab1316da0b1978a7a1c8dd73e1c2a973cb62ec",
"url": "https://api.github.com/repos/pmmp/Language/zipball/a6e4eb22587e0014f6d658732cf633262723f8d3",
"reference": "a6e4eb22587e0014f6d658732cf633262723f8d3",
"shasum": ""
},
"type": "library",
"notification-url": "https://packagist.org/downloads/",
"description": "Language resources used by PocketMine-MP",
"support": {
"issues": "https://github.com/pmmp/Language/issues",
"source": "https://github.com/pmmp/Language/tree/2.0.20"
},
"time": "2021-11-25T20:56:12+00:00"
},
{
"name": "pocketmine/log",
"version": "0.4.0",
"source": {
"type": "git",
"url": "https://github.com/pmmp/Log.git",
"reference": "e6c912c0f9055c81d23108ec2d179b96f404c043"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/pmmp/Log/zipball/e6c912c0f9055c81d23108ec2d179b96f404c043",
"reference": "e6c912c0f9055c81d23108ec2d179b96f404c043",
"shasum": ""
},
"require": {
@ -526,7 +575,7 @@
"pocketmine/spl": "<0.4"
},
"require-dev": {
"phpstan/phpstan": "0.12.80",
"phpstan/phpstan": "0.12.88",
"phpstan/phpstan-strict-rules": "^0.12.2"
},
"type": "library",
@ -542,28 +591,28 @@
"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.3.0"
"source": "https://github.com/pmmp/Log/tree/0.4.0"
},
"time": "2021-05-18T21:00:49+00:00"
"time": "2021-06-18T19:08:09+00:00"
},
{
"name": "pocketmine/log-pthreads",
"version": "0.2.0",
"version": "0.4.0",
"source": {
"type": "git",
"url": "https://github.com/pmmp/LogPthreads.git",
"reference": "6be3445c48c62eba3922f987f000bb20c81d161f"
"reference": "61f709e8cf36bcc24e4efe02acded680a1ce23cd"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/pmmp/LogPthreads/zipball/6be3445c48c62eba3922f987f000bb20c81d161f",
"reference": "6be3445c48c62eba3922f987f000bb20c81d161f",
"url": "https://api.github.com/repos/pmmp/LogPthreads/zipball/61f709e8cf36bcc24e4efe02acded680a1ce23cd",
"reference": "61f709e8cf36bcc24e4efe02acded680a1ce23cd",
"shasum": ""
},
"require": {
"ext-pthreads": "~3.2.0",
"ext-pthreads": "~3.2.0 || ^4.0",
"php": "^7.4 || ^8.0",
"pocketmine/log": "^0.2.0 || ^0.3.0"
"pocketmine/log": "^0.4.0"
},
"conflict": {
"pocketmine/spl": "<0.4"
@ -586,32 +635,32 @@
"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.2.0"
"source": "https://github.com/pmmp/LogPthreads/tree/0.4.0"
},
"time": "2021-05-18T22:15:28+00:00"
"time": "2021-11-01T21:42:09+00:00"
},
{
"name": "pocketmine/math",
"version": "0.3.0",
"version": "0.4.0",
"source": {
"type": "git",
"url": "https://github.com/pmmp/Math.git",
"reference": "83ec067b12c066fc61d9fb129daf7e61ef3b1d63"
"reference": "6d64e2555bd2e95ed024574f75d1cefc135c89fc"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/pmmp/Math/zipball/83ec067b12c066fc61d9fb129daf7e61ef3b1d63",
"reference": "83ec067b12c066fc61d9fb129daf7e61ef3b1d63",
"url": "https://api.github.com/repos/pmmp/Math/zipball/6d64e2555bd2e95ed024574f75d1cefc135c89fc",
"reference": "6d64e2555bd2e95ed024574f75d1cefc135c89fc",
"shasum": ""
},
"require": {
"php": "^7.4 || ^8.0",
"php": "^8.0",
"php-64bit": "*"
},
"require-dev": {
"irstea/phpunit-shim": "^8.5 || ^9.5",
"phpstan/extension-installer": "^1.0",
"phpstan/phpstan": "0.12.90",
"phpstan/phpstan": "0.12.99",
"phpstan/phpstan-strict-rules": "^0.12.4"
},
"type": "library",
@ -627,9 +676,9 @@
"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/0.3.0"
"source": "https://github.com/pmmp/Math/tree/0.4.0"
},
"time": "2021-07-14T18:39:31+00:00"
"time": "2021-10-29T20:33:10+00:00"
},
{
"name": "pocketmine/nbt",
@ -759,25 +808,25 @@
},
{
"name": "pocketmine/snooze",
"version": "0.3.0",
"version": "0.3.1",
"source": {
"type": "git",
"url": "https://github.com/pmmp/Snooze.git",
"reference": "fe5b1dbf0d6267da882d1f67924772bd93db833d"
"reference": "0ac8fc2a781c419a1f64ebca4d5835028f59e29b"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/pmmp/Snooze/zipball/fe5b1dbf0d6267da882d1f67924772bd93db833d",
"reference": "fe5b1dbf0d6267da882d1f67924772bd93db833d",
"url": "https://api.github.com/repos/pmmp/Snooze/zipball/0ac8fc2a781c419a1f64ebca4d5835028f59e29b",
"reference": "0ac8fc2a781c419a1f64ebca4d5835028f59e29b",
"shasum": ""
},
"require": {
"ext-pthreads": ">=3.1.7dev",
"ext-pthreads": "~3.2.0 || ^4.0",
"php-64bit": "^7.3 || ^8.0"
},
"require-dev": {
"phpstan/extension-installer": "^1.0",
"phpstan/phpstan": "0.12.88",
"phpstan/phpstan": "0.12.99",
"phpstan/phpstan-strict-rules": "^0.12.4"
},
"type": "library",
@ -793,59 +842,22 @@
"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.3.0"
"source": "https://github.com/pmmp/Snooze/tree/0.3.1"
},
"time": "2021-06-13T13:57:47+00:00"
},
{
"name": "pocketmine/spl",
"version": "dev-master",
"source": {
"type": "git",
"url": "https://github.com/pmmp/SPL.git",
"reference": "b7a8904f912c1f6d38ad867ff1120614ccb80171"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/pmmp/SPL/zipball/b7a8904f912c1f6d38ad867ff1120614ccb80171",
"reference": "b7a8904f912c1f6d38ad867ff1120614ccb80171",
"shasum": ""
},
"require": {
"php": "^7.2 || ^8.0"
},
"require-dev": {
"phpstan/phpstan": "^0.12.8"
},
"type": "library",
"autoload": {
"classmap": [
"./src"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"LGPL-3.0"
],
"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/master"
},
"time": "2021-01-15T15:19:34+00:00"
"time": "2021-11-01T20:50:08+00:00"
},
{
"name": "ramsey/collection",
"version": "1.2.1",
"version": "1.2.2",
"source": {
"type": "git",
"url": "https://github.com/ramsey/collection.git",
"reference": "eaca1dc1054ddd10cbd83c1461907bee6fb528fa"
"reference": "cccc74ee5e328031b15640b51056ee8d3bb66c0a"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/ramsey/collection/zipball/eaca1dc1054ddd10cbd83c1461907bee6fb528fa",
"reference": "eaca1dc1054ddd10cbd83c1461907bee6fb528fa",
"url": "https://api.github.com/repos/ramsey/collection/zipball/cccc74ee5e328031b15640b51056ee8d3bb66c0a",
"reference": "cccc74ee5e328031b15640b51056ee8d3bb66c0a",
"shasum": ""
},
"require": {
@ -899,7 +911,7 @@
],
"support": {
"issues": "https://github.com/ramsey/collection/issues",
"source": "https://github.com/ramsey/collection/tree/1.2.1"
"source": "https://github.com/ramsey/collection/tree/1.2.2"
},
"funding": [
{
@ -911,7 +923,7 @@
"type": "tidelift"
}
],
"time": "2021-08-06T03:41:06+00:00"
"time": "2021-10-10T03:01:02+00:00"
},
{
"name": "ramsey/uuid",
@ -1011,130 +1023,6 @@
],
"time": "2021-09-25T23:10:38+00:00"
},
{
"name": "respect/stringifier",
"version": "0.2.0",
"source": {
"type": "git",
"url": "https://github.com/Respect/Stringifier.git",
"reference": "e55af3c8aeaeaa2abb5fa47a58a8e9688cc23b59"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/Respect/Stringifier/zipball/e55af3c8aeaeaa2abb5fa47a58a8e9688cc23b59",
"reference": "e55af3c8aeaeaa2abb5fa47a58a8e9688cc23b59",
"shasum": ""
},
"require": {
"php": ">=7.1"
},
"require-dev": {
"friendsofphp/php-cs-fixer": "^2.8",
"malukenho/docheader": "^0.1.7",
"phpunit/phpunit": "^6.4"
},
"type": "library",
"autoload": {
"psr-4": {
"Respect\\Stringifier\\": "src/"
},
"files": [
"src/stringify.php"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Respect/Stringifier Contributors",
"homepage": "https://github.com/Respect/Stringifier/graphs/contributors"
}
],
"description": "Converts any value to a string",
"homepage": "http://respect.github.io/Stringifier/",
"keywords": [
"respect",
"stringifier",
"stringify"
],
"support": {
"issues": "https://github.com/Respect/Stringifier/issues",
"source": "https://github.com/Respect/Stringifier/tree/0.2.0"
},
"time": "2017-12-29T19:39:25+00:00"
},
{
"name": "respect/validation",
"version": "2.2.3",
"source": {
"type": "git",
"url": "https://github.com/Respect/Validation.git",
"reference": "4c21a7ffc9a4915673cb2c2843963919e664e627"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/Respect/Validation/zipball/4c21a7ffc9a4915673cb2c2843963919e664e627",
"reference": "4c21a7ffc9a4915673cb2c2843963919e664e627",
"shasum": ""
},
"require": {
"php": "^7.3 || ^8.0",
"respect/stringifier": "^0.2.0",
"symfony/polyfill-mbstring": "^1.2"
},
"require-dev": {
"egulias/email-validator": "^3.0",
"malukenho/docheader": "^0.1",
"mikey179/vfsstream": "^1.6",
"phpstan/phpstan": "^0.12",
"phpstan/phpstan-deprecation-rules": "^0.12",
"phpstan/phpstan-phpunit": "^0.12",
"phpunit/phpunit": "^9.3",
"psr/http-message": "^1.0",
"respect/coding-standard": "^3.0",
"squizlabs/php_codesniffer": "^3.5",
"symfony/validator": "^3.0||^4.0",
"zendframework/zend-validator": "^2.1"
},
"suggest": {
"egulias/email-validator": "Strict (RFC compliant) email validation",
"ext-bcmath": "Arbitrary Precision Mathematics",
"ext-fileinfo": "File Information",
"ext-mbstring": "Multibyte String Functions",
"symfony/validator": "Use Symfony validator through Respect\\Validation",
"zendframework/zend-validator": "Use Zend Framework validator through Respect\\Validation"
},
"type": "library",
"autoload": {
"psr-4": {
"Respect\\Validation\\": "library/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Respect/Validation Contributors",
"homepage": "https://github.com/Respect/Validation/graphs/contributors"
}
],
"description": "The most awesome validation engine ever created for PHP",
"homepage": "http://respect.github.io/Validation/",
"keywords": [
"respect",
"validation",
"validator"
],
"support": {
"issues": "https://github.com/Respect/Validation/issues",
"source": "https://github.com/Respect/Validation/tree/2.2.3"
},
"time": "2021-03-19T14:12:45+00:00"
},
{
"name": "symfony/polyfill-ctype",
"version": "v1.23.0",
@ -1214,86 +1102,6 @@
],
"time": "2021-02-19T12:13:01+00:00"
},
{
"name": "symfony/polyfill-mbstring",
"version": "v1.23.1",
"source": {
"type": "git",
"url": "https://github.com/symfony/polyfill-mbstring.git",
"reference": "9174a3d80210dca8daa7f31fec659150bbeabfc6"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/9174a3d80210dca8daa7f31fec659150bbeabfc6",
"reference": "9174a3d80210dca8daa7f31fec659150bbeabfc6",
"shasum": ""
},
"require": {
"php": ">=7.1"
},
"suggest": {
"ext-mbstring": "For best performance"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-main": "1.23-dev"
},
"thanks": {
"name": "symfony/polyfill",
"url": "https://github.com/symfony/polyfill"
}
},
"autoload": {
"psr-4": {
"Symfony\\Polyfill\\Mbstring\\": ""
},
"files": [
"bootstrap.php"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Nicolas Grekas",
"email": "p@tchwork.com"
},
{
"name": "Symfony Community",
"homepage": "https://symfony.com/contributors"
}
],
"description": "Symfony polyfill for the Mbstring extension",
"homepage": "https://symfony.com",
"keywords": [
"compatibility",
"mbstring",
"polyfill",
"portable",
"shim"
],
"support": {
"source": "https://github.com/symfony/polyfill-mbstring/tree/v1.23.1"
},
"funding": [
{
"url": "https://symfony.com/sponsor",
"type": "custom"
},
{
"url": "https://github.com/fabpot",
"type": "github"
},
{
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
"type": "tidelift"
}
],
"time": "2021-05-27T12:26:48+00:00"
},
{
"name": "symfony/polyfill-php80",
"version": "v1.23.1",
@ -1562,6 +1370,7 @@
"issues": "https://github.com/webmozart/path-util/issues",
"source": "https://github.com/webmozart/path-util/tree/2.3.0"
},
"abandoned": "symfony/filesystem",
"time": "2015-12-17T08:42:14+00:00"
}
],
@ -1695,16 +1504,16 @@
},
{
"name": "nikic/php-parser",
"version": "v4.13.0",
"version": "v4.13.1",
"source": {
"type": "git",
"url": "https://github.com/nikic/PHP-Parser.git",
"reference": "50953a2691a922aa1769461637869a0a2faa3f53"
"reference": "63a79e8daa781cac14e5195e63ed8ae231dd10fd"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/50953a2691a922aa1769461637869a0a2faa3f53",
"reference": "50953a2691a922aa1769461637869a0a2faa3f53",
"url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/63a79e8daa781cac14e5195e63ed8ae231dd10fd",
"reference": "63a79e8daa781cac14e5195e63ed8ae231dd10fd",
"shasum": ""
},
"require": {
@ -1745,9 +1554,9 @@
],
"support": {
"issues": "https://github.com/nikic/PHP-Parser/issues",
"source": "https://github.com/nikic/PHP-Parser/tree/v4.13.0"
"source": "https://github.com/nikic/PHP-Parser/tree/v4.13.1"
},
"time": "2021-09-20T12:20:58+00:00"
"time": "2021-11-03T20:52:16+00:00"
},
{
"name": "phar-io/manifest",
@ -1915,16 +1724,16 @@
},
{
"name": "phpdocumentor/reflection-docblock",
"version": "5.2.2",
"version": "5.3.0",
"source": {
"type": "git",
"url": "https://github.com/phpDocumentor/ReflectionDocBlock.git",
"reference": "069a785b2141f5bcf49f3e353548dc1cce6df556"
"reference": "622548b623e81ca6d78b721c5e029f4ce664f170"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/phpDocumentor/ReflectionDocBlock/zipball/069a785b2141f5bcf49f3e353548dc1cce6df556",
"reference": "069a785b2141f5bcf49f3e353548dc1cce6df556",
"url": "https://api.github.com/repos/phpDocumentor/ReflectionDocBlock/zipball/622548b623e81ca6d78b721c5e029f4ce664f170",
"reference": "622548b623e81ca6d78b721c5e029f4ce664f170",
"shasum": ""
},
"require": {
@ -1935,7 +1744,8 @@
"webmozart/assert": "^1.9.1"
},
"require-dev": {
"mockery/mockery": "~1.3.2"
"mockery/mockery": "~1.3.2",
"psalm/phar": "^4.8"
},
"type": "library",
"extra": {
@ -1965,22 +1775,22 @@
"description": "With this component, a library can provide support for annotations via DocBlocks or otherwise retrieve information that is embedded in a DocBlock.",
"support": {
"issues": "https://github.com/phpDocumentor/ReflectionDocBlock/issues",
"source": "https://github.com/phpDocumentor/ReflectionDocBlock/tree/master"
"source": "https://github.com/phpDocumentor/ReflectionDocBlock/tree/5.3.0"
},
"time": "2020-09-03T19:13:55+00:00"
"time": "2021-10-19T17:43:47+00:00"
},
{
"name": "phpdocumentor/type-resolver",
"version": "1.5.0",
"version": "1.5.1",
"source": {
"type": "git",
"url": "https://github.com/phpDocumentor/TypeResolver.git",
"reference": "30f38bffc6f24293dadd1823936372dfa9e86e2f"
"reference": "a12f7e301eb7258bb68acd89d4aefa05c2906cae"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/phpDocumentor/TypeResolver/zipball/30f38bffc6f24293dadd1823936372dfa9e86e2f",
"reference": "30f38bffc6f24293dadd1823936372dfa9e86e2f",
"url": "https://api.github.com/repos/phpDocumentor/TypeResolver/zipball/a12f7e301eb7258bb68acd89d4aefa05c2906cae",
"reference": "a12f7e301eb7258bb68acd89d4aefa05c2906cae",
"shasum": ""
},
"require": {
@ -2015,9 +1825,9 @@
"description": "A PSR-5 based resolver of Class names, Types and Structural Element Names",
"support": {
"issues": "https://github.com/phpDocumentor/TypeResolver/issues",
"source": "https://github.com/phpDocumentor/TypeResolver/tree/1.5.0"
"source": "https://github.com/phpDocumentor/TypeResolver/tree/1.5.1"
},
"time": "2021-09-17T15:28:14+00:00"
"time": "2021-10-02T14:08:47+00:00"
},
{
"name": "phpspec/prophecy",
@ -2088,16 +1898,16 @@
},
{
"name": "phpstan/phpstan",
"version": "0.12.98",
"version": "1.2.0",
"source": {
"type": "git",
"url": "https://github.com/phpstan/phpstan.git",
"reference": "3bb7cc246c057405dd5e290c3ecc62ab51d57e00"
"reference": "cbe085f9fdead5b6d62e4c022ca52dc9427a10ee"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/phpstan/phpstan/zipball/3bb7cc246c057405dd5e290c3ecc62ab51d57e00",
"reference": "3bb7cc246c057405dd5e290c3ecc62ab51d57e00",
"url": "https://api.github.com/repos/phpstan/phpstan/zipball/cbe085f9fdead5b6d62e4c022ca52dc9427a10ee",
"reference": "cbe085f9fdead5b6d62e4c022ca52dc9427a10ee",
"shasum": ""
},
"require": {
@ -2113,7 +1923,7 @@
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "0.12-dev"
"dev-master": "1.2-dev"
}
},
"autoload": {
@ -2128,7 +1938,7 @@
"description": "PHPStan - PHP Static Analysis Tool",
"support": {
"issues": "https://github.com/phpstan/phpstan/issues",
"source": "https://github.com/phpstan/phpstan/tree/0.12.98"
"source": "https://github.com/phpstan/phpstan/tree/1.2.0"
},
"funding": [
{
@ -2148,38 +1958,39 @@
"type": "tidelift"
}
],
"time": "2021-09-02T12:33:01+00:00"
"time": "2021-11-18T14:09:01+00:00"
},
{
"name": "phpstan/phpstan-phpunit",
"version": "0.12.22",
"version": "1.0.0",
"source": {
"type": "git",
"url": "https://github.com/phpstan/phpstan-phpunit.git",
"reference": "7c01ef93bf128b4ac8bdad38c54b2a4fd6b0b3cc"
"reference": "9eb88c9f689003a8a2a5ae9e010338ee94dc39b3"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/phpstan/phpstan-phpunit/zipball/7c01ef93bf128b4ac8bdad38c54b2a4fd6b0b3cc",
"reference": "7c01ef93bf128b4ac8bdad38c54b2a4fd6b0b3cc",
"url": "https://api.github.com/repos/phpstan/phpstan-phpunit/zipball/9eb88c9f689003a8a2a5ae9e010338ee94dc39b3",
"reference": "9eb88c9f689003a8a2a5ae9e010338ee94dc39b3",
"shasum": ""
},
"require": {
"php": "^7.1 || ^8.0",
"phpstan/phpstan": "^0.12.92"
"phpstan/phpstan": "^1.0"
},
"conflict": {
"phpunit/phpunit": "<7.0"
},
"require-dev": {
"nikic/php-parser": "^4.13.0",
"php-parallel-lint/php-parallel-lint": "^1.2",
"phpstan/phpstan-strict-rules": "^0.12.6",
"phpstan/phpstan-strict-rules": "^1.0",
"phpunit/phpunit": "^9.5"
},
"type": "phpstan-extension",
"extra": {
"branch-alias": {
"dev-master": "0.12-dev"
"dev-master": "1.0-dev"
},
"phpstan": {
"includes": [
@ -2200,37 +2011,38 @@
"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.22"
"source": "https://github.com/phpstan/phpstan-phpunit/tree/1.0.0"
},
"time": "2021-08-12T10:53:43+00:00"
"time": "2021-10-14T08:03:54+00:00"
},
{
"name": "phpstan/phpstan-strict-rules",
"version": "0.12.11",
"version": "1.1.0",
"source": {
"type": "git",
"url": "https://github.com/phpstan/phpstan-strict-rules.git",
"reference": "2b72e8e17d2034145f239126e876e5fb659675e2"
"reference": "e12d55f74a8cca18c6e684c6450767e055ba7717"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/phpstan/phpstan-strict-rules/zipball/2b72e8e17d2034145f239126e876e5fb659675e2",
"reference": "2b72e8e17d2034145f239126e876e5fb659675e2",
"url": "https://api.github.com/repos/phpstan/phpstan-strict-rules/zipball/e12d55f74a8cca18c6e684c6450767e055ba7717",
"reference": "e12d55f74a8cca18c6e684c6450767e055ba7717",
"shasum": ""
},
"require": {
"php": "^7.1 || ^8.0",
"phpstan/phpstan": "^0.12.96"
"phpstan/phpstan": "^1.2.0"
},
"require-dev": {
"nikic/php-parser": "^4.13.0",
"php-parallel-lint/php-parallel-lint": "^1.2",
"phpstan/phpstan-phpunit": "^0.12.16",
"phpstan/phpstan-phpunit": "^1.0",
"phpunit/phpunit": "^9.5"
},
"type": "phpstan-extension",
"extra": {
"branch-alias": {
"dev-master": "0.12-dev"
"dev-master": "1.0-dev"
},
"phpstan": {
"includes": [
@ -2250,29 +2062,29 @@
"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/0.12.11"
"source": "https://github.com/phpstan/phpstan-strict-rules/tree/1.1.0"
},
"time": "2021-08-21T11:36:27+00:00"
"time": "2021-11-18T09:30:29+00:00"
},
{
"name": "phpunit/php-code-coverage",
"version": "9.2.7",
"version": "9.2.9",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/php-code-coverage.git",
"reference": "d4c798ed8d51506800b441f7a13ecb0f76f12218"
"reference": "f301eb1453c9e7a1bc912ee8b0ea9db22c60223b"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/d4c798ed8d51506800b441f7a13ecb0f76f12218",
"reference": "d4c798ed8d51506800b441f7a13ecb0f76f12218",
"url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/f301eb1453c9e7a1bc912ee8b0ea9db22c60223b",
"reference": "f301eb1453c9e7a1bc912ee8b0ea9db22c60223b",
"shasum": ""
},
"require": {
"ext-dom": "*",
"ext-libxml": "*",
"ext-xmlwriter": "*",
"nikic/php-parser": "^4.12.0",
"nikic/php-parser": "^4.13.0",
"php": ">=7.3",
"phpunit/php-file-iterator": "^3.0.3",
"phpunit/php-text-template": "^2.0.2",
@ -2321,7 +2133,7 @@
],
"support": {
"issues": "https://github.com/sebastianbergmann/php-code-coverage/issues",
"source": "https://github.com/sebastianbergmann/php-code-coverage/tree/9.2.7"
"source": "https://github.com/sebastianbergmann/php-code-coverage/tree/9.2.9"
},
"funding": [
{
@ -2329,7 +2141,7 @@
"type": "github"
}
],
"time": "2021-09-17T05:39:03+00:00"
"time": "2021-11-19T15:21:02+00:00"
},
{
"name": "phpunit/php-file-iterator",
@ -3104,16 +2916,16 @@
},
{
"name": "sebastian/exporter",
"version": "4.0.3",
"version": "4.0.4",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/exporter.git",
"reference": "d89cc98761b8cb5a1a235a6b703ae50d34080e65"
"reference": "65e8b7db476c5dd267e65eea9cab77584d3cfff9"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/d89cc98761b8cb5a1a235a6b703ae50d34080e65",
"reference": "d89cc98761b8cb5a1a235a6b703ae50d34080e65",
"url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/65e8b7db476c5dd267e65eea9cab77584d3cfff9",
"reference": "65e8b7db476c5dd267e65eea9cab77584d3cfff9",
"shasum": ""
},
"require": {
@ -3162,14 +2974,14 @@
}
],
"description": "Provides the functionality to export PHP variables for visualization",
"homepage": "http://www.github.com/sebastianbergmann/exporter",
"homepage": "https://www.github.com/sebastianbergmann/exporter",
"keywords": [
"export",
"exporter"
],
"support": {
"issues": "https://github.com/sebastianbergmann/exporter/issues",
"source": "https://github.com/sebastianbergmann/exporter/tree/4.0.3"
"source": "https://github.com/sebastianbergmann/exporter/tree/4.0.4"
},
"funding": [
{
@ -3177,7 +2989,7 @@
"type": "github"
}
],
"time": "2020-09-28T05:24:23+00:00"
"time": "2021-11-11T14:18:36+00:00"
},
{
"name": "sebastian/global-state",
@ -3692,10 +3504,7 @@
],
"aliases": [],
"minimum-stability": "stable",
"stability-flags": {
"pocketmine/classloader": 20,
"pocketmine/spl": 20
},
"stability-flags": [],
"prefer-stable": false,
"prefer-lowest": false,
"platform": {
@ -3716,7 +3525,7 @@
"ext-openssl": "*",
"ext-pcre": "*",
"ext-phar": "*",
"ext-pthreads": "~3.2.0",
"ext-pthreads": "^4.0",
"ext-reflection": "*",
"ext-simplexml": "*",
"ext-sockets": "*",

View File

@ -1,13 +1,9 @@
includes:
- tests/phpstan/configs/actual-problems.neon
- tests/phpstan/configs/check-explicit-mixed-baseline.neon
- tests/phpstan/configs/gc-hacks.neon
- tests/phpstan/configs/impossible-generics.neon
- tests/phpstan/configs/l7-baseline.neon
- tests/phpstan/configs/l8-baseline.neon
- tests/phpstan/configs/php-bugs.neon
- tests/phpstan/configs/phpstan-bugs.neon
- tests/phpstan/configs/pthreads-bugs.neon
- tests/phpstan/configs/runtime-type-checks.neon
- tests/phpstan/configs/spl-fixed-array-sucks.neon
- vendor/phpstan/phpstan-phpunit/extension.neon
@ -16,11 +12,11 @@ includes:
rules:
- pocketmine\phpstan\rules\DisallowEnumComparisonRule
- pocketmine\phpstan\rules\UnsafeForeachArrayOfStringRule
# - pocketmine\phpstan\rules\ThreadedSupportedTypesRule
parameters:
level: 8
checkExplicitMixed: true
level: 9
checkMissingCallableSignature: true
treatPhpDocTypesAsCertain: false
bootstrapFiles:
@ -57,5 +53,5 @@ parameters:
#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'
anyCallable: 'callable(never, never, never, never, never, never, never, never, never, never) : mixed'
anyClosure: '\Closure(never, never, never, never, never, never, never, never, never, never) : mixed'

View File

@ -1,4 +1,691 @@
{
"-2": -2,
"-3": -3,
"-4": -4,
"-5": -5,
"-6": -6,
"-7": -7,
"-8": -8,
"-9": -9,
"-10": -10,
"-11": -11,
"-12": -12,
"-13": -13,
"-14": -14,
"-15": -15,
"-16": -16,
"-17": -17,
"-18": -18,
"-19": -19,
"-20": -20,
"-21": -21,
"-22": -22,
"-23": -23,
"-24": -24,
"-25": -25,
"-26": -26,
"-27": -27,
"-28": -28,
"-29": -29,
"-30": -30,
"-31": -31,
"-32": -32,
"-33": -33,
"-34": -34,
"-35": -35,
"-36": -36,
"-37": -37,
"-38": -38,
"-39": -39,
"-40": -40,
"-41": -41,
"-42": -42,
"-43": -43,
"-44": -44,
"-45": -45,
"-46": -46,
"-47": -47,
"-48": -48,
"-49": -49,
"-50": -50,
"-51": -51,
"-52": -52,
"-53": -53,
"-54": -54,
"-55": -55,
"-56": -56,
"-57": -57,
"-58": -58,
"-59": -59,
"-60": -60,
"-61": -61,
"-62": -62,
"-63": -63,
"-64": -64,
"-65": -65,
"-66": -66,
"-67": -67,
"-68": -68,
"-69": -69,
"-70": -70,
"-71": -71,
"-72": -72,
"-73": -73,
"-74": -74,
"-75": -75,
"-76": -76,
"-77": -77,
"-78": -78,
"-79": -79,
"-80": -80,
"-81": -81,
"-82": -82,
"-83": -83,
"-84": -84,
"-85": -85,
"-86": -86,
"-87": -87,
"-88": -88,
"-89": -89,
"-90": -90,
"-91": -91,
"-92": -92,
"-93": -93,
"-94": -94,
"-95": -95,
"-96": -96,
"-97": -97,
"-98": -98,
"-99": -99,
"-100": -100,
"-101": -101,
"-102": -102,
"-103": -103,
"-104": -104,
"-105": -105,
"-106": -106,
"-107": -107,
"-108": -108,
"-109": -109,
"-110": -110,
"-111": -111,
"-112": -112,
"-113": -113,
"-114": -114,
"-115": -115,
"-116": -116,
"-117": -117,
"-118": -118,
"-119": -119,
"-120": -120,
"-121": -121,
"-122": -122,
"-123": -123,
"-124": -124,
"-125": -125,
"-126": -126,
"-127": -127,
"-128": -128,
"-129": -129,
"-130": -130,
"-131": -131,
"-132": -132,
"-133": -133,
"-134": -134,
"-135": -135,
"-136": -136,
"-137": -137,
"-138": -138,
"-139": -139,
"-140": -140,
"-141": -141,
"-142": -142,
"-143": -143,
"-144": -144,
"-145": -145,
"-146": -146,
"-147": -147,
"-148": -148,
"-149": -149,
"-150": -150,
"-151": -151,
"-152": -152,
"-153": -153,
"-154": -154,
"-155": -155,
"-156": -156,
"-157": -157,
"-159": -159,
"-160": -160,
"-161": -161,
"-162": -162,
"-163": -163,
"-164": -164,
"-165": -165,
"-166": -166,
"-167": -167,
"-168": -168,
"-169": -169,
"-170": -170,
"-171": -171,
"-172": -172,
"-173": -173,
"-174": -174,
"-175": -175,
"-176": -176,
"-177": -177,
"-178": -178,
"-179": -179,
"-180": -180,
"-181": -181,
"-182": -182,
"-183": -183,
"-184": -184,
"-185": -185,
"-186": -186,
"-187": -187,
"-188": -188,
"-189": -189,
"-190": -190,
"-191": -191,
"-192": -192,
"-193": -193,
"-194": -194,
"-195": -195,
"-196": -196,
"-197": -197,
"-198": -198,
"-199": -199,
"-200": -200,
"-201": -201,
"-202": -202,
"-203": -203,
"-204": -204,
"-206": -206,
"-207": -207,
"-208": -208,
"-209": -209,
"-210": -210,
"-211": -211,
"-213": -213,
"-214": -214,
"0": 0,
"1": 1,
"2": 2,
"3": 3,
"4": 4,
"5": 5,
"6": 6,
"7": 7,
"8": 8,
"9": 9,
"10": 10,
"11": 11,
"12": 12,
"13": 13,
"14": 14,
"15": 15,
"16": 16,
"17": 17,
"18": 18,
"19": 19,
"20": 20,
"21": 21,
"22": 22,
"23": 23,
"24": 24,
"25": 25,
"26": 26,
"27": 27,
"28": 28,
"29": 29,
"30": 30,
"31": 31,
"32": 32,
"33": 33,
"34": 34,
"35": 35,
"36": 36,
"37": 37,
"38": 38,
"39": 39,
"40": 40,
"41": 41,
"42": 42,
"43": 43,
"44": 44,
"45": 45,
"46": 46,
"47": 47,
"48": 48,
"49": 49,
"50": 50,
"51": 51,
"52": 52,
"53": 53,
"54": 54,
"55": 55,
"56": 56,
"57": 57,
"58": 58,
"59": 59,
"60": 60,
"61": 61,
"62": 62,
"63": 63,
"64": 64,
"65": 65,
"66": 66,
"67": 67,
"68": 68,
"69": 69,
"70": 70,
"71": 71,
"72": 72,
"73": 73,
"74": 74,
"75": 75,
"76": 76,
"77": 77,
"78": 78,
"79": 79,
"80": 80,
"81": 81,
"82": 82,
"83": 83,
"84": 84,
"85": 85,
"86": 86,
"87": 87,
"88": 88,
"89": 89,
"90": 90,
"91": 91,
"92": 92,
"93": 93,
"94": 94,
"95": 95,
"96": 96,
"97": 97,
"98": 98,
"99": 99,
"100": 100,
"101": 101,
"102": 102,
"103": 103,
"104": 104,
"105": 105,
"106": 106,
"107": 107,
"108": 108,
"109": 109,
"110": 110,
"111": 111,
"112": 112,
"113": 113,
"114": 114,
"115": 115,
"116": 116,
"117": 117,
"118": 118,
"119": 119,
"120": 120,
"121": 121,
"122": 122,
"123": 123,
"124": 124,
"125": 125,
"126": 126,
"127": 127,
"128": 128,
"129": 129,
"130": 130,
"131": 131,
"132": 132,
"133": 133,
"134": 134,
"135": 135,
"136": 136,
"137": 137,
"138": 138,
"139": 139,
"140": 140,
"141": 141,
"142": 142,
"143": 143,
"144": 144,
"145": 145,
"146": 146,
"147": 147,
"148": 148,
"149": 149,
"150": 150,
"151": 151,
"152": 152,
"153": 153,
"154": 154,
"155": 155,
"156": 156,
"157": 157,
"158": 158,
"159": 159,
"160": 160,
"161": 161,
"162": 162,
"163": 163,
"164": 164,
"165": 165,
"166": 166,
"167": 167,
"168": 168,
"169": 169,
"170": 170,
"171": 171,
"172": 172,
"173": 173,
"174": 174,
"175": 175,
"176": 176,
"177": 177,
"178": 178,
"179": 179,
"180": 180,
"181": 181,
"182": 182,
"183": 183,
"184": 184,
"185": 185,
"186": 186,
"187": 187,
"188": 188,
"189": 189,
"190": 190,
"191": 191,
"192": 192,
"193": 193,
"194": 194,
"195": 195,
"196": 196,
"197": 197,
"198": 198,
"199": 199,
"200": 200,
"201": 201,
"202": 202,
"203": 203,
"204": 204,
"205": 205,
"206": 206,
"207": 207,
"208": 208,
"209": 209,
"213": 213,
"214": 214,
"215": 215,
"216": 216,
"218": 218,
"219": 219,
"220": 220,
"221": 221,
"222": 222,
"223": 223,
"224": 224,
"225": 225,
"226": 226,
"227": 227,
"228": 228,
"229": 229,
"231": 231,
"232": 232,
"233": 233,
"234": 234,
"235": 235,
"236": 236,
"237": 237,
"238": 238,
"239": 239,
"240": 240,
"241": 241,
"243": 243,
"244": 244,
"245": 245,
"246": 246,
"247": 247,
"248": 248,
"249": 249,
"250": 250,
"251": 251,
"252": 252,
"253": 253,
"254": 254,
"255": 255,
"256": 256,
"257": 257,
"258": 258,
"259": 259,
"260": 260,
"261": 261,
"262": 262,
"263": 263,
"264": 264,
"265": 265,
"266": 266,
"267": 267,
"268": 268,
"269": 269,
"270": 270,
"271": 271,
"272": 272,
"273": 273,
"274": 274,
"275": 275,
"276": 276,
"277": 277,
"278": 278,
"279": 279,
"280": 280,
"281": 281,
"282": 282,
"283": 283,
"284": 284,
"285": 285,
"286": 286,
"287": 287,
"288": 288,
"289": 289,
"290": 290,
"291": 291,
"292": 292,
"293": 293,
"294": 294,
"295": 295,
"296": 296,
"297": 297,
"298": 298,
"299": 299,
"300": 300,
"301": 301,
"302": 302,
"303": 303,
"304": 304,
"305": 305,
"306": 306,
"307": 307,
"308": 308,
"309": 309,
"310": 310,
"311": 311,
"312": 312,
"313": 313,
"314": 314,
"315": 315,
"316": 316,
"317": 317,
"318": 318,
"319": 319,
"320": 320,
"321": 321,
"322": 322,
"323": 323,
"324": 324,
"325": 325,
"328": 328,
"329": 329,
"330": 330,
"331": 331,
"332": 332,
"333": 333,
"334": 334,
"335": 335,
"336": 336,
"337": 337,
"338": 338,
"339": 339,
"340": 340,
"341": 341,
"342": 342,
"344": 344,
"345": 345,
"346": 346,
"347": 347,
"348": 348,
"349": 349,
"350": 350,
"351": 351,
"352": 352,
"353": 353,
"354": 354,
"355": 355,
"356": 356,
"357": 357,
"358": 358,
"359": 359,
"360": 360,
"361": 361,
"362": 362,
"363": 363,
"364": 364,
"365": 365,
"366": 366,
"367": 367,
"368": 368,
"369": 369,
"370": 370,
"371": 371,
"372": 372,
"373": 373,
"374": 374,
"375": 375,
"376": 376,
"377": 377,
"378": 378,
"379": 379,
"380": 380,
"381": 381,
"382": 382,
"383": 383,
"384": 384,
"385": 385,
"386": 386,
"387": 387,
"388": 388,
"389": 389,
"390": 390,
"391": 391,
"392": 392,
"393": 393,
"394": 394,
"395": 395,
"396": 396,
"397": 397,
"398": 398,
"399": 399,
"400": 400,
"401": 401,
"402": 402,
"403": 403,
"404": 404,
"405": 405,
"406": 406,
"407": 407,
"408": 408,
"409": 409,
"410": 410,
"411": 411,
"412": 412,
"413": 413,
"414": 414,
"415": 415,
"416": 416,
"417": 417,
"418": 418,
"419": 419,
"420": 420,
"421": 421,
"422": 422,
"423": 423,
"424": 424,
"425": 425,
"426": 426,
"427": 427,
"428": 428,
"429": 429,
"430": 430,
"431": 431,
"432": 432,
"433": 433,
"434": 434,
"437": 437,
"438": 438,
"441": 441,
"442": 442,
"443": 443,
"444": 444,
"445": 445,
"446": 446,
"447": 447,
"448": 448,
"449": 449,
"450": 450,
"451": 451,
"452": 452,
"453": 453,
"455": 455,
"457": 457,
"458": 458,
"459": 459,
"460": 460,
"461": 461,
"462": 462,
"463": 463,
"464": 464,
"465": 465,
"466": 466,
"467": 467,
"468": 468,
"469": 469,
"470": 470,
"471": 471,
"472": 472,
"473": 473,
"474": 474,
"475": 475,
"476": 476,
"477": 477,
"499": 499,
"500": 500,
"501": 501,
"502": 502,
"503": 503,
"504": 504,
"505": 505,
"506": 506,
"507": 507,
"508": 508,
"509": 509,
"510": 510,
"511": 511,
"513": 513,
"acacia_button": -140,
"acacia_door": 430,
"acacia_door_block": 196,
@ -226,27 +913,16 @@
"egg": 344,
"element_0": 36,
"element_1": -12,
"element_2": -13,
"element_3": -14,
"element_4": -15,
"element_5": -16,
"element_6": -17,
"element_7": -18,
"element_8": -19,
"element_9": -20,
"element_10": -21,
"element_100": -111,
"element_101": -112,
"element_102": -113,
"element_103": -114,
"element_104": -115,
"element_105": -116,
"element_106": -117,
"element_107": -118,
"element_108": -119,
"element_109": -120,
"element_11": -22,
"element_110": -121,
"element_111": -122,
"element_112": -123,
"element_113": -124,
"element_114": -125,
"element_115": -126,
"element_116": -127,
"element_117": -128,
"element_118": -129,
"element_12": -23,
"element_13": -24,
"element_14": -25,
@ -255,7 +931,6 @@
"element_17": -28,
"element_18": -29,
"element_19": -30,
"element_2": -13,
"element_20": -31,
"element_21": -32,
"element_22": -33,
@ -266,7 +941,6 @@
"element_27": -38,
"element_28": -39,
"element_29": -40,
"element_3": -14,
"element_30": -41,
"element_31": -42,
"element_32": -43,
@ -277,7 +951,6 @@
"element_37": -48,
"element_38": -49,
"element_39": -50,
"element_4": -15,
"element_40": -51,
"element_41": -52,
"element_42": -53,
@ -288,7 +961,6 @@
"element_47": -58,
"element_48": -59,
"element_49": -60,
"element_5": -16,
"element_50": -61,
"element_51": -62,
"element_52": -63,
@ -299,7 +971,6 @@
"element_57": -68,
"element_58": -69,
"element_59": -70,
"element_6": -17,
"element_60": -71,
"element_61": -72,
"element_62": -73,
@ -310,7 +981,6 @@
"element_67": -78,
"element_68": -79,
"element_69": -80,
"element_7": -18,
"element_70": -81,
"element_71": -82,
"element_72": -83,
@ -321,7 +991,6 @@
"element_77": -88,
"element_78": -89,
"element_79": -90,
"element_8": -19,
"element_80": -91,
"element_81": -92,
"element_82": -93,
@ -332,7 +1001,6 @@
"element_87": -98,
"element_88": -99,
"element_89": -100,
"element_9": -20,
"element_90": -101,
"element_91": -102,
"element_92": -103,
@ -343,6 +1011,25 @@
"element_97": -108,
"element_98": -109,
"element_99": -110,
"element_100": -111,
"element_101": -112,
"element_102": -113,
"element_103": -114,
"element_104": -115,
"element_105": -116,
"element_106": -117,
"element_107": -118,
"element_108": -119,
"element_109": -120,
"element_110": -121,
"element_111": -122,
"element_112": -123,
"element_113": -124,
"element_114": -125,
"element_115": -126,
"element_116": -127,
"element_117": -128,
"element_118": -129,
"elytra": 444,
"emerald": 388,
"emerald_block": 133,
@ -532,8 +1219,8 @@
"leather_pants": 300,
"leather_tunic": 299,
"leave": 18,
"leaves": 18,
"leave2": 161,
"leaves": 18,
"leaves2": 161,
"lectern": -194,
"lever": 69,

Submodule resources/locale deleted from c940b9f171

View File

@ -108,7 +108,7 @@ player:
verify-xuid: true
level-settings:
#The default format that levels will use when created
#The default format that worlds will use when created
default-format: leveldb
chunk-sending:
@ -176,7 +176,7 @@ aliases:
#savestop: [save-all, stop]
worlds:
#These settings will override the generator set in server.properties and allows loading multiple levels
#These settings will override the generator set in server.properties and allows loading multiple worlds
#Example:
#world:
# seed: 404

View File

@ -35,4 +35,6 @@ define('pocketmine\_CORE_CONSTANTS_INCLUDED', true);
define('pocketmine\PATH', dirname(__DIR__) . '/');
define('pocketmine\RESOURCE_PATH', dirname(__DIR__) . '/resources/');
define('pocketmine\BEDROCK_DATA_PATH', dirname(__DIR__) . '/vendor/pocketmine/bedrock-data/');
define('pocketmine\LOCALE_DATA_PATH', dirname(__DIR__) . '/vendor/pocketmine/locale-data/');
define('pocketmine\COMPOSER_AUTOLOADER_PATH', dirname(__DIR__) . '/vendor/autoload.php');

View File

@ -24,6 +24,7 @@ declare(strict_types=1);
namespace pocketmine;
use pocketmine\event\server\LowMemoryEvent;
use pocketmine\network\mcpe\cache\ChunkCache;
use pocketmine\scheduler\DumpWorkerMemoryTask;
use pocketmine\scheduler\GarbageCollectionTask;
use pocketmine\timings\Timings;
@ -187,6 +188,7 @@ class MemoryManager{
foreach($this->server->getWorldManager()->getWorlds() as $world){
$world->clearCache(true);
}
ChunkCache::pruneCaches();
}
if($this->lowMemChunkGC){
@ -350,35 +352,33 @@ class MemoryManager{
file_put_contents(Path::join($outputFolder, "staticProperties.js"), json_encode($staticProperties, JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT));
$logger->info("Wrote $staticCount static properties");
if(isset($GLOBALS)){ //This might be null if we're on a different thread
$globalVariables = [];
$globalCount = 0;
$globalVariables = [];
$globalCount = 0;
$ignoredGlobals = [
'GLOBALS' => true,
'_SERVER' => true,
'_REQUEST' => true,
'_POST' => true,
'_GET' => true,
'_FILES' => true,
'_ENV' => true,
'_COOKIE' => true,
'_SESSION' => true
];
$ignoredGlobals = [
'GLOBALS' => true,
'_SERVER' => true,
'_REQUEST' => true,
'_POST' => true,
'_GET' => true,
'_FILES' => true,
'_ENV' => true,
'_COOKIE' => true,
'_SESSION' => true
];
foreach($GLOBALS as $varName => $value){
if(isset($ignoredGlobals[$varName])){
continue;
}
$globalCount++;
$globalVariables[$varName] = self::continueDump($value, $objects, $refCounts, 0, $maxNesting, $maxStringSize);
foreach(Utils::stringifyKeys($GLOBALS) as $varName => $value){
if(isset($ignoredGlobals[$varName])){
continue;
}
file_put_contents(Path::join($outputFolder, "globalVariables.js"), json_encode($globalVariables, JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT));
$logger->info("Wrote $globalCount global variables");
$globalCount++;
$globalVariables[$varName] = self::continueDump($value, $objects, $refCounts, 0, $maxNesting, $maxStringSize);
}
file_put_contents(Path::join($outputFolder, "globalVariables.js"), json_encode($globalVariables, JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT));
$logger->info("Wrote $globalCount global variables");
foreach(get_defined_functions()["user"] as $function){
$reflect = new \ReflectionFunction($function);

View File

@ -34,6 +34,7 @@ namespace pocketmine {
use pocketmine\utils\Timezone;
use pocketmine\wizard\SetupWizard;
use Webmozart\PathUtil\Path;
use function defined;
use function extension_loaded;
use function phpversion;
use function preg_match;
@ -116,8 +117,8 @@ namespace pocketmine {
if(substr_count($pthreads_version, ".") < 2){
$pthreads_version = "0.$pthreads_version";
}
if(version_compare($pthreads_version, "3.2.0") < 0){
$messages[] = "pthreads >= 3.2.0 is required, while you have $pthreads_version.";
if(version_compare($pthreads_version, "4.0.0") < 0 || version_compare($pthreads_version, "5.0.0") > 0){
$messages[] = "pthreads ^4.0.0 is required, while you have $pthreads_version.";
}
}
@ -126,6 +127,9 @@ namespace pocketmine {
if(version_compare($leveldb_version, "0.2.1") < 0){
$messages[] = "php-leveldb >= 0.2.1 is required, while you have $leveldb_version.";
}
if(!defined('LEVELDB_ZLIB_RAW_COMPRESSION')){
$messages[] = "Given version of php-leveldb doesn't support ZLIB_RAW compression (use https://github.com/pmmp/php-leveldb)";
}
}
$chunkutils2_version = phpversion("chunkutils2");
@ -142,6 +146,10 @@ namespace pocketmine {
$messages[] = "The native PocketMine extension is no longer supported.";
}
if(!defined('AF_INET6')){
$messages[] = "IPv6 support is required, but your PHP binary was built without IPv6 support.";
}
return $messages;
}

View File

@ -34,6 +34,8 @@ use pocketmine\console\ConsoleCommandSender;
use pocketmine\console\ConsoleReaderThread;
use pocketmine\crafting\CraftingManager;
use pocketmine\crafting\CraftingManagerFromDataHelper;
use pocketmine\crash\CrashDump;
use pocketmine\crash\CrashDumpRenderer;
use pocketmine\data\java\GameModeIdMap;
use pocketmine\entity\EntityDataHelper;
use pocketmine\entity\Location;
@ -64,6 +66,7 @@ use pocketmine\network\mcpe\protocol\ProtocolInfo;
use pocketmine\network\mcpe\protocol\serializer\PacketBatch;
use pocketmine\network\mcpe\raklib\RakLibInterface;
use pocketmine\network\Network;
use pocketmine\network\NetworkInterfaceStartException;
use pocketmine\network\query\DedicatedQueryNetworkInterface;
use pocketmine\network\query\QueryHandler;
use pocketmine\network\query\QueryInfo;
@ -81,6 +84,8 @@ use pocketmine\plugin\PluginGraylist;
use pocketmine\plugin\PluginManager;
use pocketmine\plugin\PluginOwned;
use pocketmine\plugin\ScriptPluginLoader;
use pocketmine\promise\Promise;
use pocketmine\promise\PromiseResolver;
use pocketmine\resourcepacks\ResourcePackManager;
use pocketmine\scheduler\AsyncPool;
use pocketmine\snooze\SleeperHandler;
@ -97,7 +102,7 @@ use pocketmine\utils\MainLogger;
use pocketmine\utils\NotCloneable;
use pocketmine\utils\NotSerializable;
use pocketmine\utils\Process;
use pocketmine\utils\Promise;
use pocketmine\utils\SignalHandler;
use pocketmine\utils\Terminal;
use pocketmine\utils\TextFormat;
use pocketmine\utils\Utils;
@ -106,26 +111,29 @@ use pocketmine\world\format\io\WorldProviderManager;
use pocketmine\world\format\io\WritableWorldProviderManagerEntry;
use pocketmine\world\generator\Generator;
use pocketmine\world\generator\GeneratorManager;
use pocketmine\world\generator\InvalidGeneratorOptionsException;
use pocketmine\world\World;
use pocketmine\world\WorldCreationOptions;
use pocketmine\world\WorldManager;
use Ramsey\Uuid\UuidInterface;
use Webmozart\PathUtil\Path;
use function array_shift;
use function array_sum;
use function base64_encode;
use function cli_set_process_title;
use function copy;
use function count;
use function explode;
use function date;
use function fclose;
use function file_exists;
use function file_get_contents;
use function file_put_contents;
use function filemtime;
use function fopen;
use function get_class;
use function implode;
use function ini_set;
use function is_array;
use function is_dir;
use function is_resource;
use function is_string;
use function json_decode;
use function max;
@ -252,6 +260,8 @@ class Server{
/** @var Player[] */
private array $playerList = [];
private SignalHandler $signalHandler;
/**
* @var CommandSender[][]
* @phpstan-var array<string, array<int, CommandSender>>
@ -317,6 +327,10 @@ class Server{
return $this->configGroup->getConfigInt("server-port", 19132);
}
public function getPortV6() : int{
return $this->configGroup->getConfigInt("server-portv6", 19133);
}
public function getViewDistance() : int{
return max(2, $this->configGroup->getConfigInt("view-distance", 8));
}
@ -333,6 +347,11 @@ class Server{
return $str !== "" ? $str : "0.0.0.0";
}
public function getIpV6() : string{
$str = $this->configGroup->getConfigString("server-ipv6");
return $str !== "" ? $str : "::";
}
public function getServerUniqueId() : UuidInterface{
return $this->serverID;
}
@ -547,11 +566,11 @@ class Server{
$playerPos = null;
$spawn = $world->getSpawnLocation();
}
$playerPromise = new Promise();
$playerPromiseResolver = new PromiseResolver();
$world->requestChunkPopulation($spawn->getFloorX() >> Chunk::COORD_BIT_SIZE, $spawn->getFloorZ() >> Chunk::COORD_BIT_SIZE, null)->onCompletion(
function() use ($playerPromise, $class, $session, $playerInfo, $authenticated, $world, $playerPos, $spawn, $offlinePlayerData) : void{
function() use ($playerPromiseResolver, $class, $session, $playerInfo, $authenticated, $world, $playerPos, $spawn, $offlinePlayerData) : void{
if(!$session->isConnected()){
$playerPromise->reject();
$playerPromiseResolver->reject();
return;
}
@ -571,16 +590,16 @@ class Server{
if(!$player->hasPlayedBefore()){
$player->onGround = true; //TODO: this hack is needed for new players in-air ticks - they don't get detected as on-ground until they move
}
$playerPromise->resolve($player);
$playerPromiseResolver->resolve($player);
},
static function() use ($playerPromise, $session) : void{
static function() use ($playerPromiseResolver, $session) : void{
if($session->isConnected()){
$session->disconnect("Spawn terrain generation failed");
}
$playerPromise->reject();
$playerPromiseResolver->reject();
}
);
return $playerPromise;
return $playerPromiseResolver->getPromise();
}
/**
@ -736,7 +755,7 @@ class Server{
public function __construct(\DynamicClassLoader $autoloader, \AttachableThreadedLogger $logger, string $dataPath, string $pluginPath){
if(self::$instance !== null){
throw new \InvalidStateException("Only one server instance can exist at once");
throw new \LogicException("Only one server instance can exist at once");
}
self::$instance = $this;
$this->startTime = microtime(true);
@ -745,6 +764,11 @@ class Server{
$this->autoloader = $autoloader;
$this->logger = $logger;
$this->signalHandler = new SignalHandler(function() : void{
$this->logger->info("Received signal interrupt, stopping the server");
$this->shutdown();
});
try{
foreach([
$dataPath,
@ -775,6 +799,8 @@ class Server{
new Config(Path::join($this->dataPath, "server.properties"), Config::PROPERTIES, [
"motd" => VersionInfo::NAME . " Server",
"server-port" => 19132,
"server-portv6" => 19133,
"enable-ipv6" => true,
"white-list" => false,
"max-players" => 20,
"gamemode" => 0,
@ -924,7 +950,7 @@ class Server{
$this->commandMap = new SimpleCommandMap($this);
$this->craftingManager = CraftingManagerFromDataHelper::make(Path::join(\pocketmine\RESOURCE_PATH, "vanilla", "recipes.json"));
$this->craftingManager = CraftingManagerFromDataHelper::make(Path::join(\pocketmine\BEDROCK_DATA_PATH, "recipes.json"));
$this->resourceManager = new ResourcePackManager(Path::join($this->getDataPath(), "resource_packs"), $this->logger);
@ -967,91 +993,17 @@ class Server{
$this->pluginManager->loadPlugins($this->pluginPath);
$this->enablePlugins(PluginEnableOrder::STARTUP());
foreach((array) $this->configGroup->getProperty("worlds", []) as $name => $options){
if($options === null){
$options = [];
}elseif(!is_array($options)){
continue;
}
if(!$this->worldManager->loadWorld($name, true)){
$creationOptions = WorldCreationOptions::create();
//TODO: error checking
if(isset($options["generator"])){
$generatorOptions = explode(":", $options["generator"]);
$creationOptions->setGeneratorClass(GeneratorManager::getInstance()->getGenerator(array_shift($generatorOptions)));
if(count($generatorOptions) > 0){
$creationOptions->setGeneratorOptions(implode(":", $generatorOptions));
}
}
if(isset($options["difficulty"]) && is_string($options["difficulty"])){
$creationOptions->setDifficulty(World::getDifficultyFromString($options["difficulty"]));
}
if(isset($options["preset"]) && is_string($options["preset"])){
$creationOptions->setGeneratorOptions($options["preset"]);
}
if(isset($options["seed"])){
$convertedSeed = Generator::convertSeed((string) ($options["seed"] ?? ""));
if($convertedSeed !== null){
$creationOptions->setSeed($convertedSeed);
}
}
$this->worldManager->generateWorld($name, $creationOptions);
}
if(!$this->startupPrepareWorlds()){
return;
}
if($this->worldManager->getDefaultWorld() === null){
$default = $this->configGroup->getConfigString("level-name", "world");
if(trim($default) == ""){
$this->getLogger()->warning("level-name cannot be null, using default");
$default = "world";
$this->configGroup->setConfigString("level-name", "world");
}
if(!$this->worldManager->loadWorld($default, true)){
$creationOptions = WorldCreationOptions::create()
->setGeneratorClass(GeneratorManager::getInstance()->getGenerator($this->configGroup->getConfigString("level-type")))
->setGeneratorOptions($this->configGroup->getConfigString("generator-settings"));
$convertedSeed = Generator::convertSeed($this->configGroup->getConfigString("level-seed"));
if($convertedSeed !== null){
$creationOptions->setSeed($convertedSeed);
}
$this->worldManager->generateWorld($default, $creationOptions);
}
$world = $this->worldManager->getWorldByName($default);
if($world === null){
$this->getLogger()->emergency($this->getLanguage()->translate(KnownTranslationFactory::pocketmine_level_defaultError()));
$this->forceShutdown();
return;
}
$this->worldManager->setDefaultWorld($world);
}
$this->enablePlugins(PluginEnableOrder::POSTWORLD());
$useQuery = $this->configGroup->getConfigBool("enable-query", true);
if(!$this->network->registerInterface(new RakLibInterface($this)) && $useQuery){
//RakLib would normally handle the transport for Query packets
//if it's not registered we need to make sure Query still works
$this->network->registerInterface(new DedicatedQueryNetworkInterface($this->getIp(), $this->getPort(), new \PrefixedLogger($this->logger, "Dedicated Query Interface")));
}
$this->logger->info($this->getLanguage()->translate(KnownTranslationFactory::pocketmine_server_networkStart($this->getIp(), (string) $this->getPort())));
if($useQuery){
$this->network->registerRawPacketHandler(new QueryHandler($this));
if(!$this->startupPrepareNetworkInterfaces()){
$this->forceShutdown();
return;
}
foreach($this->getIPBans()->getEntries() as $entry){
$this->network->blockAddress($entry->getName(), -1);
}
if($this->configGroup->getPropertyBool("network.upnp-forwarding", false)){
$this->network->registerInterface(new UPnPNetworkInterface($this->logger, Internet::getInternalIP(), $this->getPort()));
}
if($this->configGroup->getPropertyBool("settings.send-usage", true)){
if($this->configGroup->getPropertyBool("anonymous-statistics.enabled", true)){
$this->sendUsageTicker = 6000;
$this->sendUsage(SendUsageTask::TYPE_OPEN);
}
@ -1086,6 +1038,151 @@ class Server{
}
}
private function startupPrepareWorlds() : bool{
$getGenerator = function(string $generatorName, string $generatorOptions, string $worldName) : ?string{
$generatorEntry = GeneratorManager::getInstance()->getGenerator($generatorName);
if($generatorEntry === null){
$this->logger->error($this->language->translate(KnownTranslationFactory::pocketmine_level_generationError(
$worldName,
KnownTranslationFactory::pocketmine_level_unknownGenerator($generatorName)
)));
return null;
}
try{
$generatorEntry->validateGeneratorOptions($generatorOptions);
}catch(InvalidGeneratorOptionsException $e){
$this->logger->error($this->language->translate(KnownTranslationFactory::pocketmine_level_generationError(
$worldName,
KnownTranslationFactory::pocketmine_level_invalidGeneratorOptions($generatorOptions, $generatorName, $e->getMessage())
)));
return null;
}
return $generatorEntry->getGeneratorClass();
};
foreach((array) $this->configGroup->getProperty("worlds", []) as $name => $options){
if($options === null){
$options = [];
}elseif(!is_array($options)){
continue;
}
if(!$this->worldManager->loadWorld($name, true) && !$this->worldManager->isWorldGenerated($name)){
$creationOptions = WorldCreationOptions::create();
//TODO: error checking
$generatorName = $options["generator"] ?? "default";
$generatorOptions = isset($options["preset"]) && is_string($options["preset"]) ? $options["preset"] : "";
$generatorClass = $getGenerator($generatorName, $generatorOptions, $name);
if($generatorClass === null){
continue;
}
$creationOptions->setGeneratorClass($generatorClass);
$creationOptions->setGeneratorOptions($generatorOptions);
if(isset($options["difficulty"]) && is_string($options["difficulty"])){
$creationOptions->setDifficulty(World::getDifficultyFromString($options["difficulty"]));
}
if(isset($options["seed"])){
$convertedSeed = Generator::convertSeed((string) ($options["seed"] ?? ""));
if($convertedSeed !== null){
$creationOptions->setSeed($convertedSeed);
}
}
$this->worldManager->generateWorld($name, $creationOptions);
}
}
if($this->worldManager->getDefaultWorld() === null){
$default = $this->configGroup->getConfigString("level-name", "world");
if(trim($default) == ""){
$this->getLogger()->warning("level-name cannot be null, using default");
$default = "world";
$this->configGroup->setConfigString("level-name", "world");
}
if(!$this->worldManager->loadWorld($default, true) && !$this->worldManager->isWorldGenerated($default)){
$generatorName = $this->configGroup->getConfigString("level-type");
$generatorOptions = $this->configGroup->getConfigString("generator-settings");
$generatorClass = $getGenerator($generatorName, $generatorOptions, $default);
if($generatorClass !== null){
$creationOptions = WorldCreationOptions::create()
->setGeneratorClass($generatorClass)
->setGeneratorOptions($generatorOptions);
$convertedSeed = Generator::convertSeed($this->configGroup->getConfigString("level-seed"));
if($convertedSeed !== null){
$creationOptions->setSeed($convertedSeed);
}
$this->worldManager->generateWorld($default, $creationOptions);
}
}
$world = $this->worldManager->getWorldByName($default);
if($world === null){
$this->getLogger()->emergency($this->getLanguage()->translate(KnownTranslationFactory::pocketmine_level_defaultError()));
$this->forceShutdown();
return false;
}
$this->worldManager->setDefaultWorld($world);
}
return true;
}
private function startupPrepareConnectableNetworkInterfaces(string $ip, int $port, bool $ipV6, bool $useQuery) : bool{
$prettyIp = $ipV6 ? "[$ip]" : $ip;
try{
$rakLibRegistered = $this->network->registerInterface(new RakLibInterface($this, $ip, $port, $ipV6));
}catch(NetworkInterfaceStartException $e){
$this->logger->emergency($this->language->translate(KnownTranslationFactory::pocketmine_server_networkStartFailed(
$ip,
(string) $port,
$e->getMessage()
)));
return false;
}
$this->logger->info($this->getLanguage()->translate(KnownTranslationFactory::pocketmine_server_networkStart($prettyIp, (string) $port)));
if($useQuery){
if(!$rakLibRegistered){
//RakLib would normally handle the transport for Query packets
//if it's not registered we need to make sure Query still works
$this->network->registerInterface(new DedicatedQueryNetworkInterface($ip, $port, $ipV6, new \PrefixedLogger($this->logger, "Dedicated Query Interface")));
}
$this->logger->info($this->getLanguage()->translate(KnownTranslationFactory::pocketmine_server_query_running($prettyIp, (string) $port)));
}
return true;
}
private function startupPrepareNetworkInterfaces() : bool{
$useQuery = $this->configGroup->getConfigBool("enable-query", true);
if(
!$this->startupPrepareConnectableNetworkInterfaces($this->getIp(), $this->getPort(), false, $useQuery) ||
(
$this->configGroup->getConfigBool("enable-ipv6", true) &&
!$this->startupPrepareConnectableNetworkInterfaces($this->getIpV6(), $this->getPortV6(), true, $useQuery)
)
){
return false;
}
if($useQuery){
$this->network->registerRawPacketHandler(new QueryHandler($this));
}
foreach($this->getIPBans()->getEntries() as $entry){
$this->network->blockAddress($entry->getName(), -1);
}
if($this->configGroup->getPropertyBool("network.upnp-forwarding", false)){
$this->network->registerInterface(new UPnPNetworkInterface($this->logger, Internet::getInternalIP(), $this->getPort()));
}
return true;
}
/**
* Subscribes to a particular message broadcast channel.
* The channel ID can be any arbitrary string.
@ -1110,7 +1207,7 @@ class Server{
* Unsubscribes from all broadcast channels.
*/
public function unsubscribeFromAllBroadcastChannels(CommandSender $subscriber) : void{
foreach($this->broadcastSubscribers as $channelId => $recipients){
foreach(Utils::stringifyKeys($this->broadcastSubscribers) as $channelId => $recipients){
$this->unsubscribeFromBroadcastChannel($channelId, $subscriber);
}
}
@ -1301,7 +1398,10 @@ class Server{
* Shuts the server down correctly
*/
public function shutdown() : void{
$this->isRunning = false;
if($this->isRunning){
$this->isRunning = false;
$this->signalHandler->unregister();
}
}
public function forceShutdown() : void{
@ -1313,6 +1413,9 @@ class Server{
echo "\x1b]0;\x07";
}
if($this->isRunning){
$this->logger->emergency("Forcing server shutdown");
}
try{
if(!$this->isRunning()){
$this->sendUsage(SendUsageTask::TYPE_CLOSE);
@ -1411,6 +1514,25 @@ class Server{
$this->crashDump();
}
private function writeCrashDumpFile(CrashDump $dump) : string{
$crashFolder = Path::join($this->getDataPath(), "crashdumps");
if(!is_dir($crashFolder)){
mkdir($crashFolder);
}
$crashDumpPath = Path::join($crashFolder, date("D_M_j-H.i.s-T_Y", (int) $dump->getData()->time) . ".log");
$fp = @fopen($crashDumpPath, "wb");
if(!is_resource($fp)){
throw new \RuntimeException("Unable to open new file to generate crashdump");
}
$writer = new CrashDumpRenderer($fp, $dump->getData());
$writer->renderHumanReadable();
$dump->encodeData($writer);
fclose($fp);
return $crashDumpPath;
}
public function crashDump() : void{
while(@ob_end_flush()){}
if(!$this->isRunning){
@ -1425,9 +1547,11 @@ class Server{
ini_set("memory_limit", '-1'); //Fix error dump not dumped on memory problems
try{
$this->logger->emergency($this->getLanguage()->translate(KnownTranslationFactory::pocketmine_crash_create()));
$dump = new CrashDump($this);
$dump = new CrashDump($this, $this->pluginManager ?? null);
$this->logger->emergency($this->getLanguage()->translate(KnownTranslationFactory::pocketmine_crash_submit($dump->getPath())));
$crashDumpPath = $this->writeCrashDumpFile($dump);
$this->logger->emergency($this->getLanguage()->translate(KnownTranslationFactory::pocketmine_crash_submit($crashDumpPath)));
if($this->configGroup->getPropertyBool("auto-report.enabled", true)){
$report = true;
@ -1439,8 +1563,8 @@ class Server{
}
@touch($stamp); //update file timestamp
$plugin = $dump->getData()["plugin"];
if(is_string($plugin)){
$plugin = $dump->getData()->plugin;
if($plugin !== ""){
$p = $this->pluginManager->getPlugin($plugin);
if($p instanceof Plugin and !($p->getPluginLoader() instanceof PharPluginLoader)){
$this->logger->debug("Not sending crashdump due to caused by non-phar plugin");
@ -1448,7 +1572,7 @@ class Server{
}
}
if($dump->getData()["error"]["type"] === \ParseError::class){
if($dump->getData()->error["type"] === \ParseError::class){
$report = false;
}

View File

@ -27,6 +27,8 @@ use pocketmine\utils\Config;
use function array_key_exists;
use function getopt;
use function is_bool;
use function is_int;
use function is_string;
use function strtolower;
final class ServerConfigGroup{
@ -110,16 +112,20 @@ final class ServerConfigGroup{
}else{
$value = $this->serverProperties->exists($variable) ? $this->serverProperties->get($variable) : $defaultValue;
}
if(is_bool($value)){
return $value;
}
switch(strtolower($value)){
case "on":
case "true":
case "1":
case "yes":
return true;
if(is_int($value)){
return $value !== 0;
}
if(is_string($value)){
switch(strtolower($value)){
case "on":
case "true":
case "1":
case "yes":
return true;
}
}
return false;

View File

@ -25,13 +25,14 @@ namespace pocketmine;
use pocketmine\utils\Git;
use pocketmine\utils\VersionString;
use function is_array;
use function is_int;
use function str_repeat;
final class VersionInfo{
public const NAME = "PocketMine-MP";
public const BASE_VERSION = "4.0.0-BETA4";
public const BASE_VERSION = "4.0.0-BETA14";
public const IS_DEVELOPMENT_BUILD = false;
public const BUILD_NUMBER = 0;
public const BUILD_CHANNEL = "beta";
private function __construct(){
@ -61,12 +62,29 @@ final class VersionInfo{
return self::$gitHash;
}
private static ?int $buildNumber = null;
public static function BUILD_NUMBER() : int{
if(self::$buildNumber === null){
self::$buildNumber = 0;
if(\Phar::running(true) !== ""){
$phar = new \Phar(\Phar::running(false));
$meta = $phar->getMetadata();
if(is_array($meta) && isset($meta["build"]) && is_int($meta["build"])){
self::$buildNumber = $meta["build"];
}
}
}
return self::$buildNumber;
}
/** @var VersionString|null */
private static $fullVersion = null;
public static function VERSION() : VersionString{
if(self::$fullVersion === null){
self::$fullVersion = new VersionString(self::BASE_VERSION, self::IS_DEVELOPMENT_BUILD, self::BUILD_NUMBER);
self::$fullVersion = new VersionString(self::BASE_VERSION, self::IS_DEVELOPMENT_BUILD, self::BUILD_NUMBER());
}
return self::$fullVersion;
}

View File

@ -115,7 +115,7 @@ class Bamboo extends Transparent{
return 12 + (self::getOffsetSeed($x, 0, $z) % 5);
}
public function getPositionOffset() : ?Vector3{
public function getModelPositionOffset() : ?Vector3{
$seed = self::getOffsetSeed($this->position->getFloorX(), 0, $this->position->getFloorZ());
$retX = (($seed % 12) + 1) / 16;
$retZ = ((($seed >> 8) % 12) + 1) / 16;
@ -145,12 +145,12 @@ class Bamboo extends Transparent{
public function onInteract(Item $item, int $face, Vector3 $clickVector, ?Player $player = null) : bool{
if($item instanceof Fertilizer){
$top = $this->seekToTop();
if($top->grow(self::getMaxHeight($top->position->getFloorX(), $top->position->getFloorZ()), mt_rand(1, 2))){
if($top->grow(self::getMaxHeight($top->position->getFloorX(), $top->position->getFloorZ()), mt_rand(1, 2), $player)){
$item->pop();
return true;
}
}elseif($item instanceof ItemBamboo){
if($this->seekToTop()->grow(PHP_INT_MAX, 1)){
if($this->seekToTop()->grow(PHP_INT_MAX, 1, $player)){
$item->pop();
return true;
}
@ -165,7 +165,7 @@ class Bamboo extends Transparent{
}
}
private function grow(int $maxHeight, int $growAmount) : bool{
private function grow(int $maxHeight, int $growAmount, ?Player $player) : bool{
$world = $this->position->getWorld();
if(!$world->getBlock($this->position->up())->canBeReplaced()){
return false;
@ -212,7 +212,7 @@ class Bamboo extends Transparent{
$tx->addBlock($this->position->subtract(0, $idx - $growAmount, 0), $newBlock);
}
$ev = new StructureGrowEvent($this, $tx);
$ev = new StructureGrowEvent($this, $tx, $player);
$ev->call();
if($ev->isCancelled()){
return false;
@ -229,7 +229,7 @@ class Bamboo extends Transparent{
$world = $this->position->getWorld();
if($this->ready){
$this->ready = false;
if($world->getFullLight($this->position) < 9 || !$this->grow(self::getMaxHeight($this->position->getFloorX(), $this->position->getFloorZ()), 1)){
if($world->getFullLight($this->position) < 9 || !$this->grow(self::getMaxHeight($this->position->getFloorX(), $this->position->getFloorZ()), 1, null)){
$world->setBlock($this->position, $this);
}
}elseif($world->getBlock($this->position->up())->canBeReplaced()){

View File

@ -73,7 +73,7 @@ final class BambooSapling extends Flowable{
public function onInteract(Item $item, int $face, Vector3 $clickVector, ?Player $player = null) : bool{
if($item instanceof Fertilizer || $item instanceof ItemBamboo){
if($this->grow()){
if($this->grow($player)){
$item->pop();
return true;
}
@ -87,7 +87,7 @@ final class BambooSapling extends Flowable{
}
}
private function grow() : bool{
private function grow(?Player $player) : bool{
$world = $this->position->getWorld();
if(!$world->getBlock($this->position->up())->canBeReplaced()){
return false;
@ -98,7 +98,7 @@ final class BambooSapling extends Flowable{
$tx->addBlock($this->position, $bamboo)
->addBlock($this->position->up(), (clone $bamboo)->setLeafSize(Bamboo::SMALL_LEAVES));
$ev = new StructureGrowEvent($this, $tx);
$ev = new StructureGrowEvent($this, $tx, $player);
$ev->call();
if($ev->isCancelled()){
return false;
@ -115,7 +115,7 @@ final class BambooSapling extends Flowable{
$world = $this->position->getWorld();
if($this->ready){
$this->ready = false;
if($world->getFullLight($this->position) < 9 || !$this->grow()){
if($world->getFullLight($this->position) < 9 || !$this->grow(null)){
$world->setBlock($this->position, $this);
}
}elseif($world->getBlock($this->position->up())->canBeReplaced()){

View File

@ -493,7 +493,7 @@ class Block{
return $this->position->getWorld()->getBlock($this->position->getSide($side, $step));
}
throw new \InvalidStateException("Block does not have a valid world");
throw new \LogicException("Block does not have a valid world");
}
/**
@ -577,7 +577,7 @@ class Block{
final public function getCollisionBoxes() : array{
if($this->collisionBoxes === null){
$this->collisionBoxes = $this->recalculateCollisionBoxes();
$extraOffset = $this->getPositionOffset();
$extraOffset = $this->getModelPositionOffset();
$offset = $extraOffset !== null ? $this->position->addVector($extraOffset) : $this->position;
foreach($this->collisionBoxes as $bb){
$bb->offset($offset->x, $offset->y, $offset->z);
@ -588,10 +588,10 @@ class Block{
}
/**
* Returns an additional fractional vector to shift the block's effective position by based on the current position.
* Returns an additional fractional vector to shift the block model's position by based on the current position.
* Used to randomize position of things like bamboo canes and tall grass.
*/
public function getPositionOffset() : ?Vector3{
public function getModelPositionOffset() : ?Vector3{
return null;
}

File diff suppressed because it is too large Load Diff

View File

@ -94,8 +94,7 @@ class Cake extends Transparent implements FoodSource{
public function onInteract(Item $item, int $face, Vector3 $clickVector, ?Player $player = null) : bool{
if($player !== null){
$player->consumeObject($this);
return true;
return $player->consumeObject($this);
}
return false;

View File

@ -26,6 +26,7 @@ namespace pocketmine\block;
use pocketmine\block\utils\BlockDataSerializer;
use pocketmine\block\utils\HorizontalFacingTrait;
use pocketmine\block\utils\TreeType;
use pocketmine\event\block\BlockGrowEvent;
use pocketmine\item\Fertilizer;
use pocketmine\item\Item;
use pocketmine\item\VanillaItems;
@ -94,10 +95,7 @@ class CocoaBlock extends Transparent{
}
public function onInteract(Item $item, int $face, Vector3 $clickVector, ?Player $player = null) : bool{
if($this->age < 2 and $item instanceof Fertilizer){
$this->age++;
$this->position->getWorld()->setBlock($this->position, $this);
if($item instanceof Fertilizer && $this->grow()){
$item->pop();
return true;
@ -117,12 +115,25 @@ class CocoaBlock extends Transparent{
}
public function onRandomTick() : void{
if($this->age < 2 and mt_rand(1, 5) === 1){
$this->age++;
$this->position->getWorld()->setBlock($this->position, $this);
if(mt_rand(1, 5) === 1){
$this->grow();
}
}
private function grow() : bool{
if($this->age < 2){
$block = clone $this;
$block->age++;
$ev = new BlockGrowEvent($this, $block);
$ev->call();
if(!$ev->isCancelled()){
$this->position->getWorld()->setBlock($this->position, $ev->getNewState());
return true;
}
}
return false;
}
public function getDropsForCompatibleTool(Item $item) : array{
return [
VanillaItems::COCOA_BEANS()->setCount($this->age === 2 ? mt_rand(2, 3) : 1)

View File

@ -23,7 +23,7 @@ declare(strict_types=1);
namespace pocketmine\block;
use pocketmine\crafting\CraftingGrid;
use pocketmine\block\inventory\CraftingTableInventory;
use pocketmine\item\Item;
use pocketmine\math\Vector3;
use pocketmine\player\Player;
@ -32,7 +32,7 @@ class CraftingTable extends Opaque{
public function onInteract(Item $item, int $face, Vector3 $clickVector, ?Player $player = null) : bool{
if($player instanceof Player){
$player->setCraftingGrid(new CraftingGrid($player, CraftingGrid::SIZE_BIG));
$player->setCurrentWindow(new CraftingTableInventory($this->position));
}
return true;

View File

@ -80,10 +80,9 @@ abstract class Crops extends Flowable{
$ev->call();
if(!$ev->isCancelled()){
$this->position->getWorld()->setBlock($this->position, $ev->getNewState());
$item->pop();
}
$item->pop();
return true;
}

View File

@ -0,0 +1,30 @@
<?php
/*
*
* ____ _ _ __ __ _ __ __ ____
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* @author PocketMine Team
* @link http://www.pocketmine.net/
*
*
*/
declare(strict_types=1);
namespace pocketmine\block;
class FletchingTable extends Opaque{
public function getFuelTime() : int{
return 300;
}
}

View File

@ -23,6 +23,13 @@ declare(strict_types=1);
namespace pocketmine\block;
use pocketmine\item\Item;
class Podzol extends Opaque{
public function getDropsForCompatibleTool(Item $item) : array{
return [
VanillaBlocks::DIRT()->asItem()
];
}
}

View File

@ -76,9 +76,7 @@ class Sapling extends Flowable{
}
public function onInteract(Item $item, int $face, Vector3 $clickVector, ?Player $player = null) : bool{
if($item instanceof Fertilizer){
$this->grow();
if($item instanceof Fertilizer && $this->grow($player)){
$item->pop();
return true;
@ -100,7 +98,7 @@ class Sapling extends Flowable{
public function onRandomTick() : void{
if($this->position->getWorld()->getFullLightAt($this->position->getFloorX(), $this->position->getFloorY(), $this->position->getFloorZ()) >= 8 and mt_rand(1, 7) === 1){
if($this->ready){
$this->grow();
$this->grow(null);
}else{
$this->ready = true;
$this->position->getWorld()->setBlock($this->position, $this);
@ -108,21 +106,20 @@ class Sapling extends Flowable{
}
}
private function grow() : void{
private function grow(?Player $player) : bool{
$random = new Random(mt_rand());
$tree = TreeFactory::get($random, $this->treeType);
$transaction = $tree?->getBlockTransaction($this->position->getWorld(), $this->position->getFloorX(), $this->position->getFloorY(), $this->position->getFloorZ(), $random);
if($transaction === null){
return;
return false;
}
$ev = new StructureGrowEvent($this, $transaction);
$ev = new StructureGrowEvent($this, $transaction, $player);
$ev->call();
if($ev->isCancelled()){
return;
if(!$ev->isCancelled()){
return $transaction->apply();
}
$transaction->apply();
return false;
}
public function getFuelTime() : int{

View File

@ -124,8 +124,14 @@ class Skull extends Flowable{
* @return AxisAlignedBB[]
*/
protected function recalculateCollisionBoxes() : array{
//TODO: different bounds depending on attached face
return [AxisAlignedBB::one()->contract(0.25, 0, 0.25)->trim(Facing::UP, 0.5)];
$collisionBox = AxisAlignedBB::one()->contract(0.25, 0, 0.25)->trim(Facing::UP, 0.5);
return match($this->facing){
Facing::NORTH => [$collisionBox->offset(0, 0.25, 0.25)],
Facing::SOUTH => [$collisionBox->offset(0, 0.25, -0.25)],
Facing::WEST => [$collisionBox->offset(0.25, 0.25, 0)],
Facing::EAST => [$collisionBox->offset(-0.25, 0.25, 0)],
default => [$collisionBox]
};
}
public function place(BlockTransaction $tx, Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, ?Player $player = null) : bool{

View File

@ -48,7 +48,8 @@ class Sugarcane extends Flowable{
return 0b1111;
}
private function grow() : void{
private function grow() : bool{
$grew = false;
for($y = 1; $y < 3; ++$y){
if(!$this->position->getWorld()->isInWorld($this->position->x, $this->position->y + $y, $this->position->z)){
break;
@ -61,12 +62,14 @@ class Sugarcane extends Flowable{
break;
}
$this->position->getWorld()->setBlock($b->position, $ev->getNewState());
$grew = true;
}else{
break;
}
}
$this->age = 0;
$this->position->getWorld()->setBlock($this->position, $this);
return $grew;
}
public function getAge() : int{ return $this->age; }
@ -82,12 +85,10 @@ class Sugarcane extends Flowable{
public function onInteract(Item $item, int $face, Vector3 $clickVector, ?Player $player = null) : bool{
if($item instanceof Fertilizer){
if(!$this->getSide(Facing::DOWN)->isSameType($this)){
$this->grow();
if(!$this->getSide(Facing::DOWN)->isSameType($this) && $this->grow()){
$item->pop();
}
$item->pop();
return true;
}

View File

@ -99,9 +99,9 @@ class SweetBerryBush extends Flowable{
if(!$ev->isCancelled()){
$this->position->getWorld()->setBlock($this->position, $ev->getNewState());
$item->pop();
}
$item->pop();
}elseif(($dropAmount = $this->getBerryDropAmount()) > 0){
$this->position->getWorld()->setBlock($this->position, $this->setAge(self::STAGE_BUSH_NO_BERRIES));
$this->position->getWorld()->dropItem($this->position, $this->asItem()->setCount($dropAmount));

View File

@ -24,7 +24,6 @@ declare(strict_types=1);
namespace pocketmine\block;
use pocketmine\utils\CloningRegistryTrait;
use function assert;
/**
* This doc-block is generated automatically, do not modify it manually.
@ -300,6 +299,7 @@ use function assert;
* @method static Farmland FARMLAND()
* @method static TallGrass FERN()
* @method static Fire FIRE()
* @method static FletchingTable FLETCHING_TABLE()
* @method static FlowerPot FLOWER_POT()
* @method static FrostedIce FROSTED_ICE()
* @method static Furnace FURNACE()
@ -580,12 +580,6 @@ final class VanillaBlocks{
self::_registryRegister($name, $block);
}
public static function fromString(string $name) : Block{
$result = self::_registryFromString($name);
assert($result instanceof Block);
return $result;
}
/**
* @return Block[]
*/
@ -866,6 +860,7 @@ final class VanillaBlocks{
self::register("farmland", $factory->get(60, 0));
self::register("fern", $factory->get(31, 2));
self::register("fire", $factory->get(51, 0));
self::register("fletching_table", $factory->get(456, 0));
self::register("flower_pot", $factory->get(140, 0));
self::register("frosted_ice", $factory->get(207, 0));
self::register("furnace", $factory->get(61, 2));

View File

@ -24,10 +24,10 @@ declare(strict_types=1);
namespace pocketmine\block\inventory;
use pocketmine\inventory\SimpleInventory;
use pocketmine\player\Player;
use pocketmine\inventory\TemporaryInventory;
use pocketmine\world\Position;
class AnvilInventory extends SimpleInventory implements BlockInventory{
class AnvilInventory extends SimpleInventory implements BlockInventory, TemporaryInventory{
use BlockInventoryTrait;
public const SLOT_INPUT = 0;
@ -37,13 +37,4 @@ class AnvilInventory extends SimpleInventory implements BlockInventory{
$this->holder = $holder;
parent::__construct(2);
}
public function onClose(Player $who) : void{
parent::onClose($who);
foreach($this->getContents() as $item){
$who->dropItem($item);
}
$this->clearAll();
}
}

View File

@ -25,6 +25,7 @@ namespace pocketmine\block\inventory;
use pocketmine\inventory\SimpleInventory;
use pocketmine\network\mcpe\protocol\BlockEventPacket;
use pocketmine\network\mcpe\protocol\types\BlockPosition;
use pocketmine\world\Position;
use pocketmine\world\sound\ChestCloseSound;
use pocketmine\world\sound\ChestOpenSound;
@ -50,6 +51,6 @@ class ChestInventory extends SimpleInventory implements BlockInventory{
$holder = $this->getHolder();
//event ID is always 1 for a chest
$holder->getWorld()->broadcastPacketToViewers($holder, BlockEventPacket::create(1, $isOpen ? 1 : 0, $holder->asVector3()));
$holder->getWorld()->broadcastPacketToViewers($holder, BlockEventPacket::create(BlockPosition::fromVector3($holder), 1, $isOpen ? 1 : 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\block\inventory;
use pocketmine\crafting\CraftingGrid;
use pocketmine\inventory\TemporaryInventory;
use pocketmine\world\Position;
final class CraftingTableInventory extends CraftingGrid implements BlockInventory, TemporaryInventory{
use BlockInventoryTrait;
public function __construct(Position $holder){
$this->holder = $holder;
parent::__construct(CraftingGrid::SIZE_BIG);
}
}

View File

@ -24,10 +24,10 @@ declare(strict_types=1);
namespace pocketmine\block\inventory;
use pocketmine\inventory\SimpleInventory;
use pocketmine\player\Player;
use pocketmine\inventory\TemporaryInventory;
use pocketmine\world\Position;
class EnchantInventory extends SimpleInventory implements BlockInventory{
class EnchantInventory extends SimpleInventory implements BlockInventory, TemporaryInventory{
use BlockInventoryTrait;
public const SLOT_INPUT = 0;
@ -37,13 +37,4 @@ class EnchantInventory extends SimpleInventory implements BlockInventory{
$this->holder = $holder;
parent::__construct(2);
}
public function onClose(Player $who) : void{
parent::onClose($who);
foreach($this->getContents() as $item){
$who->dropItem($item);
}
$this->clearAll();
}
}

View File

@ -28,6 +28,7 @@ use pocketmine\inventory\DelegateInventory;
use pocketmine\inventory\Inventory;
use pocketmine\inventory\PlayerEnderInventory;
use pocketmine\network\mcpe\protocol\BlockEventPacket;
use pocketmine\network\mcpe\protocol\types\BlockPosition;
use pocketmine\player\Player;
use pocketmine\world\Position;
use pocketmine\world\sound\EnderChestCloseSound;
@ -74,7 +75,7 @@ class EnderChestInventory extends DelegateInventory implements BlockInventory{
$holder = $this->getHolder();
//event ID is always 1 for a chest
$holder->getWorld()->broadcastPacketToViewers($holder, BlockEventPacket::create(1, $isOpen ? 1 : 0, $holder->asVector3()));
$holder->getWorld()->broadcastPacketToViewers($holder, BlockEventPacket::create(BlockPosition::fromVector3($holder), 1, $isOpen ? 1 : 0));
}
public function onClose(Player $who) : void{

View File

@ -24,10 +24,10 @@ declare(strict_types=1);
namespace pocketmine\block\inventory;
use pocketmine\inventory\SimpleInventory;
use pocketmine\player\Player;
use pocketmine\inventory\TemporaryInventory;
use pocketmine\world\Position;
final class LoomInventory extends SimpleInventory implements BlockInventory{
final class LoomInventory extends SimpleInventory implements BlockInventory, TemporaryInventory{
use BlockInventoryTrait;
public const SLOT_BANNER = 0;
@ -38,13 +38,4 @@ final class LoomInventory extends SimpleInventory implements BlockInventory{
$this->holder = $holder;
parent::__construct($size);
}
public function onClose(Player $who) : void{
parent::onClose($who);
foreach($this->getContents() as $item){
$who->dropItem($item);
}
$this->clearAll();
}
}

View File

@ -27,6 +27,7 @@ use pocketmine\block\BlockLegacyIds;
use pocketmine\inventory\SimpleInventory;
use pocketmine\item\Item;
use pocketmine\network\mcpe\protocol\BlockEventPacket;
use pocketmine\network\mcpe\protocol\types\BlockPosition;
use pocketmine\world\Position;
use pocketmine\world\sound\ShulkerBoxCloseSound;
use pocketmine\world\sound\ShulkerBoxOpenSound;
@ -59,6 +60,6 @@ class ShulkerBoxInventory extends SimpleInventory implements BlockInventory{
$holder = $this->getHolder();
//event ID is always 1 for a chest
$holder->getWorld()->broadcastPacketToViewers($holder, BlockEventPacket::create(1, $isOpen ? 1 : 0, $holder->asVector3()));
$holder->getWorld()->broadcastPacketToViewers($holder, BlockEventPacket::create(BlockPosition::fromVector3($holder), 1, $isOpen ? 1 : 0));
}
}

View File

@ -27,6 +27,7 @@ use pocketmine\block\utils\BlockDataSerializer;
use pocketmine\math\Facing;
use pocketmine\nbt\tag\CompoundTag;
use pocketmine\network\mcpe\protocol\BlockActorDataPacket;
use pocketmine\network\mcpe\protocol\types\BlockPosition;
use pocketmine\network\mcpe\protocol\types\CacheableNbt;
final class Bell extends Spawnable{
@ -81,6 +82,6 @@ final class Bell extends Spawnable{
$nbt->setByte(self::TAG_RINGING, 1);
$nbt->setInt(self::TAG_DIRECTION, BlockDataSerializer::writeLegacyHorizontalFacing($bellHitFace));
$nbt->setInt(self::TAG_TICKS, 0);
return BlockActorDataPacket::create($this->position->getFloorX(), $this->position->getFloorY(), $this->position->getFloorZ(), new CacheableNbt($nbt));
return BlockActorDataPacket::create(BlockPosition::fromVector3($this->position), new CacheableNbt($nbt));
}
}

View File

@ -23,8 +23,9 @@ declare(strict_types=1);
namespace pocketmine\block\tile;
use pocketmine\data\SavedDataLoadingException;
use pocketmine\math\Vector3;
use pocketmine\nbt\NbtDataException;
use pocketmine\nbt\NbtException;
use pocketmine\nbt\tag\CompoundTag;
use pocketmine\utils\SingletonTrait;
use pocketmine\utils\Utils;
@ -112,21 +113,25 @@ final class TileFactory{
/**
* @internal
* @throws NbtDataException
* @throws SavedDataLoadingException
*/
public function createFromData(World $world, CompoundTag $nbt) : ?Tile{
$type = $nbt->getString(Tile::TAG_ID, "");
if(!isset($this->knownTiles[$type])){
return null;
try{
$type = $nbt->getString(Tile::TAG_ID, "");
if(!isset($this->knownTiles[$type])){
return null;
}
$class = $this->knownTiles[$type];
assert(is_a($class, Tile::class, true));
/**
* @var Tile $tile
* @see Tile::__construct()
*/
$tile = new $class($world, new Vector3($nbt->getInt(Tile::TAG_X), $nbt->getInt(Tile::TAG_Y), $nbt->getInt(Tile::TAG_Z)));
$tile->readSaveData($nbt);
}catch(NbtException $e){
throw new SavedDataLoadingException($e->getMessage(), 0, $e);
}
$class = $this->knownTiles[$type];
assert(is_a($class, Tile::class, true));
/**
* @var Tile $tile
* @see Tile::__construct()
*/
$tile = new $class($world, new Vector3($nbt->getInt(Tile::TAG_X), $nbt->getInt(Tile::TAG_Y), $nbt->getInt(Tile::TAG_Z)));
$tile->readSaveData($nbt);
return $tile;
}

View File

@ -25,7 +25,7 @@ namespace pocketmine\block\utils;
use pocketmine\lang\KnownTranslationFactory;
use pocketmine\lang\Translatable;
use pocketmine\network\mcpe\protocol\LevelSoundEventPacket;
use pocketmine\network\mcpe\protocol\types\LevelSoundEvent;
use pocketmine\utils\EnumTrait;
/**
@ -54,18 +54,18 @@ final class RecordType{
protected static function setup() : void{
self::registerAll(
new RecordType("disk_13", "C418 - 13", LevelSoundEventPacket::SOUND_RECORD_13, KnownTranslationFactory::item_record_13_desc()),
new RecordType("disk_cat", "C418 - cat", LevelSoundEventPacket::SOUND_RECORD_CAT, KnownTranslationFactory::item_record_cat_desc()),
new RecordType("disk_blocks", "C418 - blocks", LevelSoundEventPacket::SOUND_RECORD_BLOCKS, KnownTranslationFactory::item_record_blocks_desc()),
new RecordType("disk_chirp", "C418 - chirp", LevelSoundEventPacket::SOUND_RECORD_CHIRP, KnownTranslationFactory::item_record_chirp_desc()),
new RecordType("disk_far", "C418 - far", LevelSoundEventPacket::SOUND_RECORD_FAR, KnownTranslationFactory::item_record_far_desc()),
new RecordType("disk_mall", "C418 - mall", LevelSoundEventPacket::SOUND_RECORD_MALL, KnownTranslationFactory::item_record_mall_desc()),
new RecordType("disk_mellohi", "C418 - mellohi", LevelSoundEventPacket::SOUND_RECORD_MELLOHI, KnownTranslationFactory::item_record_mellohi_desc()),
new RecordType("disk_stal", "C418 - stal", LevelSoundEventPacket::SOUND_RECORD_STAL, KnownTranslationFactory::item_record_stal_desc()),
new RecordType("disk_strad", "C418 - strad", LevelSoundEventPacket::SOUND_RECORD_STRAD, KnownTranslationFactory::item_record_strad_desc()),
new RecordType("disk_ward", "C418 - ward", LevelSoundEventPacket::SOUND_RECORD_WARD, KnownTranslationFactory::item_record_ward_desc()),
new RecordType("disk_11", "C418 - 11", LevelSoundEventPacket::SOUND_RECORD_11, KnownTranslationFactory::item_record_11_desc()),
new RecordType("disk_wait", "C418 - wait", LevelSoundEventPacket::SOUND_RECORD_WAIT, KnownTranslationFactory::item_record_wait_desc())
new RecordType("disk_13", "C418 - 13", LevelSoundEvent::RECORD_13, KnownTranslationFactory::item_record_13_desc()),
new RecordType("disk_cat", "C418 - cat", LevelSoundEvent::RECORD_CAT, KnownTranslationFactory::item_record_cat_desc()),
new RecordType("disk_blocks", "C418 - blocks", LevelSoundEvent::RECORD_BLOCKS, KnownTranslationFactory::item_record_blocks_desc()),
new RecordType("disk_chirp", "C418 - chirp", LevelSoundEvent::RECORD_CHIRP, KnownTranslationFactory::item_record_chirp_desc()),
new RecordType("disk_far", "C418 - far", LevelSoundEvent::RECORD_FAR, KnownTranslationFactory::item_record_far_desc()),
new RecordType("disk_mall", "C418 - mall", LevelSoundEvent::RECORD_MALL, KnownTranslationFactory::item_record_mall_desc()),
new RecordType("disk_mellohi", "C418 - mellohi", LevelSoundEvent::RECORD_MELLOHI, KnownTranslationFactory::item_record_mellohi_desc()),
new RecordType("disk_stal", "C418 - stal", LevelSoundEvent::RECORD_STAL, KnownTranslationFactory::item_record_stal_desc()),
new RecordType("disk_strad", "C418 - strad", LevelSoundEvent::RECORD_STRAD, KnownTranslationFactory::item_record_strad_desc()),
new RecordType("disk_ward", "C418 - ward", LevelSoundEvent::RECORD_WARD, KnownTranslationFactory::item_record_ward_desc()),
new RecordType("disk_11", "C418 - 11", LevelSoundEvent::RECORD_11, KnownTranslationFactory::item_record_11_desc()),
new RecordType("disk_wait", "C418 - wait", LevelSoundEvent::RECORD_WAIT, KnownTranslationFactory::item_record_wait_desc())
//TODO: Lena Raine - Pigstep
);
}

View File

@ -117,7 +117,7 @@ abstract class Command{
}
if($this->permissionMessage === null){
$target->sendMessage(KnownTranslationFactory::commands_generic_permission()->prefix(TextFormat::RED));
$target->sendMessage(KnownTranslationFactory::pocketmine_command_error_permission($this->name)->prefix(TextFormat::RED));
}elseif($this->permissionMessage !== ""){
$target->sendMessage(str_replace("<permission>", $permission ?? $this->permission, $this->permissionMessage));
}

View File

@ -32,7 +32,7 @@ use pocketmine\player\Player;
use function array_shift;
use function count;
use function implode;
use function preg_match;
use function inet_pton;
class BanIpCommand extends VanillaCommand{
@ -57,7 +57,7 @@ class BanIpCommand extends VanillaCommand{
$value = array_shift($args);
$reason = implode(" ", $args);
if(preg_match("/^([01]?\\d\\d?|2[0-4]\\d|25[0-5])\\.([01]?\\d\\d?|2[0-4]\\d|25[0-5])\\.([01]?\\d\\d?|2[0-4]\\d|25[0-5])\\.([01]?\\d\\d?|2[0-4]\\d|25[0-5])$/", $value)){
if(inet_pton($value) !== false){
$this->processIPBan($value, $sender, $reason);
Command::broadcastCommandMessage($sender, KnownTranslationFactory::commands_banip_success($value));

View File

@ -26,7 +26,7 @@ namespace pocketmine\command\defaults;
use pocketmine\command\CommandSender;
use pocketmine\command\utils\InvalidCommandSyntaxException;
use pocketmine\entity\effect\EffectInstance;
use pocketmine\entity\effect\VanillaEffects;
use pocketmine\entity\effect\StringToEffectParser;
use pocketmine\lang\KnownTranslationFactory;
use pocketmine\permission\DefaultPermissionNames;
use pocketmine\utils\Limits;
@ -69,9 +69,8 @@ class EffectCommand extends VanillaCommand{
return true;
}
try{
$effect = VanillaEffects::fromString($args[1]);
}catch(\InvalidArgumentException $e){
$effect = StringToEffectParser::getInstance()->parse($args[1]);
if($effect === null){
$sender->sendMessage(KnownTranslationFactory::commands_effect_notFound($args[1])->prefix(TextFormat::RED));
return true;
}

View File

@ -26,7 +26,7 @@ namespace pocketmine\command\defaults;
use pocketmine\command\CommandSender;
use pocketmine\command\utils\InvalidCommandSyntaxException;
use pocketmine\item\enchantment\EnchantmentInstance;
use pocketmine\item\enchantment\VanillaEnchantments;
use pocketmine\item\enchantment\StringToEnchantmentParser;
use pocketmine\lang\KnownTranslationFactory;
use pocketmine\permission\DefaultPermissionNames;
use pocketmine\utils\TextFormat;
@ -66,9 +66,8 @@ class EnchantCommand extends VanillaCommand{
return true;
}
try{
$enchantment = VanillaEnchantments::fromString($args[1]);
}catch(\InvalidArgumentException $e){
$enchantment = StringToEnchantmentParser::getInstance()->parse($args[1]);
if($enchantment === null){
$sender->sendMessage(KnownTranslationFactory::commands_enchant_notFound($args[1]));
return true;
}

View File

@ -68,7 +68,7 @@ class GarbageCollectorCommand extends VanillaCommand{
$sender->sendMessage(KnownTranslationFactory::pocketmine_command_gc_entities(TextFormat::RED . number_format($entitiesCollected))->prefix(TextFormat::GOLD));
$sender->sendMessage(KnownTranslationFactory::pocketmine_command_gc_cycles(TextFormat::RED . number_format($cyclesCollected))->prefix(TextFormat::GOLD));
$sender->sendMessage(KnownTranslationFactory::pocketmine_command_gc_memoryFreed(TextFormat::RED . number_format(round((($memory - memory_get_usage()) / 1024) / 1024, 2), 2) . " MB")->prefix(TextFormat::GOLD));
$sender->sendMessage(KnownTranslationFactory::pocketmine_command_gc_memoryFreed(TextFormat::RED . number_format(round((($memory - memory_get_usage()) / 1024) / 1024, 2), 2))->prefix(TextFormat::GOLD));
return true;
}
}

View File

@ -29,7 +29,7 @@ use pocketmine\command\utils\InvalidCommandSyntaxException;
use pocketmine\lang\KnownTranslationFactory;
use pocketmine\permission\DefaultPermissionNames;
use function count;
use function preg_match;
use function inet_pton;
class PardonIpCommand extends VanillaCommand{
@ -52,7 +52,7 @@ class PardonIpCommand extends VanillaCommand{
throw new InvalidCommandSyntaxException();
}
if(preg_match("/^([01]?\\d\\d?|2[0-4]\\d|25[0-5])\\.([01]?\\d\\d?|2[0-4]\\d|25[0-5])\\.([01]?\\d\\d?|2[0-4]\\d|25[0-5])\\.([01]?\\d\\d?|2[0-4]\\d|25[0-5])$/", $args[0])){
if(inet_pton($args[0]) !== false){
$sender->getServer()->getIPBans()->remove($args[0]);
$sender->getServer()->getNetwork()->unblockAddress($args[0]);
Command::broadcastCommandMessage($sender, KnownTranslationFactory::commands_unbanip_success($args[0]));

View File

@ -31,8 +31,8 @@ use pocketmine\math\Vector3;
use pocketmine\permission\DefaultPermissionNames;
use pocketmine\player\Player;
use pocketmine\utils\TextFormat;
use pocketmine\world\World;
use function count;
use function round;
class SetWorldSpawnCommand extends VanillaCommand{
@ -54,22 +54,32 @@ class SetWorldSpawnCommand extends VanillaCommand{
if($sender instanceof Player){
$location = $sender->getPosition();
$world = $location->getWorld();
$pos = $location->asVector3()->round();
$pos = $location->asVector3()->floor();
}else{
$sender->sendMessage(TextFormat::RED . "You can only perform this command as a player");
return true;
}
}elseif(count($args) === 3){
$world = $sender->getServer()->getWorldManager()->getDefaultWorld();
$pos = new Vector3($this->getInteger($sender, $args[0]), $this->getInteger($sender, $args[1]), $this->getInteger($sender, $args[2]));
if($sender instanceof Player){
$base = $sender->getPosition();
$world = $base->getWorld();
}else{
$base = new Vector3(0.0, 0.0, 0.0);
$world = $sender->getServer()->getWorldManager()->getDefaultWorld();
}
$pos = (new Vector3(
$this->getRelativeDouble($base->x, $sender, $args[0]),
$this->getRelativeDouble($base->y, $sender, $args[1], World::Y_MIN, World::Y_MAX),
$this->getRelativeDouble($base->z, $sender, $args[2]),
))->floor();
}else{
throw new InvalidCommandSyntaxException();
}
$world->setSpawnLocation($pos);
Command::broadcastCommandMessage($sender, KnownTranslationFactory::commands_setworldspawn_success((string) round($pos->x, 2), (string) round($pos->y, 2), (string) round($pos->z, 2)));
Command::broadcastCommandMessage($sender, KnownTranslationFactory::commands_setworldspawn_success((string) $pos->x, (string) $pos->y, (string) $pos->z));
return true;
}

View File

@ -32,6 +32,7 @@ use pocketmine\permission\DefaultPermissionNames;
use pocketmine\player\Player;
use pocketmine\utils\AssumptionFailedError;
use pocketmine\utils\TextFormat;
use pocketmine\world\World;
use function array_shift;
use function count;
use function round;
@ -111,9 +112,9 @@ class TeleportCommand extends VanillaCommand{
}
$x = $this->getRelativeDouble($base->x, $sender, $targetArgs[0]);
$y = $this->getRelativeDouble($base->y, $sender, $targetArgs[1], 0, 256);
$y = $this->getRelativeDouble($base->y, $sender, $targetArgs[1], World::Y_MIN, World::Y_MAX);
$z = $this->getRelativeDouble($base->z, $sender, $targetArgs[2]);
$targetLocation = new Location($x, $y, $z, $yaw, $pitch, $base->getWorld());
$targetLocation = new Location($x, $y, $z, $base->getWorld(), $yaw, $pitch);
$subject->teleport($targetLocation);
Command::broadcastCommandMessage($sender, KnownTranslationFactory::commands_tp_success_coordinates(

View File

@ -23,6 +23,7 @@ declare(strict_types=1);
namespace pocketmine\console;
use pocketmine\utils\AssumptionFailedError;
use function fclose;
use function fgets;
use function fopen;
@ -44,7 +45,9 @@ final class ConsoleReader{
fclose($this->stdin);
}
$this->stdin = fopen("php://stdin", "r");
$stdin = fopen("php://stdin", "r");
if($stdin === false) throw new AssumptionFailedError("Opening stdin should never fail");
$this->stdin = $stdin;
}
/**
@ -60,11 +63,10 @@ final class ConsoleReader{
if(($count = stream_select($r, $w, $e, 0, 200000)) === 0){ //nothing changed in 200000 microseconds
return null;
}elseif($count === false){ //stream error
$this->initStdin();
return null;
}
if(($raw = fgets($this->stdin)) === false){ //broken pipe or EOF
$this->initStdin();
usleep(200000); //prevent CPU waste if it's end of pipe
return null; //loop back round
}

View File

@ -46,7 +46,10 @@ if($socket === false){
$consoleReader = new ConsoleReader();
while(!feof($socket)){
$line = $consoleReader->readLine();
if($line !== null){
fwrite($socket, $line . "\n");
if(@fwrite($socket, ($line ?? "") . "\n") === false){
//Always send even if there's no line, to check if the parent is alive
//If the parent process was terminated forcibly, it won't close the connection properly, so feof() will return
//false even though the connection is actually broken. However, fwrite() will fail.
break;
}
}

View File

@ -31,6 +31,7 @@ use function base64_encode;
use function fgets;
use function fopen;
use function preg_replace;
use function proc_close;
use function proc_open;
use function proc_terminate;
use function sprintf;
@ -39,6 +40,7 @@ use function stream_socket_accept;
use function stream_socket_get_name;
use function stream_socket_server;
use function stream_socket_shutdown;
use function trim;
use const PHP_BINARY;
use const STREAM_SHUT_RDWR;
@ -113,7 +115,12 @@ final class ConsoleReaderThread extends Thread{
break;
}
$buffer[] = preg_replace("#\\x1b\\x5b([^\\x1b]*\\x7e|[\\x40-\\x50])#", "", $command);
$command = preg_replace("#\\x1b\\x5b([^\\x1b]*\\x7e|[\\x40-\\x50])#", "", trim($command)) ?? throw new AssumptionFailedError("This regex is assumed to be valid");
$command = preg_replace('/[[:cntrl:]]/', '', $command) ?? throw new AssumptionFailedError("This regex is assumed to be valid");
if($command === ""){
continue;
}
$buffer[] = $command;
if($notifier !== null){
$notifier->wakeupSleeper();
}
@ -124,6 +131,7 @@ final class ConsoleReaderThread extends Thread{
//gets stuck in a blocking fgets() read because stream_select() is a hunk of junk (hence the separate process in
//the first place).
proc_terminate($sub);
proc_close($sub);
stream_socket_shutdown($client, STREAM_SHUT_RDWR);
}

View File

@ -25,17 +25,14 @@ namespace pocketmine\crafting;
use pocketmine\inventory\SimpleInventory;
use pocketmine\item\Item;
use pocketmine\player\Player;
use function max;
use function min;
use const PHP_INT_MAX;
class CraftingGrid extends SimpleInventory{
abstract class CraftingGrid extends SimpleInventory{
public const SIZE_SMALL = 2;
public const SIZE_BIG = 3;
/** @var Player */
protected $holder;
/** @var int */
private $gridWidth;
@ -48,8 +45,7 @@ class CraftingGrid extends SimpleInventory{
/** @var int|null */
private $yLen;
public function __construct(Player $holder, int $gridWidth){
$this->holder = $holder;
public function __construct(int $gridWidth){
$this->gridWidth = $gridWidth;
parent::__construct($this->getGridWidth() ** 2);
}
@ -63,13 +59,6 @@ class CraftingGrid extends SimpleInventory{
$this->seekRecipeBounds();
}
/**
* @return Player
*/
public function getHolder(){
return $this->holder;
}
private function seekRecipeBounds() : void{
$minX = PHP_INT_MAX;
$maxX = 0;
@ -111,7 +100,7 @@ class CraftingGrid extends SimpleInventory{
return $this->getItem(($y + $this->startY) * $this->gridWidth + ($x + $this->startX));
}
throw new \InvalidStateException("No ingredients found in grid");
throw new \LogicException("No ingredients found in grid");
}
/**

View File

@ -21,37 +21,31 @@
declare(strict_types=1);
namespace pocketmine;
namespace pocketmine\crash;
use Composer\InstalledVersions;
use pocketmine\errorhandler\ErrorTypeToStringMap;
use pocketmine\network\mcpe\protocol\ProtocolInfo;
use pocketmine\plugin\PluginBase;
use pocketmine\plugin\PluginManager;
use pocketmine\Server;
use pocketmine\utils\AssumptionFailedError;
use pocketmine\utils\Filesystem;
use pocketmine\utils\Utils;
use pocketmine\VersionInfo;
use Webmozart\PathUtil\Path;
use function base64_encode;
use function date;
use function error_get_last;
use function fclose;
use function file;
use function file_exists;
use function file_get_contents;
use function fopen;
use function fwrite;
use function get_loaded_extensions;
use function implode;
use function is_dir;
use function is_resource;
use function json_encode;
use function json_last_error_msg;
use function ksort;
use function max;
use function mb_strtoupper;
use function microtime;
use function mkdir;
use function ob_end_clean;
use function ob_get_contents;
use function ob_start;
@ -67,9 +61,10 @@ use function zend_version;
use function zlib_encode;
use const FILE_IGNORE_NEW_LINES;
use const JSON_UNESCAPED_SLASHES;
use const PHP_EOL;
use const PHP_OS;
use const PHP_VERSION;
use const SORT_STRING;
use const ZLIB_ENCODING_DEFLATE;
class CrashDump{
@ -81,77 +76,34 @@ class CrashDump{
*/
private const FORMAT_VERSION = 4;
private const PLUGIN_INVOLVEMENT_NONE = "none";
private const PLUGIN_INVOLVEMENT_DIRECT = "direct";
private const PLUGIN_INVOLVEMENT_INDIRECT = "indirect";
public const PLUGIN_INVOLVEMENT_NONE = "none";
public const PLUGIN_INVOLVEMENT_DIRECT = "direct";
public const PLUGIN_INVOLVEMENT_INDIRECT = "indirect";
/** @var Server */
private $server;
/** @var resource */
private $fp;
/** @var float */
private $time;
/**
* @var mixed[]
* @phpstan-var array<string, mixed>
*/
private $data = [];
private CrashDumpData $data;
/** @var string */
private $encodedData = "";
/** @var string */
private $path;
private $encodedData;
public function __construct(Server $server){
$this->time = microtime(true);
private ?PluginManager $pluginManager;
public function __construct(Server $server, ?PluginManager $pluginManager){
$now = microtime(true);
$this->server = $server;
$this->pluginManager = $pluginManager;
$this->data = new CrashDumpData();
$this->data->format_version = self::FORMAT_VERSION;
$this->data->time = $now;
$this->data->uptime = $now - $this->server->getStartTime();
$crashPath = Path::join($this->server->getDataPath(), "crashdumps");
if(!is_dir($crashPath)){
mkdir($crashPath);
}
$this->path = Path::join($crashPath, 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");
}
$this->fp = $fp;
$this->data["format_version"] = self::FORMAT_VERSION;
$this->data["time"] = $this->time;
$this->data["uptime"] = $this->time - $this->server->getStartTime();
$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();
$this->pluginsData();
$this->extraData();
$this->encodeData();
fclose($this->fp);
}
public function getPath() : string{
return $this->path;
}
public function getEncodedData() : string{
return $this->encodedData;
}
/**
* @return mixed[]
* @phpstan-return array<string, mixed>
*/
public function getData() : array{
return $this->data;
}
private function encodeData() : void{
$this->addLine();
$this->addLine("----------------------REPORT THE DATA BELOW THIS LINE-----------------------");
$this->addLine();
$this->addLine("===BEGIN CRASH DUMP===");
$json = json_encode($this->data, JSON_UNESCAPED_SLASHES);
if($json === false){
throw new \RuntimeException("Failed to encode crashdump JSON: " . json_last_error_msg());
@ -159,34 +111,45 @@ class CrashDump{
$zlibEncoded = zlib_encode($json, ZLIB_ENCODING_DEFLATE, 9);
if($zlibEncoded === false) throw new AssumptionFailedError("ZLIB compression failed");
$this->encodedData = $zlibEncoded;
}
public function getEncodedData() : string{
return $this->encodedData;
}
public function getData() : CrashDumpData{
return $this->data;
}
public function encodeData(CrashDumpRenderer $renderer) : void{
$renderer->addLine();
$renderer->addLine("----------------------REPORT THE DATA BELOW THIS LINE-----------------------");
$renderer->addLine();
$renderer->addLine("===BEGIN CRASH DUMP===");
foreach(str_split(base64_encode($this->encodedData), 76) as $line){
$this->addLine($line);
$renderer->addLine($line);
}
$this->addLine("===END CRASH DUMP===");
$renderer->addLine("===END CRASH DUMP===");
}
private function pluginsData() : void{
if($this->server->getPluginManager() instanceof PluginManager){
$this->addLine();
$this->addLine("Loaded plugins:");
$this->data["plugins"] = [];
$plugins = $this->server->getPluginManager()->getPlugins();
if($this->pluginManager !== null){
$plugins = $this->pluginManager->getPlugins();
ksort($plugins, SORT_STRING);
foreach($plugins as $p){
$d = $p->getDescription();
$this->data["plugins"][$d->getName()] = [
"name" => $d->getName(),
"version" => $d->getVersion(),
"authors" => $d->getAuthors(),
"api" => $d->getCompatibleApis(),
"enabled" => $p->isEnabled(),
"depends" => $d->getDepend(),
"softDepends" => $d->getSoftDepend(),
"main" => $d->getMain(),
"load" => mb_strtoupper($d->getOrder()->name()),
"website" => $d->getWebsite()
];
$this->addLine($d->getName() . " " . $d->getVersion() . " by " . implode(", ", $d->getAuthors()) . " for API(s) " . implode(", ", $d->getCompatibleApis()));
$this->data->plugins[$d->getName()] = new CrashDumpDataPluginEntry(
name: $d->getName(),
version: $d->getVersion(),
authors: $d->getAuthors(),
api: $d->getCompatibleApis(),
enabled: $p->isEnabled(),
depends: $d->getDepend(),
softDepends: $d->getSoftDepend(),
main: $d->getMain(),
load: mb_strtoupper($d->getOrder()->name()),
website: $d->getWebsite()
);
}
}
}
@ -195,32 +158,26 @@ class CrashDump{
global $argv;
if($this->server->getConfigGroup()->getPropertyBool("auto-report.send-settings", true)){
$this->data["parameters"] = (array) $argv;
$this->data->parameters = (array) $argv;
if(($serverDotProperties = @file_get_contents(Path::join($this->server->getDataPath(), "server.properties"))) !== false){
$this->data["server.properties"] = preg_replace("#^rcon\\.password=(.*)$#m", "rcon.password=******", $serverDotProperties);
}else{
$this->data["server.properties"] = $serverDotProperties;
$this->data->serverDotProperties = preg_replace("#^rcon\\.password=(.*)$#m", "rcon.password=******", $serverDotProperties) ?? throw new AssumptionFailedError("Pattern is valid");
}
if(($pocketmineDotYml = @file_get_contents(Path::join($this->server->getDataPath(), "pocketmine.yml"))) !== false){
$this->data["pocketmine.yml"] = $pocketmineDotYml;
}else{
$this->data["pocketmine.yml"] = "";
$this->data->pocketmineDotYml = $pocketmineDotYml;
}
}else{
$this->data["pocketmine.yml"] = "";
$this->data["server.properties"] = "";
$this->data["parameters"] = [];
}
$extensions = [];
foreach(get_loaded_extensions() as $ext){
$extensions[$ext] = phpversion($ext);
$version = phpversion($ext);
if($version === false) throw new AssumptionFailedError();
$extensions[$ext] = $version;
}
$this->data["extensions"] = $extensions;
$this->data->extensions = $extensions;
if($this->server->getConfigGroup()->getPropertyBool("auto-report.send-phpinfo", true)){
ob_start();
phpinfo();
$this->data["phpinfo"] = ob_get_contents();
$this->data->phpinfo = ob_get_contents(); // @phpstan-ignore-line
ob_end_clean();
}
}
@ -252,18 +209,14 @@ class CrashDump{
if(isset($lastError["trace"])){
$lastError["trace"] = Utils::printableTrace($lastError["trace"]);
}
$this->data["lastError"] = $lastError;
$this->data->lastError = $lastError;
}
$this->data["error"] = $error;
unset($this->data["error"]["fullFile"]);
unset($this->data["error"]["trace"]);
$this->addLine("Error: " . $error["message"]);
$this->addLine("File: " . $error["file"]);
$this->addLine("Line: " . $error["line"]);
$this->addLine("Type: " . $error["type"]);
$this->data->error = $error;
unset($this->data->error["fullFile"]);
unset($this->data->error["trace"]);
$this->data["plugin_involvement"] = self::PLUGIN_INVOLVEMENT_NONE;
$this->data->plugin_involvement = self::PLUGIN_INVOLVEMENT_NONE;
if(!$this->determinePluginFromFile($error["fullFile"], true)){ //fatal errors won't leave any stack trace
foreach($error["trace"] as $frame){
if(!isset($frame["file"])){
@ -275,38 +228,25 @@ class CrashDump{
}
}
$this->addLine();
$this->addLine("Code:");
$this->data["code"] = [];
if($this->server->getConfigGroup()->getPropertyBool("auto-report.send-code", true) and file_exists($error["fullFile"])){
$file = @file($error["fullFile"], FILE_IGNORE_NEW_LINES);
if($file !== false){
for($l = max(0, $error["line"] - 10); $l < $error["line"] + 10 and isset($file[$l]); ++$l){
$this->addLine("[" . ($l + 1) . "] " . $file[$l]);
$this->data["code"][$l + 1] = $file[$l];
$this->data->code[$l + 1] = $file[$l];
}
}
}
$this->addLine();
$this->addLine("Backtrace:");
foreach(($this->data["trace"] = Utils::printableTrace($error["trace"])) as $line){
$this->addLine($line);
}
$this->addLine();
$this->data->trace = Utils::printableTrace($error["trace"]);
}
private function determinePluginFromFile(string $filePath, bool $crashFrame) : bool{
$frameCleanPath = Filesystem::cleanPath($filePath);
if(strpos($frameCleanPath, Filesystem::CLEAN_PATH_SRC_PREFIX) !== 0){
$this->addLine();
if($crashFrame){
$this->addLine("THIS CRASH WAS CAUSED BY A PLUGIN");
$this->data["plugin_involvement"] = self::PLUGIN_INVOLVEMENT_DIRECT;
$this->data->plugin_involvement = self::PLUGIN_INVOLVEMENT_DIRECT;
}else{
$this->addLine("A PLUGIN WAS INVOLVED IN THIS CRASH");
$this->data["plugin_involvement"] = self::PLUGIN_INVOLVEMENT_INDIRECT;
$this->data->plugin_involvement = self::PLUGIN_INVOLVEMENT_INDIRECT;
}
if(file_exists($filePath)){
@ -316,8 +256,7 @@ class CrashDump{
foreach($this->server->getPluginManager()->getPlugins() as $plugin){
$filePath = Filesystem::cleanPath($file->getValue($plugin));
if(strpos($frameCleanPath, $filePath) === 0){
$this->data["plugin"] = $plugin->getName();
$this->addLine("BAD PLUGIN: " . $plugin->getDescription()->getFullName());
$this->data->plugin = $plugin->getName();
break;
}
}
@ -328,7 +267,6 @@ class CrashDump{
}
private function generalData() : void{
$version = VersionInfo::VERSION();
$composerLibraries = [];
foreach(InstalledVersions::getInstalledPackages() as $package){
$composerLibraries[$package] = sprintf(
@ -338,42 +276,19 @@ class CrashDump{
);
}
$this->data["general"] = [];
$this->data["general"]["name"] = $this->server->getName();
$this->data["general"]["base_version"] = VersionInfo::BASE_VERSION;
$this->data["general"]["build"] = VersionInfo::BUILD_NUMBER;
$this->data["general"]["is_dev"] = VersionInfo::IS_DEVELOPMENT_BUILD;
$this->data["general"]["protocol"] = ProtocolInfo::CURRENT_PROTOCOL;
$this->data["general"]["git"] = VersionInfo::GIT_HASH();
$this->data["general"]["uname"] = php_uname("a");
$this->data["general"]["php"] = phpversion();
$this->data["general"]["zend"] = zend_version();
$this->data["general"]["php_os"] = PHP_OS;
$this->data["general"]["os"] = Utils::getOS();
$this->data["general"]["composer_libraries"] = $composerLibraries;
$this->addLine($this->server->getName() . " version: " . $version->getFullVersion(true) . " [Protocol " . ProtocolInfo::CURRENT_PROTOCOL . "]");
$this->addLine("Git commit: " . VersionInfo::GIT_HASH());
$this->addLine("uname -a: " . php_uname("a"));
$this->addLine("PHP Version: " . phpversion());
$this->addLine("Zend version: " . zend_version());
$this->addLine("OS : " . PHP_OS . ", " . Utils::getOS());
$this->addLine("Composer libraries: ");
foreach($composerLibraries as $library => $libraryVersion){
$this->addLine("- $library $libraryVersion");
}
}
/**
* @param string $line
*/
public function addLine($line = "") : void{
fwrite($this->fp, $line . PHP_EOL);
}
/**
* @param string $str
*/
public function add($str) : void{
fwrite($this->fp, $str);
$this->data->general = new CrashDumpDataGeneral(
name: $this->server->getName(),
base_version: VersionInfo::BASE_VERSION,
build: VersionInfo::BUILD_NUMBER(),
is_dev: VersionInfo::IS_DEVELOPMENT_BUILD,
protocol: ProtocolInfo::CURRENT_PROTOCOL,
git: VersionInfo::GIT_HASH(),
uname: php_uname("a"),
php: PHP_VERSION,
zend: zend_version(),
php_os: PHP_OS,
os: Utils::getOS(),
composer_libraries: $composerLibraries,
);
}
}

View File

@ -0,0 +1,84 @@
<?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\crash;
final class CrashDumpData implements \JsonSerializable{
public int $format_version;
public float $time;
public float $uptime;
/** @var mixed[] */
public array $lastError = [];
/** @var mixed[] */
public array $error;
public string $plugin_involvement;
public string $plugin = "";
/** @var string[] */
public array $code = [];
/** @var string[] */
public array $trace;
/**
* @var CrashDumpDataPluginEntry[]
* @phpstan-var array<string, CrashDumpDataPluginEntry>
*/
public array $plugins = [];
/** @var string[] */
public array $parameters = [];
public string $serverDotProperties = "";
public string $pocketmineDotYml = "";
/**
* @var string[]
* @phpstan-var array<string, string>
*/
public array $extensions = [];
public string $phpinfo = "";
public CrashDumpDataGeneral $general;
/**
* @return mixed[]
*/
public function jsonSerialize() : array{
$result = (array) $this;
unset($result["serverDotProperties"]);
unset($result["pocketmineDotYml"]);
$result["pocketmine.yml"] = $this->pocketmineDotYml;
$result["server.properties"] = $this->serverDotProperties;
return $result;
}
}

View File

@ -0,0 +1,46 @@
<?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\crash;
final class CrashDumpDataGeneral{
/**
* @param string[] $composer_libraries
* @phpstan-param array<string, string> $composer_libraries
*/
public function __construct(
public string $name,
public string $base_version,
public int $build,
public bool $is_dev,
public int $protocol,
public string $git,
public string $uname,
public string $php,
public string $zend,
public string $php_os,
public string $os,
public array $composer_libraries,
){}
}

View File

@ -0,0 +1,45 @@
<?php
/*
*
* ____ _ _ __ __ _ __ __ ____
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* @author PocketMine Team
* @link http://www.pocketmine.net/
*
*
*/
declare(strict_types=1);
namespace pocketmine\crash;
final class CrashDumpDataPluginEntry{
/**
* @param string[] $authors
* @param string[] $api
* @param string[] $depends
* @param string[] $softDepends
*/
public function __construct(
public string $name,
public string $version,
public array $authors,
public array $api,
public bool $enabled,
public array $depends,
public array $softDepends,
public string $main,
public string $load,
public string $website,
){}
}

View File

@ -0,0 +1,103 @@
<?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\crash;
use pocketmine\utils\Utils;
use pocketmine\utils\VersionString;
use function count;
use function date;
use function fwrite;
use function implode;
use const PHP_EOL;
final class CrashDumpRenderer{
/**
* @param resource $fp
*/
public function __construct(private $fp, private CrashDumpData $data){
}
public function renderHumanReadable() : void{
$this->addLine($this->data->general->name . " Crash Dump " . date("D M j H:i:s T Y", (int) $this->data->time));
$this->addLine();
$this->addLine("Error: " . $this->data->error["message"]);
$this->addLine("File: " . $this->data->error["file"]);
$this->addLine("Line: " . $this->data->error["line"]);
$this->addLine("Type: " . $this->data->error["type"]);
if($this->data->plugin_involvement !== CrashDump::PLUGIN_INVOLVEMENT_NONE){
$this->addLine();
$this->addLine(match($this->data->plugin_involvement){
CrashDump::PLUGIN_INVOLVEMENT_DIRECT => "THIS CRASH WAS CAUSED BY A PLUGIN",
CrashDump::PLUGIN_INVOLVEMENT_INDIRECT => "A PLUGIN WAS INVOLVED IN THIS CRASH",
default => "Unknown plugin involvement!"
});
}
if($this->data->plugin !== ""){
$this->addLine("BAD PLUGIN: " . $this->data->plugin);
}
$this->addLine();
$this->addLine("Code:");
foreach($this->data->code as $lineNumber => $line){
$this->addLine("[$lineNumber] $line");
}
$this->addLine();
$this->addLine("Backtrace:");
foreach($this->data->trace as $line){
$this->addLine($line);
}
$this->addLine();
$version = new VersionString($this->data->general->base_version, $this->data->general->is_dev, $this->data->general->build);
$this->addLine($this->data->general->name . " version: " . $version->getFullVersion(true) . " [Protocol " . $this->data->general->protocol . "]");
$this->addLine("Git commit: " . $this->data->general->git);
$this->addLine("uname -a: " . $this->data->general->uname);
$this->addLine("PHP Version: " . $this->data->general->php);
$this->addLine("Zend version: " . $this->data->general->zend);
$this->addLine("OS: " . $this->data->general->php_os . ", " . $this->data->general->os);
$this->addLine("Composer libraries: ");
foreach(Utils::stringifyKeys($this->data->general->composer_libraries) as $library => $libraryVersion){
$this->addLine("- $library $libraryVersion");
}
if(count($this->data->plugins) > 0){
$this->addLine();
$this->addLine("Loaded plugins:");
foreach($this->data->plugins as $p){
$this->addLine($p->name . " " . $p->version . " by " . implode(", ", $p->authors) . " for API(s) " . implode(", ", $p->api));
}
}
}
public function addLine(string $line = "") : void{
fwrite($this->fp, $line . PHP_EOL);
}
}

View File

@ -0,0 +1,28 @@
<?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\data;
final class SavedDataLoadingException extends \RuntimeException{
}

View File

@ -30,6 +30,6 @@ final class LegacyBlockIdToStringIdMap extends LegacyToStringBidirectionalIdMap{
use SingletonTrait;
public function __construct(){
parent::__construct(Path::join(\pocketmine\RESOURCE_PATH, 'vanilla', 'block_id_map.json'));
parent::__construct(Path::join(\pocketmine\BEDROCK_DATA_PATH, 'block_id_map.json'));
}
}

View File

@ -30,6 +30,6 @@ final class LegacyEntityIdToStringIdMap extends LegacyToStringBidirectionalIdMap
use SingletonTrait;
public function __construct(){
parent::__construct(Path::join(\pocketmine\RESOURCE_PATH, 'vanilla', 'entity_id_map.json'));
parent::__construct(Path::join(\pocketmine\BEDROCK_DATA_PATH, 'entity_id_map.json'));
}
}

View File

@ -30,6 +30,6 @@ final class LegacyItemIdToStringIdMap extends LegacyToStringBidirectionalIdMap{
use SingletonTrait;
public function __construct(){
parent::__construct(Path::join(\pocketmine\RESOURCE_PATH, 'vanilla', 'item_id_map.json'));
parent::__construct(Path::join(\pocketmine\BEDROCK_DATA_PATH, 'item_id_map.json'));
}
}

View File

@ -635,7 +635,7 @@ abstract class Entity{
$this->checkBlockIntersections();
if($this->location->y <= -16 and $this->isAlive()){
if($this->location->y <= World::Y_MIN - 16 and $this->isAlive()){
$ev = new EntityDamageEvent($this, EntityDamageEvent::CAUSE_VOID, 10);
$this->attack($ev);
$hasUpdate = true;
@ -681,10 +681,12 @@ abstract class Entity{
throw new \InvalidArgumentException("Fire ticks must be in range 0 ... " . 0x7fff . ", got $fireTicks");
}
$this->fireTicks = $fireTicks;
$this->networkPropertiesDirty = true;
}
public function extinguish() : void{
$this->fireTicks = 0;
$this->networkPropertiesDirty = true;
}
public function isFireProof() : bool{
@ -978,7 +980,7 @@ abstract class Entity{
final public function scheduleUpdate() : void{
if($this->closed){
throw new \InvalidStateException("Cannot schedule update on garbage entity " . get_class($this));
throw new \LogicException("Cannot schedule update on garbage entity " . get_class($this));
}
$this->getWorld()->updateEntities[$this->id] = $this;
}
@ -1183,9 +1185,9 @@ abstract class Entity{
($this->boundingBox->minX + $this->boundingBox->maxX) / 2,
$this->boundingBox->minY - $this->ySize,
($this->boundingBox->minZ + $this->boundingBox->maxZ) / 2,
$this->location->world,
$this->location->yaw,
$this->location->pitch,
$this->location->world
$this->location->pitch
);
$this->getWorld()->onEntityMoved($this);
@ -1416,20 +1418,21 @@ abstract class Entity{
* Called by spawnTo() to send whatever packets needed to spawn the entity to the client.
*/
protected function sendSpawnPacket(Player $player) : void{
$pk = new AddActorPacket();
$pk->entityRuntimeId = $this->getId();
$pk->type = static::getNetworkTypeId();
$pk->position = $this->location->asVector3();
$pk->motion = $this->getMotion();
$pk->yaw = $this->location->yaw;
$pk->headYaw = $this->location->yaw; //TODO
$pk->pitch = $this->location->pitch;
$pk->attributes = array_map(function(Attribute $attr) : NetworkAttribute{
return new NetworkAttribute($attr->getId(), $attr->getMinValue(), $attr->getMaxValue(), $attr->getValue(), $attr->getDefaultValue());
}, $this->attributeMap->getAll());
$pk->metadata = $this->getAllNetworkData();
$player->getNetworkSession()->sendDataPacket($pk);
$player->getNetworkSession()->sendDataPacket(AddActorPacket::create(
$this->getId(), //TODO: actor unique ID
$this->getId(),
static::getNetworkTypeId(),
$this->location->asVector3(),
$this->getMotion(),
$this->location->pitch,
$this->location->yaw,
$this->location->yaw, //TODO: head yaw
array_map(function(Attribute $attr) : NetworkAttribute{
return new NetworkAttribute($attr->getId(), $attr->getMinValue(), $attr->getMaxValue(), $attr->getValue(), $attr->getDefaultValue());
}, $this->attributeMap->getAll()),
$this->getAllNetworkData(),
[] //TODO: entity links
));
}
public function spawnTo(Player $player) : void{
@ -1437,7 +1440,7 @@ abstract class Entity{
//TODO: this will cause some visible lag during chunk resends; if the player uses a spawn egg in a chunk, the
//created entity won't be visible until after the resend arrives. However, this is better than possibly crashing
//the player by sending them entities too early.
if(!isset($this->hasSpawned[$id]) and $player->hasReceivedChunk($this->location->getFloorX() >> Chunk::COORD_BIT_SIZE, $this->location->getFloorZ() >> Chunk::COORD_BIT_SIZE)){
if(!isset($this->hasSpawned[$id]) and $player->getWorld() === $this->getWorld() and $player->hasReceivedChunk($this->location->getFloorX() >> Chunk::COORD_BIT_SIZE, $this->location->getFloorZ() >> Chunk::COORD_BIT_SIZE)){
$this->hasSpawned[$id] = $player;
$this->sendSpawnPacket($player);

View File

@ -23,6 +23,7 @@ declare(strict_types=1);
namespace pocketmine\entity;
use pocketmine\data\SavedDataLoadingException;
use pocketmine\math\Vector3;
use pocketmine\nbt\NBT;
use pocketmine\nbt\tag\CompoundTag;
@ -38,34 +39,40 @@ final class EntityDataHelper{
//NOOP
}
/**
* @throws SavedDataLoadingException
*/
public static function parseLocation(CompoundTag $nbt, World $world) : Location{
$pos = self::parseVec3($nbt, "Pos", false);
$yawPitch = $nbt->getTag("Rotation");
if(!($yawPitch instanceof ListTag) or $yawPitch->getTagType() !== NBT::TAG_Float){
throw new \UnexpectedValueException("'Rotation' should be a List<Float>");
throw new SavedDataLoadingException("'Rotation' should be a List<Float>");
}
/** @var FloatTag[] $values */
$values = $yawPitch->getValue();
if(count($values) !== 2){
throw new \UnexpectedValueException("Expected exactly 2 entries for 'Rotation'");
throw new SavedDataLoadingException("Expected exactly 2 entries for 'Rotation'");
}
return Location::fromObject($pos, $world, $values[0]->getValue(), $values[1]->getValue());
}
/**
* @throws SavedDataLoadingException
*/
public static function parseVec3(CompoundTag $nbt, string $tagName, bool $optional) : Vector3{
$pos = $nbt->getTag($tagName);
if($pos === null and $optional){
return new Vector3(0, 0, 0);
}
if(!($pos instanceof ListTag) or $pos->getTagType() !== NBT::TAG_Double){
throw new \UnexpectedValueException("'$tagName' should be a List<Double>");
if(!($pos instanceof ListTag) or ($pos->getTagType() !== NBT::TAG_Double && $pos->getTagType() !== NBT::TAG_Float)){
throw new SavedDataLoadingException("'$tagName' should be a List<Double> or List<Float>");
}
/** @var DoubleTag[] $values */
/** @var DoubleTag[]|FloatTag[] $values */
$values = $pos->getValue();
if(count($values) !== 3){
throw new \UnexpectedValueException("Expected exactly 3 entries in '$tagName' tag");
throw new SavedDataLoadingException("Expected exactly 3 entries in '$tagName' tag");
}
return new Vector3($values[0]->getValue(), $values[1]->getValue(), $values[2]->getValue());
}

View File

@ -30,6 +30,7 @@ use pocketmine\block\BlockFactory;
use pocketmine\data\bedrock\EntityLegacyIds;
use pocketmine\data\bedrock\PotionTypeIdMap;
use pocketmine\data\bedrock\PotionTypeIds;
use pocketmine\data\SavedDataLoadingException;
use pocketmine\entity\object\ExperienceOrb;
use pocketmine\entity\object\FallingBlock;
use pocketmine\entity\object\ItemEntity;
@ -45,7 +46,7 @@ use pocketmine\entity\projectile\SplashPotion;
use pocketmine\item\Item;
use pocketmine\math\Facing;
use pocketmine\math\Vector3;
use pocketmine\nbt\NbtDataException;
use pocketmine\nbt\NbtException;
use pocketmine\nbt\tag\ByteTag;
use pocketmine\nbt\tag\CompoundTag;
use pocketmine\nbt\tag\IntTag;
@ -113,12 +114,12 @@ final class EntityFactory{
$this->register(ItemEntity::class, function(World $world, CompoundTag $nbt) : ItemEntity{
$itemTag = $nbt->getCompoundTag("Item");
if($itemTag === null){
throw new \UnexpectedValueException("Expected \"Item\" NBT tag not found");
throw new SavedDataLoadingException("Expected \"Item\" NBT tag not found");
}
$item = Item::nbtDeserialize($itemTag);
if($item->isNull()){
throw new \UnexpectedValueException("Item is invalid");
throw new SavedDataLoadingException("Item is invalid");
}
return new ItemEntity(EntityDataHelper::parseLocation($nbt, $world), $item, $nbt);
}, ['Item', 'minecraft:item'], EntityLegacyIds::ITEM);
@ -126,7 +127,7 @@ final class EntityFactory{
$this->register(Painting::class, function(World $world, CompoundTag $nbt) : Painting{
$motive = PaintingMotive::getMotiveByName($nbt->getString("Motive"));
if($motive === null){
throw new \UnexpectedValueException("Unknown painting motive");
throw new SavedDataLoadingException("Unknown painting motive");
}
$blockIn = new Vector3($nbt->getInt("TileX"), $nbt->getInt("TileY"), $nbt->getInt("TileZ"));
if(($directionTag = $nbt->getTag("Direction")) instanceof ByteTag){
@ -134,7 +135,7 @@ final class EntityFactory{
}elseif(($facingTag = $nbt->getTag("Facing")) instanceof ByteTag){
$facing = Painting::DATA_TO_FACING[$facingTag->getValue()] ?? Facing::NORTH;
}else{
throw new \UnexpectedValueException("Missing facing info");
throw new SavedDataLoadingException("Missing facing info");
}
return new Painting(EntityDataHelper::parseLocation($nbt, $world), $blockIn, $facing, $motive, $nbt);
@ -151,7 +152,7 @@ final class EntityFactory{
$this->register(SplashPotion::class, function(World $world, CompoundTag $nbt) : SplashPotion{
$potionType = PotionTypeIdMap::getInstance()->fromId($nbt->getShort("PotionId", PotionTypeIds::WATER));
if($potionType === null){
throw new \UnexpectedValueException("No such potion type");
throw new SavedDataLoadingException("No such potion type");
}
return new SplashPotion(EntityDataHelper::parseLocation($nbt, $world), null, $potionType, $nbt);
}, ['ThrownPotion', 'minecraft:potion', 'thrownpotion'], EntityLegacyIds::SPLASH_POTION);
@ -222,25 +223,28 @@ final class EntityFactory{
/**
* Creates an entity from data stored on a chunk.
*
* @throws \RuntimeException
* @throws NbtDataException
* @throws SavedDataLoadingException
* @internal
*/
public function createFromData(World $world, CompoundTag $nbt) : ?Entity{
$saveId = $nbt->getTag("id") ?? $nbt->getTag("identifier");
$func = null;
if($saveId instanceof StringTag){
$func = $this->creationFuncs[$saveId->getValue()] ?? null;
}elseif($saveId instanceof IntTag){ //legacy MCPE format
$func = $this->creationFuncs[$saveId->getValue() & 0xff] ?? null;
}
if($func === null){
return null;
}
/** @var Entity $entity */
$entity = $func($world, $nbt);
try{
$saveId = $nbt->getTag("id") ?? $nbt->getTag("identifier");
$func = null;
if($saveId instanceof StringTag){
$func = $this->creationFuncs[$saveId->getValue()] ?? null;
}elseif($saveId instanceof IntTag){ //legacy MCPE format
$func = $this->creationFuncs[$saveId->getValue() & 0xff] ?? null;
}
if($func === null){
return null;
}
/** @var Entity $entity */
$entity = $func($world, $nbt);
return $entity;
return $entity;
}catch(NbtException $e){
throw new SavedDataLoadingException($e->getMessage(), 0, $e);
}
}
public function injectSaveId(string $class, CompoundTag $saveData) : void{

View File

@ -27,6 +27,8 @@ use pocketmine\entity\utils\ExperienceUtils;
use pocketmine\event\player\PlayerExperienceChangeEvent;
use pocketmine\item\Durable;
use pocketmine\item\enchantment\VanillaEnchantments;
use pocketmine\utils\AssumptionFailedError;
use pocketmine\utils\Limits;
use pocketmine\world\sound\XpCollectSound;
use pocketmine\world\sound\XpLevelUpSound;
use function array_rand;
@ -34,6 +36,7 @@ use function ceil;
use function count;
use function max;
use function min;
use function sprintf;
class ExperienceManager{
@ -141,7 +144,12 @@ class ExperienceManager{
public function setCurrentTotalXp(int $amount) : bool{
$newLevel = ExperienceUtils::getLevelFromXp($amount);
return $this->setXpAndProgress((int) $newLevel, $newLevel - ((int) $newLevel));
$xpLevel = (int) $newLevel;
$xpProgress = $newLevel - (int) $newLevel;
if($xpProgress > 1.0){
throw new AssumptionFailedError(sprintf("newLevel - (int) newLevel should never be bigger than 1, but have %.53f (newLevel=%.53f)", $xpProgress, $newLevel));
}
return $this->setXpAndProgress($xpLevel, $xpProgress);
}
/**
@ -151,6 +159,7 @@ class ExperienceManager{
* @param bool $playSound Whether to play level-up and XP gained sounds.
*/
public function addXp(int $amount, bool $playSound = true) : bool{
$amount = min($amount, Limits::INT32_MAX - $this->totalXp);
$oldLevel = $this->getXpLevel();
$oldTotal = $this->getCurrentTotalXp();
@ -223,8 +232,8 @@ class ExperienceManager{
* score when they die. (TODO: add this when MCPE supports it)
*/
public function setLifetimeTotalXp(int $amount) : void{
if($amount < 0){
throw new \InvalidArgumentException("XP must be greater than 0");
if($amount < 0 || $amount > Limits::INT32_MAX){
throw new \InvalidArgumentException("XP must be greater than 0 and less than " . Limits::INT32_MAX);
}
$this->totalXp = $amount;

View File

@ -23,6 +23,7 @@ declare(strict_types=1);
namespace pocketmine\entity;
use pocketmine\data\SavedDataLoadingException;
use pocketmine\entity\animation\TotemUseAnimation;
use pocketmine\entity\effect\EffectInstance;
use pocketmine\entity\effect\VanillaEffects;
@ -47,8 +48,10 @@ use pocketmine\nbt\tag\StringTag;
use pocketmine\network\mcpe\convert\SkinAdapterSingleton;
use pocketmine\network\mcpe\convert\TypeConverter;
use pocketmine\network\mcpe\protocol\AddPlayerPacket;
use pocketmine\network\mcpe\protocol\AdventureSettingsPacket;
use pocketmine\network\mcpe\protocol\PlayerListPacket;
use pocketmine\network\mcpe\protocol\PlayerSkinPacket;
use pocketmine\network\mcpe\protocol\types\DeviceOS;
use pocketmine\network\mcpe\protocol\types\entity\EntityIds;
use pocketmine\network\mcpe\protocol\types\entity\EntityMetadataProperties;
use pocketmine\network\mcpe\protocol\types\entity\StringMetadataProperty;
@ -102,12 +105,12 @@ class Human extends Living implements ProjectileSource, InventoryHolder{
/**
* @throws InvalidSkinException
* @throws \UnexpectedValueException
* @throws SavedDataLoadingException
*/
public static function parseSkinNBT(CompoundTag $nbt) : Skin{
$skinTag = $nbt->getCompoundTag("Skin");
if($skinTag === null){
throw new \UnexpectedValueException("Missing skin data");
throw new SavedDataLoadingException("Missing skin data");
}
return new Skin( //this throws if the skin is invalid
$skinTag->getString("Name"),
@ -145,7 +148,7 @@ class Human extends Living implements ProjectileSource, InventoryHolder{
*/
public function sendSkin(?array $targets = null) : void{
$this->server->broadcastPackets($targets ?? $this->hasSpawned, [
PlayerSkinPacket::create($this->getUniqueId(), SkinAdapterSingleton::get()->toSkinData($this->skin))
PlayerSkinPacket::create($this->getUniqueId(), "", "", SkinAdapterSingleton::get()->toSkinData($this->skin))
]);
}
@ -444,17 +447,24 @@ class Human extends Living implements ProjectileSource, InventoryHolder{
$player->getNetworkSession()->sendDataPacket(PlayerListPacket::add([PlayerListEntry::createAdditionEntry($this->uuid, $this->id, $this->getName(), SkinAdapterSingleton::get()->toSkinData($this->skin))]));
}
$pk = new AddPlayerPacket();
$pk->uuid = $this->getUniqueId();
$pk->username = $this->getName();
$pk->entityRuntimeId = $this->getId();
$pk->position = $this->location->asVector3();
$pk->motion = $this->getMotion();
$pk->yaw = $this->location->yaw;
$pk->pitch = $this->location->pitch;
$pk->item = ItemStackWrapper::legacy(TypeConverter::getInstance()->coreItemStackToNet($this->getInventory()->getItemInHand()));
$pk->metadata = $this->getAllNetworkData();
$player->getNetworkSession()->sendDataPacket($pk);
$player->getNetworkSession()->sendDataPacket(AddPlayerPacket::create(
$this->getUniqueId(),
$this->getName(),
$this->getId(), //TODO: actor unique ID
$this->getId(),
"",
$this->location->asVector3(),
$this->getMotion(),
$this->location->pitch,
$this->location->yaw,
$this->location->yaw, //TODO: head yaw
ItemStackWrapper::legacy(TypeConverter::getInstance()->coreItemStackToNet($this->getInventory()->getItemInHand())),
$this->getAllNetworkData(),
AdventureSettingsPacket::create(0, 0, 0, 0, 0, $this->getId()), //TODO
[], //TODO: entity links
"", //device ID (we intentionally don't send this - secvuln)
DeviceOS::UNKNOWN //we intentionally don't send this (secvuln)
));
//TODO: Hack for MCPE 1.2.13: DATA_NAMETAG is useless in AddPlayerPacket, so it has to be sent separately
$this->sendData([$player], [EntityMetadataProperties::NAMETAG => new StringMetadataProperty($this->getNameTag())]);

View File

@ -34,7 +34,7 @@ class Location extends Position{
/** @var float */
public $pitch;
public function __construct(float $x, float $y, float $z, float $yaw = 0.0, float $pitch = 0.0, ?World $world = null){
public function __construct(float $x, float $y, float $z, ?World $world, float $yaw, float $pitch){
$this->yaw = $yaw;
$this->pitch = $pitch;
parent::__construct($x, $y, $z, $world);
@ -44,14 +44,14 @@ class Location extends Position{
* @return Location
*/
public static function fromObject(Vector3 $pos, ?World $world, float $yaw = 0.0, float $pitch = 0.0){
return new Location($pos->x, $pos->y, $pos->z, $yaw, $pitch, $world ?? (($pos instanceof Position) ? $pos->world : null));
return new Location($pos->x, $pos->y, $pos->z, $world ?? (($pos instanceof Position) ? $pos->world : null), $yaw, $pitch);
}
/**
* Return a Location instance
*/
public function asLocation() : Location{
return new Location($this->x, $this->y, $this->z, $this->yaw, $this->pitch, $this->world);
return new Location($this->x, $this->y, $this->z, $this->world, $this->yaw, $this->pitch);
}
public function getYaw() : float{

View File

@ -25,6 +25,7 @@ namespace pocketmine\entity\animation;
use pocketmine\entity\Living;
use pocketmine\network\mcpe\protocol\ActorEventPacket;
use pocketmine\network\mcpe\protocol\types\ActorEvent;
final class ArmSwingAnimation implements Animation{
@ -37,7 +38,7 @@ final class ArmSwingAnimation implements Animation{
public function encode() : array{
return [
ActorEventPacket::create($this->entity->getId(), ActorEventPacket::ARM_SWING, 0)
ActorEventPacket::create($this->entity->getId(), ActorEvent::ARM_SWING, 0)
];
}
}

View File

@ -25,6 +25,7 @@ namespace pocketmine\entity\animation;
use pocketmine\entity\projectile\Arrow;
use pocketmine\network\mcpe\protocol\ActorEventPacket;
use pocketmine\network\mcpe\protocol\types\ActorEvent;
class ArrowShakeAnimation implements Animation{
@ -40,7 +41,7 @@ class ArrowShakeAnimation implements Animation{
public function encode() : array{
return [
ActorEventPacket::create($this->arrow->getId(), ActorEventPacket::ARROW_SHAKE, $this->durationInTicks)
ActorEventPacket::create($this->arrow->getId(), ActorEvent::ARROW_SHAKE, $this->durationInTicks)
];
}
}

View File

@ -27,6 +27,7 @@ use pocketmine\entity\Human;
use pocketmine\item\Item;
use pocketmine\network\mcpe\convert\ItemTranslator;
use pocketmine\network\mcpe\protocol\ActorEventPacket;
use pocketmine\network\mcpe\protocol\types\ActorEvent;
final class ConsumingItemAnimation implements Animation{
@ -45,7 +46,7 @@ final class ConsumingItemAnimation implements Animation{
[$netId, $netData] = ItemTranslator::getInstance()->toNetworkId($this->item->getId(), $this->item->getMeta());
return [
//TODO: need to check the data values
ActorEventPacket::create($this->human->getId(), ActorEventPacket::EATING_ITEM, ($netId << 16) | $netData)
ActorEventPacket::create($this->human->getId(), ActorEvent::EATING_ITEM, ($netId << 16) | $netData)
];
}
}

View File

@ -25,6 +25,7 @@ namespace pocketmine\entity\animation;
use pocketmine\entity\Living;
use pocketmine\network\mcpe\protocol\ActorEventPacket;
use pocketmine\network\mcpe\protocol\types\ActorEvent;
final class DeathAnimation implements Animation{
@ -37,7 +38,7 @@ final class DeathAnimation implements Animation{
public function encode() : array{
return [
ActorEventPacket::create($this->entity->getId(), ActorEventPacket::DEATH_ANIMATION, 0)
ActorEventPacket::create($this->entity->getId(), ActorEvent::DEATH_ANIMATION, 0)
];
}
}

View File

@ -25,6 +25,7 @@ namespace pocketmine\entity\animation;
use pocketmine\entity\Living;
use pocketmine\network\mcpe\protocol\ActorEventPacket;
use pocketmine\network\mcpe\protocol\types\ActorEvent;
final class HurtAnimation implements Animation{
@ -37,7 +38,7 @@ final class HurtAnimation implements Animation{
public function encode() : array{
return [
ActorEventPacket::create($this->entity->getId(), ActorEventPacket::HURT_ANIMATION, 0)
ActorEventPacket::create($this->entity->getId(), ActorEvent::HURT_ANIMATION, 0)
];
}
}

View File

@ -25,6 +25,7 @@ namespace pocketmine\entity\animation;
use pocketmine\entity\Living;
use pocketmine\network\mcpe\protocol\ActorEventPacket;
use pocketmine\network\mcpe\protocol\types\ActorEvent;
final class RespawnAnimation implements Animation{
@ -37,7 +38,7 @@ final class RespawnAnimation implements Animation{
public function encode() : array{
return [
ActorEventPacket::create($this->entity->getId(), ActorEventPacket::RESPAWN, 0)
ActorEventPacket::create($this->entity->getId(), ActorEvent::RESPAWN, 0)
];
}
}

View File

@ -25,6 +25,7 @@ namespace pocketmine\entity\animation;
use pocketmine\entity\Squid;
use pocketmine\network\mcpe\protocol\ActorEventPacket;
use pocketmine\network\mcpe\protocol\types\ActorEvent;
final class SquidInkCloudAnimation implements Animation{
@ -37,7 +38,7 @@ final class SquidInkCloudAnimation implements Animation{
public function encode() : array{
return [
ActorEventPacket::create($this->squid->getId(), ActorEventPacket::SQUID_INK_CLOUD, 0)
ActorEventPacket::create($this->squid->getId(), ActorEvent::SQUID_INK_CLOUD, 0)
];
}
}

View File

@ -25,6 +25,7 @@ namespace pocketmine\entity\animation;
use pocketmine\entity\Human;
use pocketmine\network\mcpe\protocol\ActorEventPacket;
use pocketmine\network\mcpe\protocol\types\ActorEvent;
final class TotemUseAnimation implements Animation{
@ -38,7 +39,7 @@ final class TotemUseAnimation implements Animation{
public function encode() : array{
return [
ActorEventPacket::create($this->human->getId(), ActorEventPacket::CONSUME_TOTEM, 0)
ActorEventPacket::create($this->human->getId(), ActorEvent::CONSUME_TOTEM, 0)
];
}
}

View File

@ -38,12 +38,14 @@ class Effect{
* @param Translatable|string $name Translation key used for effect name
* @param Color $color Color of bubbles given by this effect
* @param bool $bad Whether the effect is harmful
* @param int $defaultDuration
* @param bool $hasBubbles Whether the effect has potion bubbles. Some do not (e.g. Instant Damage has its own particles instead of bubbles)
*/
public function __construct(
protected Translatable|string $name,
protected Color $color,
protected bool $bad = false,
private int $defaultDuration = 600,
protected bool $hasBubbles = true
){}
@ -73,7 +75,7 @@ class Effect{
* Returns the default duration (in ticks) this effect will apply for if a duration is not specified.
*/
public function getDefaultDuration() : int{
return 600;
return $this->defaultDuration;
}
/**

View File

@ -23,10 +23,13 @@ declare(strict_types=1);
namespace pocketmine\entity\effect;
use pocketmine\color\Color;
use pocketmine\lang\Translatable;
abstract class InstantEffect extends Effect{
public function getDefaultDuration() : int{
return 1;
public function __construct(Translatable|string $name, Color $color, bool $bad = false, bool $hasBubbles = true){
parent::__construct($name, $color, $bad, 1, $hasBubbles);
}
public function canTick(EffectInstance $instance) : bool{

View File

@ -34,8 +34,8 @@ class PoisonEffect extends Effect{
/** @var bool */
private $fatal;
public function __construct(Translatable|string $name, Color $color, bool $isBad = false, bool $hasBubbles = true, bool $fatal = false){
parent::__construct($name, $color, $isBad, $hasBubbles);
public function __construct(Translatable|string $name, Color $color, bool $isBad = false, int $defaultDuration = 600, bool $hasBubbles = true, bool $fatal = false){
parent::__construct($name, $color, $isBad, $defaultDuration, $hasBubbles);
$this->fatal = $fatal;
}

View File

@ -0,0 +1,73 @@
<?php
/*
*
* ____ _ _ __ __ _ __ __ ____
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* @author PocketMine Team
* @link http://www.pocketmine.net/
*
*
*/
declare(strict_types=1);
namespace pocketmine\entity\effect;
use pocketmine\utils\SingletonTrait;
use pocketmine\utils\StringToTParser;
/**
* Handles parsing effect types from strings. This is used to interpret names in the /effect command.
*
* @phpstan-extends StringToTParser<Effect>
*/
final class StringToEffectParser extends StringToTParser{
use SingletonTrait;
private static function make() : self{
$result = new self;
$result->register("absorption", fn() => VanillaEffects::ABSORPTION());
$result->register("blindness", fn() => VanillaEffects::BLINDNESS());
$result->register("conduit_power", fn() => VanillaEffects::CONDUIT_POWER());
$result->register("fatal_poison", fn() => VanillaEffects::FATAL_POISON());
$result->register("fire_resistance", fn() => VanillaEffects::FIRE_RESISTANCE());
$result->register("haste", fn() => VanillaEffects::HASTE());
$result->register("health_boost", fn() => VanillaEffects::HEALTH_BOOST());
$result->register("hunger", fn() => VanillaEffects::HUNGER());
$result->register("instant_damage", fn() => VanillaEffects::INSTANT_DAMAGE());
$result->register("instant_health", fn() => VanillaEffects::INSTANT_HEALTH());
$result->register("invisibility", fn() => VanillaEffects::INVISIBILITY());
$result->register("jump_boost", fn() => VanillaEffects::JUMP_BOOST());
$result->register("levitation", fn() => VanillaEffects::LEVITATION());
$result->register("mining_fatigue", fn() => VanillaEffects::MINING_FATIGUE());
$result->register("nausea", fn() => VanillaEffects::NAUSEA());
$result->register("night_vision", fn() => VanillaEffects::NIGHT_VISION());
$result->register("poison", fn() => VanillaEffects::POISON());
$result->register("regeneration", fn() => VanillaEffects::REGENERATION());
$result->register("resistance", fn() => VanillaEffects::RESISTANCE());
$result->register("saturation", fn() => VanillaEffects::SATURATION());
$result->register("slowness", fn() => VanillaEffects::SLOWNESS());
$result->register("speed", fn() => VanillaEffects::SPEED());
$result->register("strength", fn() => VanillaEffects::STRENGTH());
$result->register("water_breathing", fn() => VanillaEffects::WATER_BREATHING());
$result->register("weakness", fn() => VanillaEffects::WEAKNESS());
$result->register("wither", fn() => VanillaEffects::WITHER());
return $result;
}
public function parse(string $input) : ?Effect{
return parent::parse($input);
}
}

View File

@ -26,7 +26,6 @@ namespace pocketmine\entity\effect;
use pocketmine\color\Color;
use pocketmine\lang\KnownTranslationFactory;
use pocketmine\utils\RegistryTrait;
use function assert;
/**
* This doc-block is generated automatically, do not modify it manually.
@ -69,7 +68,7 @@ final class VanillaEffects{
//TODO: bad_omen
self::register("blindness", new Effect(KnownTranslationFactory::potion_blindness(), new Color(0x1f, 0x1f, 0x23), true));
self::register("conduit_power", new Effect(KnownTranslationFactory::potion_conduitPower(), new Color(0x1d, 0xc2, 0xd1)));
self::register("fatal_poison", new PoisonEffect(KnownTranslationFactory::potion_poison(), new Color(0x4e, 0x93, 0x31), true, true, true));
self::register("fatal_poison", new PoisonEffect(KnownTranslationFactory::potion_poison(), new Color(0x4e, 0x93, 0x31), true, 600, true, true));
self::register("fire_resistance", new Effect(KnownTranslationFactory::potion_fireResistance(), new Color(0xe4, 0x9a, 0x3a)));
self::register("haste", new Effect(KnownTranslationFactory::potion_digSpeed(), new Color(0xd9, 0xc0, 0x43)));
self::register("health_boost", new HealthBoostEffect(KnownTranslationFactory::potion_healthBoost(), new Color(0xf8, 0x7d, 0x23)));
@ -85,7 +84,7 @@ final class VanillaEffects{
self::register("poison", new PoisonEffect(KnownTranslationFactory::potion_poison(), new Color(0x4e, 0x93, 0x31), true));
self::register("regeneration", new RegenerationEffect(KnownTranslationFactory::potion_regeneration(), new Color(0xcd, 0x5c, 0xab)));
self::register("resistance", new Effect(KnownTranslationFactory::potion_resistance(), new Color(0x99, 0x45, 0x3a)));
self::register("saturation", new SaturationEffect(KnownTranslationFactory::potion_saturation(), new Color(0xf8, 0x24, 0x23), false));
self::register("saturation", new SaturationEffect(KnownTranslationFactory::potion_saturation(), new Color(0xf8, 0x24, 0x23)));
//TODO: slow_falling
self::register("slowness", new SlownessEffect(KnownTranslationFactory::potion_moveSlowdown(), new Color(0x5a, 0x6c, 0x81), true));
self::register("speed", new SpeedEffect(KnownTranslationFactory::potion_moveSpeed(), new Color(0x7c, 0xaf, 0xc6)));
@ -109,10 +108,4 @@ final class VanillaEffects{
$result = self::_registryGetAll();
return $result;
}
public static function fromString(string $name) : Effect{
$result = self::_registryFromString($name);
assert($result instanceof Effect);
return $result;
}
}

View File

@ -206,14 +206,15 @@ class ItemEntity extends Entity{
}
protected function sendSpawnPacket(Player $player) : void{
$pk = new AddItemActorPacket();
$pk->entityRuntimeId = $this->getId();
$pk->position = $this->location->asVector3();
$pk->motion = $this->getMotion();
$pk->item = ItemStackWrapper::legacy(TypeConverter::getInstance()->coreItemStackToNet($this->getItem()));
$pk->metadata = $this->getAllNetworkData();
$player->getNetworkSession()->sendDataPacket($pk);
$player->getNetworkSession()->sendDataPacket(AddItemActorPacket::create(
$this->getId(), //TODO: entity unique ID
$this->getId(),
ItemStackWrapper::legacy(TypeConverter::getInstance()->coreItemStackToNet($this->getItem())),
$this->location->asVector3(),
$this->getMotion(),
$this->getAllNetworkData(),
false //TODO: I have no idea what this is needed for, but right now we don't support fishing anyway
));
}
public function getOffsetPosition(Vector3 $vector3) : Vector3{
@ -227,8 +228,8 @@ class ItemEntity extends Entity{
$item = $this->getItem();
$playerInventory = match(true){
$player->getOffHandInventory()->getItem(0)->canStackWith($item) and $player->getOffHandInventory()->canAddItem($item) => $player->getOffHandInventory(),
$player->getInventory()->canAddItem($item) => $player->getInventory(),
$player->getOffHandInventory()->getItem(0)->canStackWith($item) and $player->getOffHandInventory()->getAddableItemQuantity($item) > 0 => $player->getOffHandInventory(),
$player->getInventory()->getAddableItemQuantity($item) > 0 => $player->getInventory(),
default => null
};
@ -246,7 +247,12 @@ class ItemEntity extends Entity{
$viewer->getNetworkSession()->onPlayerPickUpItem($player, $this);
}
$ev->getInventory()?->addItem($ev->getItem());
$inventory = $ev->getInventory();
if($inventory !== null){
foreach($inventory->addItem($ev->getItem()) as $remains){
$this->getWorld()->dropItem($this->location, $remains, new Vector3(0, 0, 0));
}
}
$this->flagForDespawn();
}
}

View File

@ -149,17 +149,17 @@ class Painting extends Entity{
}
protected function sendSpawnPacket(Player $player) : void{
$pk = new AddPaintingPacket();
$pk->entityRuntimeId = $this->getId();
$pk->position = new Vector3(
($this->boundingBox->minX + $this->boundingBox->maxX) / 2,
($this->boundingBox->minY + $this->boundingBox->maxY) / 2,
($this->boundingBox->minZ + $this->boundingBox->maxZ) / 2
);
$pk->direction = self::FACING_TO_DATA[$this->facing];
$pk->title = $this->motive->getName();
$player->getNetworkSession()->sendDataPacket($pk);
$player->getNetworkSession()->sendDataPacket(AddPaintingPacket::create(
$this->getId(), //TODO: entity unique ID
$this->getId(),
new Vector3(
($this->boundingBox->minX + $this->boundingBox->maxX) / 2,
($this->boundingBox->minY + $this->boundingBox->maxY) / 2,
($this->boundingBox->minZ + $this->boundingBox->maxZ) / 2
),
self::FACING_TO_DATA[$this->facing],
$this->motive->getName()
));
}
/**

View File

@ -175,6 +175,7 @@ class Arrow extends Projectile{
$item = VanillaItems::ARROW();
$playerInventory = match(true){
!$player->hasFiniteResources() => null, //arrows are not picked up in creative
$player->getOffHandInventory()->getItem(0)->canStackWith($item) and $player->getOffHandInventory()->canAddItem($item) => $player->getOffHandInventory(),
$player->getInventory()->canAddItem($item) => $player->getInventory(),
default => null

View File

@ -77,32 +77,28 @@ abstract class Projectile extends Entity{
$this->setHealth(1);
$this->damage = $nbt->getDouble("damage", $this->damage);
do{
$blockPos = null;
$blockId = null;
$blockData = null;
(function() use ($nbt) : void{
if(($tileXTag = $nbt->getTag("tileX")) instanceof IntTag and ($tileYTag = $nbt->getTag("tileY")) instanceof IntTag and ($tileZTag = $nbt->getTag("tileZ")) instanceof IntTag){
$blockPos = new Vector3($tileXTag->getValue(), $tileYTag->getValue(), $tileZTag->getValue());
}else{
break;
return;
}
if(($blockIdTag = $nbt->getTag("blockId")) instanceof IntTag){
$blockId = $blockIdTag->getValue();
}else{
break;
return;
}
if(($blockDataTag = $nbt->getTag("blockData")) instanceof ByteTag){
$blockData = $blockDataTag->getValue();
}else{
break;
return;
}
$this->blockHit = BlockFactory::getInstance()->get($blockId, $blockData);
$this->blockHit->position($this->getWorld(), $blockPos->getFloorX(), $blockPos->getFloorY(), $blockPos->getFloorZ());
}while(false);
})();
}
public function canCollideWith(Entity $entity) : bool{
@ -170,7 +166,7 @@ abstract class Projectile extends Entity{
return $this->blockHit === null and parent::hasMovementUpdate();
}
public function move(float $dx, float $dy, float $dz) : void{
protected function move(float $dx, float $dy, float $dz) : void{
$this->blocksAround = null;
Timings::$entityMove->startTiming();

View File

@ -47,7 +47,7 @@ class HandlerList{
*/
public function register(RegisteredListener $listener) : void{
if(isset($this->handlerSlots[$listener->getPriority()][spl_object_id($listener)])){
throw new \InvalidStateException("This listener is already registered to priority {$listener->getPriority()} of event {$this->class}");
throw new \InvalidArgumentException("This listener is already registered to priority {$listener->getPriority()} of event {$this->class}");
}
$this->handlerSlots[$listener->getPriority()][spl_object_id($listener)] = $listener;
}

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