Merge branch 'stable' into next-minor

This commit is contained in:
Dylan K. Taylor 2022-04-28 21:00:23 +01:00
commit 937bb4c6ce
No known key found for this signature in database
GPG Key ID: 8927471A91CAFD3D
16 changed files with 116 additions and 64 deletions

@ -1 +1 @@
Subproject commit 1fae6b8d4ab89757316e7e70e77cadfd4fd26b3e
Subproject commit 7b357f8cf9b2d2ee3a9ad247cdc76c8ad62337f9

View File

@ -107,3 +107,15 @@ Released 17th April 2022.
- Fixed a memory leak in RakLib which could result in a server crash when players stay online for a long time.
- Fixed server crash when attempting to load a corrupted empty resource pack.
- Fixed users with the same name with differerently cased letters being able to duplicate items (userdata is matched by case-insensitive name).
# 4.2.9
Released 19th April 2022.
## Fixes
- Fixed several potential crashes when deserializing item NBT (due to insufficient validation of input data).
# 4.2.10
Released 20th April 2022.
## Fixes
- Fixed performance issue when chat messages received from the client contain many newlines. This security vulnerability was disclosed publicly necessitating a priority fix.

21
changelogs/4.3.md Normal file
View File

@ -0,0 +1,21 @@
**For Minecraft: Bedrock Edition 1.18.30**
### Note about API versions
Plugins which don't touch the protocol and compatible with any previous 4.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.
# 4.3.0
Released 20th April 2022.
## General
- Added support for Minecraft: Bedrock Edition 1.18.30.
- Removed support for older versions.
# 4.3.1
Released 23rd April 2022.
## Fixes
- Updated BedrockProtocol dependency to fix incorrect command argument types.
- Creative players no longer die in the void.

View File

@ -34,8 +34,8 @@
"adhocore/json-comment": "^1.1",
"fgrosse/phpasn1": "^2.3",
"netresearch/jsonmapper": "^4.0",
"pocketmine/bedrock-data": "~1.6.0+bedrock-1.18.10",
"pocketmine/bedrock-protocol": "~8.0.2+bedrock-1.18.10",
"pocketmine/bedrock-data": "~1.7.0+bedrock-1.18.30",
"pocketmine/bedrock-protocol": "~9.0.0+bedrock-1.18.30",
"pocketmine/binaryutils": "^0.2.1",
"pocketmine/callback-validator": "^1.0.2",
"pocketmine/classloader": "^0.2.0",
@ -53,9 +53,9 @@
"webmozart/path-util": "^2.3"
},
"require-dev": {
"phpstan/phpstan": "1.5.6",
"phpstan/phpstan": "1.6.3",
"phpstan/phpstan-phpunit": "^1.1.0",
"phpstan/phpstan-strict-rules": "^1.0.0",
"phpstan/phpstan-strict-rules": "^1.2.0",
"phpunit/phpunit": "^9.2"
},
"autoload": {

75
composer.lock generated
View File

@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
"content-hash": "312b0119034654b3c161ef945b29488e",
"content-hash": "1987b70747167a4b099962f485f46bf4",
"packages": [
{
"name": "adhocore/json-comment",
@ -249,42 +249,42 @@
},
{
"name": "pocketmine/bedrock-data",
"version": "1.6.0+bedrock-1.18.10",
"version": "1.7.0+bedrock-1.18.30",
"source": {
"type": "git",
"url": "https://github.com/pmmp/BedrockData.git",
"reference": "e98c511584a7bd58a95986374d2df4b04c6a2ba0"
"reference": "c8f323ff0cbdb36a5d95e7e4a23969f562445be0"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/pmmp/BedrockData/zipball/e98c511584a7bd58a95986374d2df4b04c6a2ba0",
"reference": "e98c511584a7bd58a95986374d2df4b04c6a2ba0",
"url": "https://api.github.com/repos/pmmp/BedrockData/zipball/c8f323ff0cbdb36a5d95e7e4a23969f562445be0",
"reference": "c8f323ff0cbdb36a5d95e7e4a23969f562445be0",
"shasum": ""
},
"type": "library",
"notification-url": "https://packagist.org/downloads/",
"license": [
"LGPL-3.0"
"CC0-1.0"
],
"description": "Blobs of data generated from Minecraft: Bedrock Edition, used by PocketMine-MP",
"support": {
"issues": "https://github.com/pmmp/BedrockData/issues",
"source": "https://github.com/pmmp/BedrockData/tree/bedrock-1.18.10"
"source": "https://github.com/pmmp/BedrockData/tree/bedrock-1.18.30"
},
"time": "2022-02-08T19:13:47+00:00"
"time": "2022-04-20T12:40:59+00:00"
},
{
"name": "pocketmine/bedrock-protocol",
"version": "8.0.2+bedrock-1.18.10",
"version": "9.0.1+bedrock-1.18.30",
"source": {
"type": "git",
"url": "https://github.com/pmmp/BedrockProtocol.git",
"reference": "d1f1afdbb4ea61ea52eb511a79ee1ca561da349c"
"reference": "9d3cc87c4d26c002dd42aa9af20c0cd47a72018e"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/pmmp/BedrockProtocol/zipball/d1f1afdbb4ea61ea52eb511a79ee1ca561da349c",
"reference": "d1f1afdbb4ea61ea52eb511a79ee1ca561da349c",
"url": "https://api.github.com/repos/pmmp/BedrockProtocol/zipball/9d3cc87c4d26c002dd42aa9af20c0cd47a72018e",
"reference": "9d3cc87c4d26c002dd42aa9af20c0cd47a72018e",
"shasum": ""
},
"require": {
@ -298,7 +298,7 @@
"ramsey/uuid": "^4.1"
},
"require-dev": {
"phpstan/phpstan": "1.5.3",
"phpstan/phpstan": "1.5.7",
"phpstan/phpstan-phpunit": "^1.0.0",
"phpstan/phpstan-strict-rules": "^1.0.0",
"phpunit/phpunit": "^9.5"
@ -316,9 +316,9 @@
"description": "An implementation of the Minecraft: Bedrock Edition protocol in PHP",
"support": {
"issues": "https://github.com/pmmp/BedrockProtocol/issues",
"source": "https://github.com/pmmp/BedrockProtocol/tree/8.0.2+bedrock-1.18.10"
"source": "https://github.com/pmmp/BedrockProtocol/tree/9.0.1+bedrock-1.18.30"
},
"time": "2022-04-01T21:55:10+00:00"
"time": "2022-04-23T14:48:16+00:00"
},
{
"name": "pocketmine/binaryutils",
@ -1819,16 +1819,16 @@
},
{
"name": "phpstan/phpstan",
"version": "1.5.6",
"version": "1.6.3",
"source": {
"type": "git",
"url": "https://github.com/phpstan/phpstan.git",
"reference": "799dd8c2d2c9c704bb55d2078078cb970cf0f6d1"
"reference": "6128620b98292e0b69ea6d799871d77163681c8e"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/phpstan/phpstan/zipball/799dd8c2d2c9c704bb55d2078078cb970cf0f6d1",
"reference": "799dd8c2d2c9c704bb55d2078078cb970cf0f6d1",
"url": "https://api.github.com/repos/phpstan/phpstan/zipball/6128620b98292e0b69ea6d799871d77163681c8e",
"reference": "6128620b98292e0b69ea6d799871d77163681c8e",
"shasum": ""
},
"require": {
@ -1854,7 +1854,7 @@
"description": "PHPStan - PHP Static Analysis Tool",
"support": {
"issues": "https://github.com/phpstan/phpstan/issues",
"source": "https://github.com/phpstan/phpstan/tree/1.5.6"
"source": "https://github.com/phpstan/phpstan/tree/1.6.3"
},
"funding": [
{
@ -1874,20 +1874,20 @@
"type": "tidelift"
}
],
"time": "2022-04-15T11:13:37+00:00"
"time": "2022-04-28T11:27:53+00:00"
},
{
"name": "phpstan/phpstan-phpunit",
"version": "1.1.0",
"version": "1.1.1",
"source": {
"type": "git",
"url": "https://github.com/phpstan/phpstan-phpunit.git",
"reference": "09133ce914f1388a8bb8c7f8573aaa3723cff52a"
"reference": "4a3c437c09075736285d1cabb5c75bf27ed0bc84"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/phpstan/phpstan-phpunit/zipball/09133ce914f1388a8bb8c7f8573aaa3723cff52a",
"reference": "09133ce914f1388a8bb8c7f8573aaa3723cff52a",
"url": "https://api.github.com/repos/phpstan/phpstan-phpunit/zipball/4a3c437c09075736285d1cabb5c75bf27ed0bc84",
"reference": "4a3c437c09075736285d1cabb5c75bf27ed0bc84",
"shasum": ""
},
"require": {
@ -1924,27 +1924,27 @@
"description": "PHPUnit extensions and rules for PHPStan",
"support": {
"issues": "https://github.com/phpstan/phpstan-phpunit/issues",
"source": "https://github.com/phpstan/phpstan-phpunit/tree/1.1.0"
"source": "https://github.com/phpstan/phpstan-phpunit/tree/1.1.1"
},
"time": "2022-03-28T09:20:49+00:00"
"time": "2022-04-20T15:24:25+00:00"
},
{
"name": "phpstan/phpstan-strict-rules",
"version": "1.1.0",
"version": "1.2.1",
"source": {
"type": "git",
"url": "https://github.com/phpstan/phpstan-strict-rules.git",
"reference": "e12d55f74a8cca18c6e684c6450767e055ba7717"
"reference": "f3ca6464eae640a556c69a02b3b77a2507475d2f"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/phpstan/phpstan-strict-rules/zipball/e12d55f74a8cca18c6e684c6450767e055ba7717",
"reference": "e12d55f74a8cca18c6e684c6450767e055ba7717",
"url": "https://api.github.com/repos/phpstan/phpstan-strict-rules/zipball/f3ca6464eae640a556c69a02b3b77a2507475d2f",
"reference": "f3ca6464eae640a556c69a02b3b77a2507475d2f",
"shasum": ""
},
"require": {
"php": "^7.1 || ^8.0",
"phpstan/phpstan": "^1.2.0"
"php": "^7.2 || ^8.0",
"phpstan/phpstan": "^1.6.3"
},
"require-dev": {
"nikic/php-parser": "^4.13.0",
@ -1954,9 +1954,6 @@
},
"type": "phpstan-extension",
"extra": {
"branch-alias": {
"dev-master": "1.0-dev"
},
"phpstan": {
"includes": [
"rules.neon"
@ -1975,9 +1972,9 @@
"description": "Extra strict and opinionated rules for PHPStan",
"support": {
"issues": "https://github.com/phpstan/phpstan-strict-rules/issues",
"source": "https://github.com/phpstan/phpstan-strict-rules/tree/1.1.0"
"source": "https://github.com/phpstan/phpstan-strict-rules/tree/1.2.1"
},
"time": "2021-11-18T09:30:29+00:00"
"time": "2022-04-28T07:20:18+00:00"
},
{
"name": "phpunit/php-code-coverage",
@ -3452,5 +3449,5 @@
"platform-overrides": {
"php": "8.0.0"
},
"plugin-api-version": "2.2.0"
"plugin-api-version": "2.3.0"
}

View File

@ -44,7 +44,7 @@ trait ContainerTrait{
abstract public function getRealInventory();
protected function loadItems(CompoundTag $tag) : void{
if(($inventoryTag = $tag->getTag(Container::TAG_ITEMS)) instanceof ListTag){
if(($inventoryTag = $tag->getTag(Container::TAG_ITEMS)) instanceof ListTag && $inventoryTag->getTagType() === NBT::TAG_Compound){
$inventory = $this->getRealInventory();
$listeners = $inventory->getListeners()->toArray();
$inventory->getListeners()->remove(...$listeners); //prevent any events being fired by initialization

View File

@ -55,6 +55,7 @@ use pocketmine\network\mcpe\protocol\types\DeviceOS;
use pocketmine\network\mcpe\protocol\types\entity\EntityIds;
use pocketmine\network\mcpe\protocol\types\entity\EntityMetadataProperties;
use pocketmine\network\mcpe\protocol\types\entity\StringMetadataProperty;
use pocketmine\network\mcpe\protocol\types\GameMode;
use pocketmine\network\mcpe\protocol\types\inventory\ItemStackWrapper;
use pocketmine\network\mcpe\protocol\types\PlayerListEntry;
use pocketmine\player\Player;
@ -479,6 +480,7 @@ class Human extends Living implements ProjectileSource, InventoryHolder{
$this->location->yaw,
$this->location->yaw, //TODO: head yaw
ItemStackWrapper::legacy(TypeConverter::getInstance()->coreItemStackToNet($this->getInventory()->getItemInHand())),
GameMode::SURVIVAL,
$this->getAllNetworkData(),
AdventureSettingsPacket::create(0, 0, 0, 0, 0, $this->getId()), //TODO
[], //TODO: entity links

View File

@ -50,9 +50,6 @@ class PlayerChangeSkinEvent extends PlayerEvent implements Cancellable{
return $this->newSkin;
}
/**
* @throws \InvalidArgumentException if the specified skin is not valid
*/
public function setNewSkin(Skin $skin) : void{
$this->newSkin = $skin;
}

View File

@ -29,6 +29,7 @@ use pocketmine\block\utils\BannerPatternLayer;
use pocketmine\block\utils\DyeColor;
use pocketmine\data\bedrock\BannerPatternTypeIdMap;
use pocketmine\data\bedrock\DyeColorIdMap;
use pocketmine\nbt\NBT;
use pocketmine\nbt\tag\CompoundTag;
use pocketmine\nbt\tag\ListTag;
use function count;
@ -98,7 +99,7 @@ class Banner extends ItemBlockWallOrFloor{
$colorIdMap = DyeColorIdMap::getInstance();
$patternIdMap = BannerPatternTypeIdMap::getInstance();
$patterns = $tag->getListTag(self::TAG_PATTERNS);
if($patterns !== null){
if($patterns !== null && $patterns->getTagType() === NBT::TAG_Compound){
/** @var CompoundTag $t */
foreach($patterns as $t){
$patternColor = $colorIdMap->fromInvertedId($t->getInt(self::TAG_PATTERN_COLOR)) ?? DyeColor::BLACK(); //TODO: missing pattern colour should be an error

View File

@ -306,7 +306,7 @@ class Item implements \JsonSerializable{
$this->canPlaceOn = [];
$canPlaceOn = $tag->getListTag("CanPlaceOn");
if($canPlaceOn !== null){
if($canPlaceOn !== null && $canPlaceOn->getTagType() === NBT::TAG_String){
/** @var StringTag $entry */
foreach($canPlaceOn as $entry){
$this->canPlaceOn[$entry->getValue()] = $entry->getValue();
@ -314,7 +314,7 @@ class Item implements \JsonSerializable{
}
$this->canDestroy = [];
$canDestroy = $tag->getListTag("CanDestroy");
if($canDestroy !== null){
if($canDestroy !== null && $canDestroy->getTagType() === NBT::TAG_String){
/** @var StringTag $entry */
foreach($canDestroy as $entry){
$this->canDestroy[$entry->getValue()] = $entry->getValue();

View File

@ -48,9 +48,16 @@ final class RuntimeBlockMapping{
/** @var CompoundTag[] */
private $bedrockKnownStates;
private function __construct(){
private static function make() : self{
return new self(
Path::join(\pocketmine\BEDROCK_DATA_PATH, "canonical_block_states.nbt"),
Path::join(\pocketmine\BEDROCK_DATA_PATH, "r12_to_current_block_map.bin")
);
}
public function __construct(string $canonicalBlockStatesFile, string $r12ToCurrentBlockMapFile){
$stream = PacketSerializer::decoder(
Utils::assumeNotFalse(file_get_contents(Path::join(\pocketmine\BEDROCK_DATA_PATH, "canonical_block_states.nbt")), "Missing required resource file"),
Utils::assumeNotFalse(file_get_contents($canonicalBlockStatesFile), "Missing required resource file"),
0,
new PacketSerializerContext(GlobalItemTypeDictionary::getInstance()->getDictionary())
);
@ -60,15 +67,15 @@ final class RuntimeBlockMapping{
}
$this->bedrockKnownStates = $list;
$this->setupLegacyMappings();
$this->setupLegacyMappings($r12ToCurrentBlockMapFile);
}
private function setupLegacyMappings() : void{
private function setupLegacyMappings(string $r12ToCurrentBlockMapFile) : void{
$legacyIdMap = LegacyBlockIdToStringIdMap::getInstance();
/** @var R12ToCurrentBlockMapEntry[] $legacyStateMap */
$legacyStateMap = [];
$legacyStateMapReader = PacketSerializer::decoder(
Utils::assumeNotFalse(file_get_contents(Path::join(\pocketmine\BEDROCK_DATA_PATH, "r12_to_current_block_map.bin")), "Missing required resource file"),
Utils::assumeNotFalse(file_get_contents($r12ToCurrentBlockMapFile), "Missing required resource file"),
0,
new PacketSerializerContext(GlobalItemTypeDictionary::getInstance()->getDictionary())
);

View File

@ -78,7 +78,7 @@ final class ChunkSerializer{
//TODO: right now we don't support 3D natively, so we just 3Dify our 2D biomes so they fill the column
$encodedBiomePalette = self::serializeBiomesAsPalette($chunk);
$stream->put(str_repeat($encodedBiomePalette, 25));
$stream->put(str_repeat($encodedBiomePalette, 24));
$stream->putByte(0); //border block array count
//Border block entry format: 1 byte (4 bits X, 4 bits Z). These are however useless since they crash the regular client.

View File

@ -174,7 +174,7 @@ class UPnP{
'/upnp:controlURL'
), "xpath query is borked");
if(count($xpathResult) === 0){
if($xpathResult === null || count($xpathResult) === 0){
throw new UPnPException("Your router does not support portforwarding");
}
$controlURL = (string) $xpathResult[0];

View File

@ -1377,8 +1377,14 @@ class Player extends Human implements CommandSender, ChunkListener, IPlayer{
public function chat(string $message) : bool{
$this->removeCurrentWindow();
//Fast length check, to make sure we don't get hung trying to explode MBs of string ...
$maxTotalLength = $this->messageCounter * (self::MAX_CHAT_BYTE_LENGTH + 1);
if(strlen($message) > $maxTotalLength){
return false;
}
$message = TextFormat::clean($message, false);
foreach(explode("\n", $message) as $messagePart){
foreach(explode("\n", $message, $this->messageCounter + 1) as $messagePart){
if(trim($messagePart) !== "" && strlen($messagePart) <= self::MAX_CHAT_BYTE_LENGTH && mb_strlen($messagePart, 'UTF-8') <= self::MAX_CHAT_CHAR_LENGTH && $this->messageCounter-- > 0){
if(strpos($messagePart, './') === 0){
$messagePart = substr($messagePart, 1);
@ -2307,7 +2313,6 @@ class Player extends Human implements CommandSender, ChunkListener, IPlayer{
if($this->isCreative()
&& $source->getCause() !== EntityDamageEvent::CAUSE_SUICIDE
&& $source->getCause() !== EntityDamageEvent::CAUSE_VOID
){
$source->cancel();
}elseif($this->allowFlight && $source->getCause() === EntityDamageEvent::CAUSE_FALL){

View File

@ -2614,8 +2614,13 @@ class World implements ChunkManager{
unset($this->changedBlocks[$chunkHash]);
if(array_key_exists($chunkHash, $this->chunkPopulationRequestMap)){
$this->logger->debug("Rejecting population promise for chunk $x $z");
$this->chunkPopulationRequestMap[$chunkHash]->reject();
unset($this->chunkPopulationRequestMap[$chunkHash]);
if(isset($this->activeChunkPopulationTasks[$chunkHash])){
$this->logger->debug("Marking population task for chunk $x $z as orphaned");
$this->activeChunkPopulationTasks[$chunkHash] = false;
}
}
$this->timings->doChunkUnload->stopTiming();
@ -2791,7 +2796,7 @@ class World implements ChunkManager{
unset($this->chunkPopulationRequestQueueIndex[$nextChunkHash]);
World::getXZ($nextChunkHash, $nextChunkX, $nextChunkZ);
if(isset($this->chunkPopulationRequestMap[$nextChunkHash])){
assert(!isset($this->activeChunkPopulationTasks[$nextChunkHash]), "Population for chunk $nextChunkX $nextChunkZ already running");
assert(!($this->activeChunkPopulationTasks[$nextChunkHash] ?? false), "Population for chunk $nextChunkX $nextChunkZ already running");
if(
!$this->orderChunkPopulation($nextChunkX, $nextChunkZ, null)->isResolved() &&
!isset($this->activeChunkPopulationTasks[$nextChunkHash])
@ -2960,10 +2965,13 @@ class World implements ChunkManager{
}
$index = World::chunkHash($x, $z);
if(!isset($this->chunkPopulationRequestMap[$index])){
$this->logger->debug("Discarding population result for chunk x=$x,z=$z - promise was already broken");
if(!isset($this->activeChunkPopulationTasks[$index])){
throw new AssumptionFailedError("This should always be set, regardless of whether the task was orphaned or not");
}
if(!$this->activeChunkPopulationTasks[$index]){
$this->logger->debug("Discarding orphaned population result for chunk x=$x,z=$z");
unset($this->activeChunkPopulationTasks[$index]);
}elseif(isset($this->activeChunkPopulationTasks[$index])){
}else{
if($dirtyChunks === 0){
$oldChunk = $this->loadChunk($x, $z);
$this->setChunk($x, $z, $chunk);

View File

@ -36,6 +36,7 @@ use pocketmine\network\mcpe\protocol\types\entity\EntityMetadataFlags;
use pocketmine\network\mcpe\protocol\types\entity\EntityMetadataProperties;
use pocketmine\network\mcpe\protocol\types\entity\FloatMetadataProperty;
use pocketmine\network\mcpe\protocol\types\entity\LongMetadataProperty;
use pocketmine\network\mcpe\protocol\types\GameMode;
use pocketmine\network\mcpe\protocol\types\inventory\ItemStack;
use pocketmine\network\mcpe\protocol\types\inventory\ItemStackWrapper;
use pocketmine\network\mcpe\protocol\types\PlayerListEntry;
@ -117,6 +118,7 @@ class FloatingTextParticle implements Particle{
0,
0,
ItemStackWrapper::legacy(ItemStack::null()),
GameMode::SURVIVAL,
$actorMetadata,
AdventureSettingsPacket::create(0, 0, 0, 0, 0, $this->entityId),
[],