mirror of
https://github.com/pmmp/PocketMine-MP.git
synced 2025-09-09 19:24:12 +00:00
Compare commits
92 Commits
Author | SHA1 | Date | |
---|---|---|---|
df1cdbe921 | |||
7846ea8acc | |||
1dc0d5f96a | |||
712ffb3e31 | |||
2a4111868c | |||
123701ed76 | |||
28dce8783f | |||
3781b62d35 | |||
859f062267 | |||
cfdbfa3d58 | |||
e9a6c0ba58 | |||
7a75fcda44 | |||
8d289ab01d | |||
6673289c33 | |||
822af4f7f5 | |||
3155c90396 | |||
1dbfedce4c | |||
3ab5b5a79d | |||
8a4bc72b34 | |||
32b07e0940 | |||
99f087e5e1 | |||
aaf7a88de7 | |||
67a0ae0246 | |||
b3fec3d86f | |||
60ef2db892 | |||
e21446e583 | |||
7bf0bc2ca7 | |||
e5a9123522 | |||
09201ac14b | |||
0697c7d316 | |||
1eae133118 | |||
d28be4eaf2 | |||
b33a75a6d1 | |||
f9c8c0e34d | |||
58ba4f680f | |||
8c5cc67e07 | |||
ab8b24bcd2 | |||
94c4f58667 | |||
c10eda5eae | |||
ed312863a7 | |||
387c13beff | |||
56fe71d939 | |||
73d8c87b76 | |||
061d851fbd | |||
a67aef0477 | |||
858024afb7 | |||
eaaf00ca2b | |||
f1723acfd3 | |||
8da27ea0aa | |||
388622d55d | |||
bac6a2a1eb | |||
b9b76eaed2 | |||
9f4fcfafdb | |||
6679c53e56 | |||
9d061e86af | |||
f7d25f251e | |||
0ccb47fb07 | |||
0973472842 | |||
f126479c37 | |||
d34f4b28b3 | |||
8a65fd273a | |||
248cc0ef49 | |||
d1726aa20c | |||
58e1e7bd6f | |||
0a5b146189 | |||
b4e1871899 | |||
78eaa0993d | |||
bee2aba813 | |||
af81f80cf3 | |||
43c5d08042 | |||
6d249026cc | |||
ed2145b6a4 | |||
3e6c157217 | |||
86beeb8255 | |||
230a3c9839 | |||
35f205b476 | |||
e7d17eb4d3 | |||
73168a0e39 | |||
e8893dd91f | |||
a4af1609ea | |||
8c4b8a9042 | |||
6492cac5c1 | |||
958a9dbf0f | |||
3ed57ce49a | |||
68f3399cfd | |||
aeab19a616 | |||
7bee72ef2d | |||
0d595e4324 | |||
e43e0189df | |||
decd1da2d0 | |||
bcc0f1e733 | |||
f62cfe8ae3 |
5
.github/dependabot.yml
vendored
5
.github/dependabot.yml
vendored
@ -6,3 +6,8 @@ updates:
|
||||
interval: daily
|
||||
time: "10:00"
|
||||
open-pull-requests-limit: 10
|
||||
|
||||
- package-ecosystem: gitsubmodule
|
||||
directory: "/"
|
||||
schedule:
|
||||
interval: daily
|
||||
|
12
.github/workflows/main.yml
vendored
12
.github/workflows/main.yml
vendored
@ -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
|
||||
|
@ -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,
|
||||
|
@ -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
|
||||
|
@ -116,4 +116,3 @@ foreach(new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator($argv[1],
|
||||
echo "No changes made to file $file\n";
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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();
|
||||
|
Submodule build/php updated: bd329dba08...30eed13faa
@ -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.
|
||||
|
15
changelogs/3.27.md
Normal file
15
changelogs/3.27.md
Normal file
@ -0,0 +1,15 @@
|
||||
**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.27.0
|
||||
- Introduced support for protocol encryption.
|
||||
- Encryption is enabled by default.
|
||||
- Fixes login replay attacks.
|
||||
- This may cause some performance degradation.
|
||||
- Encryption can be disabled by setting `network.enable-encryption` to `false` in `pocketmine.yml`. DO NOT do this unless you understand the risks involved.
|
||||
- An obsoletion notice has been added to the console during server startup.
|
@ -1590,4 +1590,58 @@ Released 1st January 2022.
|
||||
- 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.
|
||||
- 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.
|
||||
|
||||
# 4.0.8
|
||||
Released 25th January 2022.
|
||||
|
||||
## Fixes
|
||||
- Fixed ender chest not dropping itself when mined with a Silk Touch pickaxe.
|
||||
- The correct amount of fall damage is now taken when falling from a height onto hay bales.
|
||||
|
||||
# 4.0.9
|
||||
Released 5th February 2022.
|
||||
|
||||
## Fixes
|
||||
### Core
|
||||
- The spawn chunk of the default world is no longer loaded during shutdown. Previously, it would attempt to find a safe spawn to teleport players to, only to unload the target world of that safe spawn and not use it.
|
||||
- The spawn chunk of the default world is no longer loaded when unloading a non-default world containing zero players.
|
||||
- Fixed chunk version `8` in Bedrock worlds being treated as corrupted. These appeared in worlds between 1.2.13 and 1.8.0.
|
||||
|
||||
### API
|
||||
- Added missing bounds check to `Liquid->setDecay()`.
|
||||
- Fixed `StringToItemParser` returning concrete instead of concrete powder when given `<color>_concrete_powder`.
|
||||
|
||||
### Gameplay
|
||||
- Cobwebs now drop themselves when broken using shears.
|
||||
- Fixed spectator players being able to drop items.
|
||||
- Fixed collision shapes of Bell in different orientations.
|
||||
|
@ -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.4.2",
|
||||
"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"
|
||||
|
126
composer.lock
generated
126
composer.lock
generated
@ -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": "aabbf0c3280f590f48d2edb622747341",
|
||||
"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.1",
|
||||
"version": "2.4.3",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/pmmp/Language.git",
|
||||
"reference": "9fdd36f0ac3a2dfe1acacbee8b23eb6615129701"
|
||||
"reference": "4d0b081f1a79407e087968ea76aaf330db6ea2b5"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/pmmp/Language/zipball/9fdd36f0ac3a2dfe1acacbee8b23eb6615129701",
|
||||
"reference": "9fdd36f0ac3a2dfe1acacbee8b23eb6615129701",
|
||||
"url": "https://api.github.com/repos/pmmp/Language/zipball/4d0b081f1a79407e087968ea76aaf330db6ea2b5",
|
||||
"reference": "4d0b081f1a79407e087968ea76aaf330db6ea2b5",
|
||||
"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.1"
|
||||
"source": "https://github.com/pmmp/Language/tree/2.4.3"
|
||||
},
|
||||
"time": "2021-12-17T23:42:12+00:00"
|
||||
"time": "2022-01-25T23:18:24+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.11",
|
||||
"version": "9.5.13",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/sebastianbergmann/phpunit.git",
|
||||
"reference": "2406855036db1102126125537adb1406f7242fdd"
|
||||
"reference": "597cb647654ede35e43b137926dfdfef0fb11743"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/2406855036db1102126125537adb1406f7242fdd",
|
||||
"reference": "2406855036db1102126125537adb1406f7242fdd",
|
||||
"url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/597cb647654ede35e43b137926dfdfef0fb11743",
|
||||
"reference": "597cb647654ede35e43b137926dfdfef0fb11743",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@ -2475,7 +2475,7 @@
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/sebastianbergmann/phpunit/issues",
|
||||
"source": "https://github.com/sebastianbergmann/phpunit/tree/9.5.11"
|
||||
"source": "https://github.com/sebastianbergmann/phpunit/tree/9.5.13"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
@ -2487,7 +2487,7 @@
|
||||
"type": "github"
|
||||
}
|
||||
],
|
||||
"time": "2021-12-25T07:07:57+00:00"
|
||||
"time": "2022-01-24T07:33:35+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"
|
||||
}
|
||||
|
@ -31,7 +31,7 @@ use function str_repeat;
|
||||
|
||||
final class VersionInfo{
|
||||
public const NAME = "PocketMine-MP";
|
||||
public const BASE_VERSION = "4.0.4";
|
||||
public const BASE_VERSION = "4.0.9";
|
||||
public const IS_DEVELOPMENT_BUILD = false;
|
||||
public const BUILD_CHANNEL = "stable";
|
||||
|
||||
|
@ -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;
|
||||
|
||||
|
@ -29,6 +29,7 @@ use pocketmine\block\utils\BlockDataSerializer;
|
||||
use pocketmine\block\utils\HorizontalFacingTrait;
|
||||
use pocketmine\block\utils\InvalidBlockStateException;
|
||||
use pocketmine\item\Item;
|
||||
use pocketmine\math\AxisAlignedBB;
|
||||
use pocketmine\math\Facing;
|
||||
use pocketmine\math\Vector3;
|
||||
use pocketmine\player\Player;
|
||||
@ -78,6 +79,28 @@ final class Bell extends Transparent{
|
||||
return 0b1111;
|
||||
}
|
||||
|
||||
protected function recalculateCollisionBoxes() : array{
|
||||
if($this->attachmentType->equals(BellAttachmentType::FLOOR())){
|
||||
return [
|
||||
AxisAlignedBB::one()->squash(Facing::axis($this->facing), 1 / 4)->trim(Facing::UP, 3 / 16)
|
||||
];
|
||||
}
|
||||
if($this->attachmentType->equals(BellAttachmentType::CEILING())){
|
||||
return [
|
||||
AxisAlignedBB::one()->contract(1 / 4, 0, 1 / 4)->trim(Facing::DOWN, 1 / 4)
|
||||
];
|
||||
}
|
||||
|
||||
$box = AxisAlignedBB::one()
|
||||
->squash(Facing::axis(Facing::rotateY($this->facing, true)), 1 / 4)
|
||||
->trim(Facing::UP, 1 / 16)
|
||||
->trim(Facing::DOWN, 1 / 4);
|
||||
|
||||
return [
|
||||
$this->attachmentType->equals(BellAttachmentType::ONE_WALL()) ? $box->trim($this->facing, 3 / 16) : $box
|
||||
];
|
||||
}
|
||||
|
||||
public function getAttachmentType() : BellAttachmentType{ return $this->attachmentType; }
|
||||
|
||||
/** @return $this */
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -39,6 +39,9 @@ class Cobweb extends Flowable{
|
||||
}
|
||||
|
||||
public function getDropsForCompatibleTool(Item $item) : array{
|
||||
if(($item->getBlockToolType() & BlockToolType::SHEARS) !== 0){
|
||||
return [$this->asItem()];
|
||||
}
|
||||
return [
|
||||
VanillaItems::STRING()
|
||||
];
|
||||
|
@ -66,4 +66,8 @@ class EnderChest extends Transparent{
|
||||
VanillaBlocks::OBSIDIAN()->asItem()->setCount(8)
|
||||
];
|
||||
}
|
||||
|
||||
public function isAffectedBySilkTouch() : bool{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
@ -24,6 +24,7 @@ declare(strict_types=1);
|
||||
namespace pocketmine\block;
|
||||
|
||||
use pocketmine\block\utils\PillarRotationInMetadataTrait;
|
||||
use pocketmine\entity\Entity;
|
||||
|
||||
class HayBale extends Opaque{
|
||||
use PillarRotationInMetadataTrait;
|
||||
@ -35,4 +36,9 @@ class HayBale extends Opaque{
|
||||
public function getFlammability() : int{
|
||||
return 20;
|
||||
}
|
||||
|
||||
public function onEntityLand(Entity $entity) : ?float{
|
||||
$entity->fallDistance *= 0.2;
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
@ -83,6 +83,9 @@ abstract class Liquid extends Transparent{
|
||||
|
||||
/** @return $this */
|
||||
public function setDecay(int $decay) : self{
|
||||
if($decay < 0 || $decay > 7){
|
||||
throw new \InvalidArgumentException("Decay must be in range 0-7");
|
||||
}
|
||||
$this->decay = $decay;
|
||||
return $this;
|
||||
}
|
||||
@ -339,7 +342,7 @@ abstract class Liquid extends Transparent{
|
||||
$ev = new BlockSpreadEvent($block, $this, $new);
|
||||
$ev->call();
|
||||
if(!$ev->isCancelled()){
|
||||
if($block->getId() > 0){
|
||||
if($block->getId() !== BlockLegacyIds::AIR){
|
||||
$this->position->getWorld()->useBreakOn($block->position);
|
||||
}
|
||||
|
||||
|
@ -34,4 +34,4 @@ final class CraftingTableInventory extends CraftingGrid implements BlockInventor
|
||||
$this->holder = $holder;
|
||||
parent::__construct(CraftingGrid::SIZE_BIG);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -81,4 +81,4 @@ final class CrashDumpData implements \JsonSerializable{
|
||||
$result["server.properties"] = $this->serverDotProperties;
|
||||
return $result;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -43,4 +43,4 @@ final class CrashDumpDataGeneral{
|
||||
public string $os,
|
||||
public array $composer_libraries,
|
||||
){}
|
||||
}
|
||||
}
|
||||
|
@ -42,4 +42,4 @@ final class CrashDumpDataPluginEntry{
|
||||
public string $load,
|
||||
public string $website,
|
||||
){}
|
||||
}
|
||||
}
|
||||
|
@ -100,4 +100,4 @@ final class CrashDumpRenderer{
|
||||
public function addLine(string $line = "") : void{
|
||||
fwrite($this->fp, $line . PHP_EOL);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -25,4 +25,4 @@ namespace pocketmine\data;
|
||||
|
||||
final class SavedDataLoadingException extends \RuntimeException{
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -32,4 +32,4 @@ final class LegacyBiomeIdToStringIdMap extends LegacyToStringBidirectionalIdMap{
|
||||
public function __construct(){
|
||||
parent::__construct(Path::join(\pocketmine\BEDROCK_DATA_PATH, 'biome_id_map.json'));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -25,4 +25,4 @@ namespace pocketmine\entity;
|
||||
|
||||
final class InvalidSkinException extends \InvalidArgumentException{
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -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");
|
||||
}
|
||||
|
@ -70,4 +70,4 @@ final class StringToEffectParser extends StringToTParser{
|
||||
public function parse(string $input) : ?Effect{
|
||||
return parent::parse($input);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -57,4 +57,4 @@ class BlockItemPickupEvent extends BlockEvent implements Cancellable{
|
||||
public function setInventory(?Inventory $inventory) : void{
|
||||
$this->inventory = $inventory;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -37,4 +37,4 @@ class StructureGrowEvent extends BlockEvent implements Cancellable{
|
||||
public function getPlayer() : ?Player{
|
||||
return $this->player;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -45,4 +45,4 @@ class PlayerDisplayNameChangeEvent extends PlayerEvent{
|
||||
public function getNewName() : string{
|
||||
return $this->newName;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -33,4 +33,4 @@ final class PlayerCraftingInventory extends CraftingGrid implements TemporaryInv
|
||||
}
|
||||
|
||||
public function getHolder() : Player{ return $this->holder; }
|
||||
}
|
||||
}
|
||||
|
@ -25,4 +25,4 @@ namespace pocketmine\inventory;
|
||||
|
||||
interface TemporaryInventory extends Inventory{
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -46,6 +46,9 @@ class DropItemAction extends InventoryAction{
|
||||
|
||||
public function onPreExecute(Player $source) : bool{
|
||||
$ev = new PlayerDropItemEvent($source, $this->targetItem);
|
||||
if($source->isSpectator()){
|
||||
$ev->cancel();
|
||||
}
|
||||
$ev->call();
|
||||
if($ev->isCancelled()){
|
||||
return false;
|
||||
|
@ -49,7 +49,7 @@ final class StringToItemParser extends StringToTParser{
|
||||
$result->registerBlock($prefix("bed"), fn() => VanillaBlocks::BED()->setColor($color));
|
||||
$result->registerBlock($prefix("carpet"), fn() => VanillaBlocks::CARPET()->setColor($color));
|
||||
$result->registerBlock($prefix("concrete"), fn() => VanillaBlocks::CONCRETE()->setColor($color));
|
||||
$result->registerBlock($prefix("concrete_powder"), fn() => VanillaBlocks::CONCRETE()->setColor($color));
|
||||
$result->registerBlock($prefix("concrete_powder"), fn() => VanillaBlocks::CONCRETE_POWDER()->setColor($color));
|
||||
$result->registerBlock($prefix("stained_clay"), fn() => VanillaBlocks::STAINED_CLAY()->setColor($color));
|
||||
$result->registerBlock($prefix("stained_glass"), fn() => VanillaBlocks::STAINED_GLASS()->setColor($color));
|
||||
$result->registerBlock($prefix("stained_glass_pane"), fn() => VanillaBlocks::STAINED_GLASS_PANE()->setColor($color));
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -63,4 +63,4 @@ final class StringToEnchantmentParser extends StringToTParser{
|
||||
public function parse(string $input) : ?Enchantment{
|
||||
return parent::parse($input);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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,
|
||||
|
@ -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";
|
||||
|
@ -29,4 +29,4 @@ namespace pocketmine\network;
|
||||
*/
|
||||
final class NetworkInterfaceStartException extends \RuntimeException{
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -33,4 +33,4 @@ interface Compressor{
|
||||
public function decompress(string $payload) : string;
|
||||
|
||||
public function compress(string $payload) : string;
|
||||
}
|
||||
}
|
||||
|
@ -25,4 +25,4 @@ namespace pocketmine\network\mcpe\compression;
|
||||
|
||||
final class DecompressionException extends \RuntimeException{
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -61,7 +61,7 @@ class EncryptionContext{
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an EncryptionContext suitable for decrypting Minecraft packets from 1.16.200 and up.
|
||||
* Returns an EncryptionContext suitable for decrypting Minecraft packets from 1.16.220.50 (protocol version 429) and up.
|
||||
*
|
||||
* MCPE uses GCM, but without the auth tag, which defeats the whole purpose of using GCM.
|
||||
* GCM is just a wrapper around CTR which adds the auth tag, so CTR can replace GCM for this case.
|
||||
|
@ -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{
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -39,4 +39,4 @@ final class PluginLoadTriageEntry{
|
||||
public function getLoader() : PluginLoader{ return $this->loader; }
|
||||
|
||||
public function getDescription() : PluginDescription{ return $this->description; }
|
||||
}
|
||||
}
|
||||
|
@ -110,4 +110,4 @@ final class PluginLoadabilityChecker{
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -52,4 +52,4 @@ final class Promise{
|
||||
public function isResolved() : bool{
|
||||
return $this->shared->resolved;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -72,4 +72,4 @@ final class PromiseResolver{
|
||||
public function getPromise() : Promise{
|
||||
return $this->promise;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -23,6 +23,7 @@ declare(strict_types=1);
|
||||
|
||||
namespace pocketmine\thread;
|
||||
|
||||
use pocketmine\scheduler\AsyncTask;
|
||||
use const PTHREADS_INHERIT_NONE;
|
||||
|
||||
/**
|
||||
|
@ -45,4 +45,4 @@ trait SingletonTrait{
|
||||
public static function reset() : void{
|
||||
self::$instance = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -79,4 +79,4 @@ abstract class StringToTParser{
|
||||
public function getKnownAliases() : array{
|
||||
return array_keys($this->callbackMap);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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]);
|
||||
|
@ -35,4 +35,4 @@ use pocketmine\utils\NotSerializable;
|
||||
final class ChunkLockId{
|
||||
use NotCloneable;
|
||||
use NotSerializable;
|
||||
}
|
||||
}
|
||||
|
@ -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()){
|
||||
@ -949,6 +947,8 @@ class World implements ChunkManager{
|
||||
public function createBlockUpdatePackets(array $blocks) : array{
|
||||
$packets = [];
|
||||
|
||||
$blockMapping = RuntimeBlockMapping::getInstance();
|
||||
|
||||
foreach($blocks as $b){
|
||||
if(!($b instanceof Vector3)){
|
||||
throw new \TypeError("Expected Vector3 in blocks array, got " . (is_object($b) ? get_class($b) : gettype($b)));
|
||||
@ -958,7 +958,7 @@ class World implements ChunkManager{
|
||||
$blockPosition = BlockPosition::fromVector3($b);
|
||||
$packets[] = UpdateBlockPacket::create(
|
||||
$blockPosition,
|
||||
RuntimeBlockMapping::getInstance()->toRuntimeId($fullBlock->getFullId()),
|
||||
$blockMapping->toRuntimeId($fullBlock->getFullId()),
|
||||
UpdateBlockPacket::FLAG_NETWORK,
|
||||
UpdateBlockPacket::DATA_LAYER_NORMAL
|
||||
);
|
||||
@ -1107,6 +1107,7 @@ class World implements ChunkManager{
|
||||
$entity->onRandomUpdate();
|
||||
}
|
||||
|
||||
$blockFactory = BlockFactory::getInstance();
|
||||
foreach($chunk->getSubChunks() as $Y => $subChunk){
|
||||
if(!$subChunk->isEmptyFast()){
|
||||
$k = 0;
|
||||
@ -1123,8 +1124,7 @@ class World implements ChunkManager{
|
||||
$state = $subChunk->getFullBlock($x, $y, $z);
|
||||
|
||||
if(isset($this->randomTickBlocks[$state])){
|
||||
/** @var Block $block */
|
||||
$block = BlockFactory::getInstance()->fromFullBlock($state);
|
||||
$block = $blockFactory->fromFullBlock($state);
|
||||
$block->position($this, $chunkX * Chunk::EDGE_LENGTH + $x, ($Y << SubChunk::COORD_BIT_SIZE) + $y, $chunkZ * Chunk::EDGE_LENGTH + $z);
|
||||
$block->onRandomTick();
|
||||
}
|
||||
@ -2258,6 +2258,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);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -153,16 +153,18 @@ class WorldManager{
|
||||
}
|
||||
|
||||
$this->server->getLogger()->info($this->server->getLanguage()->translate(KnownTranslationFactory::pocketmine_level_unloading($world->getDisplayName())));
|
||||
try{
|
||||
$safeSpawn = $this->defaultWorld !== null ? $this->defaultWorld->getSafeSpawn() : null;
|
||||
}catch(WorldException $e){
|
||||
$safeSpawn = null;
|
||||
}
|
||||
foreach($world->getPlayers() as $player){
|
||||
if($world === $this->defaultWorld or $safeSpawn === null){
|
||||
$player->disconnect("Forced default world unload");
|
||||
}else{
|
||||
$player->teleport($safeSpawn);
|
||||
if(count($world->getPlayers()) !== 0){
|
||||
try{
|
||||
$safeSpawn = $this->defaultWorld !== null && $this->defaultWorld !== $world ? $this->defaultWorld->getSafeSpawn() : null;
|
||||
}catch(WorldException $e){
|
||||
$safeSpawn = null;
|
||||
}
|
||||
foreach($world->getPlayers() as $player){
|
||||
if($safeSpawn === null){
|
||||
$player->disconnect("Forced default world unload");
|
||||
}else{
|
||||
$player->teleport($safeSpawn);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -263,6 +263,7 @@ class LevelDB extends BaseWorldProvider implements WritableWorldProvider{
|
||||
case 11: //MCPE 1.11.0.1 beta (???)
|
||||
case 10: //MCPE 1.9 (???)
|
||||
case 9: //MCPE 1.8 (???)
|
||||
case 8: //MCPE 1.2.13 (paletted subchunks)
|
||||
case 7: //MCPE 1.2 (???)
|
||||
case 6: //MCPE 1.2.0.2 beta (???)
|
||||
case 4: //MCPE 1.1
|
||||
|
@ -124,4 +124,4 @@ final class FlatGeneratorOptions{
|
||||
return new self($structure, $biomeId, $options);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -45,4 +45,4 @@ final class GeneratorManagerEntry{
|
||||
throw $exception;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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 [];
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -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']],
|
||||
|
@ -6,4 +6,4 @@ namespace pocketmine\utils\fixtures;
|
||||
|
||||
abstract class TestAbstractClass{
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -6,4 +6,4 @@ namespace pocketmine\utils\fixtures;
|
||||
|
||||
class TestInstantiableClass extends TestAbstractClass implements TestInterface{
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -6,4 +6,4 @@ namespace pocketmine\utils\fixtures;
|
||||
|
||||
interface TestInterface{
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -6,4 +6,4 @@ namespace pocketmine\utils\fixtures;
|
||||
|
||||
class TestSubclassOfInstantiableClass extends TestInstantiableClass{
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -6,4 +6,4 @@ namespace pocketmine\utils\fixtures;
|
||||
|
||||
trait TestTrait{
|
||||
|
||||
}
|
||||
}
|
||||
|
Submodule tests/plugins/DevTools updated: 39510af5bc...e884a4c234
Reference in New Issue
Block a user