Compare commits

...

75 Commits
4.0.3 ... 4.0.7

Author SHA1 Message Date
58ba4f680f Release 4.0.7 2022-01-21 19:39:30 +00:00
8c5cc67e07 Updated baseline 2022-01-21 19:38:59 +00:00
ab8b24bcd2 Merge branch 'stable' of github.com:pmmp/PocketMine-MP into stable 2022-01-21 19:15:59 +00:00
94c4f58667 Fixed bogus test 2022-01-21 19:13:36 +00:00
c10eda5eae InGamePacketHandler: limit depth of form responses to 2
form responses should only contain string|int|float|bool|null. Arrays or objects appearing in here are likely malicious.
2022-01-21 19:11:58 +00:00
ed312863a7 ignore phpstan bug 2022-01-21 18:43:53 +00:00
387c13beff InGamePacketHandler: fixed invalid JSON being treated as form close 2022-01-21 18:32:58 +00:00
56fe71d939 InGamePacketHandler: fixed crash in form handling when invalid JSON is given 2022-01-21 17:34:13 +00:00
73d8c87b76 Bump phpunit/phpunit from 9.5.11 to 9.5.12 (#4748)
Bumps [phpunit/phpunit](https://github.com/sebastianbergmann/phpunit) from 9.5.11 to 9.5.12.
- [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.11...9.5.12)

---
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>
2022-01-21 14:53:03 +00:00
061d851fbd World: do not update entities which have been flagged for despawn
fixes #4718
2022-01-20 16:27:21 +00:00
a67aef0477 PlayerInteractEvent: updated documentation 2022-01-20 16:10:37 +00:00
858024afb7 Remove useless docs noticed by php-cs-fixer 3.5 2022-01-18 00:24:12 +00:00
eaaf00ca2b Merge branch 'stable' of github.com:pmmp/PocketMine-MP into stable 2022-01-18 00:23:39 +00:00
f1723acfd3 UnsafeForeachArrayOfStringRule: use statically analysable function reference
this will ensure that it get automatically updated during refactors.
2022-01-18 00:23:29 +00:00
8da27ea0aa UnsafeForeachArrayOfStringRule: fixed outdated function name 2022-01-18 00:15:44 +00:00
388622d55d Bump pocketmine/locale-data from 2.3.0 to 2.3.33 (#4735)
Bumps [pocketmine/locale-data](https://github.com/pmmp/Language) from 2.3.0 to 2.3.33.
- [Release notes](https://github.com/pmmp/Language/releases)
- [Commits](https://github.com/pmmp/Language/compare/2.3.0...2.3.33)

---
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>
2022-01-17 20:46:38 +00:00
9f4fcfafdb Fixed some incorrect block breaking times (#4723) 2022-01-16 20:57:16 +00:00
6679c53e56 BrewingStand: fixed collision box 2022-01-15 16:41:27 +00:00
9d061e86af 4.0.7 is next 2022-01-13 21:46:30 +00:00
f7d25f251e Release 4.0.6 2022-01-13 21:46:30 +00:00
0ccb47fb07 make-release: trap more errors 2022-01-13 21:46:06 +00:00
0973472842 actions: bump to 8.0.14 2022-01-13 21:23:23 +00:00
f126479c37 InGamePacketHandler: check the validity of facing values given by the client 2022-01-13 21:21:15 +00:00
d34f4b28b3 Bump pocketmine/binaryutils from 0.2.3 to 0.2.4 (#4726)
Bumps [pocketmine/binaryutils](https://github.com/pmmp/BinaryUtils) from 0.2.3 to 0.2.4.
- [Release notes](https://github.com/pmmp/BinaryUtils/releases)
- [Commits](https://github.com/pmmp/BinaryUtils/compare/0.2.3...0.2.4)

---
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>
2022-01-13 14:21:32 +00:00
8a65fd273a Updated RakLib to 0.14.3 2022-01-10 22:29:38 +00:00
248cc0ef49 actions: colorize diff output on CS failure 2022-01-10 22:06:07 +00:00
d1726aa20c CS: use fully_qualified_strict_types 2022-01-10 21:41:56 +00:00
58e1e7bd6f Worker: fixed missing AsyncTask import for documentation (#4719)
OCD from f5c9c02e09
2022-01-10 15:12:37 +00:00
0a5b146189 substr() returns an empty string instead of false in 8.0
an empty string will pass through preg_match_all() without any harmful effects, so we don't need to check for it.
2022-01-07 22:38:00 +00:00
b4e1871899 Updated PHPStan baseline 2022-01-07 21:49:49 +00:00
78eaa0993d Merge branch 'legacy/pm3' into stable 2022-01-07 21:48:28 +00:00
bee2aba813 Updated PHPStan baseline 2022-01-07 21:46:35 +00:00
af81f80cf3 Updated PHPStan 2022-01-07 21:45:35 +00:00
43c5d08042 Merge branch 'stable' of github.com:pmmp/PocketMine-MP into stable 2022-01-07 20:15:30 +00:00
6d249026cc Merge branch 'legacy/pm3' into stable 2022-01-07 20:15:15 +00:00
ed2145b6a4 php-cs-fixer: enforce EOF newlines 2022-01-07 20:12:21 +00:00
3e6c157217 Bump phpstan/phpstan from 1.3.1 to 1.3.3 (#4712)
Bumps [phpstan/phpstan](https://github.com/phpstan/phpstan) from 1.3.1 to 1.3.3.
- [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.3.1...1.3.3)

---
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>
2022-01-07 15:20:33 +00:00
86beeb8255 readme: update badge links
[ci skip]
2022-01-06 17:11:03 +00:00
230a3c9839 Bump phpstan/phpstan from 1.2.0 to 1.3.1 (#4702)
Bumps [phpstan/phpstan](https://github.com/phpstan/phpstan) from 1.2.0 to 1.3.1.
- [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.2.0...1.3.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>
2022-01-05 13:49:29 +00:00
35f205b476 4.0.6 is next 2022-01-04 20:51:37 +00:00
e7d17eb4d3 Release 4.0.5 2022-01-04 20:51:36 +00:00
73168a0e39 Merge branch 'legacy/pm3' into stable 2022-01-04 20:49:32 +00:00
e8893dd91f 3.26.6 is next 2022-01-04 20:47:31 +00:00
a4af1609ea Release 3.26.5 2022-01-04 20:47:31 +00:00
8c4b8a9042 CS 2022-01-04 20:44:10 +00:00
6492cac5c1 Merge pull request from GHSA-c6fg-99pr-25m9 2022-01-04 20:40:55 +00:00
958a9dbf0f Merge pull request from GHSA-c6fg-99pr-25m9
* Skin: impose length limits on skinID, geometryName and geometryData fields

* Skin: remove extra newline
2022-01-04 20:40:55 +00:00
3ed57ce49a Merge pull request from GHSA-p62j-hrxm-xcxf
This checks the following things:
- Validity of UTF-8 encoding of title, author, and page content
- Maximum soft and hard lengths of title, author, and page content (soft
  limits may be bypassed by uncancelling PlayerEditBookEvent; hard
  limits may not be bypassed)
- Maximum number of pages. Books with more than 50 pages may still be
  edited, but may not have new pages added.
2022-01-04 20:39:02 +00:00
68f3399cfd Merge pull request from GHSA-p62j-hrxm-xcxf
This checks the following things:
- Validity of UTF-8 encoding of title, author, and page content
- Maximum soft and hard lengths of title, author, and page content (soft
  limits may be bypassed by uncancelling PlayerEditBookEvent; hard
  limits may not be bypassed)
- Maximum number of pages. Books with more than 50 pages may still be
  edited, but may not have new pages added.
2022-01-04 20:39:02 +00:00
aeab19a616 Fixed world spawn point not updating to players (#4699)
closes #4383
2022-01-04 20:31:27 +00:00
7bee72ef2d Use ~ instead of ^ for constraints on BedrockData and BedrockProtocol
I got these two mixed up - they are exactly the opposite of what I thought. ~ is the stricter operator.
2022-01-04 00:54:09 +00:00
0d595e4324 Update Language dependency 2022-01-04 00:47:04 +00:00
e43e0189df InGamePacketHandler: do not pass bare integers from BookEditPacket directly into event
while these currently happen to be identical, they may not be in the future.

Really this should be represented by an enum.
2022-01-03 20:20:32 +00:00
decd1da2d0 BaseSign: remove dead TODO comment 2022-01-03 19:33:03 +00:00
bcc0f1e733 Fixed desynchronization of hunger when cancelling food-related events (#4691) 2022-01-03 19:11:32 +00:00
f62cfe8ae3 4.0.5 is next 2022-01-01 16:50:03 +00:00
b903e90dc2 Release 4.0.4 2022-01-01 16:50:02 +00:00
c8247786d7 Player: check chat length check with strlen() before mb_strlen()
mb_strlen() is O(n), whereas strlen() is O(1). If we receive very large chat messages (e.g. 2 MB), mb_strlen() will take a very long time to return a result (around 8ms on my machine).
Since the max size of a UTF-8 character is 4 bytes (according to standard), we can use strlen() with 4x the char limit to gate it and prevent this from happening.
2022-01-01 16:46:00 +00:00
f486b5f4a7 Player: fixed fall damage when sprinting down stairs (#4685)
Due to the way positions are updated over the network, we only see the end result of a movement and not its preceding actions. In addition, we don't know for sure whether the MCPE collision checks work the same exact way as PM.

TL;DR: It's possible for the client to capture and send a movement frame after they collided with a step and then already moved forward from it some distance, resulting in a weird arc pattern.

This PR checks the range between the old and new positions for collision boxes to ensure that all possible areas are checked for detecting fall damage.

This has been tested and successfully resolves various issues involving running down stairs:
- missing sounds
- random fall damage
2022-01-01 15:41:19 +00:00
54d6b83fc2 Entity: pass the appropriate value for AFFECTED_BY_GRAVITY 2022-01-01 15:39:46 +00:00
eedea38669 Improve performance of loading player inventories 2022-01-01 15:26:42 +00:00
3c6146b5e0 ContainerTrait: avoid absurdly inefficient use of setItem()
this substantially improves the performance of loading containers such as chests.
2022-01-01 15:05:32 +00:00
72f2c794ab SimpleInventory: improved performance of setContents()
avoid the overhead incurred by clear() and setItem(), because in internalSetContents(), we already have no listeners or viewers to talk to anyway, so this is just spamming shit into /dev/null.
2021-12-31 18:32:19 +00:00
38b6b39cb3 Filesystem: workaround a stupid Windows issue in safeFilePutContents()
occasionally Windows will randomly decide to deny us access to rename the file for no reason whatsoever. If this happens, we attempt an old-style copy and delete.
If the rename failed for a legit reason, the copy and delete should also fail and generate an error message. If it was Windows being a spaz, it should work normally without errors.
2021-12-29 15:26:34 +00:00
fcc4757209 Merge branch 'legacy/pm3' into stable 2021-12-27 21:54:56 +00:00
d9c70cb176 start.cmd: prevent idiotic behaviour when paths contain characters such as brackets
god I hate this shit so much
2021-12-27 21:54:32 +00:00
4aab0565c0 ChunkCache: fixed corner case in cache restart on AsyncTask error
the cache may have been destroyed since the task inception, leading to an exception being thrown.
2021-12-27 18:11:55 +00:00
8943d8a2a7 Player: fixed maximum message size limits to match vanilla bugrock 2021-12-27 16:51:47 +00:00
0da29beb1d Bump pocketmine/locale-data from 2.2.0 to 2.2.1 (#4667)
Bumps [pocketmine/locale-data](https://github.com/pmmp/Language) from 2.2.0 to 2.2.1.
- [Release notes](https://github.com/pmmp/Language/releases)
- [Commits](https://github.com/pmmp/Language/compare/2.2.0...2.2.1)

---
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-27 16:43:32 +00:00
157048264c Bump phpunit/phpunit from 9.5.10 to 9.5.11 (#4675)
Bumps [phpunit/phpunit](https://github.com/sebastianbergmann/phpunit) from 9.5.10 to 9.5.11.
- [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.10...9.5.11)

---
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-12-27 16:43:19 +00:00
b55aa78aec Changelog: Replaced non-existent method (#4676) 2021-12-27 15:33:02 +00:00
091673d8f1 Fixed "You can only sleep at night" message (#4671) 2021-12-23 23:52:07 +00:00
e3614d1a82 Entity: fixed game performance issue with large scale entities
this->size refers to the scaled height, but the client wants the base (unscaled) size in these properties.
This caused immense lag when, for example, setting the scale of a player to 10, because their collision box would become 180 by 60, instead of the expected 18 by 6.
2021-12-18 22:38:45 +00:00
93caf72f34 KickCommand: Add missing space
closes #4660
closes #4661
2021-12-17 21:09:14 +00:00
e6e1bca676 4.0.4 is next 2021-12-16 01:35:43 +00:00
73 changed files with 448 additions and 205 deletions

View File

@ -13,7 +13,7 @@ jobs:
strategy:
matrix:
image: [ubuntu-20.04]
php: [8.0.11]
php: [8.0.14]
steps:
- name: Build and prepare PHP cache
@ -31,7 +31,7 @@ jobs:
fail-fast: false
matrix:
image: [ubuntu-20.04]
php: [8.0.11]
php: [8.0.14]
steps:
- uses: actions/checkout@v2
@ -69,7 +69,7 @@ jobs:
fail-fast: false
matrix:
image: [ubuntu-20.04]
php: [8.0.11]
php: [8.0.14]
steps:
- uses: actions/checkout@v2
@ -107,7 +107,7 @@ jobs:
fail-fast: false
matrix:
image: [ubuntu-20.04]
php: [8.0.11]
php: [8.0.14]
steps:
- uses: actions/checkout@v2
@ -147,7 +147,7 @@ jobs:
fail-fast: false
matrix:
image: [ubuntu-20.04]
php: [8.0.11]
php: [8.0.14]
steps:
- uses: actions/checkout@v2
@ -201,4 +201,4 @@ jobs:
tools: php-cs-fixer:3.2
- name: Run PHP-CS-Fixer
run: php-cs-fixer fix --dry-run --diff
run: php-cs-fixer fix --dry-run --diff --ansi

View File

@ -36,6 +36,7 @@ return (new PhpCsFixer\Config)
],
'declare_strict_types' => true,
'elseif' => true,
'fully_qualified_strict_types' => true,
'global_namespace_import' => [
'import_constants' => true,
'import_functions' => true,
@ -74,6 +75,7 @@ return (new PhpCsFixer\Config)
'return_type_declaration' => [
'space_before' => 'one'
],
'single_blank_line_at_eof' => true,
'single_import_per_statement' => true,
'strict_param' => true,
'unary_operator_spaces' => true,

View File

@ -4,13 +4,13 @@
</p>
<p align="center">
<img src="https://github.com/pmmp/PocketMine-MP/workflows/CI/badge.svg" alt="CI" />
<img alt="GitHub release (latest SemVer)" src="https://img.shields.io/github/v/release/pmmp/PocketMine-MP?label=release&sort=semver">
<a href="https://github.com/pmmp/PocketMine-MP/actions/workflows/main.yml"><img src="https://github.com/pmmp/PocketMine-MP/workflows/CI/badge.svg" alt="CI" /></a>
<a href="https://github.com/pmmp/PocketMine-MP/releases/latest"><img alt="GitHub release (latest SemVer)" src="https://img.shields.io/github/v/release/pmmp/PocketMine-MP?label=release&sort=semver"></a>
<a href="https://hub.docker.com/r/pmmp/pocketmine-mp"><img src="https://img.shields.io/docker/v/pmmp/pocketmine-mp?logo=docker&label=image" alt="Docker image version (latest semver)" /></a>
<a href="https://discord.gg/bmSAZBG"><img src="https://img.shields.io/discord/373199722573201408?label=discord&color=7289DA&logo=discord" alt="Discord" /></a>
<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">
<a href="https://github.com/pmmp/PocketMine-MP/releases"><img alt="GitHub all releases" src="https://img.shields.io/github/downloads/pmmp/PocketMine-MP/total?label=downloads%40total"></a>
<a href="https://github.com/pmmp/PocketMine-MP/releases/latest"><img alt="GitHub release (latest by SemVer)" src="https://img.shields.io/github/downloads/pmmp/PocketMine-MP/latest/total?sort=semver"></a>
</p>
## Getting started

View File

@ -116,4 +116,3 @@ foreach(new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator($argv[1],
echo "No changes made to file $file\n";
}
}

View File

@ -75,6 +75,14 @@ const ACCEPTED_OPTS = [
"channel" => "Release channel to post this build into"
];
function systemWrapper(string $command, string $errorMessage) : void{
system($command, $result);
if($result !== 0){
echo "error: $errorMessage; aborting\n";
exit(1);
}
}
function main() : void{
$filteredOpts = [];
foreach(Utils::stringifyKeys(getopt("", ["current:", "next:", "channel:", "help"])) as $optName => $optValue){
@ -115,7 +123,7 @@ function main() : void{
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"');
systemWrapper('git add "' . dirname(__DIR__) . '/changelogs"', "failed to stage changelog changes");
system('git diff --cached --quiet "' . dirname(__DIR__) . '/changelogs"', $result);
if($result === 0){
echo "error: no changelog changes detected; aborting\n";
@ -123,14 +131,15 @@ function main() : void{
}
$versionInfoPath = dirname(__DIR__) . '/src/VersionInfo.php';
replaceVersion($versionInfoPath, $currentVer->getBaseVersion(), false, $channel);
system('git commit -m "Release ' . $currentVer->getBaseVersion() . '" --include "' . $versionInfoPath . '"');
system('git tag ' . $currentVer->getBaseVersion());
systemWrapper('git commit -m "Release ' . $currentVer->getBaseVersion() . '" --include "' . $versionInfoPath . '"', "failed to create release commit");
systemWrapper('git tag ' . $currentVer->getBaseVersion(), "failed to create release tag");
replaceVersion($versionInfoPath, $nextVer->getBaseVersion(), true, $channel);
system('git add "' . $versionInfoPath . '"');
system('git commit -m "' . $nextVer->getBaseVersion() . ' is next" --include "' . $versionInfoPath . '"');
systemWrapper('git add "' . $versionInfoPath . '"', "failed to stage changes for post-release commit");
systemWrapper('git commit -m "' . $nextVer->getBaseVersion() . ' is next" --include "' . $versionInfoPath . '"', "failed to create post-release commit");
echo "pushing changes in 5 seconds\n";
sleep(5);
system('git push origin HEAD ' . $currentVer->getBaseVersion());
systemWrapper('git push origin HEAD ' . $currentVer->getBaseVersion(), "failed to push changes to remote");
}
main();

View File

@ -26,3 +26,7 @@ Plugin developers should **only** update their required API to this version if y
- Fixed skins appearing black when using RTX resource packs.
- Fixed chunks containing furnaces in old worlds (pre-2017) being discarded as corrupted.
- This was caused by a strict corruption check detecting bad data created by a bug in PocketMine-MP that was fixed in 2017.
# 3.26.5
- Fixed several denial-of-service attack vectors related to writable book text length and encoding.
- Fixed several denial-of-service attack vectors related to skin data field lengths.

View File

@ -496,7 +496,7 @@ However, if we add `src-namespace-prefix: pmmp\TesterPlugin` to the `plugin.yml`
- `Human->onPickupXp()` -> `ExperienceManager->onPickupXp()`
- `Human->resetXpCooldown()` -> `ExperienceManager->resetXpCooldown()`
- The following API methods have been removed:
- `Human->getRawUniqueId()`: use `Human->getUniqueId()->toBinary()` instead
- `Human->getRawUniqueId()`: use `Human->getUniqueId()->getBytes()` instead
- The following classes have been removed:
- `Creature`
- `Damageable`
@ -1576,3 +1576,47 @@ Released 16th December 2021.
- Fixed player arm swing animation not being shown when attacks were cancelled by attack cooldown.
- Fixed being unable to use `/deop` to de-op a player whose name appeared in `ops.txt` with uppercase letters in it.
- Added a check for valid tile class in `BlockIdentifier`.
# 4.0.4
Released 1st January 2022.
## General
- Improved performance of loading chests and other containers from world saves.
- Improved performance of loading player inventories from saved data.
## Fixes
- Fixed a crash that could occur when a chunk failed to be prepared for chunk sending.
- Fixed fall damage when sprinting down stairs.
- Fixed message length limit for chat (now 512 instead of 255, and accounts for UTF-8).
- Fixed incorrect message being displayed when trying to sleep in a bed which is too far away.
- Fixed missing space between `Kicked by admin.` and `Reason` when using `/kick` to kick a player.
- Fixed client-side performance issue of entities with very large scale.
# 4.0.5
Released 4th January 2022.
## Fixes
- Fixed several denial-of-service attack vectors related to writable book text length and encoding.
- Fixed several denial-of-service attack vectors related to skin data field lengths.
- Fixed food bar desync when cancelling `PlayerItemConsumeEvent` in a plugin.
- Fixed compass needles not updating when the world spawn is changed.
# 4.0.6
Released 13th January 2022.
## Fixes
- Fixed server crash on invalid facing values provided by the client when placing or breaking blocks.
- Fixed documentation link to AsyncTask in Worker.
# 4.0.7
Released 21st January 2022.
## General
- Max nesting of form responses is now limited to 2.
- Updated outdated documentation of `PlayerInteractEvent`.
## Fixes
- Fixed server crash on invalid JSON provided by the client in `ModalFormResponsePacket`.
- Fixed ender pearls teleporting players when thrown by a player directly against a wall when cancelling `ProjectileLaunchEvent`.
- Fixed collision box of brewing stand.
- Fixed break times and tool types of bamboo, nether wart blocks, infested stone and leaves.

View File

@ -34,14 +34,14 @@
"adhocore/json-comment": "^1.1",
"fgrosse/phpasn1": "^2.3",
"netresearch/jsonmapper": "^4.0",
"pocketmine/bedrock-data": "^1.5.0+bedrock-1.18.0",
"pocketmine/bedrock-protocol": "^7.0.0+bedrock-1.18.0",
"pocketmine/bedrock-data": "~1.5.0+bedrock-1.18.0",
"pocketmine/bedrock-protocol": "~7.1.0+bedrock-1.18.0",
"pocketmine/binaryutils": "^0.2.1",
"pocketmine/callback-validator": "^1.0.2",
"pocketmine/classloader": "^0.2.0",
"pocketmine/color": "^0.2.0",
"pocketmine/errorhandler": "^0.3.0",
"pocketmine/locale-data": "^2.1.0",
"pocketmine/locale-data": "~2.3.0",
"pocketmine/log": "^0.4.0",
"pocketmine/log-pthreads": "^0.4.0",
"pocketmine/math": "^0.4.0",
@ -53,7 +53,7 @@
"webmozart/path-util": "^2.3"
},
"require-dev": {
"phpstan/phpstan": "1.2.0",
"phpstan/phpstan": "1.3.3",
"phpstan/phpstan-phpunit": "^1.0.0",
"phpstan/phpstan-strict-rules": "^1.0.0",
"phpunit/phpunit": "^9.2"

128
composer.lock generated
View File

@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
"content-hash": "7e9247927fa23baf3e899811c8119f95",
"content-hash": "055bec16a9bbc839f4410d09b09f2703",
"packages": [
{
"name": "adhocore/json-comment",
@ -322,16 +322,16 @@
},
{
"name": "pocketmine/binaryutils",
"version": "0.2.3",
"version": "0.2.4",
"source": {
"type": "git",
"url": "https://github.com/pmmp/BinaryUtils.git",
"reference": "dc94786fc6c30012b1892f548dbb8a8c9c0a8cd9"
"reference": "5ac7eea91afbad8dc498f5ce34ce6297d5e6ea9a"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/pmmp/BinaryUtils/zipball/dc94786fc6c30012b1892f548dbb8a8c9c0a8cd9",
"reference": "dc94786fc6c30012b1892f548dbb8a8c9c0a8cd9",
"url": "https://api.github.com/repos/pmmp/BinaryUtils/zipball/5ac7eea91afbad8dc498f5ce34ce6297d5e6ea9a",
"reference": "5ac7eea91afbad8dc498f5ce34ce6297d5e6ea9a",
"shasum": ""
},
"require": {
@ -340,7 +340,7 @@
},
"require-dev": {
"phpstan/extension-installer": "^1.0",
"phpstan/phpstan": "1.2.0",
"phpstan/phpstan": "1.3.0",
"phpstan/phpstan-phpunit": "^1.0",
"phpstan/phpstan-strict-rules": "^1.0.0",
"phpunit/phpunit": "^9.5"
@ -358,9 +358,9 @@
"description": "Classes and methods for conveniently handling binary data",
"support": {
"issues": "https://github.com/pmmp/BinaryUtils/issues",
"source": "https://github.com/pmmp/BinaryUtils/tree/0.2.3"
"source": "https://github.com/pmmp/BinaryUtils/tree/0.2.4"
},
"time": "2021-12-04T20:56:05+00:00"
"time": "2022-01-12T18:06:33+00:00"
},
{
"name": "pocketmine/callback-validator",
@ -535,16 +535,16 @@
},
{
"name": "pocketmine/locale-data",
"version": "2.2.0",
"version": "2.3.33",
"source": {
"type": "git",
"url": "https://github.com/pmmp/Language.git",
"reference": "dc88ad618a482e55b7c9fec162257efa62a67d6f"
"reference": "44998ca9c055f872a33e59cd4d2736d081ba84b5"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/pmmp/Language/zipball/dc88ad618a482e55b7c9fec162257efa62a67d6f",
"reference": "dc88ad618a482e55b7c9fec162257efa62a67d6f",
"url": "https://api.github.com/repos/pmmp/Language/zipball/44998ca9c055f872a33e59cd4d2736d081ba84b5",
"reference": "44998ca9c055f872a33e59cd4d2736d081ba84b5",
"shasum": ""
},
"type": "library",
@ -552,9 +552,9 @@
"description": "Language resources used by PocketMine-MP",
"support": {
"issues": "https://github.com/pmmp/Language/issues",
"source": "https://github.com/pmmp/Language/tree/2.2.0"
"source": "https://github.com/pmmp/Language/tree/2.3.33"
},
"time": "2021-12-15T02:01:24+00:00"
"time": "2022-01-16T22:08:04+00:00"
},
{
"name": "pocketmine/log",
@ -726,16 +726,16 @@
},
{
"name": "pocketmine/raklib",
"version": "0.14.2",
"version": "0.14.3",
"source": {
"type": "git",
"url": "https://github.com/pmmp/RakLib.git",
"reference": "e3a861187470e1facc6625040128f447ebbcbaec"
"reference": "4798576fec0364266dce23b368a7fec5e5de7927"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/pmmp/RakLib/zipball/e3a861187470e1facc6625040128f447ebbcbaec",
"reference": "e3a861187470e1facc6625040128f447ebbcbaec",
"url": "https://api.github.com/repos/pmmp/RakLib/zipball/4798576fec0364266dce23b368a7fec5e5de7927",
"reference": "4798576fec0364266dce23b368a7fec5e5de7927",
"shasum": ""
},
"require": {
@ -747,8 +747,8 @@
"pocketmine/log": "^0.3.0 || ^0.4.0"
},
"require-dev": {
"phpstan/phpstan": "0.12.99",
"phpstan/phpstan-strict-rules": "^0.12.2"
"phpstan/phpstan": "1.3.3",
"phpstan/phpstan-strict-rules": "^1.0"
},
"type": "library",
"autoload": {
@ -763,9 +763,9 @@
"description": "A RakNet server implementation written in PHP",
"support": {
"issues": "https://github.com/pmmp/RakLib/issues",
"source": "https://github.com/pmmp/RakLib/tree/0.14.2"
"source": "https://github.com/pmmp/RakLib/tree/0.14.3"
},
"time": "2021-10-04T20:39:11+00:00"
"time": "2022-01-10T21:29:48+00:00"
},
{
"name": "pocketmine/raklib-ipc",
@ -1027,21 +1027,24 @@
},
{
"name": "symfony/polyfill-ctype",
"version": "v1.23.0",
"version": "v1.24.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/polyfill-ctype.git",
"reference": "46cd95797e9df938fdd2b03693b5fca5e64b01ce"
"reference": "30885182c981ab175d4d034db0f6f469898070ab"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/46cd95797e9df938fdd2b03693b5fca5e64b01ce",
"reference": "46cd95797e9df938fdd2b03693b5fca5e64b01ce",
"url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/30885182c981ab175d4d034db0f6f469898070ab",
"reference": "30885182c981ab175d4d034db0f6f469898070ab",
"shasum": ""
},
"require": {
"php": ">=7.1"
},
"provide": {
"ext-ctype": "*"
},
"suggest": {
"ext-ctype": "For best performance"
},
@ -1086,7 +1089,7 @@
"portable"
],
"support": {
"source": "https://github.com/symfony/polyfill-ctype/tree/v1.23.0"
"source": "https://github.com/symfony/polyfill-ctype/tree/v1.24.0"
},
"funding": [
{
@ -1102,20 +1105,20 @@
"type": "tidelift"
}
],
"time": "2021-02-19T12:13:01+00:00"
"time": "2021-10-20T20:35:02+00:00"
},
{
"name": "symfony/polyfill-php80",
"version": "v1.23.1",
"version": "v1.24.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/polyfill-php80.git",
"reference": "1100343ed1a92e3a38f9ae122fc0eb21602547be"
"reference": "57b712b08eddb97c762a8caa32c84e037892d2e9"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/1100343ed1a92e3a38f9ae122fc0eb21602547be",
"reference": "1100343ed1a92e3a38f9ae122fc0eb21602547be",
"url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/57b712b08eddb97c762a8caa32c84e037892d2e9",
"reference": "57b712b08eddb97c762a8caa32c84e037892d2e9",
"shasum": ""
},
"require": {
@ -1169,7 +1172,7 @@
"shim"
],
"support": {
"source": "https://github.com/symfony/polyfill-php80/tree/v1.23.1"
"source": "https://github.com/symfony/polyfill-php80/tree/v1.24.0"
},
"funding": [
{
@ -1185,20 +1188,20 @@
"type": "tidelift"
}
],
"time": "2021-07-28T13:41:28+00:00"
"time": "2021-09-13T13:58:33+00:00"
},
{
"name": "symfony/polyfill-php81",
"version": "v1.23.0",
"version": "v1.24.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/polyfill-php81.git",
"reference": "e66119f3de95efc359483f810c4c3e6436279436"
"reference": "5de4ba2d41b15f9bd0e19b2ab9674135813ec98f"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/polyfill-php81/zipball/e66119f3de95efc359483f810c4c3e6436279436",
"reference": "e66119f3de95efc359483f810c4c3e6436279436",
"url": "https://api.github.com/repos/symfony/polyfill-php81/zipball/5de4ba2d41b15f9bd0e19b2ab9674135813ec98f",
"reference": "5de4ba2d41b15f9bd0e19b2ab9674135813ec98f",
"shasum": ""
},
"require": {
@ -1248,7 +1251,7 @@
"shim"
],
"support": {
"source": "https://github.com/symfony/polyfill-php81/tree/v1.23.0"
"source": "https://github.com/symfony/polyfill-php81/tree/v1.24.0"
},
"funding": [
{
@ -1264,7 +1267,7 @@
"type": "tidelift"
}
],
"time": "2021-05-21T13:25:03+00:00"
"time": "2021-09-13T13:58:11+00:00"
},
{
"name": "webmozart/assert",
@ -1463,9 +1466,6 @@
"require": {
"php": "^7.1 || ^8.0"
},
"replace": {
"myclabs/deep-copy": "self.version"
},
"require-dev": {
"doctrine/collections": "^1.0",
"doctrine/common": "^2.6",
@ -1783,16 +1783,16 @@
},
{
"name": "phpdocumentor/type-resolver",
"version": "1.5.1",
"version": "1.6.0",
"source": {
"type": "git",
"url": "https://github.com/phpDocumentor/TypeResolver.git",
"reference": "a12f7e301eb7258bb68acd89d4aefa05c2906cae"
"reference": "93ebd0014cab80c4ea9f5e297ea48672f1b87706"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/phpDocumentor/TypeResolver/zipball/a12f7e301eb7258bb68acd89d4aefa05c2906cae",
"reference": "a12f7e301eb7258bb68acd89d4aefa05c2906cae",
"url": "https://api.github.com/repos/phpDocumentor/TypeResolver/zipball/93ebd0014cab80c4ea9f5e297ea48672f1b87706",
"reference": "93ebd0014cab80c4ea9f5e297ea48672f1b87706",
"shasum": ""
},
"require": {
@ -1827,9 +1827,9 @@
"description": "A PSR-5 based resolver of Class names, Types and Structural Element Names",
"support": {
"issues": "https://github.com/phpDocumentor/TypeResolver/issues",
"source": "https://github.com/phpDocumentor/TypeResolver/tree/1.5.1"
"source": "https://github.com/phpDocumentor/TypeResolver/tree/1.6.0"
},
"time": "2021-10-02T14:08:47+00:00"
"time": "2022-01-04T19:58:01+00:00"
},
{
"name": "phpspec/prophecy",
@ -1900,16 +1900,16 @@
},
{
"name": "phpstan/phpstan",
"version": "1.2.0",
"version": "1.3.3",
"source": {
"type": "git",
"url": "https://github.com/phpstan/phpstan.git",
"reference": "cbe085f9fdead5b6d62e4c022ca52dc9427a10ee"
"reference": "151a51f6149855785fbd883e79768c0abc96b75f"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/phpstan/phpstan/zipball/cbe085f9fdead5b6d62e4c022ca52dc9427a10ee",
"reference": "cbe085f9fdead5b6d62e4c022ca52dc9427a10ee",
"url": "https://api.github.com/repos/phpstan/phpstan/zipball/151a51f6149855785fbd883e79768c0abc96b75f",
"reference": "151a51f6149855785fbd883e79768c0abc96b75f",
"shasum": ""
},
"require": {
@ -1925,7 +1925,7 @@
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.2-dev"
"dev-master": "1.3-dev"
}
},
"autoload": {
@ -1940,7 +1940,7 @@
"description": "PHPStan - PHP Static Analysis Tool",
"support": {
"issues": "https://github.com/phpstan/phpstan/issues",
"source": "https://github.com/phpstan/phpstan/tree/1.2.0"
"source": "https://github.com/phpstan/phpstan/tree/1.3.3"
},
"funding": [
{
@ -1960,7 +1960,7 @@
"type": "tidelift"
}
],
"time": "2021-11-18T14:09:01+00:00"
"time": "2022-01-07T09:49:03+00:00"
},
{
"name": "phpstan/phpstan-phpunit",
@ -2388,16 +2388,16 @@
},
{
"name": "phpunit/phpunit",
"version": "9.5.10",
"version": "9.5.12",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/phpunit.git",
"reference": "c814a05837f2edb0d1471d6e3f4ab3501ca3899a"
"reference": "93d4bf4c37aec6384bb9e5d390d9049a463a7256"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/c814a05837f2edb0d1471d6e3f4ab3501ca3899a",
"reference": "c814a05837f2edb0d1471d6e3f4ab3501ca3899a",
"url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/93d4bf4c37aec6384bb9e5d390d9049a463a7256",
"reference": "93d4bf4c37aec6384bb9e5d390d9049a463a7256",
"shasum": ""
},
"require": {
@ -2475,11 +2475,11 @@
],
"support": {
"issues": "https://github.com/sebastianbergmann/phpunit/issues",
"source": "https://github.com/sebastianbergmann/phpunit/tree/9.5.10"
"source": "https://github.com/sebastianbergmann/phpunit/tree/9.5.12"
},
"funding": [
{
"url": "https://phpunit.de/donate.html",
"url": "https://phpunit.de/sponsors.html",
"type": "custom"
},
{
@ -2487,7 +2487,7 @@
"type": "github"
}
],
"time": "2021-09-25T07:38:51+00:00"
"time": "2022-01-21T05:54:47+00:00"
},
{
"name": "sebastian/cli-parser",
@ -3541,5 +3541,5 @@
"platform-overrides": {
"php": "8.0.0"
},
"plugin-api-version": "2.1.0"
"plugin-api-version": "2.2.0"
}

View File

@ -31,7 +31,7 @@ use function str_repeat;
final class VersionInfo{
public const NAME = "PocketMine-MP";
public const BASE_VERSION = "4.0.3";
public const BASE_VERSION = "4.0.7";
public const IS_DEVELOPMENT_BUILD = false;
public const BUILD_CHANNEL = "stable";

View File

@ -37,8 +37,6 @@ use function assert;
use function strlen;
abstract class BaseSign extends Transparent{
//TODO: conditionally useless properties, find a way to fix
protected SignText $text;
protected ?int $editorEntityRuntimeId = null;

View File

@ -145,7 +145,7 @@ class Bed extends Transparent{
$isNight = ($time >= World::TIME_NIGHT and $time < World::TIME_SUNRISE);
if(!$isNight){
$player->sendMessage(KnownTranslationFactory::tile_bed_tooFar()->prefix(TextFormat::GRAY));
$player->sendMessage(KnownTranslationFactory::tile_bed_noSleep()->prefix(TextFormat::GRAY));
return true;
}

View File

@ -115,7 +115,14 @@ class BlockFactory{
$this->registerAllMeta(new ActivatorRail(new BID(Ids::ACTIVATOR_RAIL, 0), "Activator Rail", $railBreakInfo));
$this->registerAllMeta(new Air(new BID(Ids::AIR, 0), "Air", BlockBreakInfo::indestructible(-1.0)));
$this->registerAllMeta(new Anvil(new BID(Ids::ANVIL, 0), "Anvil", new BlockBreakInfo(5.0, BlockToolType::PICKAXE, ToolTier::WOOD()->getHarvestLevel(), 6000.0)));
$this->registerAllMeta(new Bamboo(new BID(Ids::BAMBOO, 0), "Bamboo", new BlockBreakInfo(2.0 /* 1.0 in PC */, BlockToolType::AXE)));
$this->registerAllMeta(new Bamboo(new BID(Ids::BAMBOO, 0), "Bamboo", new class(2.0 /* 1.0 in PC */, BlockToolType::AXE) extends BlockBreakInfo{
public function getBreakTime(Item $item) : float{
if($item->getBlockToolType() === BlockToolType::SWORD){
return 0.0;
}
return parent::getBreakTime($item);
}
}));
$this->registerAllMeta(new BambooSapling(new BID(Ids::BAMBOO_SAPLING, 0), "Bamboo Sapling", BlockBreakInfo::instant()));
$bannerBreakInfo = new BlockBreakInfo(1.0, BlockToolType::AXE);
@ -270,7 +277,7 @@ class BlockFactory{
$this->registerAllMeta(new NetherPortal(new BID(Ids::PORTAL, 0), "Nether Portal", BlockBreakInfo::indestructible(0.0)));
$this->registerAllMeta(new NetherQuartzOre(new BID(Ids::NETHER_QUARTZ_ORE, 0), "Nether Quartz Ore", new BlockBreakInfo(3.0, BlockToolType::PICKAXE, ToolTier::WOOD()->getHarvestLevel())));
$this->registerAllMeta(new NetherReactor(new BID(Ids::NETHERREACTOR, 0), "Nether Reactor Core", new BlockBreakInfo(3.0, BlockToolType::PICKAXE, ToolTier::WOOD()->getHarvestLevel())));
$this->registerAllMeta(new Opaque(new BID(Ids::NETHER_WART_BLOCK, 0), "Nether Wart Block", new BlockBreakInfo(1.0)));
$this->registerAllMeta(new Opaque(new BID(Ids::NETHER_WART_BLOCK, 0), "Nether Wart Block", new BlockBreakInfo(1.0, BlockToolType::HOE)));
$this->registerAllMeta(new NetherWartPlant(new BID(Ids::NETHER_WART_PLANT, 0, ItemIds::NETHER_WART), "Nether Wart", BlockBreakInfo::instant()));
$this->registerAllMeta(new Netherrack(new BID(Ids::NETHERRACK, 0), "Netherrack", new BlockBreakInfo(0.4, BlockToolType::PICKAXE, ToolTier::WOOD()->getHarvestLevel())));
$this->registerAllMeta(new Note(new BID(Ids::NOTEBLOCK, 0, null, TileNote::class), "Note Block", new BlockBreakInfo(0.8, BlockToolType::AXE)));
@ -365,7 +372,7 @@ class BlockFactory{
$crackedStoneBrick = new Opaque(new BID(Ids::STONEBRICK, Meta::STONE_BRICK_CRACKED), "Cracked Stone Bricks", $stoneBreakInfo),
$chiseledStoneBrick = new Opaque(new BID(Ids::STONEBRICK, Meta::STONE_BRICK_CHISELED), "Chiseled Stone Bricks", $stoneBreakInfo)
);
$infestedStoneBreakInfo = new BlockBreakInfo(0.75);
$infestedStoneBreakInfo = new BlockBreakInfo(0.75, BlockToolType::PICKAXE);
$this->registerAllMeta(
new InfestedStone(new BID(Ids::MONSTER_EGG, Meta::INFESTED_STONE), "Infested Stone", $infestedStoneBreakInfo, $stone),
new InfestedStone(new BID(Ids::MONSTER_EGG, Meta::INFESTED_STONE_BRICK), "Infested Stone Brick", $infestedStoneBreakInfo, $stoneBrick),
@ -441,7 +448,7 @@ class BlockFactory{
$this->registerAllMeta(new UnderwaterTorch(new BID(Ids::UNDERWATER_TORCH, 0), "Underwater Torch", BlockBreakInfo::instant()));
$this->registerAllMeta(new Vine(new BID(Ids::VINE, 0), "Vines", new BlockBreakInfo(0.2, BlockToolType::AXE)));
$this->registerAllMeta(new Water(new BIDFlattened(Ids::FLOWING_WATER, [Ids::STILL_WATER], 0), "Water", BlockBreakInfo::indestructible(500.0)));
$this->registerAllMeta(new WaterLily(new BID(Ids::LILY_PAD, 0), "Lily Pad", new BlockBreakInfo(0.6)));
$this->registerAllMeta(new WaterLily(new BID(Ids::LILY_PAD, 0), "Lily Pad", BlockBreakInfo::instant()));
$weightedPressurePlateBreakInfo = new BlockBreakInfo(0.5, BlockToolType::PICKAXE, ToolTier::WOOD()->getHarvestLevel());
$this->registerAllMeta(new WeightedPressurePlateHeavy(new BID(Ids::HEAVY_WEIGHTED_PRESSURE_PLATE, 0), "Weighted Pressure Plate Heavy", $weightedPressurePlateBreakInfo));
@ -449,7 +456,14 @@ class BlockFactory{
$this->registerAllMeta(new Wheat(new BID(Ids::WHEAT_BLOCK, 0), "Wheat Block", BlockBreakInfo::instant()));
$planksBreakInfo = new BlockBreakInfo(2.0, BlockToolType::AXE, 0, 15.0);
$leavesBreakInfo = new BlockBreakInfo(0.2, BlockToolType::SHEARS);
$leavesBreakInfo = new class(0.2, BlockToolType::HOE) extends BlockBreakInfo{
public function getBreakTime(Item $item) : float{
if($item->getBlockToolType() === BlockToolType::SHEARS){
return 0.0;
}
return parent::getBreakTime($item);
}
};
$signBreakInfo = new BlockBreakInfo(1.0, BlockToolType::AXE);
$logBreakInfo = new BlockBreakInfo(2.0, BlockToolType::AXE);
$woodenDoorBreakInfo = new BlockBreakInfo(3.0, BlockToolType::AXE, 0, 15.0);

View File

@ -26,6 +26,9 @@ namespace pocketmine\block;
use pocketmine\block\tile\BrewingStand as TileBrewingStand;
use pocketmine\block\utils\BrewingStandSlot;
use pocketmine\item\Item;
use pocketmine\math\Axis;
use pocketmine\math\AxisAlignedBB;
use pocketmine\math\Facing;
use pocketmine\math\Vector3;
use pocketmine\player\Player;
use function array_key_exists;
@ -67,6 +70,19 @@ class BrewingStand extends Transparent{
return 0b111;
}
protected function recalculateCollisionBoxes() : array{
return [
//bottom slab part - in PC this is also inset on X/Z by 1/16, but Bedrock sucks
AxisAlignedBB::one()->trim(Facing::UP, 7 / 8),
//center post
AxisAlignedBB::one()
->squash(Axis::X, 7 / 16)
->squash(Axis::Z, 7 / 16)
->trim(Facing::UP, 1 / 8)
];
}
public function hasSlot(BrewingStandSlot $slot) : bool{
return array_key_exists($slot->id(), $this->slots);
}

View File

@ -34,4 +34,4 @@ final class CraftingTableInventory extends CraftingGrid implements BlockInventor
$this->holder = $holder;
parent::__construct(CraftingGrid::SIZE_BIG);
}
}
}

View File

@ -48,11 +48,14 @@ trait ContainerTrait{
$inventory = $this->getRealInventory();
$listeners = $inventory->getListeners()->toArray();
$inventory->getListeners()->remove(...$listeners); //prevent any events being fired by initialization
$inventory->clearAll();
$newContents = [];
/** @var CompoundTag $itemNBT */
foreach($inventoryTag as $itemNBT){
$inventory->setItem($itemNBT->getByte("Slot"), Item::nbtDeserialize($itemNBT));
$newContents[$itemNBT->getByte("Slot")] = Item::nbtDeserialize($itemNBT);
}
$inventory->setContents($newContents);
$inventory->getListeners()->add(...$listeners);
}

View File

@ -59,7 +59,7 @@ class KickCommand extends VanillaCommand{
$reason = trim(implode(" ", $args));
if(($player = $sender->getServer()->getPlayerByPrefix($name)) instanceof Player){
$player->kick("Kicked by admin." . ($reason !== "" ? "Reason: " . $reason : ""));
$player->kick("Kicked by admin." . ($reason !== "" ? " Reason: " . $reason : ""));
if($reason !== ""){
Command::broadcastCommandMessage($sender, KnownTranslationFactory::commands_kick_success_reason($player->getName(), $reason));
}else{

View File

@ -65,4 +65,4 @@ final class FurnaceRecipeManager{
public function match(Item $input) : ?FurnaceRecipe{
return $this->furnaceRecipes[$input->getId() . ":" . $input->getMeta()] ?? $this->furnaceRecipes[$input->getId() . ":?"] ?? null;
}
}
}

View File

@ -81,4 +81,4 @@ final class CrashDumpData implements \JsonSerializable{
$result["server.properties"] = $this->serverDotProperties;
return $result;
}
}
}

View File

@ -43,4 +43,4 @@ final class CrashDumpDataGeneral{
public string $os,
public array $composer_libraries,
){}
}
}

View File

@ -42,4 +42,4 @@ final class CrashDumpDataPluginEntry{
public string $load,
public string $website,
){}
}
}

View File

@ -100,4 +100,4 @@ final class CrashDumpRenderer{
public function addLine(string $line = "") : void{
fwrite($this->fp, $line . PHP_EOL);
}
}
}

View File

@ -25,4 +25,4 @@ namespace pocketmine\data;
final class SavedDataLoadingException extends \RuntimeException{
}
}

View File

@ -32,4 +32,4 @@ final class LegacyBiomeIdToStringIdMap extends LegacyToStringBidirectionalIdMap{
public function __construct(){
parent::__construct(Path::join(\pocketmine\BEDROCK_DATA_PATH, 'biome_id_map.json'));
}
}
}

View File

@ -1589,8 +1589,8 @@ abstract class Entity{
protected function syncNetworkData(EntityMetadataCollection $properties) : void{
$properties->setByte(EntityMetadataProperties::ALWAYS_SHOW_NAMETAG, $this->alwaysShowNameTag ? 1 : 0);
$properties->setFloat(EntityMetadataProperties::BOUNDING_BOX_HEIGHT, $this->size->getHeight());
$properties->setFloat(EntityMetadataProperties::BOUNDING_BOX_WIDTH, $this->size->getWidth());
$properties->setFloat(EntityMetadataProperties::BOUNDING_BOX_HEIGHT, $this->size->getHeight() / $this->scale);
$properties->setFloat(EntityMetadataProperties::BOUNDING_BOX_WIDTH, $this->size->getWidth() / $this->scale);
$properties->setFloat(EntityMetadataProperties::SCALE, $this->scale);
$properties->setLong(EntityMetadataProperties::LEAD_HOLDER_EID, -1);
$properties->setLong(EntityMetadataProperties::OWNER_EID, $this->ownerId ?? -1);
@ -1599,7 +1599,7 @@ abstract class Entity{
$properties->setString(EntityMetadataProperties::SCORE_TAG, $this->scoreTag);
$properties->setByte(EntityMetadataProperties::COLOR, 0);
$properties->setGenericFlag(EntityMetadataFlags::AFFECTED_BY_GRAVITY, true);
$properties->setGenericFlag(EntityMetadataFlags::AFFECTED_BY_GRAVITY, $this->gravityEnabled);
$properties->setGenericFlag(EntityMetadataFlags::CAN_CLIMB, $this->canClimb);
$properties->setGenericFlag(EntityMetadataFlags::CAN_SHOW_NAMETAG, $this->nameTagVisible);
$properties->setGenericFlag(EntityMetadataFlags::HAS_COLLISION, true);

View File

@ -217,6 +217,19 @@ class Human extends Living implements ProjectileSource, InventoryHolder{
$this->uuid = Uuid::uuid3(Uuid::NIL, ((string) $this->getId()) . $this->skin->getSkinData() . $this->getNameTag());
}
/**
* @param Item[] $items
* @phpstan-param array<int, Item> $items
*/
private static function populateInventoryFromListTag(Inventory $inventory, array $items) : void{
$listeners = $inventory->getListeners()->toArray();
$inventory->getListeners()->clear();
$inventory->setContents($items);
$inventory->getListeners()->add(...$listeners);
}
protected function initEntity(CompoundTag $nbt) : void{
parent::initEntity($nbt);
@ -247,10 +260,8 @@ class Human extends Living implements ProjectileSource, InventoryHolder{
$inventoryTag = $nbt->getListTag("Inventory");
if($inventoryTag !== null){
$armorListeners = $this->armorInventory->getListeners()->toArray();
$this->armorInventory->getListeners()->clear();
$inventoryListeners = $this->inventory->getListeners()->toArray();
$this->inventory->getListeners()->clear();
$inventoryItems = [];
$armorInventoryItems = [];
/** @var CompoundTag $item */
foreach($inventoryTag as $i => $item){
@ -258,14 +269,14 @@ class Human extends Living implements ProjectileSource, InventoryHolder{
if($slot >= 0 and $slot < 9){ //Hotbar
//Old hotbar saving stuff, ignore it
}elseif($slot >= 100 and $slot < 104){ //Armor
$this->armorInventory->setItem($slot - 100, Item::nbtDeserialize($item));
$armorInventoryItems[$slot - 100] = Item::nbtDeserialize($item);
}elseif($slot >= 9 and $slot < $this->inventory->getSize() + 9){
$this->inventory->setItem($slot - 9, Item::nbtDeserialize($item));
$inventoryItems[$slot - 9] = Item::nbtDeserialize($item);
}
}
$this->armorInventory->getListeners()->add(...$armorListeners);
$this->inventory->getListeners()->add(...$inventoryListeners);
self::populateInventoryFromListTag($this->inventory, $inventoryItems);
self::populateInventoryFromListTag($this->armorInventory, $armorInventoryItems);
}
$offHand = $nbt->getCompoundTag("OffHandItem");
if($offHand !== null){
@ -279,10 +290,13 @@ class Human extends Living implements ProjectileSource, InventoryHolder{
$enderChestInventoryTag = $nbt->getListTag("EnderChestInventory");
if($enderChestInventoryTag !== null){
$enderChestInventoryItems = [];
/** @var CompoundTag $item */
foreach($enderChestInventoryTag as $i => $item){
$this->enderInventory->setItem($item->getByte("Slot"), Item::nbtDeserialize($item));
$enderChestInventoryItems[$item->getByte("Slot")] = Item::nbtDeserialize($item);
}
self::populateInventoryFromListTag($this->enderInventory, $enderChestInventoryItems);
}
$this->inventory->setHeldItemIndex($nbt->getInt("SelectedInventorySlot", 0));

View File

@ -25,4 +25,4 @@ namespace pocketmine\entity;
final class InvalidSkinException extends \InvalidArgumentException{
}
}

View File

@ -24,6 +24,7 @@ declare(strict_types=1);
namespace pocketmine\entity;
use Ahc\Json\Comment as CommentedJsonDecoder;
use pocketmine\utils\Limits;
use function implode;
use function in_array;
use function json_encode;
@ -48,7 +49,17 @@ final class Skin{
/** @var string */
private $geometryData;
private static function checkLength(string $string, string $name, int $maxLength) : void{
if(strlen($string) > $maxLength){
throw new InvalidSkinException("$name must be at most $maxLength bytes, but have " . strlen($string) . " bytes");
}
}
public function __construct(string $skinId, string $skinData, string $capeData = "", string $geometryName = "", string $geometryData = ""){
self::checkLength($skinId, "Skin ID", Limits::INT16_MAX);
self::checkLength($geometryName, "Geometry name", Limits::INT16_MAX);
self::checkLength($geometryData, "Geometry data", Limits::INT32_MAX);
if($skinId === ""){
throw new InvalidSkinException("Skin ID must not be empty");
}

View File

@ -70,4 +70,4 @@ final class StringToEffectParser extends StringToTParser{
public function parse(string $input) : ?Effect{
return parent::parse($input);
}
}
}

View File

@ -103,8 +103,6 @@ class BlockBreakEvent extends BlockEvent implements Cancellable{
/**
* Variadic hack for easy array member type enforcement.
*
* @param Item ...$drops
*/
public function setDropsVariadic(Item ...$drops) : void{
$this->blockDrops = $drops;

View File

@ -57,4 +57,4 @@ class BlockItemPickupEvent extends BlockEvent implements Cancellable{
public function setInventory(?Inventory $inventory) : void{
$this->inventory = $inventory;
}
}
}

View File

@ -37,4 +37,4 @@ class StructureGrowEvent extends BlockEvent implements Cancellable{
public function getPlayer() : ?Player{
return $this->player;
}
}
}

View File

@ -45,4 +45,4 @@ class PlayerDisplayNameChangeEvent extends PlayerEvent{
public function getNewName() : string{
return $this->newName;
}
}
}

View File

@ -31,7 +31,8 @@ use pocketmine\math\Vector3;
use pocketmine\player\Player;
/**
* Called when a player interacts or touches a block (including air?)
* Called when a player interacts or touches a block.
* This is called for both left click (start break) and right click (use).
*/
class PlayerInteractEvent extends PlayerEvent implements Cancellable{
use CancellableTrait;

View File

@ -52,8 +52,6 @@ interface Inventory{
*
* Returns the Items that did not fit.
*
* @param Item ...$slots
*
* @return Item[]
*/
public function addItem(Item ...$slots) : array;
@ -72,8 +70,6 @@ interface Inventory{
* Removes the given Item from the inventory.
* It will return the Items that couldn't be removed.
*
* @param Item ...$slots
*
* @return Item[]
*/
public function removeItem(Item ...$slots) : array;

View File

@ -33,4 +33,4 @@ final class PlayerCraftingInventory extends CraftingGrid implements TemporaryInv
}
public function getHolder() : Player{ return $this->holder; }
}
}

View File

@ -71,10 +71,10 @@ class SimpleInventory extends BaseInventory{
protected function internalSetContents(array $items) : void{
for($i = 0, $size = $this->getSize(); $i < $size; ++$i){
if(!isset($items[$i])){
$this->clear($i);
if(!isset($items[$i]) || $items[$i]->isNull()){
$this->slots[$i] = null;
}else{
$this->setItem($i, $items[$i]);
$this->slots[$i] = clone $items[$i];
}
}
}

View File

@ -25,4 +25,4 @@ namespace pocketmine\inventory;
interface TemporaryInventory extends Inventory{
}
}

View File

@ -23,17 +23,32 @@ declare(strict_types=1);
namespace pocketmine\item;
use pocketmine\utils\Limits;
use pocketmine\utils\Utils;
use function sprintf;
use function strlen;
class WritableBookPage{
public const PAGE_LENGTH_HARD_LIMIT_BYTES = Limits::INT16_MAX;
public const PHOTO_NAME_LENGTH_HARD_LIMIT_BYTES = Limits::INT16_MAX;
/** @var string */
private $text;
/** @var string */
private $photoName;
/**
* @throws \InvalidArgumentException
*/
private static function checkLength(string $string, string $name, int $maxLength) : void{
if(strlen($string) > $maxLength){
throw new \InvalidArgumentException(sprintf("$name must be at most %d bytes, but have %d bytes", $maxLength, strlen($string)));
}
}
public function __construct(string $text, string $photoName = ""){
//TODO: data validation
self::checkLength($text, "Text", self::PAGE_LENGTH_HARD_LIMIT_BYTES);
self::checkLength($photoName, "Photo name", self::PHOTO_NAME_LENGTH_HARD_LIMIT_BYTES);
Utils::checkUTF8($text);
$this->text = $text;
$this->photoName = $photoName;

View File

@ -24,7 +24,10 @@ declare(strict_types=1);
namespace pocketmine\item;
use pocketmine\nbt\tag\CompoundTag;
use pocketmine\utils\Limits;
use pocketmine\utils\Utils;
use function sprintf;
use function strlen;
class WrittenBook extends WritableBookBase{
@ -85,6 +88,9 @@ class WrittenBook extends WritableBookBase{
* @return $this
*/
public function setAuthor(string $authorName) : self{
if(strlen($authorName) > Limits::INT16_MAX){
throw new \InvalidArgumentException(sprintf("Author must be at most %d bytes, but have %d bytes", Limits::INT16_MAX, strlen($authorName)));
}
Utils::checkUTF8($authorName);
$this->author = $authorName;
return $this;
@ -103,6 +109,9 @@ class WrittenBook extends WritableBookBase{
* @return $this
*/
public function setTitle(string $title) : self{
if(strlen($title) > Limits::INT16_MAX){
throw new \InvalidArgumentException(sprintf("Title must be at most %d bytes, but have %d bytes", Limits::INT16_MAX, strlen($title)));
}
Utils::checkUTF8($title);
$this->title = $title;
return $this;

View File

@ -63,4 +63,4 @@ final class StringToEnchantmentParser extends StringToTParser{
public function parse(string $input) : ?Enchantment{
return parent::parse($input);
}
}
}

View File

@ -1974,6 +1974,26 @@ final class KnownTranslationFactory{
]);
}
public static function pocketmine_server_obsolete_warning1(Translatable|string $param0, Translatable|string $param1) : Translatable{
return new Translatable(KnownTranslationKeys::POCKETMINE_SERVER_OBSOLETE_WARNING1, [
0 => $param0,
1 => $param1,
]);
}
public static function pocketmine_server_obsolete_warning2(Translatable|string $param0, Translatable|string $param1) : Translatable{
return new Translatable(KnownTranslationKeys::POCKETMINE_SERVER_OBSOLETE_WARNING2, [
0 => $param0,
1 => $param1,
]);
}
public static function pocketmine_server_obsolete_warning3(Translatable|string $param0) : Translatable{
return new Translatable(KnownTranslationKeys::POCKETMINE_SERVER_OBSOLETE_WARNING3, [
0 => $param0,
]);
}
public static function pocketmine_server_query_running(Translatable|string $param0, Translatable|string $param1) : Translatable{
return new Translatable(KnownTranslationKeys::POCKETMINE_SERVER_QUERY_RUNNING, [
0 => $param0,

View File

@ -406,6 +406,9 @@ final class KnownTranslationKeys{
public const POCKETMINE_SERVER_LICENSE = "pocketmine.server.license";
public const POCKETMINE_SERVER_NETWORKSTART = "pocketmine.server.networkStart";
public const POCKETMINE_SERVER_NETWORKSTARTFAILED = "pocketmine.server.networkStartFailed";
public const POCKETMINE_SERVER_OBSOLETE_WARNING1 = "pocketmine.server.obsolete.warning1";
public const POCKETMINE_SERVER_OBSOLETE_WARNING2 = "pocketmine.server.obsolete.warning2";
public const POCKETMINE_SERVER_OBSOLETE_WARNING3 = "pocketmine.server.obsolete.warning3";
public const POCKETMINE_SERVER_QUERY_RUNNING = "pocketmine.server.query.running";
public const POCKETMINE_SERVER_START = "pocketmine.server.start";
public const POCKETMINE_SERVER_STARTFINISHED = "pocketmine.server.startFinished";

View File

@ -29,4 +29,4 @@ namespace pocketmine\network;
*/
final class NetworkInterfaceStartException extends \RuntimeException{
}
}

View File

@ -128,10 +128,12 @@ class ChunkCache implements ChunkListener{
$chunk,
$this->caches[$chunkHash],
$this->compressor,
function() use ($chunkX, $chunkZ) : void{
function() use ($chunkHash, $chunkX, $chunkZ) : void{
$this->world->getLogger()->error("Failed preparing chunk $chunkX $chunkZ, retrying");
$this->restartPendingRequest($chunkX, $chunkZ);
if(isset($this->caches[$chunkHash])){
$this->restartPendingRequest($chunkX, $chunkZ);
}
}
)
);

View File

@ -33,4 +33,4 @@ interface Compressor{
public function decompress(string $payload) : string;
public function compress(string $payload) : string;
}
}

View File

@ -25,4 +25,4 @@ namespace pocketmine\network\mcpe\compression;
final class DecompressionException extends \RuntimeException{
}
}

View File

@ -27,6 +27,7 @@ use pocketmine\block\BaseSign;
use pocketmine\block\ItemFrame;
use pocketmine\block\utils\SignText;
use pocketmine\entity\animation\ConsumingItemAnimation;
use pocketmine\entity\Attribute;
use pocketmine\entity\InvalidSkinException;
use pocketmine\event\player\PlayerEditBookEvent;
use pocketmine\inventory\transaction\action\InventoryAction;
@ -36,7 +37,9 @@ use pocketmine\inventory\transaction\TransactionException;
use pocketmine\inventory\transaction\TransactionValidationException;
use pocketmine\item\VanillaItems;
use pocketmine\item\WritableBook;
use pocketmine\item\WritableBookPage;
use pocketmine\item\WrittenBook;
use pocketmine\math\Facing;
use pocketmine\math\Vector3;
use pocketmine\nbt\tag\CompoundTag;
use pocketmine\nbt\tag\StringTag;
@ -95,28 +98,34 @@ use pocketmine\network\mcpe\protocol\types\PlayerAction;
use pocketmine\network\PacketHandlingException;
use pocketmine\player\Player;
use pocketmine\utils\AssumptionFailedError;
use pocketmine\utils\Limits;
use pocketmine\utils\TextFormat;
use function array_push;
use function base64_encode;
use function count;
use function fmod;
use function implode;
use function in_array;
use function is_infinite;
use function is_nan;
use function json_decode;
use function json_encode;
use function json_last_error_msg;
use function max;
use function mb_strlen;
use function microtime;
use function preg_match;
use function sprintf;
use function strlen;
use function strpos;
use function substr;
use function trim;
use const JSON_THROW_ON_ERROR;
/**
* This handler handles packets related to general gameplay.
*/
class InGamePacketHandler extends PacketHandler{
private const MAX_FORM_RESPONSE_DEPTH = 2; //modal/simple will be 1, custom forms 2 - they will never contain anything other than string|int|float|bool|null
/** @var Player */
private $player;
@ -355,6 +364,8 @@ class InGamePacketHandler extends PacketHandler{
}
//TODO: end hack for client spam bug
self::validateFacing($data->getFace());
$blockPos = $data->getBlockPosition();
$vBlockPos = new Vector3($blockPos->getX(), $blockPos->getY(), $blockPos->getZ());
if(!$this->player->interactBlock($vBlockPos, $data->getFace(), $clickPos)){
@ -371,6 +382,8 @@ class InGamePacketHandler extends PacketHandler{
case UseItemTransactionData::ACTION_CLICK_AIR:
if($this->player->isUsingItem()){
if(!$this->player->consumeHeldItem()){
$hungerAttr = $this->player->getAttributeMap()->get(Attribute::HUNGER) ?? throw new AssumptionFailedError();
$hungerAttr->markSynchronized(false);
$this->inventoryManager->syncSlot($this->player->getInventory(), $this->player->getInventory()->getHeldItemIndex());
}
return true;
@ -384,6 +397,15 @@ class InGamePacketHandler extends PacketHandler{
return false;
}
/**
* @throws PacketHandlingException
*/
private static function validateFacing(int $facing) : void{
if(!in_array($facing, Facing::ALL, true)){
throw new PacketHandlingException("Invalid facing value $facing");
}
}
/**
* Internal function used to execute rollbacks when an action fails on a block.
*/
@ -496,6 +518,7 @@ class InGamePacketHandler extends PacketHandler{
switch($packet->action){
case PlayerAction::START_BREAK:
self::validateFacing($packet->face);
if(!$this->player->attackBlock($pos, $packet->face)){
$this->onFailedBlockAction($pos, $packet->face);
}
@ -539,6 +562,7 @@ class InGamePacketHandler extends PacketHandler{
case PlayerAction::STOP_GLIDE:
break; //TODO
case PlayerAction::CRACK_BREAK:
self::validateFacing($packet->face);
$this->player->continueBreakBlock($pos, $packet->face);
break;
case PlayerAction::START_SWIMMING:
@ -708,6 +732,24 @@ class InGamePacketHandler extends PacketHandler{
return false; //TODO
}
/**
* @throws PacketHandlingException
*/
private function checkBookText(string $string, string $fieldName, int $softLimit, int $hardLimit, bool &$cancel) : string{
if(strlen($string) > $hardLimit){
throw new PacketHandlingException(sprintf("Book %s must be at most %d bytes, but have %d bytes", $fieldName, $hardLimit, strlen($string)));
}
$result = TextFormat::clean($string, false);
//strlen() is O(1), mb_strlen() is O(n)
if(strlen($result) > $softLimit * 4 || mb_strlen($result, 'UTF-8') > $softLimit){
$cancel = true;
$this->session->getLogger()->debug("Cancelled book edit due to $fieldName exceeded soft limit of $softLimit chars");
}
return $result;
}
public function handleBookEdit(BookEditPacket $packet) : bool{
//TODO: break this up into book API things
$oldBook = $this->player->getInventory()->getItem($packet->inventorySlot);
@ -717,10 +759,11 @@ class InGamePacketHandler extends PacketHandler{
$newBook = clone $oldBook;
$modifiedPages = [];
$cancel = false;
switch($packet->type){
case BookEditPacket::TYPE_REPLACE_PAGE:
$newBook->setPageText($packet->pageNumber, $packet->text);
$text = self::checkBookText($packet->text, "page text", 256, WritableBookPage::PAGE_LENGTH_HARD_LIMIT_BYTES, $cancel);
$newBook->setPageText($packet->pageNumber, $text);
$modifiedPages[] = $packet->pageNumber;
break;
case BookEditPacket::TYPE_ADD_PAGE:
@ -729,7 +772,8 @@ class InGamePacketHandler extends PacketHandler{
//TODO: the client can send insert-before actions on trailing client-side pages which cause odd behaviour on the server
return false;
}
$newBook->insertPage($packet->pageNumber, $packet->text);
$text = self::checkBookText($packet->text, "page text", 256, WritableBookPage::PAGE_LENGTH_HARD_LIMIT_BYTES, $cancel);
$newBook->insertPage($packet->pageNumber, $text);
$modifiedPages[] = $packet->pageNumber;
break;
case BookEditPacket::TYPE_DELETE_PAGE:
@ -748,18 +792,46 @@ class InGamePacketHandler extends PacketHandler{
$modifiedPages = [$packet->pageNumber, $packet->secondaryPageNumber];
break;
case BookEditPacket::TYPE_SIGN_BOOK:
/** @var WrittenBook $newBook */
$title = self::checkBookText($packet->title, "title", 16, Limits::INT16_MAX, $cancel);
//this one doesn't have a limit in vanilla, so we have to improvise
$author = self::checkBookText($packet->author, "author", 256, Limits::INT16_MAX, $cancel);
$newBook = VanillaItems::WRITTEN_BOOK()
->setPages($oldBook->getPages())
->setAuthor($packet->author)
->setTitle($packet->title)
->setAuthor($author)
->setTitle($title)
->setGeneration(WrittenBook::GENERATION_ORIGINAL);
break;
default:
return false;
}
$event = new PlayerEditBookEvent($this->player, $oldBook, $newBook, $packet->type, $modifiedPages);
//for redundancy, in case of protocol changes, we don't want to pass these directly
$action = match($packet->type){
BookEditPacket::TYPE_REPLACE_PAGE => PlayerEditBookEvent::ACTION_REPLACE_PAGE,
BookEditPacket::TYPE_ADD_PAGE => PlayerEditBookEvent::ACTION_ADD_PAGE,
BookEditPacket::TYPE_DELETE_PAGE => PlayerEditBookEvent::ACTION_DELETE_PAGE,
BookEditPacket::TYPE_SWAP_PAGES => PlayerEditBookEvent::ACTION_SWAP_PAGES,
BookEditPacket::TYPE_SIGN_BOOK => PlayerEditBookEvent::ACTION_SIGN_BOOK,
default => throw new AssumptionFailedError("We already filtered unknown types in the switch above")
};
/*
* Plugins may have created books with more than 50 pages; we allow plugins to do this, but not players.
* Don't allow the page count to grow past 50, but allow deleting, swapping or altering text of existing pages.
*/
$oldPageCount = count($oldBook->getPages());
$newPageCount = count($newBook->getPages());
if(($newPageCount > $oldPageCount && $newPageCount > 50)){
$this->session->getLogger()->debug("Cancelled book edit due to adding too many pages (new page count would be $newPageCount)");
$cancel = true;
}
$event = new PlayerEditBookEvent($this->player, $oldBook, $newBook, $action, $modifiedPages);
if($cancel){
$event->cancel();
}
$event->call();
if($event->isCancelled()){
return true;
@ -808,14 +880,18 @@ class InGamePacketHandler extends PacketHandler{
}
$fixed = "[" . implode(",", $newParts) . "]";
if(($ret = json_decode($fixed, $assoc)) === null){
throw new \InvalidArgumentException("Failed to fix JSON: " . json_last_error_msg() . "(original: $json, modified: $fixed)");
try{
return json_decode($fixed, $assoc, self::MAX_FORM_RESPONSE_DEPTH, JSON_THROW_ON_ERROR);
}catch(\JsonException $e){
throw PacketHandlingException::wrap($e, "Failed to fix JSON (original: $json, modified: $fixed)");
}
return $ret;
}
return json_decode($json, $assoc);
try{
return json_decode($json, $assoc, self::MAX_FORM_RESPONSE_DEPTH, JSON_THROW_ON_ERROR);
}catch(\JsonException $e){
throw PacketHandlingException::wrap($e);
}
}
public function handleServerSettingsRequest(ServerSettingsRequestPacket $packet) : bool{

View File

@ -59,4 +59,4 @@ final class RakLibThreadCrashInfo{
public function makePrettyMessage() : string{
return sprintf("%s: \"%s\" in %s on line %d", $this->class ?? "Fatal error", $this->message, Filesystem::cleanPath($this->file), $this->line);
}
}
}

View File

@ -134,6 +134,7 @@ use function floor;
use function get_class;
use function is_int;
use function max;
use function mb_strlen;
use function microtime;
use function min;
use function preg_match;
@ -1080,6 +1081,10 @@ class Player extends Human implements CommandSender, ChunkListener, IPlayer{
$bb->minY = $this->location->y - 0.2;
$bb->maxY = $this->location->y + 0.2;
//we're already at the new position at this point; check if there are blocks we might have landed on between
//the old and new positions (running down stairs necessitates this)
$bb = $bb->addCoord(-$dx, -$dy, -$dz);
$this->onGround = $this->isCollided = count($this->getWorld()->getCollisionBlocks($bb, true)) > 0;
}
}
@ -1320,7 +1325,7 @@ class Player extends Human implements CommandSender, ChunkListener, IPlayer{
$message = TextFormat::clean($message, false);
foreach(explode("\n", $message) as $messagePart){
if(trim($messagePart) !== "" and strlen($messagePart) <= 255 and $this->messageCounter-- > 0){
if(trim($messagePart) !== "" and strlen($messagePart) <= 512 * 4 and mb_strlen($messagePart, 'UTF-8') <= 512 and $this->messageCounter-- > 0){
if(strpos($messagePart, './') === 0){
$messagePart = substr($messagePart, 1);
}

View File

@ -39,4 +39,4 @@ final class PluginLoadTriageEntry{
public function getLoader() : PluginLoader{ return $this->loader; }
public function getDescription() : PluginDescription{ return $this->description; }
}
}

View File

@ -110,4 +110,4 @@ final class PluginLoadabilityChecker{
return null;
}
}
}

View File

@ -52,4 +52,4 @@ final class Promise{
public function isResolved() : bool{
return $this->shared->resolved;
}
}
}

View File

@ -72,4 +72,4 @@ final class PromiseResolver{
public function getPromise() : Promise{
return $this->promise;
}
}
}

View File

@ -23,6 +23,7 @@ declare(strict_types=1);
namespace pocketmine\thread;
use pocketmine\scheduler\AsyncTask;
use const PTHREADS_INHERIT_NONE;
/**

View File

@ -265,12 +265,33 @@ final class Filesystem{
throw new \RuntimeException("Failed to write to temporary file $temporaryFileName (possibly out of free disk space)");
}
//TODO: the @ prevents us receiving the actual error message, but right now it's necessary since we can't assume
//that the error handler has been set :(
$renameTemporaryFileResult = $context !== null ?
rename($temporaryFileName, $fileName, $context) :
rename($temporaryFileName, $fileName);
@rename($temporaryFileName, $fileName, $context) :
@rename($temporaryFileName, $fileName);
if(!$renameTemporaryFileResult){
throw new \RuntimeException("Failed to move temporary file contents into target file");
/*
* The following code works around a bug in Windows where rename() will periodically decide to give us a
* spurious "Access is denied (code: 5)" error. As far as I could determine, the fault comes from Windows
* itself, but since I couldn't reliably reproduce the issue it's very hard to debug.
*
* The following code can be used to test. Usually it will fail anywhere before 100,000 iterations.
*
* for($i = 0; $i < 10_000_000; ++$i){
* file_put_contents('ops.txt.0.tmp', 'some data ' . $i, 0);
* if(!rename('ops.txt.0.tmp', 'ops.txt')){
* throw new \Error("something weird happened");
* }
* }
*/
$copyTemporaryFileResult = $context !== null ?
copy($temporaryFileName, $fileName, $context) :
copy($temporaryFileName, $fileName);
if(!$copyTemporaryFileResult){
throw new \RuntimeException("Failed to move temporary file contents into target file");
}
@unlink($temporaryFileName);
}
}
}

View File

@ -45,4 +45,4 @@ trait SingletonTrait{
public static function reset() : void{
self::$instance = null;
}
}
}

View File

@ -79,4 +79,4 @@ abstract class StringToTParser{
public function getKnownAliases() : array{
return array_keys($this->callbackMap);
}
}
}

View File

@ -503,9 +503,6 @@ final class Utils{
*/
public static function parseDocComment(string $docComment) : array{
$rawDocComment = substr($docComment, 3, -2); //remove the opening and closing markers
if($rawDocComment === false){ //usually empty doc comment, but this is safer and statically analysable
return [];
}
preg_match_all('/(*ANYCRLF)^[\t ]*(?:\* )?@([a-zA-Z\-]+)(?:[\t ]+(.+?))?[\t ]*$/m', $rawDocComment, $matches);
return array_combine($matches[1], $matches[2]);

View File

@ -35,4 +35,4 @@ use pocketmine\utils\NotSerializable;
final class ChunkLockId{
use NotCloneable;
use NotSerializable;
}
}

View File

@ -755,8 +755,6 @@ class World implements ChunkManager{
/**
* @internal
*
* @param Player ...$targets If empty, will send to all players in the world.
*/
public function sendTime(Player ...$targets) : void{
if(count($targets) === 0){
@ -856,7 +854,7 @@ class World implements ChunkManager{
//Update entities that need update
Timings::$tickEntity->startTiming();
foreach($this->updateEntities as $id => $entity){
if($entity->isClosed() or !$entity->onUpdate($currentTick)){
if($entity->isClosed() or $entity->isFlaggedForDespawn() or !$entity->onUpdate($currentTick)){
unset($this->updateEntities[$id]);
}
if($entity->isFlaggedForDespawn()){
@ -2258,6 +2256,11 @@ class World implements ChunkManager{
$previousSpawn = $this->getSpawnLocation();
$this->provider->getWorldData()->setSpawn($pos);
(new SpawnChangeEvent($this, $previousSpawn))->call();
$location = Position::fromObject($pos, $this);
foreach($this->players as $player){
$player->getNetworkSession()->syncWorldSpawnPoint($location);
}
}
/**

View File

@ -124,4 +124,4 @@ final class FlatGeneratorOptions{
return new self($structure, $biomeId, $options);
}
}
}

View File

@ -45,4 +45,4 @@ final class GeneratorManagerEntry{
throw $exception;
}
}
}
}

View File

@ -16,7 +16,7 @@ if exist bin\php\php.exe (
)
if "%PHP_BINARY%"=="" (
echo Couldn't find a PHP binary in system PATH or %~dp0\bin\php
echo Couldn't find a PHP binary in system PATH or "%~dp0bin\php"
echo Please refer to the installation instructions at https://doc.pmmp.io/en/rtfd/installation.html
pause
exit 1

View File

@ -830,11 +830,6 @@ parameters:
count: 1
path: ../../../src/plugin/PluginDescription.php
-
message: "#^Parameter \\#1 \\$plugin of method pocketmine\\\\plugin\\\\PluginDescription\\:\\:loadMap\\(\\) expects array, mixed given\\.$#"
count: 1
path: ../../../src/plugin/PluginDescription.php
-
message: "#^Parameter \\#2 \\$subject of function preg_match expects string, mixed given\\.$#"
count: 1
@ -900,11 +895,6 @@ parameters:
count: 2
path: ../../../src/resourcepacks/ZippedResourcePack.php
-
message: "#^Parameter \\#2 \\$code of class pocketmine\\\\resourcepacks\\\\ResourcePackException constructor expects int, mixed given\\.$#"
count: 1
path: ../../../src/resourcepacks/ZippedResourcePack.php
-
message: "#^Parameter \\#2 \\$length of function fread expects int\\<0, max\\>, int given\\.$#"
count: 1
@ -1055,11 +1045,6 @@ parameters:
count: 1
path: ../../../src/utils/Utils.php
-
message: "#^Part \\$errno \\(mixed\\) of encapsed string cannot be cast to string\\.$#"
count: 1
path: ../../../src/utils/Utils.php
-
message: "#^Cannot call method getFullBlock\\(\\) on pocketmine\\\\world\\\\format\\\\SubChunk\\|null\\.$#"
count: 1

View File

@ -35,11 +35,6 @@ parameters:
count: 1
path: ../../../src/plugin/ScriptPluginLoader.php
-
message: "#^Strict comparison using \\=\\=\\= between string and false will always evaluate to false\\.$#"
count: 1
path: ../../../src/utils/Utils.php
-
message: "#^Call to function is_resource\\(\\) with resource will always evaluate to true\\.$#"
count: 2

View File

@ -34,6 +34,7 @@ use PHPStan\Type\StringType;
use PHPStan\Type\Type;
use PHPStan\Type\TypeTraverser;
use PHPStan\Type\VerbosityLevel;
use pocketmine\utils\Utils;
use function sprintf;
/**
@ -77,14 +78,15 @@ final class UnsafeForeachArrayOfStringRule implements Rule{
return $type;
});
if($hasCastableKeyTypes && !$expectsIntKeyTypes){
$func = \Closure::fromCallable([Utils::class, 'stringifyKeys']);
return [
RuleErrorBuilder::message(sprintf(
"Unsafe foreach on array with key type %s (they might be casted to int).",
$iterableType->getIterableKeyType()->describe(VerbosityLevel::value())
))->tip("Use Utils::foreachWithStringKeys() for a safe Generator-based iterator.")->build()
))->tip(sprintf("Use %s() for a safe Generator-based iterator.", Utils::getNiceClosureName($func)))->build()
];
}
return [];
}
}
}

View File

@ -45,7 +45,7 @@ class StupidJsonDecodeTest extends TestCase{
["[\n \"a\",\"b,c,d,e\\\" \",,0,1,2, false, 0.001]", ['a', 'b,c,d,e" ', '', 0, 1, 2, false, 0.001]],
["0", 0],
["false", false],
["NULL", null],
["null", null],
['["\",,\"word","a\",,\"word2",]', ['",,"word', 'a",,"word2', '']],
['["\",,\"word","a\",,\"word2",""]', ['",,"word', 'a",,"word2', '']],
['["Hello,, PocketMine"]', ['Hello,, PocketMine']],

View File

@ -6,4 +6,4 @@ namespace pocketmine\utils\fixtures;
abstract class TestAbstractClass{
}
}

View File

@ -6,4 +6,4 @@ namespace pocketmine\utils\fixtures;
class TestInstantiableClass extends TestAbstractClass implements TestInterface{
}
}

View File

@ -6,4 +6,4 @@ namespace pocketmine\utils\fixtures;
interface TestInterface{
}
}

View File

@ -6,4 +6,4 @@ namespace pocketmine\utils\fixtures;
class TestSubclassOfInstantiableClass extends TestInstantiableClass{
}
}

View File

@ -6,4 +6,4 @@ namespace pocketmine\utils\fixtures;
trait TestTrait{
}
}