Compare commits

...

586 Commits

Author SHA1 Message Date
178dcb71a9 Release 4.0.2 2021-12-12 23:27:50 +00:00
0a58fd5472 GeneratorManager: fixed addGenerator() being case-sensitive when overwrite=true
this was caused by 083a1e1ff6.

This was discovered by a new PHPStan rule I'm working on, which disallows overwriting the values of parameter variables. During the refactor of this function to correct the error, another error appeared: Variable might not be defined.

This is yet another excellent example of why mutability is bad.
2021-12-12 21:58:07 +00:00
e06eefeab0 build/generate-known-translation-apis: fixed incorrect positional parameter order
closes #4639
2021-12-11 21:28:52 +00:00
ede07c4314 Mark KnownTranslationKeys and KnownTranslationFactory as @internal 2021-12-11 21:24:18 +00:00
cba00bf1e2 Merge branch 'stable' of github.com:pmmp/PocketMine-MP into stable 2021-12-10 23:24:38 +00:00
e81bee3866 ConsoleReaderThread: disable opcache for console reader subprocess 2021-12-10 23:24:18 +00:00
e6b85988b2 Bump fgrosse/phpasn1 from 2.3.0 to 2.3.1 (#4636)
Bumps [fgrosse/phpasn1](https://github.com/fgrosse/PHPASN1) from 2.3.0 to 2.3.1.
- [Release notes](https://github.com/fgrosse/PHPASN1/releases)
- [Changelog](https://github.com/fgrosse/PHPASN1/blob/master/CHANGELOG.md)
- [Commits](https://github.com/fgrosse/PHPASN1/compare/v2.3.0...v2.3.1)

---
updated-dependencies:
- dependency-name: fgrosse/phpasn1
  dependency-type: direct:production
  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-12-10 22:37:28 +00:00
b50591303b README: make shield show download count for 4.0.1, not 3.26.3 2021-12-10 20:23:48 +00:00
448f26cefc SimpleCommandMap: do not strip backslashes from unquoted command arguments 2021-12-10 18:27:49 +00:00
fa48100da5 PluginDescription: ensure base type of decoded document is actually an array
fixes #4628
2021-12-10 18:08:50 +00:00
bcf8a3424c Merge branch 'legacy/pm3' into stable 2021-12-10 18:02:06 +00:00
69d5bfa0d4 3.26.4 is next 2021-12-10 17:55:11 +00:00
549fb923bf Release 3.26.3 2021-12-10 17:55:07 +00:00
6d5c463bdd PlayerExperienceChangeEvent: added range checks to setNewProgress()
WE FINALLY FUCKING FOUND IT

This took several years to identify because PHP's exception stack traces don't show the actual values of parameters, but rather the values of the variables they were assigned to.

This means that if the parameter variable is mutated, the exception trace will show the value of the variable inside the function, not the value that was actually passed.
2021-12-10 17:29:57 +00:00
911ad344c9 Human: do not mutate parameter variables in setXpAndProgress()
this caused a mystery that took 3 entire years to debug.
2021-12-10 17:27:28 +00:00
3b77462935 WritableBookBase: fixed crash when finding pages containing corrupted UTF-8 characters
maybe we should treat this as corrupted? but for now, it's consistent with how we deal with signs.
2021-12-10 16:39:13 +00:00
6b40ed7bf8 Merge branch 'stable' of github.com:pmmp/PocketMine-MP into stable 2021-12-10 16:32:32 +00:00
1ed9302f5a ItemEntity: clone items given to the constructor directly
this fixes some bizarre mutability issues that occurred when using World->dropItem() with the same object multiple times.
2021-12-10 16:31:56 +00:00
b3dab0beef readme: added total downloads & latest downloads badges
[ci skip]
2021-12-10 00:40:29 +00:00
6ddaed97fa 4.0.2 is next 2021-12-09 00:48:45 +00:00
036b90d247 Release 4.0.1 2021-12-09 00:48:42 +00:00
d909cd8a91 Merge branch 'legacy/pm3' into stable 2021-12-09 00:33:05 +00:00
06eaf9f273 3.26.3 is next 2021-12-09 00:27:03 +00:00
1e56ed2ea3 Release 3.26.2 2021-12-09 00:26:59 +00:00
dccb8a3595 Merge branch 'legacy/pm3' into stable 2021-12-09 00:00:11 +00:00
0ace807756 Merge commit 'b081394125f90c14d6894b24e2edb32f3284b3a0' into stable 2021-12-08 23:59:51 +00:00
40895a86e5 draft-release: stick a banner on the release notes to declare obsolescence 2021-12-08 23:55:43 +00:00
b081394125 Do not restrict the allowed update channels client-side
we really should have an endpoint on the server that deals with this.
2021-12-08 21:57:16 +00:00
f48cf68cac updater: log a message when an update was found, but it's an older version 2021-12-08 21:55:44 +00:00
264cff70ec Release new PM3 builds onto pm3 channel 2021-12-08 21:55:12 +00:00
3aabfa4ab0 bootstrap: display value of PHPRC when PHP binary is borked
PHPRC overrides the search path for php.ini, which might break the php.ini locating.
2021-12-08 20:48:44 +00:00
0793e7e094 PluginLoadabilityChecker: fixed logic of extension compatibility check
if the extension doesn't specify any version, we can't do any constraint other than *.
2021-12-08 20:08:53 +00:00
3d9e19546f EntityShootBowEvent: fixed incorrect field type 2021-12-07 23:35:45 +00:00
e0eeb87ea0 World: simplify tile position checking code 2021-12-07 16:45:20 +00:00
78ffad5ffc World: add checks for tile position outside of world bounds, closes #4622 2021-12-07 16:41:52 +00:00
5a351d3b17 StringToItemParser: fixed not recognizing slime or slime_block 2021-12-06 23:51:30 +00:00
0c012ca5d9 Replace usages of ItemFactory in tests with VanillaItems 2021-12-06 23:45:36 +00:00
0530cb72df StringToItemParser: fixed some bogus aliases inherited from Item::fromString() 2021-12-06 23:44:41 +00:00
ee060f3e02 Update PHPUnit dependency junk 2021-12-06 16:42:40 +00:00
e7deffa9af Update in-house dependency versions 2021-12-06 16:41:43 +00:00
6e4b73c183 FallingBlock: fixed crash when block is unable to be determined 2021-12-06 16:40:47 +00:00
62f150586f Bump pocketmine/locale-data from 2.0.20 to 2.0.22 (#4621)
Bumps [pocketmine/locale-data](https://github.com/pmmp/Language) from 2.0.20 to 2.0.22.
- [Release notes](https://github.com/pmmp/Language/releases)
- [Commits](https://github.com/pmmp/Language/compare/2.0.20...2.0.22)

---
updated-dependencies:
- dependency-name: pocketmine/locale-data
  dependency-type: direct:production
  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-12-06 15:01:12 +00:00
8ed9551ac9 Bump pocketmine/binaryutils from 0.2.2 to 0.2.3 (#4620)
Bumps [pocketmine/binaryutils](https://github.com/pmmp/BinaryUtils) from 0.2.2 to 0.2.3.
- [Release notes](https://github.com/pmmp/BinaryUtils/releases)
- [Commits](https://github.com/pmmp/BinaryUtils/compare/0.2.2...0.2.3)

---
updated-dependencies:
- dependency-name: pocketmine/binaryutils
  dependency-type: direct:production
  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-12-06 14:59:42 +00:00
4d2d0f1d35 changelog: mention removal of Player->getLowerCaseName()
closes #4618
2021-12-06 00:58:21 +00:00
cac9db9bcc changelog: fixed mistake in CreativeInventory documentation, closes #4616 2021-12-05 15:01:45 +00:00
300d194185 CS again 2021-12-05 01:09:03 +00:00
13340a21d3 fix CS 2021-12-05 01:01:16 +00:00
27f599793a tools: added old-but-gold server-ping.php 2021-12-05 01:00:24 +00:00
527e975fa9 shut 2021-12-05 00:45:23 +00:00
8e37f86480 Avoid file_put_contents() when overwriting files
this fixes many cases of corruption during disk-full situations - file_put_contents() would write an empty file, destroying the original data.
fixes #3152
2021-12-05 00:26:48 +00:00
8e8cee45b8 Config: use JSON_THROW_ON_ERROR for encoding 2021-12-04 21:44:12 +00:00
1a046c6cd5 LevelDB: fixed server crash when corrupted / invalid blockstate NBT is encountered 2021-12-04 18:17:17 +00:00
e61aaaccca LevelDB: removed hack for problem fixed by 1f9400f901 2021-12-04 16:20:57 +00:00
1b86355c40 Server: Suppress "Minecraft network interface running" messages if RakLibInterface registration is cancelled (#4603) 2021-12-02 20:29:01 +00:00
1669d33f7e Updated DevTools submodule to pmmp/DevTools@39510af5bc 2021-12-02 00:58:15 +00:00
2da65c5a6e 4.0.1 is next 2021-12-01 22:33:58 +00:00
468faa464b Release 4.0.0 2021-12-01 22:33:52 +00:00
59de045ecb PM4 LET'S GOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO
Merge branch 'master' into stable
2021-12-01 22:19:37 +00:00
bd8308cc6f changelog: mention pocketmine subdirectory removal 2021-12-01 22:15:38 +00:00
edc3bae172 Merge branch 'stable' 2021-12-01 22:11:44 +00:00
06e7030817 Prepare changelog for 4.0.0 2021-12-01 22:09:34 +00:00
cb0af44ccb start.sh: improve errors when PHP isn't found 2021-11-30 23:51:35 +00:00
d535f02096 Make nicer errors for PHP binary not being found 2021-11-30 23:45:25 +00:00
7665f4f443 start.sh: remove 7 2021-11-30 23:43:17 +00:00
20d6b69813 3.26.2 is next 2021-11-30 22:27:42 +00:00
6b7d0307af Release 3.26.1 2021-11-30 22:27:42 +00:00
baeac2eb07 Fixed tiles not being sent with chunks 2021-11-30 22:19:28 +00:00
2850ea1e89 4.0.0-BETA16 is next 2021-11-30 19:27:05 +00:00
d560cf17fc Release 4.0.0-BETA15 2021-11-30 19:27:04 +00:00
3f6efd0018 Merge branch 'stable' 2021-11-30 19:20:40 +00:00
aea124af74 Fix inconsistent class name 2021-11-30 19:17:26 +00:00
8620e67d88 Protocol changes for 1.18.0 2021-11-30 19:16:38 +00:00
d5f81fe261 3.26.1 is next 2021-11-30 18:53:36 +00:00
0aeac3af7d Release 3.26.0 2021-11-30 18:53:36 +00:00
9931c1d50a Protocol changes for 1.18.0 2021-11-30 18:46:29 +00:00
d21a3d8750 4.0.0-BETA15 is next 2021-11-30 01:26:07 +00:00
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
9e6d740570 Release 4.0.0-BETA4 2021-10-06 23:49:13 +01:00
8e3772ceef Block: fixed incorrect behaviour of isSameState() for multi-ID blocks
fixes #4492
2021-10-06 23:16:03 +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
90800a4124 Config: Try to coerce types, similar to YAML 2021-10-06 21:09:23 +01:00
4b00465e24 Clean PHPStan baselines 2021-10-06 02:14:30 +01:00
10b3596eef PluginDescription: use typed properties 2021-10-06 02:00:55 +01:00
258c38f9cd PluginDescription: loosen invalid permission message (it might be wrong type as well as not existing) 2021-10-06 01:45:40 +01:00
d07517fe8b Use an object to represent command entries in plugin manifest 2021-10-06 01:42:03 +01:00
31a176286d Do not register plugin commands without valid permissions
this could lead to harmful results, e.g. if a developer typo'd while writing the plugin.yml, an admin-only command could become accessible to everyone, since commands are by default accessible by everyone.
2021-10-06 01:18:14 +01:00
1fafce6d6f PluginBase: remove special true/false handling for command permissions
these aren't accepted as permission names anymore, and they never worked properly anyway.
2021-10-06 01:12:02 +01:00
5061bbbc25 fuck you git x2 2021-10-06 01:01:20 +01:00
a101d1cdf9 Drop pocketmine.plugin.fileError in favour of pocketmine.plugin.loadError
fileError was unnecessarily noisy, putting the directory path on the console twice. This conveys just as much information but with less wasted space.
2021-10-05 23:31:00 +01:00
fec48003d9 ..... 2021-10-05 20:29:24 +01:00
e25c03eec1 Gracefully handle errors loading plugin manifest
this isn't perfect, but it covers the common cases.
Now, the server won't spam crashdumps just because some plugin declared nested permissions.
2021-10-05 20:28:43 +01:00
7245d15abe PermissionParser: Throw more specific exceptions 2021-10-05 19:57:26 +01:00
13178a47a5 fuck you git 2021-10-05 19:11:10 +01:00
817ab88c70 Properly handle errors decoding network item NBT
since the NBT is now decoded immediately now, any incorrect NBT will cause exceptions to be thrown that we weren't handling, causing server crashes.
2021-10-05 19:10:55 +01:00
fef8297907 GiveCommand: don't crash on bogus item NBT 2021-10-05 19:09:46 +01:00
dbeaf27cb7 Document that Item::setNamedTag() may cause NbtException to be thrown
if the NBT is bogus for some reason
in PM3, these kinds of bugs wouldn't show up until/unless the item NBT was actually used, but on PM4, we decode it ahead of time, so the errors always show up immediately.
2021-10-05 19:09:22 +01:00
2db79cf58d Fix build 2021-10-05 18:41:47 +01:00
7d06b76aaf PluginManager: account for possible invalid format of API version
we're seeing a lot of crashes because of this.
2021-10-05 18:36:00 +01:00
0ad663ff50 Merge remote-tracking branch 'origin/stable' 2021-10-05 01:17:59 +01:00
a27c14c00c phpstan: exclude build/php from analysis
in case I built PHP in there, I don't want the install_data getting analysed and screwing up the analysis.
2021-10-05 00:14:44 +00:00
5b26abcb0e NetworkSession: fixed code copy pasta
these are not, in fact, equivalent.
2021-10-05 01:02:15 +01:00
f2d6059613 NetworkSession: Sync world spawn on world change 2021-10-04 22:51:31 +01:00
bb6ea8cbdc Do not call PlayerLoginEvent during the Player constructor
this closes a lot of loopholes in the login sequence that plugins were using to cause crashes.
2021-10-04 22:36:50 +01:00
356a49d225 NetworkSession: account for possibility of syncGameMode() being called before the player is ready to receive it
close #4323
2021-10-04 22:13:42 +01:00
6332af3e59 Require RakLib 0.14.2 minimum 2021-10-04 21:50:11 +01:00
fb570970a8 Localize gamemode command errors 2021-10-02 21:22:54 +01:00
30e10c38b6 Localize /help 2021-10-02 20:59:36 +01:00
05dc675d5b Replace commands.generic.notFound with a custom PM version
this also fixes #4379.
2021-10-02 20:42:59 +01:00
d63b9d1648 WorldManager: localize strings for world loading, generation and conversion 2021-10-02 20:33:32 +01:00
f9e6fd44bc Merge branch 'stable'
it looks like I goofed up the last merge and the changelog didn't get
merged into master.
2021-10-02 20:18:06 +01:00
0108888450 Process: silence taskkill complaining that it can't commit suicide
since taskkill is a subprocess of the server process, it gets included in taskkill's own attempted killing spree, but taskkill (wisely) won't kill itself.
2021-10-02 17:23:26 +01:00
dd0c2fed82 Process: add subprocess parameter to kill()
fix CommandReader subprocess lingering on a crash and fucking up the console
2021-10-02 16:56:24 +01:00
2566123e49 Remove unnecessary constant from PHPStan bootstrap 2021-10-02 16:34:38 +01:00
54174eefa0 Make sure COMPOSER_AUTOLOADER_PATH is always declared
Sacrifice dynamic composer autoloader path to do this, because we don't
need it anyway - it was a misconceived feature from the days when I used
the same workspace for PM3 and PM4 both.
2021-10-02 15:27:17 +01:00
f5266ec816 World: remove dead code leftover from 34f01a3ce3
fixes #4486
2021-10-02 12:33:46 +01:00
c6b2c63a9b Remove a couple more dead errors from PHPStan baseline 2021-10-02 00:52:47 +01:00
f26f063164 UPnP: catch InternetException when attempting portforward
we might fail to get the internal IP for some reason, which shouldn't crash the server.
2021-10-02 00:52:14 +01:00
81d5598e96 UPnP: Fixed server crash on failure to find UPnP device
https://crash.pmmp.io/view/5241010
2021-10-01 23:27:58 +01:00
c7e9138994 PopulationTask: reduce code duplication 2021-10-01 23:18:56 +01:00
88f799da2c more AssumptionFailedError hacks for PHPStan :(
the code in this class is really horrible
2021-10-01 23:05:48 +01:00
8de30e8162 FastChunkSerializer no longer serializes light by default
the core doesn't use this anywhere.
serializeWithoutLight() has been renamed to serializeTerrain() to more accurately describe what it does.
2021-10-01 22:57:22 +01:00
e6f6a036ef LightPopulationTask: do not copy existing light arrays
this task wipes out the light arrays and recalculates them from scratch, so it's pointless to copy any preexisting light arrays anyway.
2021-10-01 22:34:11 +01:00
32f8b8163e Clean out PHPStan l7 baseline 2021-10-01 22:19:36 +01:00
5b818827db Chunk: stop exposing SplFixedArray<SubChunk> to the API
this fixes a large number of PHPStan errors, and also brings us a step closer to negative-build-height readiness.
2021-10-01 22:17:28 +01:00
42bf9578ce Remove unused constants 2021-10-01 22:05:03 +01:00
aee4a00a50 Updated dependencies 2021-10-01 21:40:31 +01:00
2fdd8d039e RakLib 0.14.1 2021-10-01 21:39:26 +01:00
349f37b15f resource packs: manifest may also contain a list of dependencies
... which we should be verifying the presence of, as the server.
2021-10-01 21:14:28 +01:00
afa3349c04 Acknowledge the presence of capabilities field in resource pack manifest
closes #4485
2021-10-01 21:09:53 +01:00
6a8280b1ba Lever: add block property APIs 2021-09-29 00:20:57 +01:00
003c002208 Bump phpunit/phpunit from 9.5.9 to 9.5.10 (#4482)
Bumps [phpunit/phpunit](https://github.com/sebastianbergmann/phpunit) from 9.5.9 to 9.5.10.
- [Release notes](https://github.com/sebastianbergmann/phpunit/releases)
- [Changelog](https://github.com/sebastianbergmann/phpunit/blob/master/ChangeLog-9.5.md)
- [Commits](https://github.com/sebastianbergmann/phpunit/compare/9.5.9...9.5.10)

---
updated-dependencies:
- dependency-name: phpunit/phpunit
  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-09-28 21:04:11 +01:00
d417b1e2f5 Projectile: fixed move() not using the given parameters (#4481)
it was using this->motion instead, which usually would be the same, but maybe not.
2021-09-28 21:03:03 +01:00
65e468e3c2 Updated build/php submodule to pmmp/php-build-scripts@6aac46e500 2021-09-28 21:00:13 +01:00
a11cf8c296 Update PHP versions used by GitHub Actions 2021-09-28 20:52:40 +01:00
c931c52617 AsyncTask: added newline 2021-09-27 13:53:30 +01:00
b3e8314b9f PTHREADS_INHERIT_CONSTANTS is no longer needed for MainLogger to log exceptions
cleaned paths are now referenced from Filesystem instead of namespace constants.
2021-09-26 21:41:24 +01:00
f138004913 PlayerDeathEvent: fixed property type variance issue PHPStan complains about 2021-09-26 21:20:42 +01:00
8e2d06a880 ChunkSerializer: support writing 0 bpb palettes on the wire
these are now supported as of 1.17.30.
2021-09-25 01:17:32 +01:00
eb80515e99 Fixed incorrect parameter checking in BlockFactory::get() (#4476) 2021-09-24 15:47:11 +01:00
1cb540387c 4.0.0-BETA4 is next 2021-09-23 21:51:36 +01:00
9bc07a9cc0 Release 4.0.0-BETA3 2021-09-23 21:51:23 +01:00
5f1e66478b changelog: mention UPnP API changes 2021-09-22 23:12:56 +01:00
36b8217e68 Updated to RakLib 0.14.0 2021-09-22 23:05:24 +01:00
d455188d03 3.23.2 is next 2021-09-22 01:00:50 +01:00
14fba36636 Release 3.23.1 2021-09-22 01:00:50 +01:00
43ac3fbf3e actions: use newer PHP versions 2021-09-22 00:51:06 +01:00
352162a6e6 Fixed PHP 7.4 build 2021-09-22 00:50:00 +01:00
b3601c9390 Regenerate PHPStan baselines 2021-09-22 00:45:07 +01:00
817fec9e3d EducationSettingsPacket: safeguard against purity issue reported by PHPStan
while annoying, PHPStan is right to complain about this, because putBool() is impure, meaning that these fields could have been mutated in the call.
We know they didn't, but PHPStan doesn't, and we can't mark the method as pure because .. well .. it isn't.
2021-09-22 00:44:52 +01:00
3813caf5ec Updated BedrockProtocol and BedrockData for 1.17.30 2021-09-22 00:36:21 +01:00
e472c117e0 Merge branch 'stable' 2021-09-22 00:33:49 +01:00
ceeef7c729 3.23.1 is next 2021-09-22 00:29:24 +01:00
7f1b2a0ee5 Release 3.23.0 2021-09-22 00:29:24 +01:00
27324a3aeb Protocol changes for 1.17.30 2021-09-22 00:26:39 +01:00
133398c69a changelog: add newline
[ci skip]
2021-09-19 22:57:22 +01:00
52b6952771 changelog: baseline for 4.0.0-BETA3
[ci skip]
2021-09-19 22:55:48 +01:00
1ce388ca0b Liquid: add getMinAdjacentSourcesToFormSource(), remove circular dependency between Liquid and Water
this unpleasantly-named method allows controlling the source-forming behaviour of liquids by changing the required number of adjacent sources that must be present in order for a new source to form. This allows stuff like non-infinite water.
2021-09-19 15:59:16 +01:00
971cbe3929 Liquid: restore mistakenly removed check 2021-09-19 15:42:17 +01:00
18de35ffc7 Liquid: use facing instead of hardcoded integers 2021-09-19 15:37:03 +01:00
576c33ee8f Liquid: make flow vector calculation less cancerous to read 2021-09-18 23:04:28 +01:00
6b2ab15ea1 MinimumCostFlowCalculator: fix bug caused by recent change 2021-09-18 16:20:01 +01:00
027f7e249b MinimumCostFlowCalculator: Use match statements where possible
coincidentally, this also fixes the build.
2021-09-18 16:17:08 +01:00
a9c4238c59 Liquid: Extract a big chunk of code to MinimumCostFlowCalculator 2021-09-18 16:13:38 +01:00
34e1b244fa Liquid: split canFlowInto() over multiple lines
the original version is very hard to read.
2021-09-18 15:53:54 +01:00
b047100719 Liquid: improve minimum cost calculation handling 2021-09-18 15:52:16 +01:00
1b5071e074 Liquid: make some code slightly less cancerous to read 2021-09-18 15:28:45 +01:00
3836a57ba6 Player: add getPlayerInfo(), closes #4450 2021-09-17 22:17:36 +01:00
87dc763d92 actions: test that generated code is consistent 2021-09-17 16:46:27 +01:00
43b2e1a0e8 tools/convert-world: improve error messages and exit codes
die with a string exits with zero? wtf?
2021-09-16 15:28:20 +01:00
05e2bef5ce ItemFactory: fix crash when checking if blockitem IDs are registered 2021-09-16 14:53:19 +01:00
6cf181b579 LevelDB: Use arrow functions for better readability 2021-09-16 14:44:56 +01:00
9490b78640 Move packet handler default implementations to BedrockProtocol
in many cases this will now require zero changes to PM at all to be compatible with a new protocol version.
2021-09-15 22:27:49 +01:00
59f3622f69 changelog: mention PluginLoadOrder changes (#4458)
[ci skip]
2021-09-15 17:18:53 +01:00
a1c82da2f2 Liquid: remove useless continue 2021-09-12 16:03:52 +01:00
84170ad3e1 Furnace: fixed deactivation after being reloaded from disk (regression from PM3)
closes #4430
2021-09-12 15:49:33 +01:00
ace8841d5d Explosion: allow the normal blockupdate mechanism to deal with explosions
in PM4, all blockupdates are buffered, so the old 7x performance penalty that used to be incurred by doing this is no longer a problem.
Also, this actually reduces the overhead of explosions themselves by moving the onNearbyBlockChange() burden off explodeB() and into the main world ticking function.
2021-09-12 15:45:02 +01:00
5ddd94b7e8 Remove redundant World->isChunkGenerated() calls
isChunkGenerated() merely checks if the chunk can be loaded from disk, if it's not in the runtime cache already.
This is pointless in all of these cases, because the check is prefaced by an isChunkLoaded() check, which already limits the possibility anyway. If the chunk is not generated, it'll also be considered not loaded.
2021-09-12 15:21:09 +01:00
f0fa561c2f World: use arrow functions in useBreakOn() 2021-09-12 15:16:55 +01:00
33a7c05425 Updated PHPStan baselines 2021-09-11 23:12:43 +01:00
273aa8ab42 Drop useless usage translation strings for commands with no parameters 2021-09-11 17:06:26 +01:00
3b7580688c Stop auto-translating string descriptions/usages for commands
Require usage of Translatable for translations.
2021-09-11 16:46:40 +01:00
b65e3c69b1 4.0.0-BETA3 is next 2021-09-10 17:18:32 +01:00
367 changed files with 11698 additions and 6756 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

@ -13,20 +13,14 @@ jobs:
strategy:
matrix:
image: [ubuntu-20.04]
php: [8.0.9]
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
@ -37,28 +31,16 @@ jobs:
fail-fast: false
matrix:
image: [ubuntu-20.04]
php: [8.0.9]
php: [8.0.11]
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
@ -87,30 +69,16 @@ jobs:
fail-fast: false
matrix:
image: [ubuntu-20.04]
php: [8.0.9]
php: [8.0.11]
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
@ -139,30 +107,18 @@ jobs:
fail-fast: false
matrix:
image: [ubuntu-20.04]
php: [8.0.9]
php: [8.0.11]
steps:
- uses: actions/checkout@v2
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
@ -183,6 +139,52 @@ jobs:
- name: Run integration tests
run: ./tests/travis.sh -t4
codegen:
name: Generated Code consistency checks
needs: build-php
runs-on: ${{ matrix.image }}
strategy:
fail-fast: false
matrix:
image: [ubuntu-20.04]
php: [8.0.11]
steps:
- uses: actions/checkout@v2
- name: Setup PHP
uses: pmmp/setup-php-action@e232f72a4330a07aae8418e8aa56b64efcdda636
with:
php-version: ${{ matrix.php }}
install-path: "./bin"
- name: Install Composer
run: curl -sS https://getcomposer.org/installer | php
- name: Restore Composer package cache
uses: actions/cache@v2
with:
path: |
~/.cache/composer/files
~/.cache/composer/vcs
key: "composer-v2-cache-${{ matrix.php }}-${{ hashFiles('./composer.lock') }}"
restore-keys: |
composer-v2-cache-
- name: Install Composer dependencies
run: php composer.phar install --no-dev --prefer-dist --no-interaction
- name: Regenerate registry annotations
run: php build/generate-registry-annotations.php src
- name: Regenerate KnownTranslation APIs
run: php build/generate-known-translation-apis.php
- name: Verify code is unchanged
run: |
git diff
git diff --quiet
codestyle:
name: Code Style checks
runs-on: ubuntu-20.04
@ -193,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,9 +5,12 @@
<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>
<br>
<img alt="GitHub all releases" src="https://img.shields.io/github/downloads/pmmp/PocketMine-MP/total?label=downloads%40total">
<img alt="GitHub release (latest by SemVer)" src="https://img.shields.io/github/downloads/pmmp/PocketMine-MP/latest/total?sort=semver">
</p>
## Getting started

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;
@ -40,6 +41,7 @@ use function preg_match_all;
use function str_replace;
use function strtoupper;
use const INI_SCANNER_RAW;
use const SORT_NUMERIC;
use const SORT_STRING;
use const STDERR;
@ -94,13 +96,15 @@ function generate_known_translation_keys(array $languageDefinitions) : void{
/**
* This class contains constants for all the translations known to PocketMine-MP as per the used version of pmmp/Language.
* This class is generated automatically, do NOT modify it by hand.
*
* @internal
*/
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";
@ -126,6 +130,8 @@ function generate_known_translation_factory(array $languageDefinitions) : void{
* This class contains factory methods for all the translations known to PocketMine-MP as per the used version of
* pmmp/Language.
* This class is generated automatically, do NOT modify it by hand.
*
* @internal
*/
final class KnownTranslationFactory{
@ -135,17 +141,22 @@ HEADER;
$parameterRegex = '/{%(.+?)}/';
$translationContainerClass = (new \ReflectionClass(Translatable::class))->getShortName();
foreach($languageDefinitions as $key => $value){
foreach(Utils::stringifyKeys($languageDefinitions) as $key => $value){
$parameters = [];
$allParametersPositional = true;
if(preg_match_all($parameterRegex, $value, $matches) > 0){
foreach($matches[1] as $parameterName){
if(is_numeric($parameterName)){
$parameters[$parameterName] = "param$parameterName";
}else{
$parameters[$parameterName] = $parameterName;
$allParametersPositional = false;
}
}
}
if($allParametersPositional){
ksort($parameters, SORT_NUMERIC);
}
echo "\tpublic static function " .
functionify($key) .
"(" . implode(", ", array_map(fn(string $paramName) => "$translationContainerClass|string \$$paramName", $parameters)) . ") : $translationContainerClass{\n";
@ -172,7 +183,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

14
changelogs/3.23.md Normal file
View File

@ -0,0 +1,14 @@
**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.23.0
- Added support for Minecraft: Bedrock Edition 1.17.30.
- Removed compatibility with earlier versions.
# 3.23.1
- Fixed broken build of 3.23.0.

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.

23
changelogs/3.26.md Normal file
View File

@ -0,0 +1,23 @@
**For Minecraft: Bedrock Edition 1.18.0**
### Note about API versions
Plugins which don't touch the protocol and compatible with any previous 3.x.y version will also run on these releases and do not need API bumps.
Plugin developers should **only** update their required API to this version if you need the changes in this build.
**WARNING: If your plugin uses the protocol, you're not shielded by API change constraints.** You should consider using the `mcpe-protocol` directive in `plugin.yml` as a constraint if you do.
# 3.26.0
- Added support for Minecraft: Bedrock Edition 1.18.0.
- Removed compatibility with earlier versions.
# 3.26.1
- Fixed a bug in chunk sending that caused double chests to not be paired, signs to be blank, and various other issues.
# 3.26.2
- Improved error messages shown by `start.cmd`, `start.sh` and `start.ps1` when the PHP binary was not found.
- The value of PHPRC is now shown when erroring out due to unsatisfied PHP requirements.
- Removed restriction on the range of valid channels for `auto-updater.channel` in `pocketmine.yml`.
# 3.26.3
- `PlayerExperienceChangeEvent->setNewProgress()` now performs range checks. This fixes the root of a very old and confusing crash bug which took several years to identify the cause of.
- Note that the defective plugin(s) which caused this problem will still cause a server crash, but the plugin responsible will now get blamed correctly.

1767
changelogs/4.0-beta.md Normal file

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -7,7 +7,7 @@
"require": {
"php": "^8.0",
"php-64bit": "*",
"ext-chunkutils2": "^0.3.0",
"ext-chunkutils2": "^0.3.1",
"ext-crypto": "^0.3.1",
"ext-ctype": "*",
"ext-curl": "*",
@ -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": "1.0.0+bedrock1.17.10",
"pocketmine/bedrock-data": "^1.5.0+bedrock-1.18.0",
"pocketmine/bedrock-protocol": "^7.0.0+bedrock-1.18.0",
"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.13.1",
"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"

748
composer.lock generated

File diff suppressed because it is too large Load Diff

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:
@ -38,6 +34,9 @@ parameters:
- tests/phpunit
- tests/plugins/TesterPlugin
- tools
excludePaths:
analyseAndScan:
- build/php
dynamicConstantNames:
- pocketmine\VersionInfo::IS_DEVELOPMENT_BUILD
- pocketmine\DEBUG
@ -54,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 95b9c82f25

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,3 +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;
}
@ -205,6 +213,8 @@ JIT_WARNING
}
critical_error("PHP binary used: " . $binary);
critical_error("Loaded php.ini: " . (($file = php_ini_loaded_file()) !== false ? $file : "none"));
$phprc = getenv("PHPRC");
critical_error("Value of PHPRC environment variable: " . ($phprc === false ? "" : $phprc));
critical_error("Please recompile PHP with the needed configuration, or refer to the installation instructions at http://pmmp.rtfd.io/en/rtfd/installation.html.");
echo PHP_EOL;
exit(1);
@ -214,20 +224,13 @@ JIT_WARNING
error_reporting(-1);
set_ini_entries();
$opts = getopt("", ["bootstrap:"]);
if(isset($opts["bootstrap"])){
$bootstrap = ($real = realpath($opts["bootstrap"])) !== false ? $real : $opts["bootstrap"];
}else{
$bootstrap = dirname(__FILE__, 2) . '/vendor/autoload.php';
}
if($bootstrap === false or !is_file($bootstrap)){
$bootstrap = dirname(__FILE__, 2) . '/vendor/autoload.php';
if(!is_file($bootstrap)){
critical_error("Composer autoloader not found at " . $bootstrap);
critical_error("Please install/update Composer dependencies or use provided builds.");
exit(1);
}
define('pocketmine\COMPOSER_AUTOLOADER_PATH', $bootstrap);
require_once(\pocketmine\COMPOSER_AUTOLOADER_PATH);
require_once($bootstrap);
$composerGitHash = InstalledVersions::getReference('pocketmine/pocketmine-mp');
if($composerGitHash !== null){
@ -307,7 +310,7 @@ JIT_WARNING
if(ThreadManager::getInstance()->stopAll() > 0){
$logger->debug("Some threads could not be stopped, performing a force-kill");
Process::kill(Process::pid());
Process::kill(Process::pid(), true);
}
}while(false);

View File

@ -34,12 +34,15 @@ 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;
use pocketmine\event\HandlerListManager;
use pocketmine\event\player\PlayerCreationEvent;
use pocketmine\event\player\PlayerDataSaveEvent;
use pocketmine\event\player\PlayerLoginEvent;
use pocketmine\event\server\CommandEvent;
use pocketmine\event\server\DataPacketSendEvent;
use pocketmine\event\server\QueryRegenerateEvent;
@ -63,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;
@ -80,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;
@ -96,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;
@ -105,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;
@ -251,6 +260,8 @@ class Server{
/** @var Player[] */
private array $playerList = [];
private SignalHandler $signalHandler;
/**
* @var CommandSender[][]
* @phpstan-var array<string, array<int, CommandSender>>
@ -316,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));
}
@ -332,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;
}
@ -517,9 +537,13 @@ class Server{
if(!$ev->isCancelled()){
Timings::$syncPlayerDataSave->time(function() use ($name, $ev) : void{
$nbt = new BigEndianNbtSerializer();
$contents = zlib_encode($nbt->write(new TreeRoot($ev->getSaveData())), ZLIB_ENCODING_GZIP);
if($contents === false){
throw new AssumptionFailedError("zlib_encode() failed unexpectedly");
}
try{
file_put_contents($this->getPlayerDataPath($name), zlib_encode($nbt->write(new TreeRoot($ev->getSaveData())), ZLIB_ENCODING_GZIP));
}catch(\ErrorException $e){
Filesystem::safeFilePutContents($this->getPlayerDataPath($name), $contents);
}catch(\RuntimeException | \ErrorException $e){
$this->logger->critical($this->getLanguage()->translate(KnownTranslationFactory::pocketmine_data_saveError($name, $e->getMessage())));
$this->logger->logException($e);
}
@ -546,11 +570,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;
}
@ -570,16 +594,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();
}
/**
@ -735,7 +759,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);
@ -744,6 +768,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,
@ -774,6 +803,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,
@ -923,7 +954,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);
@ -966,91 +997,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);
}
@ -1085,6 +1042,153 @@ 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;
}
if($rakLibRegistered){
$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.
@ -1109,7 +1213,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);
}
}
@ -1293,20 +1397,17 @@ class Server{
$commandLine = $ev->getCommand();
}
if($this->commandMap->dispatch($sender, $commandLine)){
return true;
}
$sender->sendMessage(KnownTranslationFactory::commands_generic_notFound()->prefix(TextFormat::RED));
return false;
return $this->commandMap->dispatch($sender, $commandLine);
}
/**
* 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{
@ -1318,6 +1419,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);
@ -1371,7 +1475,7 @@ class Server{
}catch(\Throwable $e){
$this->logger->logException($e);
$this->logger->emergency("Crashed while crashing, killing process");
@Process::kill(Process::pid());
@Process::kill(Process::pid(), true);
}
}
@ -1416,6 +1520,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){
@ -1430,9 +1553,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;
@ -1444,8 +1569,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");
@ -1453,7 +1578,7 @@ class Server{
}
}
if($dump->getData()["error"]["type"] === \ParseError::class){
if($dump->getData()->error["type"] === \ParseError::class){
$report = false;
}
@ -1501,7 +1626,7 @@ class Server{
echo "--- Waiting $spacing seconds to throttle automatic restart (you can kill the process safely now) ---" . PHP_EOL;
sleep($spacing);
}
@Process::kill(Process::pid());
@Process::kill(Process::pid(), true);
exit(1);
}
@ -1527,7 +1652,28 @@ class Server{
}
}
public function addOnlinePlayer(Player $player) : void{
public function addOnlinePlayer(Player $player) : bool{
$ev = new PlayerLoginEvent($player, "Plugin reason");
$ev->call();
if($ev->isCancelled() or !$player->isConnected()){
$player->disconnect($ev->getKickMessage());
return false;
}
$session = $player->getNetworkSession();
$position = $player->getPosition();
$this->logger->info($this->language->translate(KnownTranslationFactory::pocketmine_player_logIn(
TextFormat::AQUA . $player->getName() . TextFormat::WHITE,
$session->getIp(),
(string) $session->getPort(),
(string) $player->getId(),
$position->getWorld()->getDisplayName(),
(string) round($position->x, 4),
(string) round($position->y, 4),
(string) round($position->z, 4)
)));
foreach($this->playerList as $p){
$p->getNetworkSession()->onPlayerAdded($player);
}
@ -1537,6 +1683,8 @@ class Server{
if($this->sendUsageTicker > 0){
$this->uniquePlayers[$rawUUID] = $rawUUID;
}
return true;
}
public function removeOnlinePlayer(Player $player) : void{

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,14 +25,15 @@ 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-BETA2";
public const BASE_VERSION = "4.0.2";
public const IS_DEVELOPMENT_BUILD = false;
public const BUILD_NUMBER = 0;
public const BUILD_CHANNEL = "beta";
public const BUILD_CHANNEL = "stable";
private function __construct(){
//NOOP
@ -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

@ -37,8 +37,6 @@ use pocketmine\world\BlockTransaction;
use pocketmine\world\sound\BellRingSound;
final class Bell extends Transparent{
private const BELL_RINGING_REPEAT_TICKS = 20;
use HorizontalFacingTrait;
private BellAttachmentType $attachmentType;

View File

@ -179,7 +179,7 @@ class Block{
* Returns whether the given block has the same type and properties as this block.
*/
public function isSameState(Block $other) : bool{
return $this->isSameType($other) and $this->writeStateToMeta() === $other->writeStateToMeta();
return $this->getFullId() === $other->getFullId();
}
/**
@ -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,50 +23,72 @@ declare(strict_types=1);
namespace pocketmine\block;
use pocketmine\block\utils\BlockDataSerializer;
use pocketmine\block\utils\LeverFacing;
use pocketmine\item\Item;
use pocketmine\math\Axis;
use pocketmine\math\Facing;
use pocketmine\math\Vector3;
use pocketmine\player\Player;
use pocketmine\utils\AssumptionFailedError;
use pocketmine\world\BlockTransaction;
use pocketmine\world\sound\RedstonePowerOffSound;
use pocketmine\world\sound\RedstonePowerOnSound;
class Lever extends Flowable{
protected const BOTTOM = 0;
protected const SIDE = 1;
protected const TOP = 2;
protected LeverFacing $facing;
protected bool $activated = false;
protected int $leverPos = self::BOTTOM;
protected int $facing = Facing::NORTH;
protected bool $powered = false;
public function __construct(BlockIdentifier $idInfo, string $name, BlockBreakInfo $breakInfo){
$this->facing = LeverFacing::UP_AXIS_X();
parent::__construct($idInfo, $name, $breakInfo);
}
protected function writeStateToMeta() : int{
if($this->leverPos === self::BOTTOM){
$rotationMeta = Facing::axis($this->facing) === Axis::Z ? 7 : 0;
}elseif($this->leverPos === self::TOP){
$rotationMeta = Facing::axis($this->facing) === Axis::Z ? 5 : 6;
}else{
$rotationMeta = 6 - BlockDataSerializer::writeHorizontalFacing($this->facing);
}
return $rotationMeta | ($this->powered ? BlockLegacyMetadata::LEVER_FLAG_POWERED : 0);
$rotationMeta = match($this->facing->id()){
LeverFacing::DOWN_AXIS_X()->id() => 0,
LeverFacing::EAST()->id() => 1,
LeverFacing::WEST()->id() => 2,
LeverFacing::SOUTH()->id() => 3,
LeverFacing::NORTH()->id() => 4,
LeverFacing::UP_AXIS_Z()->id() => 5,
LeverFacing::UP_AXIS_X()->id() => 6,
LeverFacing::DOWN_AXIS_Z()->id() => 7,
default => throw new AssumptionFailedError(),
};
return $rotationMeta | ($this->activated ? BlockLegacyMetadata::LEVER_FLAG_POWERED : 0);
}
public function readStateFromData(int $id, int $stateMeta) : void{
$rotationMeta = $stateMeta & 0x07;
if($rotationMeta === 5 or $rotationMeta === 6){
$this->leverPos = self::TOP;
$this->facing = $rotationMeta === 5 ? Facing::SOUTH : Facing::EAST;
}elseif($rotationMeta === 7 or $rotationMeta === 0){
$this->leverPos = self::BOTTOM;
$this->facing = $rotationMeta === 7 ? Facing::SOUTH : Facing::EAST;
}else{
$this->leverPos = self::SIDE;
$this->facing = BlockDataSerializer::readHorizontalFacing(6 - $rotationMeta);
}
$this->facing = match($rotationMeta){
0 => LeverFacing::DOWN_AXIS_X(),
1 => LeverFacing::EAST(),
2 => LeverFacing::WEST(),
3 => LeverFacing::SOUTH(),
4 => LeverFacing::NORTH(),
5 => LeverFacing::UP_AXIS_Z(),
6 => LeverFacing::UP_AXIS_X(),
7 => LeverFacing::DOWN_AXIS_Z(),
default => throw new AssumptionFailedError("0x07 mask should make this impossible"), //phpstan doesn't understand :(
};
$this->powered = ($stateMeta & BlockLegacyMetadata::LEVER_FLAG_POWERED) !== 0;
$this->activated = ($stateMeta & BlockLegacyMetadata::LEVER_FLAG_POWERED) !== 0;
}
public function getFacing() : LeverFacing{ return $this->facing; }
/** @return $this */
public function setFacing(LeverFacing $facing) : self{
$this->facing = $facing;
return $this;
}
public function isActivated() : bool{ return $this->activated; }
/** @return $this */
public function setActivated(bool $activated) : self{
$this->activated = $activated;
return $this;
}
public function getStateBitmask() : int{
@ -78,39 +100,37 @@ class Lever extends Flowable{
return false;
}
if(Facing::axis($face) === Axis::Y){
$selectUpDownPos = function(LeverFacing $x, LeverFacing $z) use ($player) : LeverFacing{
if($player !== null){
$this->facing = Facing::opposite($player->getHorizontalFacing());
return Facing::axis($player->getHorizontalFacing()) === Axis::X ? $x : $z;
}
$this->leverPos = $face === Facing::DOWN ? self::BOTTOM : self::TOP;
}else{
$this->facing = $face;
$this->leverPos = self::SIDE;
}
return $x;
};
$this->facing = match($face){
Facing::DOWN => $selectUpDownPos(LeverFacing::DOWN_AXIS_X(), LeverFacing::DOWN_AXIS_Z()),
Facing::UP => $selectUpDownPos(LeverFacing::UP_AXIS_X(), LeverFacing::UP_AXIS_Z()),
Facing::NORTH => LeverFacing::NORTH(),
Facing::SOUTH => LeverFacing::SOUTH(),
Facing::WEST => LeverFacing::WEST(),
Facing::EAST => LeverFacing::EAST(),
default => throw new AssumptionFailedError("Bad facing value"),
};
return parent::place($tx, $item, $blockReplace, $blockClicked, $face, $clickVector, $player);
}
public function onNearbyBlockChange() : void{
if($this->leverPos === self::BOTTOM){
$face = Facing::UP;
}elseif($this->leverPos === self::TOP){
$face = Facing::DOWN;
}else{
$face = Facing::opposite($this->facing);
}
if(!$this->getSide($face)->isSolid()){
if(!$this->getSide(Facing::opposite($this->facing->getFacing()))->isSolid()){
$this->position->getWorld()->useBreakOn($this->position);
}
}
public function onInteract(Item $item, int $face, Vector3 $clickVector, ?Player $player = null) : bool{
$this->powered = !$this->powered;
$this->activated = !$this->activated;
$this->position->getWorld()->setBlock($this->position, $this);
$this->position->getWorld()->addSound(
$this->position->add(0.5, 0.5, 0.5),
$this->powered ? new RedstonePowerOnSound() : new RedstonePowerOffSound()
$this->activated ? new RedstonePowerOnSound() : new RedstonePowerOffSound()
);
return true;
}

View File

@ -24,19 +24,17 @@ declare(strict_types=1);
namespace pocketmine\block;
use pocketmine\block\utils\BlockDataSerializer;
use pocketmine\block\utils\MinimumCostFlowCalculator;
use pocketmine\entity\Entity;
use pocketmine\event\block\BlockFormEvent;
use pocketmine\event\block\BlockSpreadEvent;
use pocketmine\item\Item;
use pocketmine\math\AxisAlignedBB;
use pocketmine\math\Facing;
use pocketmine\math\Vector3;
use pocketmine\world\sound\FizzSound;
use pocketmine\world\sound\Sound;
use pocketmine\world\World;
use function array_fill;
use function intdiv;
use function lcg_value;
use function min;
abstract class Liquid extends Transparent{
@ -46,13 +44,6 @@ abstract class Liquid extends Transparent{
protected ?Vector3 $flowVector = null;
/** @var int[] */
private array $flowCostVisited = [];
private const CAN_FLOW_DOWN = 1;
private const CAN_FLOW = 0;
private const BLOCKED = -1;
protected bool $falling = false;
protected int $decay = 0; //PC "level" property
protected bool $still = false;
@ -186,21 +177,17 @@ abstract class Liquid extends Transparent{
$world = $this->position->getWorld();
for($j = 0; $j < 4; ++$j){
foreach(Facing::HORIZONTAL as $j){
$x = $this->position->x;
$y = $this->position->y;
$z = $this->position->z;
if($j === 0){
--$x;
}elseif($j === 1){
++$x;
}elseif($j === 2){
--$z;
}elseif($j === 3){
++$z;
}
match($j){
Facing::WEST => --$x,
Facing::EAST => ++$x,
Facing::NORTH => --$z,
Facing::SOUTH => ++$z
};
$sideBlock = $world->getBlockAt($x, $y, $z);
$blockDecay = $this->getEffectiveFlowDecay($sideBlock);
@ -231,17 +218,15 @@ abstract class Liquid extends Transparent{
$vector = new Vector3($vX, $vY, $vZ);
if($this->falling){
if(
!$this->canFlowInto($world->getBlockAt($this->position->x, $this->position->y, $this->position->z - 1)) or
!$this->canFlowInto($world->getBlockAt($this->position->x, $this->position->y, $this->position->z + 1)) or
!$this->canFlowInto($world->getBlockAt($this->position->x - 1, $this->position->y, $this->position->z)) or
!$this->canFlowInto($world->getBlockAt($this->position->x + 1, $this->position->y, $this->position->z)) or
!$this->canFlowInto($world->getBlockAt($this->position->x, $this->position->y + 1, $this->position->z - 1)) or
!$this->canFlowInto($world->getBlockAt($this->position->x, $this->position->y + 1, $this->position->z + 1)) or
!$this->canFlowInto($world->getBlockAt($this->position->x - 1, $this->position->y + 1, $this->position->z)) or
!$this->canFlowInto($world->getBlockAt($this->position->x + 1, $this->position->y + 1, $this->position->z))
){
$vector = $vector->normalize()->add(0, -6, 0);
foreach(Facing::HORIZONTAL as $facing){
$pos = $this->position->getSide($facing);
if(
!$this->canFlowInto($world->getBlockAt($pos->x, $pos->y, $pos->z)) ||
!$this->canFlowInto($world->getBlockAt($pos->x, $pos->y + 1, $pos->z))
){
$vector = $vector->normalize()->add(0, -6, 0);
break;
}
}
}
@ -264,6 +249,14 @@ abstract class Liquid extends Transparent{
return 1;
}
/**
* Returns the number of source blocks of this liquid that must be horizontally adjacent to this block in order for
* this block to become a source block itself, or null if the liquid does not exhibit source-forming behaviour.
*/
public function getMinAdjacentSourcesToFormSource() : ?int{
return null;
}
public function onNearbyBlockChange() : void{
if(!$this->checkForHarden()){
$this->position->getWorld()->scheduleDelayedBlockUpdate($this->position, $this->tickRate());
@ -273,13 +266,15 @@ abstract class Liquid extends Transparent{
public function onScheduledUpdate() : void{
$multiplier = $this->getFlowDecayPerBlock();
$world = $this->position->getWorld();
if(!$this->isSource()){
$smallestFlowDecay = -100;
$this->adjacentSources = 0;
$smallestFlowDecay = $this->getSmallestFlowDecay($this->position->getWorld()->getBlockAt($this->position->x, $this->position->y, $this->position->z - 1), $smallestFlowDecay);
$smallestFlowDecay = $this->getSmallestFlowDecay($this->position->getWorld()->getBlockAt($this->position->x, $this->position->y, $this->position->z + 1), $smallestFlowDecay);
$smallestFlowDecay = $this->getSmallestFlowDecay($this->position->getWorld()->getBlockAt($this->position->x - 1, $this->position->y, $this->position->z), $smallestFlowDecay);
$smallestFlowDecay = $this->getSmallestFlowDecay($this->position->getWorld()->getBlockAt($this->position->x + 1, $this->position->y, $this->position->z), $smallestFlowDecay);
$smallestFlowDecay = $this->getSmallestFlowDecay($world->getBlockAt($this->position->x, $this->position->y, $this->position->z - 1), $smallestFlowDecay);
$smallestFlowDecay = $this->getSmallestFlowDecay($world->getBlockAt($this->position->x, $this->position->y, $this->position->z + 1), $smallestFlowDecay);
$smallestFlowDecay = $this->getSmallestFlowDecay($world->getBlockAt($this->position->x - 1, $this->position->y, $this->position->z), $smallestFlowDecay);
$smallestFlowDecay = $this->getSmallestFlowDecay($world->getBlockAt($this->position->x + 1, $this->position->y, $this->position->z), $smallestFlowDecay);
$newDecay = $smallestFlowDecay + $multiplier;
$falling = false;
@ -288,13 +283,14 @@ abstract class Liquid extends Transparent{
$newDecay = -1;
}
if($this->getEffectiveFlowDecay($this->position->getWorld()->getBlockAt($this->position->x, $this->position->y + 1, $this->position->z)) >= 0){
if($this->getEffectiveFlowDecay($world->getBlockAt($this->position->x, $this->position->y + 1, $this->position->z)) >= 0){
$falling = true;
}
if($this->adjacentSources >= 2 and $this instanceof Water){
$bottomBlock = $this->position->getWorld()->getBlockAt($this->position->x, $this->position->y - 1, $this->position->z);
if($bottomBlock->isSolid() or ($bottomBlock instanceof Water and $bottomBlock->isSource())){
$minAdjacentSources = $this->getMinAdjacentSourcesToFormSource();
if($minAdjacentSources !== null && $this->adjacentSources >= $minAdjacentSources){
$bottomBlock = $world->getBlockAt($this->position->x, $this->position->y - 1, $this->position->z);
if($bottomBlock->isSolid() or ($bottomBlock instanceof Liquid and $bottomBlock->isSameType($this) and $bottomBlock->isSource())){
$newDecay = 0;
$falling = false;
}
@ -302,17 +298,17 @@ abstract class Liquid extends Transparent{
if($falling !== $this->falling or (!$falling and $newDecay !== $this->decay)){
if(!$falling and $newDecay < 0){
$this->position->getWorld()->setBlock($this->position, VanillaBlocks::AIR());
$world->setBlock($this->position, VanillaBlocks::AIR());
return;
}
$this->falling = $falling;
$this->decay = $falling ? 0 : $newDecay;
$this->position->getWorld()->setBlock($this->position, $this); //local block update will cause an update to be scheduled
$world->setBlock($this->position, $this); //local block update will cause an update to be scheduled
}
}
$bottomBlock = $this->position->getWorld()->getBlockAt($this->position->x, $this->position->y - 1, $this->position->z);
$bottomBlock = $world->getBlockAt($this->position->x, $this->position->y - 1, $this->position->z);
$this->flowIntoBlock($bottomBlock, 0, true);
@ -324,22 +320,9 @@ abstract class Liquid extends Transparent{
}
if($adjacentDecay < 8){
$flags = $this->getOptimalFlowDirections();
if($flags[0]){
$this->flowIntoBlock($this->position->getWorld()->getBlockAt($this->position->x - 1, $this->position->y, $this->position->z), $adjacentDecay, false);
}
if($flags[1]){
$this->flowIntoBlock($this->position->getWorld()->getBlockAt($this->position->x + 1, $this->position->y, $this->position->z), $adjacentDecay, false);
}
if($flags[2]){
$this->flowIntoBlock($this->position->getWorld()->getBlockAt($this->position->x, $this->position->y, $this->position->z - 1), $adjacentDecay, false);
}
if($flags[3]){
$this->flowIntoBlock($this->position->getWorld()->getBlockAt($this->position->x, $this->position->y, $this->position->z + 1), $adjacentDecay, false);
$calculator = new MinimumCostFlowCalculator($this->position->getWorld(), $this->getFlowDecayPerBlock(), \Closure::fromCallable([$this, 'canFlowInto']));
foreach($calculator->getOptimalFlowDirections($this->position->getFloorX(), $this->position->getFloorY(), $this->position->getFloorZ()) as $facing){
$this->flowIntoBlock($world->getBlock($this->position->getSide($facing)), $adjacentDecay, false);
}
}
}
@ -365,109 +348,6 @@ abstract class Liquid extends Transparent{
}
}
private function calculateFlowCost(int $blockX, int $blockY, int $blockZ, int $accumulatedCost, int $maxCost, int $originOpposite, int $lastOpposite) : int{
$cost = 1000;
for($j = 0; $j < 4; ++$j){
if($j === $originOpposite or $j === $lastOpposite){
continue;
}
$x = $blockX;
$y = $blockY;
$z = $blockZ;
if($j === 0){
--$x;
}elseif($j === 1){
++$x;
}elseif($j === 2){
--$z;
}elseif($j === 3){
++$z;
}
if(!isset($this->flowCostVisited[$hash = World::blockHash($x, $y, $z)])){
$blockSide = $this->position->getWorld()->getBlockAt($x, $y, $z);
if(!$this->canFlowInto($blockSide)){
$this->flowCostVisited[$hash] = self::BLOCKED;
}elseif($this->position->getWorld()->getBlockAt($x, $y - 1, $z)->canBeFlowedInto()){
$this->flowCostVisited[$hash] = self::CAN_FLOW_DOWN;
}else{
$this->flowCostVisited[$hash] = self::CAN_FLOW;
}
}
$status = $this->flowCostVisited[$hash];
if($status === self::BLOCKED){
continue;
}elseif($status === self::CAN_FLOW_DOWN){
return $accumulatedCost;
}
if($accumulatedCost >= $maxCost){
continue;
}
$realCost = $this->calculateFlowCost($x, $y, $z, $accumulatedCost + 1, $maxCost, $originOpposite, $j ^ 0x01);
if($realCost < $cost){
$cost = $realCost;
}
}
return $cost;
}
/**
* @return bool[]
*/
private function getOptimalFlowDirections() : array{
$flowCost = array_fill(0, 4, 1000);
$maxCost = intdiv(4, $this->getFlowDecayPerBlock());
for($j = 0; $j < 4; ++$j){
$x = $this->position->x;
$y = $this->position->y;
$z = $this->position->z;
if($j === 0){
--$x;
}elseif($j === 1){
++$x;
}elseif($j === 2){
--$z;
}elseif($j === 3){
++$z;
}
$block = $this->position->getWorld()->getBlockAt($x, $y, $z);
if(!$this->canFlowInto($block)){
$this->flowCostVisited[World::blockHash($x, $y, $z)] = self::BLOCKED;
continue;
}elseif($this->position->getWorld()->getBlockAt($x, $y - 1, $z)->canBeFlowedInto()){
$this->flowCostVisited[World::blockHash($x, $y, $z)] = self::CAN_FLOW_DOWN;
$flowCost[$j] = $maxCost = 0;
}elseif($maxCost > 0){
$this->flowCostVisited[World::blockHash($x, $y, $z)] = self::CAN_FLOW;
$flowCost[$j] = $this->calculateFlowCost($x, $y, $z, 1, $maxCost, $j ^ 0x01, $j ^ 0x01);
$maxCost = min($maxCost, $flowCost[$j]);
}
}
$this->flowCostVisited = [];
$minCost = min($flowCost);
$isOptimalFlowDirection = [];
for($i = 0; $i < 4; ++$i){
$isOptimalFlowDirection[$i] = ($flowCost[$i] === $minCost);
}
return $isOptimalFlowDirection;
}
/** @phpstan-impure */
private function getSmallestFlowDecay(Block $block, int $decay) : int{
if(!($block instanceof Liquid) or !$block->isSameType($this)){
@ -500,6 +380,9 @@ abstract class Liquid extends Transparent{
}
protected function canFlowInto(Block $block) : bool{
return $this->position->getWorld()->isInWorld($block->position->x, $block->position->y, $block->position->z) and $block->canBeFlowedInto() and !($block instanceof Liquid and $block->isSource()); //TODO: I think this should only be liquids of the same type
return
$this->position->getWorld()->isInWorld($block->position->x, $block->position->y, $block->position->z) and
$block->canBeFlowedInto() and
!($block instanceof Liquid and $block->isSource()); //TODO: I think this should only be liquids of the same type
}
}

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

@ -46,6 +46,10 @@ class Water extends Liquid{
return 5;
}
public function getMinAdjacentSourcesToFormSource() : ?int{
return 2;
}
public function onEntityInside(Entity $entity) : bool{
$entity->resetFallDistance();
if($entity->isOnFire()){

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

@ -82,6 +82,10 @@ abstract class Furnace extends Spawnable implements Container, Nameable{
$this->loadName($nbt);
$this->loadItems($nbt);
if($this->remainingFuelTime > 0){
$this->position->getWorld()->scheduleDelayedBlockUpdate($this->position, 1);
}
}
protected function writeSaveData(CompoundTag $nbt) : void{

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

@ -0,0 +1,67 @@
<?php
/*
*
* ____ _ _ __ __ _ __ __ ____
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* @author PocketMine Team
* @link http://www.pocketmine.net/
*
*
*/
declare(strict_types=1);
namespace pocketmine\block\utils;
use pocketmine\math\Facing;
use pocketmine\utils\EnumTrait;
/**
* This doc-block is generated automatically, do not modify it manually.
* This must be regenerated whenever registry members are added, removed or changed.
* @see build/generate-registry-annotations.php
* @generate-registry-docblock
*
* @method static LeverFacing DOWN_AXIS_X()
* @method static LeverFacing DOWN_AXIS_Z()
* @method static LeverFacing EAST()
* @method static LeverFacing NORTH()
* @method static LeverFacing SOUTH()
* @method static LeverFacing UP_AXIS_X()
* @method static LeverFacing UP_AXIS_Z()
* @method static LeverFacing WEST()
*/
final class LeverFacing{
use EnumTrait {
__construct as Enum___construct;
}
protected static function setup() : void{
self::registerAll(
new self("up_axis_x", Facing::UP),
new self("up_axis_z", Facing::UP),
new self("down_axis_x", Facing::DOWN),
new self("down_axis_z", Facing::DOWN),
new self("north", Facing::NORTH),
new self("east", Facing::EAST),
new self("south", Facing::SOUTH),
new self("west", Facing::WEST),
);
}
private function __construct(string $enumName, private int $facing){
$this->Enum___construct($enumName);
}
public function getFacing() : int{ return $this->facing; }
}

View File

@ -0,0 +1,154 @@
<?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\utils;
use pocketmine\block\Block;
use pocketmine\math\Facing;
use pocketmine\world\World;
use function array_fill_keys;
use function intdiv;
use function min;
/**
* Calculates the path(s) of least resistance for liquid flow.
*/
final class MinimumCostFlowCalculator{
private const CAN_FLOW_DOWN = 1;
private const CAN_FLOW = 0;
private const BLOCKED = -1;
/** @var int[] */
private array $flowCostVisited = [];
/**
* @phpstan-param \Closure(Block) : bool $canFlowInto
*/
public function __construct(
private World $world,
private int $flowDecayPerBlock,
private \Closure $canFlowInto
){}
private function calculateFlowCost(int $blockX, int $blockY, int $blockZ, int $accumulatedCost, int $maxCost, int $originOpposite, int $lastOpposite) : int{
$cost = 1000;
foreach(Facing::HORIZONTAL as $j){
if($j === $originOpposite or $j === $lastOpposite){
continue;
}
$x = $blockX;
$y = $blockY;
$z = $blockZ;
match($j){
Facing::WEST => --$x,
Facing::EAST => ++$x,
Facing::NORTH => --$z,
Facing::SOUTH => ++$z
};
if(!isset($this->flowCostVisited[$hash = World::blockHash($x, $y, $z)])){
if(!$this->world->isInWorld($x, $y, $z) || !$this->canFlowInto($this->world->getBlockAt($x, $y, $z))){
$this->flowCostVisited[$hash] = self::BLOCKED;
}elseif($this->world->getBlockAt($x, $y - 1, $z)->canBeFlowedInto()){
$this->flowCostVisited[$hash] = self::CAN_FLOW_DOWN;
}else{
$this->flowCostVisited[$hash] = self::CAN_FLOW;
}
}
$status = $this->flowCostVisited[$hash];
if($status === self::BLOCKED){
continue;
}elseif($status === self::CAN_FLOW_DOWN){
return $accumulatedCost;
}
if($accumulatedCost >= $maxCost){
continue;
}
$realCost = $this->calculateFlowCost($x, $y, $z, $accumulatedCost + 1, $maxCost, $originOpposite, Facing::opposite($j));
if($realCost < $cost){
$cost = $realCost;
}
}
return $cost;
}
/**
* @return int[]
*/
public function getOptimalFlowDirections(int $originX, int $originY, int $originZ) : array{
$flowCost = array_fill_keys(Facing::HORIZONTAL, 1000);
$maxCost = intdiv(4, $this->flowDecayPerBlock);
foreach(Facing::HORIZONTAL as $j){
$x = $originX;
$y = $originY;
$z = $originZ;
match($j){
Facing::WEST => --$x,
Facing::EAST => ++$x,
Facing::NORTH => --$z,
Facing::SOUTH => ++$z
};
if(!$this->world->isInWorld($x, $y, $z) || !$this->canFlowInto($this->world->getBlockAt($x, $y, $z))){
$this->flowCostVisited[World::blockHash($x, $y, $z)] = self::BLOCKED;
}elseif($this->world->getBlockAt($x, $y - 1, $z)->canBeFlowedInto()){
$this->flowCostVisited[World::blockHash($x, $y, $z)] = self::CAN_FLOW_DOWN;
$flowCost[$j] = $maxCost = 0;
}elseif($maxCost > 0){
$this->flowCostVisited[World::blockHash($x, $y, $z)] = self::CAN_FLOW;
$opposite = Facing::opposite($j);
$flowCost[$j] = $this->calculateFlowCost($x, $y, $z, 1, $maxCost, $opposite, $opposite);
$maxCost = min($maxCost, $flowCost[$j]);
}
}
$this->flowCostVisited = [];
$minCost = min($flowCost);
$isOptimalFlowDirection = [];
foreach($flowCost as $facing => $cost){
if($cost === $minCost){
$isOptimalFlowDirection[] = $facing;
}
}
return $isOptimalFlowDirection;
}
private function canFlowInto(Block $block) : bool{
return ($this->canFlowInto)($block);
}
}

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

@ -58,10 +58,10 @@ abstract class Command{
/** @var CommandMap|null */
private $commandMap = null;
/** @var string */
/** @var Translatable|string */
protected $description = "";
/** @var string */
/** @var Translatable|string */
protected $usageMessage;
/** @var string|null */
@ -76,7 +76,7 @@ abstract class Command{
/**
* @param string[] $aliases
*/
public function __construct(string $name, string $description = "", ?string $usageMessage = null, array $aliases = []){
public function __construct(string $name, Translatable|string $description = "", Translatable|string|null $usageMessage = null, array $aliases = []){
$this->name = $name;
$this->setLabel($name);
$this->setDescription($description);
@ -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));
}
@ -200,11 +200,11 @@ abstract class Command{
return $this->permissionMessage;
}
public function getDescription() : string{
public function getDescription() : Translatable|string{
return $this->description;
}
public function getUsage() : string{
public function getUsage() : Translatable|string{
return $this->usageMessage;
}
@ -218,7 +218,7 @@ abstract class Command{
}
}
public function setDescription(string $description) : void{
public function setDescription(Translatable|string $description) : void{
$this->description = $description;
}
@ -226,7 +226,7 @@ abstract class Command{
$this->permissionMessage = $permissionMessage;
}
public function setUsage(string $usage) : void{
public function setUsage(Translatable|string $usage) : void{
$this->usageMessage = $usage;
}

View File

@ -67,6 +67,7 @@ use pocketmine\command\defaults\WhitelistCommand;
use pocketmine\command\utils\InvalidCommandSyntaxException;
use pocketmine\lang\KnownTranslationFactory;
use pocketmine\Server;
use pocketmine\utils\TextFormat;
use function array_shift;
use function count;
use function explode;
@ -205,31 +206,28 @@ class SimpleCommandMap implements CommandMap{
foreach($matches[0] as $k => $_){
for($i = 1; $i <= 2; ++$i){
if($matches[$i][$k] !== ""){
$args[$k] = stripslashes($matches[$i][$k]);
$args[$k] = $i === 1 ? stripslashes($matches[$i][$k]) : $matches[$i][$k];
break;
}
}
}
$sentCommandLabel = array_shift($args);
if($sentCommandLabel === null){
return false;
}
$target = $this->getCommand($sentCommandLabel);
if($target === null){
return false;
if($sentCommandLabel !== null && ($target = $this->getCommand($sentCommandLabel)) !== null){
$target->timings->startTiming();
try{
$target->execute($sender, $sentCommandLabel, $args);
}catch(InvalidCommandSyntaxException $e){
$sender->sendMessage($sender->getLanguage()->translate(KnownTranslationFactory::commands_generic_usage($target->getUsage())));
}finally{
$target->timings->stopTiming();
}
return true;
}
$target->timings->startTiming();
try{
$target->execute($sender, $sentCommandLabel, $args);
}catch(InvalidCommandSyntaxException $e){
$sender->sendMessage($sender->getLanguage()->translate(KnownTranslationFactory::commands_generic_usage($sender->getLanguage()->translateString($target->getUsage()))));
}finally{
$target->timings->stopTiming();
}
return true;
$sender->sendMessage(KnownTranslationFactory::pocketmine_command_notFound($sentCommandLabel ?? "", "/help")->prefix(TextFormat::RED));
return false;
}
public function clearCommands() : void{

View File

@ -27,7 +27,6 @@ use pocketmine\command\Command;
use pocketmine\command\CommandSender;
use pocketmine\command\utils\InvalidCommandSyntaxException;
use pocketmine\lang\KnownTranslationFactory;
use pocketmine\lang\KnownTranslationKeys;
use pocketmine\permission\DefaultPermissionNames;
use pocketmine\player\Player;
use function array_shift;
@ -39,8 +38,8 @@ class BanCommand extends VanillaCommand{
public function __construct(string $name){
parent::__construct(
$name,
KnownTranslationKeys::POCKETMINE_COMMAND_BAN_PLAYER_DESCRIPTION,
KnownTranslationKeys::COMMANDS_BAN_USAGE
KnownTranslationFactory::pocketmine_command_ban_player_description(),
KnownTranslationFactory::commands_ban_usage()
);
$this->setPermission(DefaultPermissionNames::COMMAND_BAN_PLAYER);
}

View File

@ -27,21 +27,20 @@ use pocketmine\command\Command;
use pocketmine\command\CommandSender;
use pocketmine\command\utils\InvalidCommandSyntaxException;
use pocketmine\lang\KnownTranslationFactory;
use pocketmine\lang\KnownTranslationKeys;
use pocketmine\permission\DefaultPermissionNames;
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{
public function __construct(string $name){
parent::__construct(
$name,
KnownTranslationKeys::POCKETMINE_COMMAND_BAN_IP_DESCRIPTION,
KnownTranslationKeys::COMMANDS_BANIP_USAGE
KnownTranslationFactory::pocketmine_command_ban_ip_description(),
KnownTranslationFactory::commands_banip_usage()
);
$this->setPermission(DefaultPermissionNames::COMMAND_BAN_IP);
}
@ -58,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,6 @@ namespace pocketmine\command\defaults;
use pocketmine\command\CommandSender;
use pocketmine\command\utils\InvalidCommandSyntaxException;
use pocketmine\lang\KnownTranslationFactory;
use pocketmine\lang\KnownTranslationKeys;
use pocketmine\permission\BanEntry;
use pocketmine\permission\DefaultPermissionNames;
use function array_map;
@ -41,8 +40,8 @@ class BanListCommand extends VanillaCommand{
public function __construct(string $name){
parent::__construct(
$name,
KnownTranslationKeys::POCKETMINE_COMMAND_BANLIST_DESCRIPTION,
KnownTranslationKeys::COMMANDS_BANLIST_USAGE
KnownTranslationFactory::pocketmine_command_banlist_description(),
KnownTranslationFactory::commands_banlist_usage()
);
$this->setPermission(DefaultPermissionNames::COMMAND_BAN_LIST);
}

View File

@ -30,7 +30,6 @@ use pocketmine\item\LegacyStringToItemParser;
use pocketmine\item\LegacyStringToItemParserException;
use pocketmine\item\StringToItemParser;
use pocketmine\lang\KnownTranslationFactory;
use pocketmine\lang\KnownTranslationKeys;
use pocketmine\permission\DefaultPermissionNames;
use pocketmine\player\Player;
use pocketmine\utils\TextFormat;
@ -43,8 +42,8 @@ class ClearCommand extends VanillaCommand{
public function __construct(string $name){
parent::__construct(
$name,
KnownTranslationKeys::POCKETMINE_COMMAND_CLEAR_DESCRIPTION,
KnownTranslationKeys::POCKETMINE_COMMAND_CLEAR_USAGE
KnownTranslationFactory::pocketmine_command_clear_description(),
KnownTranslationFactory::pocketmine_command_clear_usage()
);
$this->setPermission(implode(";", [DefaultPermissionNames::COMMAND_CLEAR_SELF, DefaultPermissionNames::COMMAND_CLEAR_OTHER]));
}

View File

@ -27,7 +27,6 @@ use pocketmine\command\CommandSender;
use pocketmine\command\utils\InvalidCommandSyntaxException;
use pocketmine\data\java\GameModeIdMap;
use pocketmine\lang\KnownTranslationFactory;
use pocketmine\lang\KnownTranslationKeys;
use pocketmine\permission\DefaultPermissionNames;
use pocketmine\player\GameMode;
use function count;
@ -37,8 +36,8 @@ class DefaultGamemodeCommand extends VanillaCommand{
public function __construct(string $name){
parent::__construct(
$name,
KnownTranslationKeys::POCKETMINE_COMMAND_DEFAULTGAMEMODE_DESCRIPTION,
KnownTranslationKeys::COMMANDS_DEFAULTGAMEMODE_USAGE
KnownTranslationFactory::pocketmine_command_defaultgamemode_description(),
KnownTranslationFactory::commands_defaultgamemode_usage()
);
$this->setPermission(DefaultPermissionNames::COMMAND_DEFAULTGAMEMODE);
}
@ -54,7 +53,7 @@ class DefaultGamemodeCommand extends VanillaCommand{
$gameMode = GameMode::fromString($args[0]);
if($gameMode === null){
$sender->sendMessage("Unknown game mode");
$sender->sendMessage(KnownTranslationFactory::pocketmine_command_gamemode_unknown($args[0]));
return true;
}

View File

@ -27,7 +27,6 @@ use pocketmine\command\Command;
use pocketmine\command\CommandSender;
use pocketmine\command\utils\InvalidCommandSyntaxException;
use pocketmine\lang\KnownTranslationFactory;
use pocketmine\lang\KnownTranslationKeys;
use pocketmine\permission\DefaultPermissionNames;
use pocketmine\player\Player;
use pocketmine\utils\TextFormat;
@ -39,8 +38,8 @@ class DeopCommand extends VanillaCommand{
public function __construct(string $name){
parent::__construct(
$name,
KnownTranslationKeys::POCKETMINE_COMMAND_DEOP_DESCRIPTION,
KnownTranslationKeys::COMMANDS_DEOP_USAGE
KnownTranslationFactory::pocketmine_command_deop_description(),
KnownTranslationFactory::commands_deop_usage()
);
$this->setPermission(DefaultPermissionNames::COMMAND_OP_TAKE);
}

View File

@ -27,7 +27,6 @@ use pocketmine\command\Command;
use pocketmine\command\CommandSender;
use pocketmine\command\utils\InvalidCommandSyntaxException;
use pocketmine\lang\KnownTranslationFactory;
use pocketmine\lang\KnownTranslationKeys;
use pocketmine\permission\DefaultPermissionNames;
use pocketmine\world\World;
use function count;
@ -37,8 +36,8 @@ class DifficultyCommand extends VanillaCommand{
public function __construct(string $name){
parent::__construct(
$name,
KnownTranslationKeys::POCKETMINE_COMMAND_DIFFICULTY_DESCRIPTION,
KnownTranslationKeys::COMMANDS_DIFFICULTY_USAGE
KnownTranslationFactory::pocketmine_command_difficulty_description(),
KnownTranslationFactory::commands_difficulty_usage()
);
$this->setPermission(DefaultPermissionNames::COMMAND_DIFFICULTY);
}

View File

@ -26,9 +26,8 @@ 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\lang\KnownTranslationKeys;
use pocketmine\permission\DefaultPermissionNames;
use pocketmine\utils\Limits;
use pocketmine\utils\TextFormat;
@ -40,8 +39,8 @@ class EffectCommand extends VanillaCommand{
public function __construct(string $name){
parent::__construct(
$name,
KnownTranslationKeys::POCKETMINE_COMMAND_EFFECT_DESCRIPTION,
KnownTranslationKeys::COMMANDS_EFFECT_USAGE
KnownTranslationFactory::pocketmine_command_effect_description(),
KnownTranslationFactory::commands_effect_usage()
);
$this->setPermission(DefaultPermissionNames::COMMAND_EFFECT);
}
@ -70,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,9 +26,8 @@ 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\lang\KnownTranslationKeys;
use pocketmine\permission\DefaultPermissionNames;
use pocketmine\utils\TextFormat;
use function count;
@ -38,8 +37,8 @@ class EnchantCommand extends VanillaCommand{
public function __construct(string $name){
parent::__construct(
$name,
KnownTranslationKeys::POCKETMINE_COMMAND_ENCHANT_DESCRIPTION,
KnownTranslationKeys::COMMANDS_ENCHANT_USAGE
KnownTranslationFactory::pocketmine_command_enchant_description(),
KnownTranslationFactory::commands_enchant_usage()
);
$this->setPermission(DefaultPermissionNames::COMMAND_ENCHANT);
}
@ -67,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

@ -27,7 +27,6 @@ use pocketmine\command\Command;
use pocketmine\command\CommandSender;
use pocketmine\command\utils\InvalidCommandSyntaxException;
use pocketmine\lang\KnownTranslationFactory;
use pocketmine\lang\KnownTranslationKeys;
use pocketmine\permission\DefaultPermissionNames;
use pocketmine\player\GameMode;
use pocketmine\player\Player;
@ -39,8 +38,8 @@ class GamemodeCommand extends VanillaCommand{
public function __construct(string $name){
parent::__construct(
$name,
KnownTranslationKeys::POCKETMINE_COMMAND_GAMEMODE_DESCRIPTION,
KnownTranslationKeys::COMMANDS_GAMEMODE_USAGE
KnownTranslationFactory::pocketmine_command_gamemode_description(),
KnownTranslationFactory::commands_gamemode_usage()
);
$this->setPermission(DefaultPermissionNames::COMMAND_GAMEMODE);
}
@ -56,7 +55,7 @@ class GamemodeCommand extends VanillaCommand{
$gameMode = GameMode::fromString($args[0]);
if($gameMode === null){
$sender->sendMessage("Unknown game mode");
$sender->sendMessage(KnownTranslationFactory::pocketmine_command_gamemode_unknown($args[0]));
return true;
}
@ -75,7 +74,7 @@ class GamemodeCommand extends VanillaCommand{
$target->setGamemode($gameMode);
if(!$gameMode->equals($target->getGamemode())){
$sender->sendMessage("Game mode change for " . $target->getName() . " failed!");
$sender->sendMessage(KnownTranslationFactory::pocketmine_command_gamemode_failure($target->getName()));
}else{
if($target === $sender){
Command::broadcastCommandMessage($sender, KnownTranslationFactory::commands_gamemode_success_self($gameMode->getTranslatableName()));

View File

@ -25,7 +25,6 @@ namespace pocketmine\command\defaults;
use pocketmine\command\CommandSender;
use pocketmine\lang\KnownTranslationFactory;
use pocketmine\lang\KnownTranslationKeys;
use pocketmine\permission\DefaultPermissionNames;
use pocketmine\utils\TextFormat;
use function count;
@ -38,8 +37,7 @@ class GarbageCollectorCommand extends VanillaCommand{
public function __construct(string $name){
parent::__construct(
$name,
KnownTranslationKeys::POCKETMINE_COMMAND_GC_DESCRIPTION,
KnownTranslationKeys::POCKETMINE_COMMAND_GC_USAGE
KnownTranslationFactory::pocketmine_command_gc_description()
);
$this->setPermission(DefaultPermissionNames::COMMAND_GC);
}
@ -70,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

@ -30,9 +30,9 @@ use pocketmine\item\LegacyStringToItemParser;
use pocketmine\item\LegacyStringToItemParserException;
use pocketmine\item\StringToItemParser;
use pocketmine\lang\KnownTranslationFactory;
use pocketmine\lang\KnownTranslationKeys;
use pocketmine\nbt\JsonNbtParser;
use pocketmine\nbt\NbtDataException;
use pocketmine\nbt\NbtException;
use pocketmine\permission\DefaultPermissionNames;
use pocketmine\utils\TextFormat;
use function array_slice;
@ -44,8 +44,8 @@ class GiveCommand extends VanillaCommand{
public function __construct(string $name){
parent::__construct(
$name,
KnownTranslationKeys::POCKETMINE_COMMAND_GIVE_DESCRIPTION,
KnownTranslationKeys::POCKETMINE_COMMAND_GIVE_USAGE
KnownTranslationFactory::pocketmine_command_give_description(),
KnownTranslationFactory::pocketmine_command_give_usage()
);
$this->setPermission(DefaultPermissionNames::COMMAND_GIVE);
}
@ -87,7 +87,12 @@ class GiveCommand extends VanillaCommand{
return true;
}
$item->setNamedTag($tags);
try{
$item->setNamedTag($tags);
}catch(NbtException $e){
$sender->sendMessage(KnownTranslationFactory::commands_give_tagError($e->getMessage()));
return true;
}
}
//TODO: overflow

View File

@ -26,7 +26,7 @@ namespace pocketmine\command\defaults;
use pocketmine\command\Command;
use pocketmine\command\CommandSender;
use pocketmine\lang\KnownTranslationFactory;
use pocketmine\lang\KnownTranslationKeys;
use pocketmine\lang\Translatable;
use pocketmine\permission\DefaultPermissionNames;
use pocketmine\utils\TextFormat;
use function array_chunk;
@ -46,8 +46,8 @@ class HelpCommand extends VanillaCommand{
public function __construct(string $name){
parent::__construct(
$name,
KnownTranslationKeys::POCKETMINE_COMMAND_HELP_DESCRIPTION,
KnownTranslationKeys::COMMANDS_HELP_USAGE,
KnownTranslationFactory::pocketmine_command_help_description(),
KnownTranslationFactory::commands_help_usage(),
["?"]
);
$this->setPermission(DefaultPermissionNames::COMMAND_HELP);
@ -92,7 +92,9 @@ class HelpCommand extends VanillaCommand{
$lang = $sender->getLanguage();
if(isset($commands[$pageNumber - 1])){
foreach($commands[$pageNumber - 1] as $command){
$sender->sendMessage(TextFormat::DARK_GREEN . "/" . $command->getName() . ": " . TextFormat::WHITE . $lang->translateString($command->getDescription()));
$description = $command->getDescription();
$descriptionString = $description instanceof Translatable ? $lang->translate($description) : $description;
$sender->sendMessage(TextFormat::DARK_GREEN . "/" . $command->getName() . ": " . TextFormat::WHITE . $descriptionString);
}
}
@ -100,15 +102,23 @@ class HelpCommand extends VanillaCommand{
}else{
if(($cmd = $sender->getServer()->getCommandMap()->getCommand(strtolower($commandName))) instanceof Command){
if($cmd->testPermissionSilent($sender)){
$message = TextFormat::YELLOW . "--------- " . TextFormat::WHITE . " Help: /" . $cmd->getName() . TextFormat::YELLOW . " ---------\n";
$message .= TextFormat::GOLD . "Description: " . TextFormat::WHITE . $sender->getLanguage()->translateString($cmd->getDescription()) . "\n";
$message .= TextFormat::GOLD . "Usage: " . TextFormat::WHITE . implode("\n" . TextFormat::WHITE, explode("\n", $sender->getLanguage()->translateString($cmd->getUsage()))) . "\n";
$sender->sendMessage($message);
$lang = $sender->getLanguage();
$description = $cmd->getDescription();
$descriptionString = $description instanceof Translatable ? $lang->translate($description) : $description;
$sender->sendMessage(KnownTranslationFactory::pocketmine_command_help_specificCommand_header($commandName)
->format(TextFormat::YELLOW . "--------- " . TextFormat::WHITE, TextFormat::YELLOW . " ---------"));
$sender->sendMessage(KnownTranslationFactory::pocketmine_command_help_specificCommand_description(TextFormat::WHITE . $descriptionString)
->prefix(TextFormat::GOLD));
$usage = $cmd->getUsage();
$usageString = $usage instanceof Translatable ? $lang->translate($usage) : $usage;
$sender->sendMessage(KnownTranslationFactory::pocketmine_command_help_specificCommand_usage(TextFormat::WHITE . implode("\n" . TextFormat::WHITE, explode("\n", $usageString)))
->prefix(TextFormat::GOLD));
return true;
}
}
$sender->sendMessage(TextFormat::RED . "No help for " . strtolower($commandName));
$sender->sendMessage(KnownTranslationFactory::pocketmine_command_notFound($commandName, "/help")->prefix(TextFormat::RED));
return true;
}

View File

@ -27,7 +27,6 @@ use pocketmine\command\Command;
use pocketmine\command\CommandSender;
use pocketmine\command\utils\InvalidCommandSyntaxException;
use pocketmine\lang\KnownTranslationFactory;
use pocketmine\lang\KnownTranslationKeys;
use pocketmine\permission\DefaultPermissionNames;
use pocketmine\player\Player;
use pocketmine\utils\TextFormat;
@ -41,8 +40,8 @@ class KickCommand extends VanillaCommand{
public function __construct(string $name){
parent::__construct(
$name,
KnownTranslationKeys::POCKETMINE_COMMAND_KICK_DESCRIPTION,
KnownTranslationKeys::COMMANDS_KICK_USAGE
KnownTranslationFactory::pocketmine_command_kick_description(),
KnownTranslationFactory::commands_kick_usage()
);
$this->setPermission(DefaultPermissionNames::COMMAND_KICK);
}

View File

@ -28,7 +28,6 @@ use pocketmine\command\CommandSender;
use pocketmine\command\utils\InvalidCommandSyntaxException;
use pocketmine\event\entity\EntityDamageEvent;
use pocketmine\lang\KnownTranslationFactory;
use pocketmine\lang\KnownTranslationKeys;
use pocketmine\permission\DefaultPermissionNames;
use pocketmine\player\Player;
use pocketmine\utils\TextFormat;
@ -40,8 +39,8 @@ class KillCommand extends VanillaCommand{
public function __construct(string $name){
parent::__construct(
$name,
KnownTranslationKeys::POCKETMINE_COMMAND_KILL_DESCRIPTION,
KnownTranslationKeys::POCKETMINE_COMMAND_KILL_USAGE,
KnownTranslationFactory::pocketmine_command_kill_description(),
KnownTranslationFactory::pocketmine_command_kill_usage(),
["suicide"]
);
$this->setPermission(implode(";", [DefaultPermissionNames::COMMAND_KILL_SELF, DefaultPermissionNames::COMMAND_KILL_OTHER]));

View File

@ -25,7 +25,6 @@ namespace pocketmine\command\defaults;
use pocketmine\command\CommandSender;
use pocketmine\lang\KnownTranslationFactory;
use pocketmine\lang\KnownTranslationKeys;
use pocketmine\permission\DefaultPermissionNames;
use pocketmine\player\Player;
use function array_filter;
@ -40,8 +39,7 @@ class ListCommand extends VanillaCommand{
public function __construct(string $name){
parent::__construct(
$name,
KnownTranslationKeys::POCKETMINE_COMMAND_LIST_DESCRIPTION,
KnownTranslationKeys::COMMANDS_PLAYERS_USAGE
KnownTranslationFactory::pocketmine_command_list_description()
);
$this->setPermission(DefaultPermissionNames::COMMAND_LIST);
}

View File

@ -26,7 +26,6 @@ namespace pocketmine\command\defaults;
use pocketmine\command\CommandSender;
use pocketmine\command\utils\InvalidCommandSyntaxException;
use pocketmine\lang\KnownTranslationFactory;
use pocketmine\lang\KnownTranslationKeys;
use pocketmine\permission\DefaultPermissionNames;
use pocketmine\player\Player;
use pocketmine\utils\TextFormat;
@ -38,8 +37,8 @@ class MeCommand extends VanillaCommand{
public function __construct(string $name){
parent::__construct(
$name,
KnownTranslationKeys::POCKETMINE_COMMAND_ME_DESCRIPTION,
KnownTranslationKeys::COMMANDS_ME_USAGE
KnownTranslationFactory::pocketmine_command_me_description(),
KnownTranslationFactory::commands_me_usage()
);
$this->setPermission(DefaultPermissionNames::COMMAND_ME);
}

View File

@ -27,7 +27,6 @@ use pocketmine\command\Command;
use pocketmine\command\CommandSender;
use pocketmine\command\utils\InvalidCommandSyntaxException;
use pocketmine\lang\KnownTranslationFactory;
use pocketmine\lang\KnownTranslationKeys;
use pocketmine\permission\DefaultPermissionNames;
use pocketmine\player\Player;
use pocketmine\utils\TextFormat;
@ -39,8 +38,8 @@ class OpCommand extends VanillaCommand{
public function __construct(string $name){
parent::__construct(
$name,
KnownTranslationKeys::POCKETMINE_COMMAND_OP_DESCRIPTION,
KnownTranslationKeys::COMMANDS_OP_USAGE
KnownTranslationFactory::pocketmine_command_op_description(),
KnownTranslationFactory::commands_op_usage()
);
$this->setPermission(DefaultPermissionNames::COMMAND_OP_GIVE);
}

View File

@ -27,7 +27,6 @@ use pocketmine\command\Command;
use pocketmine\command\CommandSender;
use pocketmine\command\utils\InvalidCommandSyntaxException;
use pocketmine\lang\KnownTranslationFactory;
use pocketmine\lang\KnownTranslationKeys;
use pocketmine\permission\DefaultPermissionNames;
use function count;
@ -36,8 +35,8 @@ class PardonCommand extends VanillaCommand{
public function __construct(string $name){
parent::__construct(
$name,
KnownTranslationKeys::POCKETMINE_COMMAND_UNBAN_PLAYER_DESCRIPTION,
KnownTranslationKeys::COMMANDS_UNBAN_USAGE,
KnownTranslationFactory::pocketmine_command_unban_player_description(),
KnownTranslationFactory::commands_unban_usage(),
["unban"]
);
$this->setPermission(DefaultPermissionNames::COMMAND_UNBAN_PLAYER);

View File

@ -27,18 +27,17 @@ use pocketmine\command\Command;
use pocketmine\command\CommandSender;
use pocketmine\command\utils\InvalidCommandSyntaxException;
use pocketmine\lang\KnownTranslationFactory;
use pocketmine\lang\KnownTranslationKeys;
use pocketmine\permission\DefaultPermissionNames;
use function count;
use function preg_match;
use function inet_pton;
class PardonIpCommand extends VanillaCommand{
public function __construct(string $name){
parent::__construct(
$name,
KnownTranslationKeys::POCKETMINE_COMMAND_UNBAN_IP_DESCRIPTION,
KnownTranslationKeys::COMMANDS_UNBANIP_USAGE,
KnownTranslationFactory::pocketmine_command_unban_ip_description(),
KnownTranslationFactory::commands_unbanip_usage(),
["unban-ip"]
);
$this->setPermission(DefaultPermissionNames::COMMAND_UNBAN_IP);
@ -53,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

@ -30,7 +30,6 @@ use pocketmine\command\utils\InvalidCommandSyntaxException;
use pocketmine\item\ItemFactory;
use pocketmine\item\VanillaItems;
use pocketmine\lang\KnownTranslationFactory;
use pocketmine\lang\KnownTranslationKeys;
use pocketmine\math\Vector3;
use pocketmine\permission\DefaultPermissionNames;
use pocketmine\player\Player;
@ -79,8 +78,8 @@ class ParticleCommand extends VanillaCommand{
public function __construct(string $name){
parent::__construct(
$name,
KnownTranslationKeys::POCKETMINE_COMMAND_PARTICLE_DESCRIPTION,
KnownTranslationKeys::POCKETMINE_COMMAND_PARTICLE_USAGE
KnownTranslationFactory::pocketmine_command_particle_description(),
KnownTranslationFactory::pocketmine_command_particle_usage()
);
$this->setPermission(DefaultPermissionNames::COMMAND_PARTICLE);
}

View File

@ -25,7 +25,6 @@ namespace pocketmine\command\defaults;
use pocketmine\command\CommandSender;
use pocketmine\lang\KnownTranslationFactory;
use pocketmine\lang\KnownTranslationKeys;
use pocketmine\permission\DefaultPermissionNames;
use pocketmine\plugin\Plugin;
use pocketmine\utils\TextFormat;
@ -40,8 +39,8 @@ class PluginsCommand extends VanillaCommand{
public function __construct(string $name){
parent::__construct(
$name,
KnownTranslationKeys::POCKETMINE_COMMAND_PLUGINS_DESCRIPTION,
KnownTranslationKeys::POCKETMINE_COMMAND_PLUGINS_USAGE,
KnownTranslationFactory::pocketmine_command_plugins_description(),
null,
["pl"]
);
$this->setPermission(DefaultPermissionNames::COMMAND_PLUGINS);

View File

@ -26,7 +26,6 @@ namespace pocketmine\command\defaults;
use pocketmine\command\Command;
use pocketmine\command\CommandSender;
use pocketmine\lang\KnownTranslationFactory;
use pocketmine\lang\KnownTranslationKeys;
use pocketmine\permission\DefaultPermissionNames;
use function microtime;
use function round;
@ -36,8 +35,7 @@ class SaveCommand extends VanillaCommand{
public function __construct(string $name){
parent::__construct(
$name,
KnownTranslationKeys::POCKETMINE_COMMAND_SAVE_DESCRIPTION,
KnownTranslationKeys::COMMANDS_SAVE_USAGE
KnownTranslationFactory::pocketmine_command_save_description()
);
$this->setPermission(DefaultPermissionNames::COMMAND_SAVE_PERFORM);
}

View File

@ -26,7 +26,6 @@ namespace pocketmine\command\defaults;
use pocketmine\command\Command;
use pocketmine\command\CommandSender;
use pocketmine\lang\KnownTranslationFactory;
use pocketmine\lang\KnownTranslationKeys;
use pocketmine\permission\DefaultPermissionNames;
class SaveOffCommand extends VanillaCommand{
@ -34,8 +33,7 @@ class SaveOffCommand extends VanillaCommand{
public function __construct(string $name){
parent::__construct(
$name,
KnownTranslationKeys::POCKETMINE_COMMAND_SAVEOFF_DESCRIPTION,
KnownTranslationKeys::COMMANDS_SAVE_OFF_USAGE
KnownTranslationFactory::pocketmine_command_saveoff_description()
);
$this->setPermission(DefaultPermissionNames::COMMAND_SAVE_DISABLE);
}

View File

@ -26,7 +26,6 @@ namespace pocketmine\command\defaults;
use pocketmine\command\Command;
use pocketmine\command\CommandSender;
use pocketmine\lang\KnownTranslationFactory;
use pocketmine\lang\KnownTranslationKeys;
use pocketmine\permission\DefaultPermissionNames;
class SaveOnCommand extends VanillaCommand{
@ -34,8 +33,7 @@ class SaveOnCommand extends VanillaCommand{
public function __construct(string $name){
parent::__construct(
$name,
KnownTranslationKeys::POCKETMINE_COMMAND_SAVEON_DESCRIPTION,
KnownTranslationKeys::COMMANDS_SAVE_ON_USAGE
KnownTranslationFactory::pocketmine_command_saveon_description()
);
$this->setPermission(DefaultPermissionNames::COMMAND_SAVE_ENABLE);
}

View File

@ -27,7 +27,6 @@ use pocketmine\command\CommandSender;
use pocketmine\command\utils\InvalidCommandSyntaxException;
use pocketmine\console\ConsoleCommandSender;
use pocketmine\lang\KnownTranslationFactory;
use pocketmine\lang\KnownTranslationKeys;
use pocketmine\permission\DefaultPermissionNames;
use pocketmine\player\Player;
use pocketmine\utils\TextFormat;
@ -39,8 +38,8 @@ class SayCommand extends VanillaCommand{
public function __construct(string $name){
parent::__construct(
$name,
KnownTranslationKeys::POCKETMINE_COMMAND_SAY_DESCRIPTION,
KnownTranslationKeys::COMMANDS_SAY_USAGE
KnownTranslationFactory::pocketmine_command_say_description(),
KnownTranslationFactory::commands_say_usage()
);
$this->setPermission(DefaultPermissionNames::COMMAND_SAY);
}

View File

@ -25,7 +25,6 @@ namespace pocketmine\command\defaults;
use pocketmine\command\CommandSender;
use pocketmine\lang\KnownTranslationFactory;
use pocketmine\lang\KnownTranslationKeys;
use pocketmine\permission\DefaultPermissionNames;
use pocketmine\player\Player;
@ -34,8 +33,7 @@ class SeedCommand extends VanillaCommand{
public function __construct(string $name){
parent::__construct(
$name,
KnownTranslationKeys::POCKETMINE_COMMAND_SEED_DESCRIPTION,
KnownTranslationKeys::COMMANDS_SEED_USAGE
KnownTranslationFactory::pocketmine_command_seed_description()
);
$this->setPermission(DefaultPermissionNames::COMMAND_SEED);
}

View File

@ -27,21 +27,20 @@ use pocketmine\command\Command;
use pocketmine\command\CommandSender;
use pocketmine\command\utils\InvalidCommandSyntaxException;
use pocketmine\lang\KnownTranslationFactory;
use pocketmine\lang\KnownTranslationKeys;
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{
public function __construct(string $name){
parent::__construct(
$name,
KnownTranslationKeys::POCKETMINE_COMMAND_SETWORLDSPAWN_DESCRIPTION,
KnownTranslationKeys::COMMANDS_SETWORLDSPAWN_USAGE
KnownTranslationFactory::pocketmine_command_setworldspawn_description(),
KnownTranslationFactory::commands_setworldspawn_usage()
);
$this->setPermission(DefaultPermissionNames::COMMAND_SETWORLDSPAWN);
}
@ -55,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

@ -27,7 +27,6 @@ use pocketmine\command\Command;
use pocketmine\command\CommandSender;
use pocketmine\command\utils\InvalidCommandSyntaxException;
use pocketmine\lang\KnownTranslationFactory;
use pocketmine\lang\KnownTranslationKeys;
use pocketmine\permission\DefaultPermissionNames;
use pocketmine\player\Player;
use pocketmine\utils\TextFormat;
@ -41,8 +40,8 @@ class SpawnpointCommand extends VanillaCommand{
public function __construct(string $name){
parent::__construct(
$name,
KnownTranslationKeys::POCKETMINE_COMMAND_SPAWNPOINT_DESCRIPTION,
KnownTranslationKeys::COMMANDS_SPAWNPOINT_USAGE
KnownTranslationFactory::pocketmine_command_spawnpoint_description(),
KnownTranslationFactory::commands_spawnpoint_usage()
);
$this->setPermission(DefaultPermissionNames::COMMAND_SPAWNPOINT);
}

View File

@ -24,7 +24,7 @@ declare(strict_types=1);
namespace pocketmine\command\defaults;
use pocketmine\command\CommandSender;
use pocketmine\lang\KnownTranslationKeys;
use pocketmine\lang\KnownTranslationFactory;
use pocketmine\permission\DefaultPermissionNames;
use pocketmine\utils\Process;
use pocketmine\utils\TextFormat;
@ -39,8 +39,7 @@ class StatusCommand extends VanillaCommand{
public function __construct(string $name){
parent::__construct(
$name,
KnownTranslationKeys::POCKETMINE_COMMAND_STATUS_DESCRIPTION,
KnownTranslationKeys::POCKETMINE_COMMAND_STATUS_USAGE
KnownTranslationFactory::pocketmine_command_status_description()
);
$this->setPermission(DefaultPermissionNames::COMMAND_STATUS);
}

View File

@ -26,7 +26,6 @@ namespace pocketmine\command\defaults;
use pocketmine\command\Command;
use pocketmine\command\CommandSender;
use pocketmine\lang\KnownTranslationFactory;
use pocketmine\lang\KnownTranslationKeys;
use pocketmine\permission\DefaultPermissionNames;
class StopCommand extends VanillaCommand{
@ -34,8 +33,7 @@ class StopCommand extends VanillaCommand{
public function __construct(string $name){
parent::__construct(
$name,
KnownTranslationKeys::POCKETMINE_COMMAND_STOP_DESCRIPTION,
KnownTranslationKeys::COMMANDS_STOP_USAGE
KnownTranslationFactory::pocketmine_command_stop_description()
);
$this->setPermission(DefaultPermissionNames::COMMAND_STOP);
}

View File

@ -28,11 +28,11 @@ use pocketmine\command\CommandSender;
use pocketmine\command\utils\InvalidCommandSyntaxException;
use pocketmine\entity\Location;
use pocketmine\lang\KnownTranslationFactory;
use pocketmine\lang\KnownTranslationKeys;
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;
@ -42,8 +42,8 @@ class TeleportCommand extends VanillaCommand{
public function __construct(string $name){
parent::__construct(
$name,
KnownTranslationKeys::POCKETMINE_COMMAND_TP_DESCRIPTION,
KnownTranslationKeys::COMMANDS_TP_USAGE,
KnownTranslationFactory::pocketmine_command_tp_description(),
KnownTranslationFactory::commands_tp_usage(),
["teleport"]
);
$this->setPermission(DefaultPermissionNames::COMMAND_TELEPORT);
@ -112,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

@ -27,7 +27,6 @@ use pocketmine\command\Command;
use pocketmine\command\CommandSender;
use pocketmine\command\utils\InvalidCommandSyntaxException;
use pocketmine\lang\KnownTranslationFactory;
use pocketmine\lang\KnownTranslationKeys;
use pocketmine\permission\DefaultPermissionNames;
use pocketmine\player\Player;
use pocketmine\utils\TextFormat;
@ -40,8 +39,8 @@ class TellCommand extends VanillaCommand{
public function __construct(string $name){
parent::__construct(
$name,
KnownTranslationKeys::POCKETMINE_COMMAND_TELL_DESCRIPTION,
KnownTranslationKeys::COMMANDS_MESSAGE_USAGE,
KnownTranslationFactory::pocketmine_command_tell_description(),
KnownTranslationFactory::commands_message_usage(),
["w", "msg"]
);
$this->setPermission(DefaultPermissionNames::COMMAND_TELL);

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