mirror of
https://github.com/pmmp/PocketMine-MP.git
synced 2025-09-09 11:16:57 +00:00
Compare commits
75 Commits
Author | SHA1 | Date | |
---|---|---|---|
58ba4f680f | |||
8c5cc67e07 | |||
ab8b24bcd2 | |||
94c4f58667 | |||
c10eda5eae | |||
ed312863a7 | |||
387c13beff | |||
56fe71d939 | |||
73d8c87b76 | |||
061d851fbd | |||
a67aef0477 | |||
858024afb7 | |||
eaaf00ca2b | |||
f1723acfd3 | |||
8da27ea0aa | |||
388622d55d | |||
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 | |||
b903e90dc2 | |||
c8247786d7 | |||
f486b5f4a7 | |||
54d6b83fc2 | |||
eedea38669 | |||
3c6146b5e0 | |||
72f2c794ab | |||
38b6b39cb3 | |||
fcc4757209 | |||
d9c70cb176 | |||
4aab0565c0 | |||
8943d8a2a7 | |||
0da29beb1d | |||
157048264c | |||
b55aa78aec | |||
091673d8f1 | |||
e3614d1a82 | |||
93caf72f34 | |||
e6e1bca676 |
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();
|
||||
|
@ -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.
|
||||
|
@ -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.
|
||||
|
@ -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
128
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": "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"
|
||||
}
|
||||
|
@ -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";
|
||||
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -34,4 +34,4 @@ final class CraftingTableInventory extends CraftingGrid implements BlockInventor
|
||||
$this->holder = $holder;
|
||||
parent::__construct(CraftingGrid::SIZE_BIG);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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{
|
||||
|
@ -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'));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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));
|
||||
|
@ -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; }
|
||||
}
|
||||
}
|
||||
|
@ -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];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -25,4 +25,4 @@ namespace pocketmine\inventory;
|
||||
|
||||
interface TemporaryInventory extends Inventory{
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -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{
|
||||
|
||||
}
|
||||
}
|
||||
|
6
src/network/mcpe/cache/ChunkCache.php
vendored
6
src/network/mcpe/cache/ChunkCache.php
vendored
@ -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);
|
||||
}
|
||||
}
|
||||
)
|
||||
);
|
||||
|
@ -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{
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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;
|
||||
|
||||
/**
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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()){
|
||||
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -124,4 +124,4 @@ final class FlatGeneratorOptions{
|
||||
return new self($structure, $biomeId, $options);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -45,4 +45,4 @@ final class GeneratorManagerEntry{
|
||||
throw $exception;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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{
|
||||
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user