diff --git a/composer.json b/composer.json index 728478e48..47e798b16 100644 --- a/composer.json +++ b/composer.json @@ -33,10 +33,10 @@ "composer-runtime-api": "^2.0", "adhocore/json-comment": "~1.2.0", "pocketmine/netresearch-jsonmapper": "~v4.2.1000", - "pocketmine/bedrock-block-upgrade-schema": "~3.4.0+bedrock-1.20.50", - "pocketmine/bedrock-data": "~2.7.0+bedrock-1.20.50", - "pocketmine/bedrock-item-upgrade-schema": "~1.6.0+bedrock-1.20.50", - "pocketmine/bedrock-protocol": "~26.0.0+bedrock-1.20.50", + "pocketmine/bedrock-block-upgrade-schema": "~3.5.0+bedrock-1.20.60", + "pocketmine/bedrock-data": "~2.8.0+bedrock-1.20.60", + "pocketmine/bedrock-item-upgrade-schema": "~1.7.0+bedrock-1.20.60", + "pocketmine/bedrock-protocol": "~27.0.0+bedrock-1.20.60", "pocketmine/binaryutils": "^0.2.1", "pocketmine/callback-validator": "^1.0.2", "pocketmine/color": "^0.3.0", diff --git a/composer.lock b/composer.lock index a668d5aad..47aeeaeca 100644 --- a/composer.lock +++ b/composer.lock @@ -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": "fecd5b7c364cb3a0f3a832004f594101", + "content-hash": "d923f5fd75f0d33eb5198268a74a58b4", "packages": [ { "name": "adhocore/json-comment", @@ -122,16 +122,16 @@ }, { "name": "pocketmine/bedrock-block-upgrade-schema", - "version": "3.4.0", + "version": "3.5.0", "source": { "type": "git", "url": "https://github.com/pmmp/BedrockBlockUpgradeSchema.git", - "reference": "9872eb37f15080b19c2b7861085e549c48dda92d" + "reference": "1ed4ba738333c4b4afe4fef8e9326a45c89f12e3" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/pmmp/BedrockBlockUpgradeSchema/zipball/9872eb37f15080b19c2b7861085e549c48dda92d", - "reference": "9872eb37f15080b19c2b7861085e549c48dda92d", + "url": "https://api.github.com/repos/pmmp/BedrockBlockUpgradeSchema/zipball/1ed4ba738333c4b4afe4fef8e9326a45c89f12e3", + "reference": "1ed4ba738333c4b4afe4fef8e9326a45c89f12e3", "shasum": "" }, "type": "library", @@ -142,22 +142,22 @@ "description": "Schemas describing how to upgrade saved block data in older Minecraft: Bedrock Edition world saves", "support": { "issues": "https://github.com/pmmp/BedrockBlockUpgradeSchema/issues", - "source": "https://github.com/pmmp/BedrockBlockUpgradeSchema/tree/3.4.0" + "source": "https://github.com/pmmp/BedrockBlockUpgradeSchema/tree/3.5.0" }, - "time": "2023-11-08T15:22:06+00:00" + "time": "2024-02-07T11:46:50+00:00" }, { "name": "pocketmine/bedrock-data", - "version": "2.7.0+bedrock-1.20.50", + "version": "2.8.0+bedrock-1.20.60", "source": { "type": "git", "url": "https://github.com/pmmp/BedrockData.git", - "reference": "36f975dfca7520b7d36b0b39429f274464c9bc13" + "reference": "d8ea0355b7c835564af9fe6e273e650ac62c84a2" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/pmmp/BedrockData/zipball/36f975dfca7520b7d36b0b39429f274464c9bc13", - "reference": "36f975dfca7520b7d36b0b39429f274464c9bc13", + "url": "https://api.github.com/repos/pmmp/BedrockData/zipball/d8ea0355b7c835564af9fe6e273e650ac62c84a2", + "reference": "d8ea0355b7c835564af9fe6e273e650ac62c84a2", "shasum": "" }, "type": "library", @@ -168,22 +168,22 @@ "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.20.50" + "source": "https://github.com/pmmp/BedrockData/tree/bedrock-1.20.60" }, - "time": "2023-12-06T13:59:08+00:00" + "time": "2024-02-07T11:23:46+00:00" }, { "name": "pocketmine/bedrock-item-upgrade-schema", - "version": "1.6.0", + "version": "1.7.0", "source": { "type": "git", "url": "https://github.com/pmmp/BedrockItemUpgradeSchema.git", - "reference": "d374e5fd8302977675dcd2a42733abd3ee476ca1" + "reference": "69772dd58e2b2c7b7513fa2bcdc46e782228641c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/pmmp/BedrockItemUpgradeSchema/zipball/d374e5fd8302977675dcd2a42733abd3ee476ca1", - "reference": "d374e5fd8302977675dcd2a42733abd3ee476ca1", + "url": "https://api.github.com/repos/pmmp/BedrockItemUpgradeSchema/zipball/69772dd58e2b2c7b7513fa2bcdc46e782228641c", + "reference": "69772dd58e2b2c7b7513fa2bcdc46e782228641c", "shasum": "" }, "type": "library", @@ -194,22 +194,22 @@ "description": "JSON schemas for upgrading items found in older Minecraft: Bedrock world saves", "support": { "issues": "https://github.com/pmmp/BedrockItemUpgradeSchema/issues", - "source": "https://github.com/pmmp/BedrockItemUpgradeSchema/tree/1.6.0" + "source": "https://github.com/pmmp/BedrockItemUpgradeSchema/tree/1.7.0" }, - "time": "2023-11-08T18:12:14+00:00" + "time": "2024-02-07T11:58:05+00:00" }, { "name": "pocketmine/bedrock-protocol", - "version": "26.0.0+bedrock-1.20.50", + "version": "27.0.1+bedrock-1.20.60", "source": { "type": "git", "url": "https://github.com/pmmp/BedrockProtocol.git", - "reference": "f278a0b6d4fa1e2e0408a125f323a3118b1968df" + "reference": "0cebb55f6e904f722b14d420f6b2c84c7fa69f10" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/pmmp/BedrockProtocol/zipball/f278a0b6d4fa1e2e0408a125f323a3118b1968df", - "reference": "f278a0b6d4fa1e2e0408a125f323a3118b1968df", + "url": "https://api.github.com/repos/pmmp/BedrockProtocol/zipball/0cebb55f6e904f722b14d420f6b2c84c7fa69f10", + "reference": "0cebb55f6e904f722b14d420f6b2c84c7fa69f10", "shasum": "" }, "require": { @@ -241,9 +241,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/26.0.0+bedrock-1.20.50" + "source": "https://github.com/pmmp/BedrockProtocol/tree/27.0.1+bedrock-1.20.60" }, - "time": "2023-12-06T14:08:37+00:00" + "time": "2024-02-07T11:53:50+00:00" }, { "name": "pocketmine/binaryutils", diff --git a/src/Server.php b/src/Server.php index 48f641947..3f12f7669 100644 --- a/src/Server.php +++ b/src/Server.php @@ -60,6 +60,7 @@ use pocketmine\network\mcpe\NetworkSession; use pocketmine\network\mcpe\PacketBroadcaster; use pocketmine\network\mcpe\protocol\ProtocolInfo; use pocketmine\network\mcpe\protocol\serializer\PacketSerializerContext; +use pocketmine\network\mcpe\protocol\types\CompressionAlgorithm; use pocketmine\network\mcpe\raklib\RakLibInterface; use pocketmine\network\mcpe\StandardEntityEventBroadcaster; use pocketmine\network\mcpe\StandardPacketBroadcaster; @@ -125,6 +126,7 @@ use Symfony\Component\Filesystem\Path; use function array_fill; use function array_sum; use function base64_encode; +use function chr; use function cli_set_process_title; use function copy; use function count; @@ -1373,19 +1375,26 @@ class Server{ try{ $timings->startTiming(); - if($sync === null){ - $threshold = $compressor->getCompressionThreshold(); - $sync = !$this->networkCompressionAsync || $threshold === null || strlen($buffer) < $threshold; + $threshold = $compressor->getCompressionThreshold(); + if($threshold === null || strlen($buffer) < $compressor->getCompressionThreshold()){ + $compressionType = CompressionAlgorithm::NONE; + $compressed = $buffer; + + }else{ + $sync ??= !$this->networkCompressionAsync; + + if(!$sync && strlen($buffer) >= $this->networkCompressionAsyncThreshold){ + $promise = new CompressBatchPromise(); + $task = new CompressBatchTask($buffer, $promise, $compressor); + $this->asyncPool->submitTask($task); + return $promise; + } + + $compressionType = $compressor->getNetworkId(); + $compressed = $compressor->compress($buffer); } - if(!$sync && strlen($buffer) >= $this->networkCompressionAsyncThreshold){ - $promise = new CompressBatchPromise(); - $task = new CompressBatchTask($buffer, $promise, $compressor); - $this->asyncPool->submitTask($task); - return $promise; - } - - return $compressor->compress($buffer); + return chr($compressionType) . $compressed; }finally{ $timings->stopTiming(); } diff --git a/src/data/bedrock/block/BlockStateData.php b/src/data/bedrock/block/BlockStateData.php index 1417fa014..b089eea5b 100644 --- a/src/data/bedrock/block/BlockStateData.php +++ b/src/data/bedrock/block/BlockStateData.php @@ -42,7 +42,7 @@ final class BlockStateData{ public const CURRENT_VERSION = (1 << 24) | //major (20 << 16) | //minor - (50 << 8) | //patch + (60 << 8) | //patch (1); //revision public const TAG_NAME = "name"; diff --git a/src/data/bedrock/block/BlockStateNames.php b/src/data/bedrock/block/BlockStateNames.php index 9b28e936d..75b45e88e 100644 --- a/src/data/bedrock/block/BlockStateNames.php +++ b/src/data/bedrock/block/BlockStateNames.php @@ -56,7 +56,6 @@ final class BlockStateNames{ public const CHEMISTRY_TABLE_TYPE = "chemistry_table_type"; public const CHISEL_TYPE = "chisel_type"; public const CLUSTER_COUNT = "cluster_count"; - public const COLOR = "color"; public const COLOR_BIT = "color_bit"; public const COMPOSTER_FILL_LEVEL = "composter_fill_level"; public const CONDITIONAL_BIT = "conditional_bit"; @@ -145,6 +144,7 @@ final class BlockStateNames{ public const TALL_GRASS_TYPE = "tall_grass_type"; public const TOGGLE_BIT = "toggle_bit"; public const TORCH_FACING_DIRECTION = "torch_facing_direction"; + public const TRIAL_SPAWNER_STATE = "trial_spawner_state"; public const TRIGGERED_BIT = "triggered_bit"; public const TURTLE_EGG_COUNT = "turtle_egg_count"; public const TWISTING_VINES_AGE = "twisting_vines_age"; diff --git a/src/data/bedrock/block/BlockStateStringValues.php b/src/data/bedrock/block/BlockStateStringValues.php index 4a05fa33e..d9d8a748d 100644 --- a/src/data/bedrock/block/BlockStateStringValues.php +++ b/src/data/bedrock/block/BlockStateStringValues.php @@ -62,23 +62,6 @@ final class BlockStateStringValues{ public const CHISEL_TYPE_LINES = "lines"; public const CHISEL_TYPE_SMOOTH = "smooth"; - public const COLOR_BLACK = "black"; - public const COLOR_BLUE = "blue"; - public const COLOR_BROWN = "brown"; - public const COLOR_CYAN = "cyan"; - public const COLOR_GRAY = "gray"; - public const COLOR_GREEN = "green"; - public const COLOR_LIGHT_BLUE = "light_blue"; - public const COLOR_LIME = "lime"; - public const COLOR_MAGENTA = "magenta"; - public const COLOR_ORANGE = "orange"; - public const COLOR_PINK = "pink"; - public const COLOR_PURPLE = "purple"; - public const COLOR_RED = "red"; - public const COLOR_SILVER = "silver"; - public const COLOR_WHITE = "white"; - public const COLOR_YELLOW = "yellow"; - public const CORAL_COLOR_BLUE = "blue"; public const CORAL_COLOR_PINK = "pink"; public const CORAL_COLOR_PURPLE = "purple"; diff --git a/src/data/bedrock/block/BlockTypeNames.php b/src/data/bedrock/block/BlockTypeNames.php index fdca40a3a..1d8bfadfa 100644 --- a/src/data/bedrock/block/BlockTypeNames.php +++ b/src/data/bedrock/block/BlockTypeNames.php @@ -517,10 +517,40 @@ final class BlockTypeNames{ public const GREEN_WOOL = "minecraft:green_wool"; public const GRINDSTONE = "minecraft:grindstone"; public const HANGING_ROOTS = "minecraft:hanging_roots"; + public const HARD_BLACK_STAINED_GLASS = "minecraft:hard_black_stained_glass"; + public const HARD_BLACK_STAINED_GLASS_PANE = "minecraft:hard_black_stained_glass_pane"; + public const HARD_BLUE_STAINED_GLASS = "minecraft:hard_blue_stained_glass"; + public const HARD_BLUE_STAINED_GLASS_PANE = "minecraft:hard_blue_stained_glass_pane"; + public const HARD_BROWN_STAINED_GLASS = "minecraft:hard_brown_stained_glass"; + public const HARD_BROWN_STAINED_GLASS_PANE = "minecraft:hard_brown_stained_glass_pane"; + public const HARD_CYAN_STAINED_GLASS = "minecraft:hard_cyan_stained_glass"; + public const HARD_CYAN_STAINED_GLASS_PANE = "minecraft:hard_cyan_stained_glass_pane"; public const HARD_GLASS = "minecraft:hard_glass"; public const HARD_GLASS_PANE = "minecraft:hard_glass_pane"; - public const HARD_STAINED_GLASS = "minecraft:hard_stained_glass"; - public const HARD_STAINED_GLASS_PANE = "minecraft:hard_stained_glass_pane"; + public const HARD_GRAY_STAINED_GLASS = "minecraft:hard_gray_stained_glass"; + public const HARD_GRAY_STAINED_GLASS_PANE = "minecraft:hard_gray_stained_glass_pane"; + public const HARD_GREEN_STAINED_GLASS = "minecraft:hard_green_stained_glass"; + public const HARD_GREEN_STAINED_GLASS_PANE = "minecraft:hard_green_stained_glass_pane"; + public const HARD_LIGHT_BLUE_STAINED_GLASS = "minecraft:hard_light_blue_stained_glass"; + public const HARD_LIGHT_BLUE_STAINED_GLASS_PANE = "minecraft:hard_light_blue_stained_glass_pane"; + public const HARD_LIGHT_GRAY_STAINED_GLASS = "minecraft:hard_light_gray_stained_glass"; + public const HARD_LIGHT_GRAY_STAINED_GLASS_PANE = "minecraft:hard_light_gray_stained_glass_pane"; + public const HARD_LIME_STAINED_GLASS = "minecraft:hard_lime_stained_glass"; + public const HARD_LIME_STAINED_GLASS_PANE = "minecraft:hard_lime_stained_glass_pane"; + public const HARD_MAGENTA_STAINED_GLASS = "minecraft:hard_magenta_stained_glass"; + public const HARD_MAGENTA_STAINED_GLASS_PANE = "minecraft:hard_magenta_stained_glass_pane"; + public const HARD_ORANGE_STAINED_GLASS = "minecraft:hard_orange_stained_glass"; + public const HARD_ORANGE_STAINED_GLASS_PANE = "minecraft:hard_orange_stained_glass_pane"; + public const HARD_PINK_STAINED_GLASS = "minecraft:hard_pink_stained_glass"; + public const HARD_PINK_STAINED_GLASS_PANE = "minecraft:hard_pink_stained_glass_pane"; + public const HARD_PURPLE_STAINED_GLASS = "minecraft:hard_purple_stained_glass"; + public const HARD_PURPLE_STAINED_GLASS_PANE = "minecraft:hard_purple_stained_glass_pane"; + public const HARD_RED_STAINED_GLASS = "minecraft:hard_red_stained_glass"; + public const HARD_RED_STAINED_GLASS_PANE = "minecraft:hard_red_stained_glass_pane"; + public const HARD_WHITE_STAINED_GLASS = "minecraft:hard_white_stained_glass"; + public const HARD_WHITE_STAINED_GLASS_PANE = "minecraft:hard_white_stained_glass_pane"; + public const HARD_YELLOW_STAINED_GLASS = "minecraft:hard_yellow_stained_glass"; + public const HARD_YELLOW_STAINED_GLASS_PANE = "minecraft:hard_yellow_stained_glass_pane"; public const HARDENED_CLAY = "minecraft:hardened_clay"; public const HAY_BLOCK = "minecraft:hay_block"; public const HEAVY_WEIGHTED_PRESSURE_PLATE = "minecraft:heavy_weighted_pressure_plate"; @@ -900,6 +930,7 @@ final class BlockTypeNames{ public const TORCHFLOWER_CROP = "minecraft:torchflower_crop"; public const TRAPDOOR = "minecraft:trapdoor"; public const TRAPPED_CHEST = "minecraft:trapped_chest"; + public const TRIAL_SPAWNER = "minecraft:trial_spawner"; public const TRIP_WIRE = "minecraft:trip_wire"; public const TRIPWIRE_HOOK = "minecraft:tripwire_hook"; public const TUBE_CORAL = "minecraft:tube_coral"; diff --git a/src/data/bedrock/block/convert/BlockObjectToStateSerializer.php b/src/data/bedrock/block/convert/BlockObjectToStateSerializer.php index f70162ac5..b0b06ac90 100644 --- a/src/data/bedrock/block/convert/BlockObjectToStateSerializer.php +++ b/src/data/bedrock/block/convert/BlockObjectToStateSerializer.php @@ -315,6 +315,44 @@ final class BlockObjectToStateSerializer implements BlockStateSerializer{ } public function registerFlatColorBlockSerializers() : void{ + $this->map(Blocks::STAINED_HARDENED_GLASS(), fn(StainedHardenedGlass $block) => Writer::create(match($block->getColor()){ + DyeColor::BLACK => Ids::HARD_BLACK_STAINED_GLASS, + DyeColor::BLUE => Ids::HARD_BLUE_STAINED_GLASS, + DyeColor::BROWN => Ids::HARD_BROWN_STAINED_GLASS, + DyeColor::CYAN => Ids::HARD_CYAN_STAINED_GLASS, + DyeColor::GRAY => Ids::HARD_GRAY_STAINED_GLASS, + DyeColor::GREEN => Ids::HARD_GREEN_STAINED_GLASS, + DyeColor::LIGHT_BLUE => Ids::HARD_LIGHT_BLUE_STAINED_GLASS, + DyeColor::LIGHT_GRAY => Ids::HARD_LIGHT_GRAY_STAINED_GLASS, + DyeColor::LIME => Ids::HARD_LIME_STAINED_GLASS, + DyeColor::MAGENTA => Ids::HARD_MAGENTA_STAINED_GLASS, + DyeColor::ORANGE => Ids::HARD_ORANGE_STAINED_GLASS, + DyeColor::PINK => Ids::HARD_PINK_STAINED_GLASS, + DyeColor::PURPLE => Ids::HARD_PURPLE_STAINED_GLASS, + DyeColor::RED => Ids::HARD_RED_STAINED_GLASS, + DyeColor::WHITE => Ids::HARD_WHITE_STAINED_GLASS, + DyeColor::YELLOW => Ids::HARD_YELLOW_STAINED_GLASS, + })); + + $this->map(Blocks::STAINED_HARDENED_GLASS_PANE(), fn(StainedHardenedGlassPane $block) => Writer::create(match($block->getColor()){ + DyeColor::BLACK => Ids::HARD_BLACK_STAINED_GLASS_PANE, + DyeColor::BLUE => Ids::HARD_BLUE_STAINED_GLASS_PANE, + DyeColor::BROWN => Ids::HARD_BROWN_STAINED_GLASS_PANE, + DyeColor::CYAN => Ids::HARD_CYAN_STAINED_GLASS_PANE, + DyeColor::GRAY => Ids::HARD_GRAY_STAINED_GLASS_PANE, + DyeColor::GREEN => Ids::HARD_GREEN_STAINED_GLASS_PANE, + DyeColor::LIGHT_BLUE => Ids::HARD_LIGHT_BLUE_STAINED_GLASS_PANE, + DyeColor::LIGHT_GRAY => Ids::HARD_LIGHT_GRAY_STAINED_GLASS_PANE, + DyeColor::LIME => Ids::HARD_LIME_STAINED_GLASS_PANE, + DyeColor::MAGENTA => Ids::HARD_MAGENTA_STAINED_GLASS_PANE, + DyeColor::ORANGE => Ids::HARD_ORANGE_STAINED_GLASS_PANE, + DyeColor::PINK => Ids::HARD_PINK_STAINED_GLASS_PANE, + DyeColor::PURPLE => Ids::HARD_PURPLE_STAINED_GLASS_PANE, + DyeColor::RED => Ids::HARD_RED_STAINED_GLASS_PANE, + DyeColor::WHITE => Ids::HARD_WHITE_STAINED_GLASS_PANE, + DyeColor::YELLOW => Ids::HARD_YELLOW_STAINED_GLASS_PANE, + })); + $this->map(Blocks::GLAZED_TERRACOTTA(), function(GlazedTerracotta $block) : Writer{ return Writer::create(match($block->getColor()){ DyeColor::BLACK => Ids::BLACK_GLAZED_TERRACOTTA, @@ -1617,14 +1655,6 @@ final class BlockObjectToStateSerializer implements BlockStateSerializer{ ->writeString(StateNames::SPONGE_TYPE, $block->isWet() ? StringValues::SPONGE_TYPE_WET : StringValues::SPONGE_TYPE_DRY); }); $this->map(Blocks::SPRUCE_SAPLING(), fn(Sapling $block) => Helper::encodeSapling($block, StringValues::SAPLING_TYPE_SPRUCE)); - $this->map(Blocks::STAINED_HARDENED_GLASS(), function(StainedHardenedGlass $block) : Writer{ - return Writer::create(Ids::HARD_STAINED_GLASS) - ->writeColor($block->getColor()); - }); - $this->map(Blocks::STAINED_HARDENED_GLASS_PANE(), function(StainedHardenedGlassPane $block) : Writer{ - return Writer::create(Ids::HARD_STAINED_GLASS_PANE) - ->writeColor($block->getColor()); - }); $this->map(Blocks::STONECUTTER(), fn(Stonecutter $block) => Writer::create(Ids::STONECUTTER_BLOCK) ->writeCardinalHorizontalFacing($block->getFacing())); $this->map(Blocks::STONE_BRICKS(), fn() => Helper::encodeStoneBricks(StringValues::STONE_BRICK_TYPE_DEFAULT)); diff --git a/src/data/bedrock/block/convert/BlockStateReader.php b/src/data/bedrock/block/convert/BlockStateReader.php index 6bb0c8bf8..ea44e90b4 100644 --- a/src/data/bedrock/block/convert/BlockStateReader.php +++ b/src/data/bedrock/block/convert/BlockStateReader.php @@ -25,7 +25,6 @@ namespace pocketmine\data\bedrock\block\convert; use pocketmine\block\utils\BellAttachmentType; use pocketmine\block\utils\CoralType; -use pocketmine\block\utils\DyeColor; use pocketmine\block\utils\SlabType; use pocketmine\block\utils\WallConnectionType; use pocketmine\data\bedrock\block\BlockLegacyMetadata; @@ -236,30 +235,6 @@ final class BlockStateReader{ }; } - /** @throws BlockStateDeserializeException */ - public function readColor() : DyeColor{ - // * color (StringTag) = black, blue, brown, cyan, gray, green, light_blue, lime, magenta, orange, pink, purple, red, silver, white, yellow - return match($color = $this->readString(BlockStateNames::COLOR)){ - StringValues::COLOR_BLACK => DyeColor::BLACK, - StringValues::COLOR_BLUE => DyeColor::BLUE, - StringValues::COLOR_BROWN => DyeColor::BROWN, - StringValues::COLOR_CYAN => DyeColor::CYAN, - StringValues::COLOR_GRAY => DyeColor::GRAY, - StringValues::COLOR_GREEN => DyeColor::GREEN, - StringValues::COLOR_LIGHT_BLUE => DyeColor::LIGHT_BLUE, - StringValues::COLOR_LIME => DyeColor::LIME, - StringValues::COLOR_MAGENTA => DyeColor::MAGENTA, - StringValues::COLOR_ORANGE => DyeColor::ORANGE, - StringValues::COLOR_PINK => DyeColor::PINK, - StringValues::COLOR_PURPLE => DyeColor::PURPLE, - StringValues::COLOR_RED => DyeColor::RED, - StringValues::COLOR_SILVER => DyeColor::LIGHT_GRAY, - StringValues::COLOR_WHITE => DyeColor::WHITE, - StringValues::COLOR_YELLOW => DyeColor::YELLOW, - default => throw $this->badValueException(BlockStateNames::COLOR, $color), - }; - } - /** @throws BlockStateDeserializeException */ public function readCoralFacing() : int{ return $this->parseFacingValue($this->readInt(BlockStateNames::CORAL_DIRECTION), [ diff --git a/src/data/bedrock/block/convert/BlockStateToObjectDeserializer.php b/src/data/bedrock/block/convert/BlockStateToObjectDeserializer.php index 18e9b3e32..294126367 100644 --- a/src/data/bedrock/block/convert/BlockStateToObjectDeserializer.php +++ b/src/data/bedrock/block/convert/BlockStateToObjectDeserializer.php @@ -185,6 +185,48 @@ final class BlockStateToObjectDeserializer implements BlockStateDeserializer{ } private function registerFlatColorBlockDeserializers() : void{ + foreach([ + Ids::HARD_BLACK_STAINED_GLASS => DyeColor::BLACK, + Ids::HARD_BLUE_STAINED_GLASS => DyeColor::BLUE, + Ids::HARD_BROWN_STAINED_GLASS => DyeColor::BROWN, + Ids::HARD_CYAN_STAINED_GLASS => DyeColor::CYAN, + Ids::HARD_GRAY_STAINED_GLASS => DyeColor::GRAY, + Ids::HARD_GREEN_STAINED_GLASS => DyeColor::GREEN, + Ids::HARD_LIGHT_BLUE_STAINED_GLASS => DyeColor::LIGHT_BLUE, + Ids::HARD_LIGHT_GRAY_STAINED_GLASS => DyeColor::LIGHT_GRAY, + Ids::HARD_LIME_STAINED_GLASS => DyeColor::LIME, + Ids::HARD_MAGENTA_STAINED_GLASS => DyeColor::MAGENTA, + Ids::HARD_ORANGE_STAINED_GLASS => DyeColor::ORANGE, + Ids::HARD_PINK_STAINED_GLASS => DyeColor::PINK, + Ids::HARD_PURPLE_STAINED_GLASS => DyeColor::PURPLE, + Ids::HARD_RED_STAINED_GLASS => DyeColor::RED, + Ids::HARD_WHITE_STAINED_GLASS => DyeColor::WHITE, + Ids::HARD_YELLOW_STAINED_GLASS => DyeColor::YELLOW, + ] as $id => $color){ + $this->map($id, fn(Reader $in) => Blocks::STAINED_HARDENED_GLASS()->setColor($color)); + } + + foreach([ + Ids::HARD_BLACK_STAINED_GLASS_PANE => DyeColor::BLACK, + Ids::HARD_BLUE_STAINED_GLASS_PANE => DyeColor::BLUE, + Ids::HARD_BROWN_STAINED_GLASS_PANE => DyeColor::BROWN, + Ids::HARD_CYAN_STAINED_GLASS_PANE => DyeColor::CYAN, + Ids::HARD_GRAY_STAINED_GLASS_PANE => DyeColor::GRAY, + Ids::HARD_GREEN_STAINED_GLASS_PANE => DyeColor::GREEN, + Ids::HARD_LIGHT_BLUE_STAINED_GLASS_PANE => DyeColor::LIGHT_BLUE, + Ids::HARD_LIGHT_GRAY_STAINED_GLASS_PANE => DyeColor::LIGHT_GRAY, + Ids::HARD_LIME_STAINED_GLASS_PANE => DyeColor::LIME, + Ids::HARD_MAGENTA_STAINED_GLASS_PANE => DyeColor::MAGENTA, + Ids::HARD_ORANGE_STAINED_GLASS_PANE => DyeColor::ORANGE, + Ids::HARD_PINK_STAINED_GLASS_PANE => DyeColor::PINK, + Ids::HARD_PURPLE_STAINED_GLASS_PANE => DyeColor::PURPLE, + Ids::HARD_RED_STAINED_GLASS_PANE => DyeColor::RED, + Ids::HARD_WHITE_STAINED_GLASS_PANE => DyeColor::WHITE, + Ids::HARD_YELLOW_STAINED_GLASS_PANE => DyeColor::YELLOW, + ] as $id => $color){ + $this->map($id, fn(Reader $in) => Blocks::STAINED_HARDENED_GLASS_PANE()->setColor($color)); + } + foreach([ Ids::BLACK_GLAZED_TERRACOTTA => DyeColor::BLACK, Ids::BLUE_GLAZED_TERRACOTTA => DyeColor::BLUE, @@ -1159,14 +1201,6 @@ final class BlockStateToObjectDeserializer implements BlockStateDeserializer{ ->setShape($in->readBoundedInt(StateNames::RAIL_DIRECTION, 0, 5)); }); $this->mapStairs(Ids::GRANITE_STAIRS, fn() => Blocks::GRANITE_STAIRS()); - $this->map(Ids::HARD_STAINED_GLASS, function(Reader $in) : Block{ - return Blocks::STAINED_HARDENED_GLASS() - ->setColor($in->readColor()); - }); - $this->map(Ids::HARD_STAINED_GLASS_PANE, function(Reader $in) : Block{ - return Blocks::STAINED_HARDENED_GLASS_PANE() - ->setColor($in->readColor()); - }); $this->map(Ids::HAY_BLOCK, function(Reader $in) : Block{ $in->ignored(StateNames::DEPRECATED); return Blocks::HAY_BALE()->setAxis($in->readPillarAxis()); diff --git a/src/data/bedrock/block/convert/BlockStateWriter.php b/src/data/bedrock/block/convert/BlockStateWriter.php index f5f34fff6..69efa4d0f 100644 --- a/src/data/bedrock/block/convert/BlockStateWriter.php +++ b/src/data/bedrock/block/convert/BlockStateWriter.php @@ -25,7 +25,6 @@ namespace pocketmine\data\bedrock\block\convert; use pocketmine\block\utils\BellAttachmentType; use pocketmine\block\utils\CoralType; -use pocketmine\block\utils\DyeColor; use pocketmine\block\utils\SlabType; use pocketmine\block\utils\WallConnectionType; use pocketmine\block\utils\WoodType; @@ -193,29 +192,6 @@ final class BlockStateWriter{ }); } - /** @return $this */ - public function writeColor(DyeColor $color) : self{ - $this->writeString(BlockStateNames::COLOR, match($color){ - DyeColor::BLACK => StringValues::COLOR_BLACK, - DyeColor::BLUE => StringValues::COLOR_BLUE, - DyeColor::BROWN => StringValues::COLOR_BROWN, - DyeColor::CYAN => StringValues::COLOR_CYAN, - DyeColor::GRAY => StringValues::COLOR_GRAY, - DyeColor::GREEN => StringValues::COLOR_GREEN, - DyeColor::LIGHT_BLUE => StringValues::COLOR_LIGHT_BLUE, - DyeColor::LIGHT_GRAY => StringValues::COLOR_SILVER, - DyeColor::LIME => StringValues::COLOR_LIME, - DyeColor::MAGENTA => StringValues::COLOR_MAGENTA, - DyeColor::ORANGE => StringValues::COLOR_ORANGE, - DyeColor::PINK => StringValues::COLOR_PINK, - DyeColor::PURPLE => StringValues::COLOR_PURPLE, - DyeColor::RED => StringValues::COLOR_RED, - DyeColor::WHITE => StringValues::COLOR_WHITE, - DyeColor::YELLOW => StringValues::COLOR_YELLOW, - }); - return $this; - } - /** @return $this */ public function writeCoralFacing(int $value) : self{ $this->writeInt(BlockStateNames::CORAL_DIRECTION, match($value){ diff --git a/src/data/bedrock/item/ItemSerializerDeserializerRegistrar.php b/src/data/bedrock/item/ItemSerializerDeserializerRegistrar.php index 0c6dadc46..bbc295b72 100644 --- a/src/data/bedrock/item/ItemSerializerDeserializerRegistrar.php +++ b/src/data/bedrock/item/ItemSerializerDeserializerRegistrar.php @@ -348,7 +348,7 @@ final class ItemSerializerDeserializerRegistrar{ $this->map1to1Item(Ids::RIB_ARMOR_TRIM_SMITHING_TEMPLATE, Items::RIB_ARMOR_TRIM_SMITHING_TEMPLATE()); $this->map1to1Item(Ids::ROTTEN_FLESH, Items::ROTTEN_FLESH()); $this->map1to1Item(Ids::SALMON, Items::RAW_SALMON()); - $this->map1to1Item(Ids::SCUTE, Items::SCUTE()); + $this->map1to1Item(Ids::TURTLE_SCUTE, Items::SCUTE()); $this->map1to1Item(Ids::SENTRY_ARMOR_TRIM_SMITHING_TEMPLATE, Items::SENTRY_ARMOR_TRIM_SMITHING_TEMPLATE()); $this->map1to1Item(Ids::SHAPER_ARMOR_TRIM_SMITHING_TEMPLATE, Items::SHAPER_ARMOR_TRIM_SMITHING_TEMPLATE()); $this->map1to1Item(Ids::SHEARS, Items::SHEARS()); diff --git a/src/data/bedrock/item/ItemTypeNames.php b/src/data/bedrock/item/ItemTypeNames.php index c1534a0f0..3f01ff1a8 100644 --- a/src/data/bedrock/item/ItemTypeNames.php +++ b/src/data/bedrock/item/ItemTypeNames.php @@ -38,6 +38,8 @@ final class ItemTypeNames{ public const ANGLER_POTTERY_SHERD = "minecraft:angler_pottery_sherd"; public const APPLE = "minecraft:apple"; public const ARCHER_POTTERY_SHERD = "minecraft:archer_pottery_sherd"; + public const ARMADILLO_SCUTE = "minecraft:armadillo_scute"; + public const ARMADILLO_SPAWN_EGG = "minecraft:armadillo_spawn_egg"; public const ARMOR_STAND = "minecraft:armor_stand"; public const ARMS_UP_POTTERY_SHERD = "minecraft:arms_up_pottery_sherd"; public const ARROW = "minecraft:arrow"; @@ -79,6 +81,7 @@ final class ItemTypeNames{ public const BOW = "minecraft:bow"; public const BOWL = "minecraft:bowl"; public const BREAD = "minecraft:bread"; + public const BREEZE_SPAWN_EGG = "minecraft:breeze_spawn_egg"; public const BREWER_POTTERY_SHERD = "minecraft:brewer_pottery_sherd"; public const BREWING_STAND = "minecraft:brewing_stand"; public const BRICK = "minecraft:brick"; @@ -238,6 +241,8 @@ final class ItemTypeNames{ public const GREEN_DYE = "minecraft:green_dye"; public const GUARDIAN_SPAWN_EGG = "minecraft:guardian_spawn_egg"; public const GUNPOWDER = "minecraft:gunpowder"; + public const HARD_STAINED_GLASS = "minecraft:hard_stained_glass"; + public const HARD_STAINED_GLASS_PANE = "minecraft:hard_stained_glass_pane"; public const HEART_OF_THE_SEA = "minecraft:heart_of_the_sea"; public const HEART_POTTERY_SHERD = "minecraft:heart_pottery_sherd"; public const HEARTBREAK_POTTERY_SHERD = "minecraft:heartbreak_pottery_sherd"; @@ -404,7 +409,6 @@ final class ItemTypeNames{ public const SALMON = "minecraft:salmon"; public const SALMON_BUCKET = "minecraft:salmon_bucket"; public const SALMON_SPAWN_EGG = "minecraft:salmon_spawn_egg"; - public const SCUTE = "minecraft:scute"; public const SENTRY_ARMOR_TRIM_SMITHING_TEMPLATE = "minecraft:sentry_armor_trim_smithing_template"; public const SHAPER_ARMOR_TRIM_SMITHING_TEMPLATE = "minecraft:shaper_armor_trim_smithing_template"; public const SHEAF_POTTERY_SHERD = "minecraft:sheaf_pottery_sherd"; @@ -466,11 +470,13 @@ final class ItemTypeNames{ public const TORCHFLOWER_SEEDS = "minecraft:torchflower_seeds"; public const TOTEM_OF_UNDYING = "minecraft:totem_of_undying"; public const TRADER_LLAMA_SPAWN_EGG = "minecraft:trader_llama_spawn_egg"; + public const TRIAL_KEY = "minecraft:trial_key"; public const TRIDENT = "minecraft:trident"; public const TROPICAL_FISH = "minecraft:tropical_fish"; public const TROPICAL_FISH_BUCKET = "minecraft:tropical_fish_bucket"; public const TROPICAL_FISH_SPAWN_EGG = "minecraft:tropical_fish_spawn_egg"; public const TURTLE_HELMET = "minecraft:turtle_helmet"; + public const TURTLE_SCUTE = "minecraft:turtle_scute"; public const TURTLE_SPAWN_EGG = "minecraft:turtle_spawn_egg"; public const VEX_ARMOR_TRIM_SMITHING_TEMPLATE = "minecraft:vex_armor_trim_smithing_template"; public const VEX_SPAWN_EGG = "minecraft:vex_spawn_egg"; @@ -497,6 +503,7 @@ final class ItemTypeNames{ public const WITCH_SPAWN_EGG = "minecraft:witch_spawn_egg"; public const WITHER_SKELETON_SPAWN_EGG = "minecraft:wither_skeleton_spawn_egg"; public const WITHER_SPAWN_EGG = "minecraft:wither_spawn_egg"; + public const WOLF_ARMOR = "minecraft:wolf_armor"; public const WOLF_SPAWN_EGG = "minecraft:wolf_spawn_egg"; public const WOODEN_AXE = "minecraft:wooden_axe"; public const WOODEN_DOOR = "minecraft:wooden_door"; diff --git a/src/network/mcpe/ChunkRequestTask.php b/src/network/mcpe/ChunkRequestTask.php index 87a4553c3..ac07d5321 100644 --- a/src/network/mcpe/ChunkRequestTask.php +++ b/src/network/mcpe/ChunkRequestTask.php @@ -30,6 +30,7 @@ use pocketmine\network\mcpe\protocol\LevelChunkPacket; use pocketmine\network\mcpe\protocol\serializer\PacketBatch; use pocketmine\network\mcpe\protocol\serializer\PacketSerializerContext; use pocketmine\network\mcpe\protocol\types\ChunkPosition; +use pocketmine\network\mcpe\protocol\types\DimensionIds; use pocketmine\network\mcpe\serializer\ChunkSerializer; use pocketmine\scheduler\AsyncTask; use pocketmine\thread\NonThreadSafeValue; @@ -43,16 +44,22 @@ class ChunkRequestTask extends AsyncTask{ protected string $chunk; protected int $chunkX; protected int $chunkZ; + /** @phpstan-var DimensionIds::* */ + private int $dimensionId; /** @phpstan-var NonThreadSafeValue */ protected NonThreadSafeValue $compressor; private string $tiles; - public function __construct(int $chunkX, int $chunkZ, Chunk $chunk, CompressBatchPromise $promise, Compressor $compressor){ + /** + * @phpstan-param DimensionIds::* $dimensionId + */ + public function __construct(int $chunkX, int $chunkZ, int $dimensionId, Chunk $chunk, CompressBatchPromise $promise, Compressor $compressor){ $this->compressor = new NonThreadSafeValue($compressor); $this->chunk = FastChunkSerializer::serializeTerrain($chunk); $this->chunkX = $chunkX; $this->chunkZ = $chunkZ; + $this->dimensionId = $dimensionId; $this->tiles = ChunkSerializer::serializeTiles($chunk); $this->storeLocal(self::TLS_KEY_PROMISE, $promise); @@ -60,14 +67,18 @@ class ChunkRequestTask extends AsyncTask{ public function onRun() : void{ $chunk = FastChunkSerializer::deserializeTerrain($this->chunk); - $subCount = ChunkSerializer::getSubChunkCount($chunk); + $dimensionId = $this->dimensionId; + + $subCount = ChunkSerializer::getSubChunkCount($chunk, $dimensionId); $converter = TypeConverter::getInstance(); $encoderContext = new PacketSerializerContext($converter->getItemTypeDictionary()); - $payload = ChunkSerializer::serializeFullChunk($chunk, $converter->getBlockTranslator(), $encoderContext, $this->tiles); + $payload = ChunkSerializer::serializeFullChunk($chunk, $dimensionId, $converter->getBlockTranslator(), $encoderContext, $this->tiles); $stream = new BinaryStream(); - PacketBatch::encodePackets($stream, $encoderContext, [LevelChunkPacket::create(new ChunkPosition($this->chunkX, $this->chunkZ), $subCount, false, null, $payload)]); - $this->setResult($this->compressor->deserialize()->compress($stream->getBuffer())); + PacketBatch::encodePackets($stream, $encoderContext, [LevelChunkPacket::create(new ChunkPosition($this->chunkX, $this->chunkZ), $dimensionId, $subCount, false, null, $payload)]); + + $compressor = $this->compressor->deserialize(); + $this->setResult(chr($compressor->getNetworkId()) . $compressor->compress($stream->getBuffer())); } public function onCompletion() : void{ diff --git a/src/network/mcpe/NetworkSession.php b/src/network/mcpe/NetworkSession.php index 1a4c85255..8ac4db98f 100644 --- a/src/network/mcpe/NetworkSession.php +++ b/src/network/mcpe/NetworkSession.php @@ -86,6 +86,7 @@ use pocketmine\network\mcpe\protocol\types\command\CommandEnum; use pocketmine\network\mcpe\protocol\types\command\CommandOverload; use pocketmine\network\mcpe\protocol\types\command\CommandParameter; use pocketmine\network\mcpe\protocol\types\command\CommandPermissions; +use pocketmine\network\mcpe\protocol\types\CompressionAlgorithm; use pocketmine\network\mcpe\protocol\types\DimensionIds; use pocketmine\network\mcpe\protocol\types\PlayerListEntry; use pocketmine\network\mcpe\protocol\types\PlayerPermissions; @@ -119,6 +120,7 @@ use function implode; use function in_array; use function is_string; use function json_encode; +use function ord; use function random_bytes; use function str_split; use function strcasecmp; @@ -355,15 +357,27 @@ class NetworkSession{ } } + if(strlen($payload) < 1){ + throw new PacketHandlingException("No bytes in payload"); + } + if($this->enableCompression){ Timings::$playerNetworkReceiveDecompress->startTiming(); - try{ - $decompressed = $this->compressor->decompress($payload); - }catch(DecompressionException $e){ - $this->logger->debug("Failed to decompress packet: " . base64_encode($payload)); - throw PacketHandlingException::wrap($e, "Compressed packet batch decode error"); - }finally{ - Timings::$playerNetworkReceiveDecompress->stopTiming(); + $compressionType = ord($payload[0]); + $compressed = substr($payload, 1); + if($compressionType === CompressionAlgorithm::NONE){ + $decompressed = $compressed; + }elseif($compressionType === $this->compressor->getNetworkId()){ + try{ + $decompressed = $this->compressor->decompress($compressed); + }catch(DecompressionException $e){ + $this->logger->debug("Failed to decompress packet: " . base64_encode($compressed)); + throw PacketHandlingException::wrap($e, "Compressed packet batch decode error"); + }finally{ + Timings::$playerNetworkReceiveDecompress->stopTiming(); + } + }else{ + throw new PacketHandlingException("Packet compressed with unexpected compression type $compressionType"); } }else{ $decompressed = $payload; diff --git a/src/network/mcpe/cache/ChunkCache.php b/src/network/mcpe/cache/ChunkCache.php index 71010a041..6d8020085 100644 --- a/src/network/mcpe/cache/ChunkCache.php +++ b/src/network/mcpe/cache/ChunkCache.php @@ -27,6 +27,7 @@ use pocketmine\math\Vector3; use pocketmine\network\mcpe\ChunkRequestTask; use pocketmine\network\mcpe\compression\CompressBatchPromise; use pocketmine\network\mcpe\compression\Compressor; +use pocketmine\network\mcpe\protocol\types\DimensionIds; use pocketmine\world\ChunkListener; use pocketmine\world\ChunkListenerNoOpTrait; use pocketmine\world\format\Chunk; @@ -116,6 +117,7 @@ class ChunkCache implements ChunkListener{ new ChunkRequestTask( $chunkX, $chunkZ, + DimensionIds::OVERWORLD, //TODO: not hardcode this $chunk, $this->caches[$chunkHash], $this->compressor diff --git a/src/network/mcpe/compression/CompressBatchTask.php b/src/network/mcpe/compression/CompressBatchTask.php index 96e9051b6..44ccef8b0 100644 --- a/src/network/mcpe/compression/CompressBatchTask.php +++ b/src/network/mcpe/compression/CompressBatchTask.php @@ -43,7 +43,8 @@ class CompressBatchTask extends AsyncTask{ } public function onRun() : void{ - $this->setResult($this->compressor->deserialize()->compress($this->data)); + $compressor = $this->compressor->deserialize(); + $this->setResult(chr($compressor->getNetworkId()) . $compressor->compress($this->data)); } public function onCompletion() : void{ diff --git a/src/network/mcpe/compression/Compressor.php b/src/network/mcpe/compression/Compressor.php index a299f4eb0..fbb98e789 100644 --- a/src/network/mcpe/compression/Compressor.php +++ b/src/network/mcpe/compression/Compressor.php @@ -23,6 +23,8 @@ declare(strict_types=1); namespace pocketmine\network\mcpe\compression; +use pocketmine\network\mcpe\protocol\types\CompressionAlgorithm; + interface Compressor{ /** * @throws DecompressionException @@ -31,6 +33,14 @@ interface Compressor{ public function compress(string $payload) : string; + /** + * Returns the canonical ID of this compressor, used to tell the remote end how to decompress a packet compressed + * with this compressor. + * + * @return CompressionAlgorithm::* + */ + public function getNetworkId() : int; + /** * Returns the minimum size of packet batch that the compressor will attempt to compress. * diff --git a/src/network/mcpe/compression/ZlibCompressor.php b/src/network/mcpe/compression/ZlibCompressor.php index 066ba876a..a6000e781 100644 --- a/src/network/mcpe/compression/ZlibCompressor.php +++ b/src/network/mcpe/compression/ZlibCompressor.php @@ -23,6 +23,7 @@ declare(strict_types=1); namespace pocketmine\network\mcpe\compression; +use pocketmine\network\mcpe\protocol\types\CompressionAlgorithm; use pocketmine\utils\SingletonTrait; use pocketmine\utils\Utils; use function function_exists; @@ -75,4 +76,8 @@ final class ZlibCompressor implements Compressor{ libdeflate_deflate_compress($payload, $level) : Utils::assumeNotFalse(zlib_encode($payload, ZLIB_ENCODING_RAW, $level), "ZLIB compression failed"); } + + public function getNetworkId() : int{ + return CompressionAlgorithm::ZLIB; + } } diff --git a/src/network/mcpe/handler/SessionStartPacketHandler.php b/src/network/mcpe/handler/SessionStartPacketHandler.php index dd7ae47a8..8163574db 100644 --- a/src/network/mcpe/handler/SessionStartPacketHandler.php +++ b/src/network/mcpe/handler/SessionStartPacketHandler.php @@ -27,7 +27,6 @@ use pocketmine\network\mcpe\NetworkSession; use pocketmine\network\mcpe\protocol\NetworkSettingsPacket; use pocketmine\network\mcpe\protocol\ProtocolInfo; use pocketmine\network\mcpe\protocol\RequestNetworkSettingsPacket; -use pocketmine\network\mcpe\protocol\types\CompressionAlgorithm; final class SessionStartPacketHandler extends PacketHandler{ @@ -50,7 +49,7 @@ final class SessionStartPacketHandler extends PacketHandler{ //TODO: we're filling in the defaults to get pre-1.19.30 behaviour back for now, but we should explore the new options in the future $this->session->sendDataPacket(NetworkSettingsPacket::create( NetworkSettingsPacket::COMPRESS_EVERYTHING, - CompressionAlgorithm::ZLIB, + $this->session->getCompressor()->getNetworkId(), false, 0, 0 diff --git a/src/network/mcpe/serializer/ChunkSerializer.php b/src/network/mcpe/serializer/ChunkSerializer.php index afda6b7bb..bd2b0736c 100644 --- a/src/network/mcpe/serializer/ChunkSerializer.php +++ b/src/network/mcpe/serializer/ChunkSerializer.php @@ -31,6 +31,7 @@ use pocketmine\network\mcpe\convert\BlockTranslator; use pocketmine\network\mcpe\protocol\serializer\NetworkNbtSerializer; use pocketmine\network\mcpe\protocol\serializer\PacketSerializer; use pocketmine\network\mcpe\protocol\serializer\PacketSerializerContext; +use pocketmine\network\mcpe\protocol\types\DimensionIds; use pocketmine\utils\Binary; use pocketmine\utils\BinaryStream; use pocketmine\world\format\Chunk; @@ -43,12 +44,34 @@ final class ChunkSerializer{ //NOOP } + /** + * Returns the min/max subchunk index expected in the protocol. + * This has no relation to the world height supported by PM. + * + * @phpstan-param DimensionIds::* $dimensionId + * @return int[] + * @phpstan-return array{int, int} + */ + public static function getDimensionChunkBounds(int $dimensionId) : array{ + return match($dimensionId){ + DimensionIds::OVERWORLD => [-4, 19], + DimensionIds::NETHER => [0, 7], + DimensionIds::THE_END => [0, 15], + default => throw new \InvalidArgumentException("Unknown dimension ID $dimensionId"), + }; + } + /** * Returns the number of subchunks that will be sent from the given chunk. * Chunks are sent in a stack, so every chunk below the top non-empty one must be sent. + * + * @phpstan-param DimensionIds::* $dimensionId */ - public static function getSubChunkCount(Chunk $chunk) : int{ - for($y = Chunk::MAX_SUBCHUNK_INDEX, $count = count($chunk->getSubChunks()); $y >= Chunk::MIN_SUBCHUNK_INDEX; --$y, --$count){ + public static function getSubChunkCount(Chunk $chunk, int $dimensionId) : int{ + //if the protocol world bounds ever exceed the PM supported bounds again in the future, we might need to + //polyfill some stuff here + [$minSubChunkIndex, $maxSubChunkIndex] = self::getDimensionChunkBounds($dimensionId); + for($y = $maxSubChunkIndex, $count = count($chunk->getSubChunks()); $y >= $minSubChunkIndex; --$y, --$count){ if($chunk->getSubChunk($y)->isEmptyFast()){ continue; } @@ -58,18 +81,23 @@ final class ChunkSerializer{ return 0; } - public static function serializeFullChunk(Chunk $chunk, BlockTranslator $blockTranslator, PacketSerializerContext $encoderContext, ?string $tiles = null) : string{ + /** + * @phpstan-param DimensionIds::* $dimensionId + */ + public static function serializeFullChunk(Chunk $chunk, int $dimensionId, BlockTranslator $blockTranslator, PacketSerializerContext $encoderContext, ?string $tiles = null) : string{ $stream = PacketSerializer::encoder($encoderContext); - $subChunkCount = self::getSubChunkCount($chunk); + $subChunkCount = self::getSubChunkCount($chunk, $dimensionId); $writtenCount = 0; - for($y = Chunk::MIN_SUBCHUNK_INDEX; $writtenCount < $subChunkCount; ++$y, ++$writtenCount){ + + [$minSubChunkIndex, $maxSubChunkIndex] = self::getDimensionChunkBounds($dimensionId); + for($y = $minSubChunkIndex; $writtenCount < $subChunkCount; ++$y, ++$writtenCount){ self::serializeSubChunk($chunk->getSubChunk($y), $blockTranslator, $stream, false); } $biomeIdMap = LegacyBiomeIdToStringIdMap::getInstance(); //all biomes must always be written :( - for($y = Chunk::MIN_SUBCHUNK_INDEX; $y <= Chunk::MAX_SUBCHUNK_INDEX; ++$y){ + for($y = $minSubChunkIndex; $y <= $maxSubChunkIndex; ++$y){ self::serializeBiomePalette($chunk->getSubChunk($y)->getBiomeArray(), $biomeIdMap, $stream); } diff --git a/src/world/format/io/data/BedrockWorldData.php b/src/world/format/io/data/BedrockWorldData.php index cb5468a52..bf8682547 100644 --- a/src/world/format/io/data/BedrockWorldData.php +++ b/src/world/format/io/data/BedrockWorldData.php @@ -51,12 +51,12 @@ use function time; class BedrockWorldData extends BaseNbtWorldData{ public const CURRENT_STORAGE_VERSION = 10; - public const CURRENT_STORAGE_NETWORK_VERSION = 630; + public const CURRENT_STORAGE_NETWORK_VERSION = 649; public const CURRENT_CLIENT_VERSION_TARGET = [ 1, //major 20, //minor - 50, //patch - 3, //revision + 60, //patch + 4, //revision 0 //is beta ];