diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index ecadf8af3c3..ebe5d9cb57f 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -31,7 +31,7 @@ jobs: uses: shivammathur/setup-php@2.29.0 with: php-version: 8.2 - tools: php-cs-fixer:3.38 + tools: php-cs-fixer:3.49 env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/build/generate-build-info-json.php b/build/generate-build-info-json.php index b29d1c7285e..a2e7489f3a6 100644 --- a/build/generate-build-info-json.php +++ b/build/generate-build-info-json.php @@ -21,6 +21,9 @@ declare(strict_types=1); +use pocketmine\network\mcpe\protocol\ProtocolInfo; +use pocketmine\VersionInfo; + require dirname(__DIR__) . '/vendor/autoload.php'; if(count($argv) !== 7){ @@ -30,12 +33,12 @@ echo json_encode([ "php_version" => sprintf("%d.%d", PHP_MAJOR_VERSION, PHP_MINOR_VERSION), //deprecated - "base_version" => \pocketmine\VersionInfo::BASE_VERSION, + "base_version" => VersionInfo::BASE_VERSION, "build" => (int) $argv[4], - "is_dev" => \pocketmine\VersionInfo::IS_DEVELOPMENT_BUILD, - "channel" => \pocketmine\VersionInfo::BUILD_CHANNEL, + "is_dev" => VersionInfo::IS_DEVELOPMENT_BUILD, + "channel" => VersionInfo::BUILD_CHANNEL, "git_commit" => $argv[1], - "mcpe_version" => \pocketmine\network\mcpe\protocol\ProtocolInfo::MINECRAFT_VERSION_NETWORK, + "mcpe_version" => ProtocolInfo::MINECRAFT_VERSION_NETWORK, "date" => time(), //TODO: maybe we should embed this in VersionInfo? "details_url" => "https://github.com/$argv[3]/releases/tag/$argv[2]", "download_url" => "https://github.com/$argv[3]/releases/download/$argv[2]/PocketMine-MP.phar", diff --git a/changelogs/5.11.md b/changelogs/5.11.md new file mode 100644 index 00000000000..9ec0a3a6cc8 --- /dev/null +++ b/changelogs/5.11.md @@ -0,0 +1,26 @@ +# 5.11.0 +Released 7th February 2024. + +**For Minecraft: Bedrock Edition 1.20.60** + +This is a support release for Minecraft: Bedrock Edition 1.20.60. + +**Plugin compatibility:** Plugins for previous 5.x versions will run unchanged on this release, unless they use internal APIs, reflection, or packages like the `pocketmine\network\mcpe` or `pocketmine\data` namespace. +Do not update plugin minimum API versions unless you need new features added in this release. + +**WARNING: If your plugin uses the `pocketmine\network\mcpe` namespace, you're not shielded by API change constraints.** +Consider using the `mcpe-protocol` directive in `plugin.yml` as a constraint if you're using packets directly. + +## General +- Added support for Minecraft: Bedrock Edition 1.20.60. +- Removed support for earlier versions. + +## Fixes +- Fixed `tools/generate-item-upgrade-schema.php` not correctly handling items whose IDs were changed multiple times. +- Fixed `ServerKiller` not working correctly in some cases (incorrectly handled wake-up conditions). +- `ItemBlock`s of `Air` blocks are now always considered as "null" items regardless of count, and don't occupy inventory slots. + +## Internals +- Restructured GitHub Actions CI workflows to make them easier to maintain (no need to update PHP versions in multiple places anymore). +- GitHub Actions CodeStyle workflow now uses php-cs-fixer 3.49.x. +- Dependabot updates are now processed weekly instead of daily. diff --git a/composer.json b/composer.json index 728478e4854..47e798b1643 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 a668d5aad56..47aeeaecab0 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 48f641947d8..73bfdb85a24 100644 --- a/src/Server.php +++ b/src/Server.php @@ -60,6 +60,7 @@ 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 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; @@ -737,7 +739,7 @@ public function getOps() : Config{ * @return string[][] */ public function getCommandAliases() : array{ - $section = $this->configGroup->getProperty(YmlServerProperties::ALIASES); + $section = $this->configGroup->getProperty(Yml::ALIASES); $result = []; if(is_array($section)){ foreach($section as $key => $value){ @@ -861,7 +863,7 @@ public function __construct( $this->logger->emergency($this->language->translate(KnownTranslationFactory::pocketmine_server_devBuild_error1(VersionInfo::NAME))); $this->logger->emergency($this->language->translate(KnownTranslationFactory::pocketmine_server_devBuild_error2())); $this->logger->emergency($this->language->translate(KnownTranslationFactory::pocketmine_server_devBuild_error3())); - $this->logger->emergency($this->language->translate(KnownTranslationFactory::pocketmine_server_devBuild_error4(YmlServerProperties::SETTINGS_ENABLE_DEV_BUILDS))); + $this->logger->emergency($this->language->translate(KnownTranslationFactory::pocketmine_server_devBuild_error4(Yml::SETTINGS_ENABLE_DEV_BUILDS))); $this->logger->emergency($this->language->translate(KnownTranslationFactory::pocketmine_server_devBuild_error5("https://github.com/pmmp/PocketMine-MP/releases"))); $this->forceShutdownExit(); @@ -1373,19 +1375,26 @@ public function prepareBatch(string $buffer, Compressor $compressor, ?bool $sync 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; + } - 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); } - return $compressor->compress($buffer); + return chr($compressionType) . $compressed; }finally{ $timings->stopTiming(); } @@ -1467,7 +1476,7 @@ public function forceShutdown() : void{ } if(isset($this->network)){ - $this->network->getSessionManager()->close($this->configGroup->getPropertyString(YmlServerProperties::SETTINGS_SHUTDOWN_MESSAGE, "Server closed")); + $this->network->getSessionManager()->close($this->configGroup->getPropertyString(Yml::SETTINGS_SHUTDOWN_MESSAGE, "Server closed")); } if(isset($this->worldManager)){ diff --git a/src/VersionInfo.php b/src/VersionInfo.php index 6c7963405e1..c87bc899b8c 100644 --- a/src/VersionInfo.php +++ b/src/VersionInfo.php @@ -31,7 +31,7 @@ final class VersionInfo{ public const NAME = "PocketMine-MP"; - public const BASE_VERSION = "5.10.1"; + public const BASE_VERSION = "5.11.1"; public const IS_DEVELOPMENT_BUILD = true; public const BUILD_CHANNEL = "stable"; diff --git a/src/block/VanillaBlocks.php b/src/block/VanillaBlocks.php index 67a77c183bc..9c0e7d3b7c7 100644 --- a/src/block/VanillaBlocks.php +++ b/src/block/VanillaBlocks.php @@ -788,7 +788,7 @@ public static function getAll() : array{ } protected static function setup() : void{ - $railBreakInfo = new Info(new BlockBreakInfo(0.7)); + $railBreakInfo = new Info(new BreakInfo(0.7)); self::register("activator_rail", new ActivatorRail(new BID(Ids::ACTIVATOR_RAIL), "Activator Rail", $railBreakInfo)); self::register("air", new Air(new BID(Ids::AIR), "Air", new Info(BreakInfo::indestructible(-1.0)))); self::register("anvil", new Anvil(new BID(Ids::ANVIL), "Anvil", new Info(BreakInfo::pickaxe(5.0, ToolTier::WOOD, 6000.0)))); @@ -1638,7 +1638,7 @@ public function isAffectedBySilkTouch() : bool{ self::register("cave_vines", new CaveVines(new BID(Ids::CAVE_VINES), "Cave Vines", new Info(BreakInfo::instant()))); - self::register("small_dripleaf", new SmallDripleaf(new BID(Ids::SMALL_DRIPLEAF), "Small Dripleaf", new Info(BreakInfo::instant(BlockToolType::SHEARS, toolHarvestLevel: 1)))); + self::register("small_dripleaf", new SmallDripleaf(new BID(Ids::SMALL_DRIPLEAF), "Small Dripleaf", new Info(BreakInfo::instant(ToolType::SHEARS, toolHarvestLevel: 1)))); self::register("big_dripleaf_head", new BigDripleafHead(new BID(Ids::BIG_DRIPLEAF_HEAD), "Big Dripleaf", new Info(BreakInfo::instant()))); self::register("big_dripleaf_stem", new BigDripleafStem(new BID(Ids::BIG_DRIPLEAF_STEM), "Big Dripleaf Stem", new Info(BreakInfo::instant()))); } diff --git a/src/block/WoodLikeBlockIdHelper.php b/src/block/WoodLikeBlockIdHelper.php index 5f668608a81..88fdff3a6ec 100644 --- a/src/block/WoodLikeBlockIdHelper.php +++ b/src/block/WoodLikeBlockIdHelper.php @@ -171,7 +171,7 @@ public static function getSignInfo(WoodType $treeType) : array{ }; } - public static function getTrapdoorIdentifier(WoodType $treeType) : BlockIdentifier{ + public static function getTrapdoorIdentifier(WoodType $treeType) : BID{ return new BID(match($treeType){ WoodType::OAK => Ids::OAK_TRAPDOOR, WoodType::SPRUCE => Ids::SPRUCE_TRAPDOOR, @@ -186,7 +186,7 @@ public static function getTrapdoorIdentifier(WoodType $treeType) : BlockIdentifi }); } - public static function getButtonIdentifier(WoodType $treeType) : BlockIdentifier{ + public static function getButtonIdentifier(WoodType $treeType) : BID{ return new BID(match($treeType){ WoodType::OAK => Ids::OAK_BUTTON, WoodType::SPRUCE => Ids::SPRUCE_BUTTON, @@ -201,7 +201,7 @@ public static function getButtonIdentifier(WoodType $treeType) : BlockIdentifier }); } - public static function getPressurePlateIdentifier(WoodType $treeType) : BlockIdentifier{ + public static function getPressurePlateIdentifier(WoodType $treeType) : BID{ return new BID(match($treeType){ WoodType::OAK => Ids::OAK_PRESSURE_PLATE, WoodType::SPRUCE => Ids::SPRUCE_PRESSURE_PLATE, @@ -216,7 +216,7 @@ public static function getPressurePlateIdentifier(WoodType $treeType) : BlockIde }); } - public static function getDoorIdentifier(WoodType $treeType) : BlockIdentifier{ + public static function getDoorIdentifier(WoodType $treeType) : BID{ return new BID(match($treeType){ WoodType::OAK => Ids::OAK_DOOR, WoodType::SPRUCE => Ids::SPRUCE_DOOR, @@ -231,7 +231,7 @@ public static function getDoorIdentifier(WoodType $treeType) : BlockIdentifier{ }); } - public static function getFenceGateIdentifier(WoodType $treeType) : BlockIdentifier{ + public static function getFenceGateIdentifier(WoodType $treeType) : BID{ return new BID(match($treeType){ WoodType::OAK => Ids::OAK_FENCE_GATE, WoodType::SPRUCE => Ids::SPRUCE_FENCE_GATE, @@ -246,7 +246,7 @@ public static function getFenceGateIdentifier(WoodType $treeType) : BlockIdentif }); } - public static function getStairsIdentifier(WoodType $treeType) : BlockIdentifier{ + public static function getStairsIdentifier(WoodType $treeType) : BID{ return new BID(match($treeType){ WoodType::OAK => Ids::OAK_STAIRS, WoodType::SPRUCE => Ids::SPRUCE_STAIRS, diff --git a/src/data/bedrock/block/BlockStateData.php b/src/data/bedrock/block/BlockStateData.php index 1417fa0144a..b089eea5bdf 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 9b28e936d83..75b45e88eca 100644 --- a/src/data/bedrock/block/BlockStateNames.php +++ b/src/data/bedrock/block/BlockStateNames.php @@ -56,7 +56,6 @@ private function __construct(){ 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 @@ private function __construct(){ 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 4a05fa33e9f..d9d8a748d0f 100644 --- a/src/data/bedrock/block/BlockStateStringValues.php +++ b/src/data/bedrock/block/BlockStateStringValues.php @@ -62,23 +62,6 @@ private function __construct(){ 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 fdca40a3a9b..1d8bfadfa4d 100644 --- a/src/data/bedrock/block/BlockTypeNames.php +++ b/src/data/bedrock/block/BlockTypeNames.php @@ -517,10 +517,40 @@ private function __construct(){ 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 @@ private function __construct(){ 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 f70162ac5da..b0b06ac9087 100644 --- a/src/data/bedrock/block/convert/BlockObjectToStateSerializer.php +++ b/src/data/bedrock/block/convert/BlockObjectToStateSerializer.php @@ -315,6 +315,44 @@ private function registerCandleSerializers() : void{ } 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 @@ private function registerSerializers() : void{ ->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 6bb0c8bf819..ea44e90b4c8 100644 --- a/src/data/bedrock/block/convert/BlockStateReader.php +++ b/src/data/bedrock/block/convert/BlockStateReader.php @@ -25,7 +25,6 @@ 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 @@ public function readCardinalHorizontalFacing() : int{ }; } - /** @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/BlockStateSerializerHelper.php b/src/data/bedrock/block/convert/BlockStateSerializerHelper.php index 2b7e89b57e5..2b91234381f 100644 --- a/src/data/bedrock/block/convert/BlockStateSerializerHelper.php +++ b/src/data/bedrock/block/convert/BlockStateSerializerHelper.php @@ -57,42 +57,42 @@ final class BlockStateSerializerHelper{ - public static function encodeAllSidedLog(Wood $block) : BlockStateWriter{ - return BlockStateWriter::create(Ids::WOOD) + public static function encodeAllSidedLog(Wood $block) : Writer{ + return Writer::create(Ids::WOOD) ->writeBool(BlockStateNames::STRIPPED_BIT, $block->isStripped()) ->writePillarAxis($block->getAxis()) ->writeLegacyWoodType($block->getWoodType()); } - public static function encodeButton(Button $block, BlockStateWriter $out) : BlockStateWriter{ + public static function encodeButton(Button $block, Writer $out) : Writer{ return $out ->writeFacingDirection($block->getFacing()) ->writeBool(BlockStateNames::BUTTON_PRESSED_BIT, $block->isPressed()); } - public static function encodeCandle(Candle $block, BlockStateWriter $out) : BlockStateWriter{ + public static function encodeCandle(Candle $block, Writer $out) : Writer{ return $out ->writeBool(StateNames::LIT, $block->isLit()) ->writeInt(StateNames::CANDLES, $block->getCount() - 1); } - public static function encodeChemistryTable(ChemistryTable $block, string $chemistryTableType, BlockStateWriter $out) : BlockStateWriter{ + public static function encodeChemistryTable(ChemistryTable $block, string $chemistryTableType, Writer $out) : Writer{ return $out ->writeString(BlockStateNames::CHEMISTRY_TABLE_TYPE, $chemistryTableType) ->writeLegacyHorizontalFacing(Facing::opposite($block->getFacing())); } - public static function encodeCrops(Crops $block, BlockStateWriter $out) : BlockStateWriter{ + public static function encodeCrops(Crops $block, Writer $out) : Writer{ return $out->writeInt(BlockStateNames::GROWTH, $block->getAge()); } - public static function encodeColoredTorch(Torch $block, bool $highBit, BlockStateWriter $out) : BlockStateWriter{ + public static function encodeColoredTorch(Torch $block, bool $highBit, Writer $out) : Writer{ return $out ->writeBool(BlockStateNames::COLOR_BIT, $highBit) ->writeTorchFacing($block->getFacing()); } - public static function encodeCauldron(string $liquid, int $fillLevel) : BlockStateWriter{ + public static function encodeCauldron(string $liquid, int $fillLevel) : Writer{ return Writer::create(Ids::CAULDRON) ->writeString(BlockStateNames::CAULDRON_LIQUID, $liquid) ->writeInt(BlockStateNames::FILL_LEVEL, $fillLevel); @@ -107,7 +107,7 @@ public static function selectCopperId(CopperOxidation $oxidation, string $noneId }; } - public static function encodeDoor(Door $block, BlockStateWriter $out) : BlockStateWriter{ + public static function encodeDoor(Door $block, Writer $out) : Writer{ return $out ->writeBool(BlockStateNames::UPPER_BLOCK_BIT, $block->isTop()) ->writeLegacyHorizontalFacing(Facing::rotateY($block->getFacing(), true)) @@ -115,111 +115,111 @@ public static function encodeDoor(Door $block, BlockStateWriter $out) : BlockSta ->writeBool(BlockStateNames::OPEN_BIT, $block->isOpen()); } - public static function encodeDoublePlant(DoublePlant $block, string $doublePlantType, BlockStateWriter $out) : BlockStateWriter{ + public static function encodeDoublePlant(DoublePlant $block, string $doublePlantType, Writer $out) : Writer{ return $out ->writeBool(BlockStateNames::UPPER_BLOCK_BIT, $block->isTop()) ->writeString(BlockStateNames::DOUBLE_PLANT_TYPE, $doublePlantType); } - public static function encodeFenceGate(FenceGate $block, BlockStateWriter $out) : BlockStateWriter{ + public static function encodeFenceGate(FenceGate $block, Writer $out) : Writer{ return $out ->writeLegacyHorizontalFacing($block->getFacing()) ->writeBool(BlockStateNames::IN_WALL_BIT, $block->isInWall()) ->writeBool(BlockStateNames::OPEN_BIT, $block->isOpen()); } - public static function encodeFloorSign(FloorSign $block, BlockStateWriter $out) : BlockStateWriter{ + public static function encodeFloorSign(FloorSign $block, Writer $out) : Writer{ return $out ->writeInt(BlockStateNames::GROUND_SIGN_DIRECTION, $block->getRotation()); } - public static function encodeFurnace(Furnace $block, string $unlitId, string $litId) : BlockStateWriter{ - return BlockStateWriter::create($block->isLit() ? $litId : $unlitId) + public static function encodeFurnace(Furnace $block, string $unlitId, string $litId) : Writer{ + return Writer::create($block->isLit() ? $litId : $unlitId) ->writeCardinalHorizontalFacing($block->getFacing()); } - public static function encodeItemFrame(ItemFrame $block, string $id) : BlockStateWriter{ + public static function encodeItemFrame(ItemFrame $block, string $id) : Writer{ return Writer::create($id) ->writeBool(StateNames::ITEM_FRAME_MAP_BIT, $block->hasMap()) ->writeBool(StateNames::ITEM_FRAME_PHOTO_BIT, false) ->writeFacingDirection($block->getFacing()); } - public static function encodeLeaves(Leaves $block, BlockStateWriter $out) : BlockStateWriter{ + public static function encodeLeaves(Leaves $block, Writer $out) : Writer{ return $out ->writeBool(BlockStateNames::PERSISTENT_BIT, $block->isNoDecay()) ->writeBool(BlockStateNames::UPDATE_BIT, $block->isCheckDecay()); } - public static function encodeLeaves1(Leaves $block, string $type) : BlockStateWriter{ - return self::encodeLeaves($block, BlockStateWriter::create(Ids::LEAVES) + public static function encodeLeaves1(Leaves $block, string $type) : Writer{ + return self::encodeLeaves($block, Writer::create(Ids::LEAVES) ->writeString(BlockStateNames::OLD_LEAF_TYPE, $type)); } - public static function encodeLeaves2(Leaves $block, string $type) : BlockStateWriter{ - return self::encodeLeaves($block, BlockStateWriter::create(Ids::LEAVES2) + public static function encodeLeaves2(Leaves $block, string $type) : Writer{ + return self::encodeLeaves($block, Writer::create(Ids::LEAVES2) ->writeString(BlockStateNames::NEW_LEAF_TYPE, $type)); } - public static function encodeLiquid(Liquid $block, string $stillId, string $flowingId) : BlockStateWriter{ - return BlockStateWriter::create($block->isStill() ? $stillId : $flowingId) + public static function encodeLiquid(Liquid $block, string $stillId, string $flowingId) : Writer{ + return Writer::create($block->isStill() ? $stillId : $flowingId) ->writeInt(BlockStateNames::LIQUID_DEPTH, $block->getDecay() | ($block->isFalling() ? 0x8 : 0)); } - public static function encodeLog(Wood $block, string $unstrippedId, string $strippedId) : BlockStateWriter{ + public static function encodeLog(Wood $block, string $unstrippedId, string $strippedId) : Writer{ $out = $block->isStripped() ? - BlockStateWriter::create($strippedId) : - BlockStateWriter::create($unstrippedId); + Writer::create($strippedId) : + Writer::create($unstrippedId); return $out ->writePillarAxis($block->getAxis()); } - public static function encodeMushroomBlock(RedMushroomBlock $block, BlockStateWriter $out) : BlockStateWriter{ + public static function encodeMushroomBlock(RedMushroomBlock $block, Writer $out) : Writer{ return $out ->writeInt(BlockStateNames::HUGE_MUSHROOM_BITS, MushroomBlockTypeIdMap::getInstance()->toId($block->getMushroomBlockType())); } - public static function encodeQuartz(string $type, int $axis) : BlockStateWriter{ - return BlockStateWriter::create(Ids::QUARTZ_BLOCK) + public static function encodeQuartz(string $type, int $axis) : Writer{ + return Writer::create(Ids::QUARTZ_BLOCK) ->writeString(BlockStateNames::CHISEL_TYPE, $type) ->writePillarAxis($axis); //this isn't needed for all types, but we have to write it anyway } - public static function encodeRedFlower(string $type) : BlockStateWriter{ - return BlockStateWriter::create(Ids::RED_FLOWER)->writeString(BlockStateNames::FLOWER_TYPE, $type); + public static function encodeRedFlower(string $type) : Writer{ + return Writer::create(Ids::RED_FLOWER)->writeString(BlockStateNames::FLOWER_TYPE, $type); } - public static function encodeSandstone(string $id, string $type) : BlockStateWriter{ - return BlockStateWriter::create($id)->writeString(BlockStateNames::SAND_STONE_TYPE, $type); + public static function encodeSandstone(string $id, string $type) : Writer{ + return Writer::create($id)->writeString(BlockStateNames::SAND_STONE_TYPE, $type); } - public static function encodeSapling(Sapling $block, string $type) : BlockStateWriter{ - return BlockStateWriter::create(Ids::SAPLING) + public static function encodeSapling(Sapling $block, string $type) : Writer{ + return Writer::create(Ids::SAPLING) ->writeBool(BlockStateNames::AGE_BIT, $block->isReady()) ->writeString(BlockStateNames::SAPLING_TYPE, $type); } - public static function encodeSimplePressurePlate(SimplePressurePlate $block, BlockStateWriter $out) : BlockStateWriter{ + public static function encodeSimplePressurePlate(SimplePressurePlate $block, Writer $out) : Writer{ //TODO: not sure what the deal is here ... seems like a mojang bug / artifact of bad implementation? //best to keep this separate from weighted plates anyway... return $out ->writeInt(BlockStateNames::REDSTONE_SIGNAL, $block->isPressed() ? 15 : 0); } - public static function encodeSlab(Slab $block, string $singleId, string $doubleId) : BlockStateWriter{ + public static function encodeSlab(Slab $block, string $singleId, string $doubleId) : Writer{ $slabType = $block->getSlabType(); - return BlockStateWriter::create($slabType === SlabType::DOUBLE ? $doubleId : $singleId) + return Writer::create($slabType === SlabType::DOUBLE ? $doubleId : $singleId) //this is (intentionally) also written for double slabs (as zero) to maintain bug parity with MCPE ->writeSlabPosition($slabType === SlabType::DOUBLE ? SlabType::BOTTOM : $slabType); } - public static function encodeStairs(Stair $block, BlockStateWriter $out) : BlockStateWriter{ + public static function encodeStairs(Stair $block, Writer $out) : Writer{ return $out ->writeBool(BlockStateNames::UPSIDE_DOWN_BIT, $block->isUpsideDown()) ->writeWeirdoHorizontalFacing($block->getFacing()); } - public static function encodeStem(Stem $block, BlockStateWriter $out) : BlockStateWriter{ + public static function encodeStem(Stem $block, Writer $out) : Writer{ //In PM, we use Facing::UP to indicate that the stem is not attached to a pumpkin/melon, since this makes the //most intuitive sense (the stem is pointing at the sky). However, Bedrock uses the DOWN state for this, which //is absurd, and I refuse to make our API similarly absurd. @@ -228,40 +228,40 @@ public static function encodeStem(Stem $block, BlockStateWriter $out) : BlockSta ->writeFacingWithoutUp($facing === Facing::UP ? Facing::DOWN : $facing); } - public static function encodeStoneBricks(string $type) : BlockStateWriter{ - return BlockStateWriter::create(Ids::STONEBRICK) + public static function encodeStoneBricks(string $type) : Writer{ + return Writer::create(Ids::STONEBRICK) ->writeString(BlockStateNames::STONE_BRICK_TYPE, $type); } - private static function encodeStoneSlab(Slab $block, string $singleId, string $doubleId, string $typeKey, string $typeValue) : BlockStateWriter{ + private static function encodeStoneSlab(Slab $block, string $singleId, string $doubleId, string $typeKey, string $typeValue) : Writer{ return self::encodeSlab($block, $singleId, $doubleId) ->writeString($typeKey, $typeValue); } - public static function encodeStoneSlab1(Slab $block, string $typeValue) : BlockStateWriter{ + public static function encodeStoneSlab1(Slab $block, string $typeValue) : Writer{ return self::encodeStoneSlab($block, Ids::STONE_BLOCK_SLAB, Ids::DOUBLE_STONE_BLOCK_SLAB, BlockStateNames::STONE_SLAB_TYPE, $typeValue); } - public static function encodeStoneSlab2(Slab $block, string $typeValue) : BlockStateWriter{ + public static function encodeStoneSlab2(Slab $block, string $typeValue) : Writer{ return self::encodeStoneSlab($block, Ids::STONE_BLOCK_SLAB2, Ids::DOUBLE_STONE_BLOCK_SLAB2, BlockStateNames::STONE_SLAB_TYPE_2, $typeValue); } - public static function encodeStoneSlab3(Slab $block, string $typeValue) : BlockStateWriter{ + public static function encodeStoneSlab3(Slab $block, string $typeValue) : Writer{ return self::encodeStoneSlab($block, Ids::STONE_BLOCK_SLAB3, Ids::DOUBLE_STONE_BLOCK_SLAB3, BlockStateNames::STONE_SLAB_TYPE_3, $typeValue); } - public static function encodeStoneSlab4(Slab $block, string $typeValue) : BlockStateWriter{ + public static function encodeStoneSlab4(Slab $block, string $typeValue) : Writer{ return self::encodeStoneSlab($block, Ids::STONE_BLOCK_SLAB4, Ids::DOUBLE_STONE_BLOCK_SLAB4, BlockStateNames::STONE_SLAB_TYPE_4, $typeValue); } - public static function encodeTrapdoor(Trapdoor $block, BlockStateWriter $out) : BlockStateWriter{ + public static function encodeTrapdoor(Trapdoor $block, Writer $out) : Writer{ return $out ->write5MinusHorizontalFacing($block->getFacing()) ->writeBool(BlockStateNames::UPSIDE_DOWN_BIT, $block->isTop()) ->writeBool(BlockStateNames::OPEN_BIT, $block->isOpen()); } - public static function encodeWall(Wall $block, BlockStateWriter $out) : BlockStateWriter{ + public static function encodeWall(Wall $block, Writer $out) : Writer{ return $out ->writeBool(BlockStateNames::WALL_POST_BIT, $block->isPost()) ->writeWallConnectionType(BlockStateNames::WALL_CONNECTION_TYPE_EAST, $block->getConnection(Facing::EAST)) @@ -270,17 +270,17 @@ public static function encodeWall(Wall $block, BlockStateWriter $out) : BlockSta ->writeWallConnectionType(BlockStateNames::WALL_CONNECTION_TYPE_WEST, $block->getConnection(Facing::WEST)); } - public static function encodeLegacyWall(Wall $block, string $type) : BlockStateWriter{ - return self::encodeWall($block, BlockStateWriter::create(Ids::COBBLESTONE_WALL)) + public static function encodeLegacyWall(Wall $block, string $type) : Writer{ + return self::encodeWall($block, Writer::create(Ids::COBBLESTONE_WALL)) ->writeString(BlockStateNames::WALL_BLOCK_TYPE, $type); } - public static function encodeWallSign(WallSign $block, BlockStateWriter $out) : BlockStateWriter{ + public static function encodeWallSign(WallSign $block, Writer $out) : Writer{ return $out ->writeHorizontalFacing($block->getFacing()); } - public static function encodeWoodenSlab(Slab $block, string $typeValue) : BlockStateWriter{ + public static function encodeWoodenSlab(Slab $block, string $typeValue) : Writer{ return self::encodeSlab($block, Ids::WOODEN_SLAB, Ids::DOUBLE_WOODEN_SLAB) ->writeString(BlockStateNames::WOOD_TYPE, $typeValue); } diff --git a/src/data/bedrock/block/convert/BlockStateToObjectDeserializer.php b/src/data/bedrock/block/convert/BlockStateToObjectDeserializer.php index 18e9b3e3225..2941263675d 100644 --- a/src/data/bedrock/block/convert/BlockStateToObjectDeserializer.php +++ b/src/data/bedrock/block/convert/BlockStateToObjectDeserializer.php @@ -185,6 +185,48 @@ private function registerCandleDeserializers() : void{ } 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 @@ private function registerDeserializers() : void{ ->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 f5f34fff651..69efa4d0fd0 100644 --- a/src/data/bedrock/block/convert/BlockStateWriter.php +++ b/src/data/bedrock/block/convert/BlockStateWriter.php @@ -25,7 +25,6 @@ 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 @@ public function writeCardinalHorizontalFacing(int $value) : self{ }); } - /** @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 0c6dadc462f..bbc295b7251 100644 --- a/src/data/bedrock/item/ItemSerializerDeserializerRegistrar.php +++ b/src/data/bedrock/item/ItemSerializerDeserializerRegistrar.php @@ -348,7 +348,7 @@ private function register1to1ItemMappings() : void{ $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 c1534a0f0ea..3f01ff1a88f 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 87a4553c3ea..05a4f20c109 100644 --- a/src/network/mcpe/ChunkRequestTask.php +++ b/src/network/mcpe/ChunkRequestTask.php @@ -30,12 +30,14 @@ 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; use pocketmine\utils\BinaryStream; use pocketmine\world\format\Chunk; use pocketmine\world\format\io\FastChunkSerializer; +use function chr; class ChunkRequestTask extends AsyncTask{ private const TLS_KEY_PROMISE = "promise"; @@ -43,16 +45,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 +68,18 @@ public function __construct(int $chunkX, int $chunkZ, Chunk $chunk, CompressBatc 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 1a4c85255e7..8ac4db98fc7 100644 --- a/src/network/mcpe/NetworkSession.php +++ b/src/network/mcpe/NetworkSession.php @@ -86,6 +86,7 @@ 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 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 @@ public function handleEncoded(string $payload) : void{ } } + 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 71010a041c1..6d802008578 100644 --- a/src/network/mcpe/cache/ChunkCache.php +++ b/src/network/mcpe/cache/ChunkCache.php @@ -27,6 +27,7 @@ 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 @@ public function request(int $chunkX, int $chunkZ) : CompressBatchPromise{ 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 96e9051b683..a513cfa86cd 100644 --- a/src/network/mcpe/compression/CompressBatchTask.php +++ b/src/network/mcpe/compression/CompressBatchTask.php @@ -25,6 +25,7 @@ use pocketmine\scheduler\AsyncTask; use pocketmine\thread\NonThreadSafeValue; +use function chr; class CompressBatchTask extends AsyncTask{ @@ -43,7 +44,8 @@ public function __construct( } 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 a299f4eb08a..fbb98e78905 100644 --- a/src/network/mcpe/compression/Compressor.php +++ b/src/network/mcpe/compression/Compressor.php @@ -23,6 +23,8 @@ namespace pocketmine\network\mcpe\compression; +use pocketmine\network\mcpe\protocol\types\CompressionAlgorithm; + interface Compressor{ /** * @throws DecompressionException @@ -31,6 +33,14 @@ public function decompress(string $payload) : string; 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 066ba876a72..a6000e78130 100644 --- a/src/network/mcpe/compression/ZlibCompressor.php +++ b/src/network/mcpe/compression/ZlibCompressor.php @@ -23,6 +23,7 @@ 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 @@ public function compress(string $payload) : string{ 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 dd7ae47a854..8163574dbd0 100644 --- a/src/network/mcpe/handler/SessionStartPacketHandler.php +++ b/src/network/mcpe/handler/SessionStartPacketHandler.php @@ -27,7 +27,6 @@ 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 @@ public function handleRequestNetworkSettings(RequestNetworkSettingsPacket $packe //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 afda6b7bbc7..e089daef569 100644 --- a/src/network/mcpe/serializer/ChunkSerializer.php +++ b/src/network/mcpe/serializer/ChunkSerializer.php @@ -31,6 +31,7 @@ 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 @@ private function __construct(){ //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 = $maxSubChunkIndex - $minSubChunkIndex + 1; $y >= $minSubChunkIndex; --$y, --$count){ if($chunk->getSubChunk($y)->isEmptyFast()){ continue; } @@ -58,18 +81,23 @@ public static function getSubChunkCount(Chunk $chunk) : int{ 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/utils/MainLogger.php b/src/utils/MainLogger.php index 402a68edbbd..ffd56b041ac 100644 --- a/src/utils/MainLogger.php +++ b/src/utils/MainLogger.php @@ -23,7 +23,6 @@ namespace pocketmine\utils; -use LogLevel; use pmmp\thread\Thread as NativeThread; use pocketmine\thread\log\AttachableThreadSafeLogger; use pocketmine\thread\log\ThreadSafeLoggerAttachment; @@ -132,28 +131,28 @@ public function logException(\Throwable $e, $trace = null){ public function log($level, $message){ switch($level){ - case LogLevel::EMERGENCY: + case \LogLevel::EMERGENCY: $this->emergency($message); break; - case LogLevel::ALERT: + case \LogLevel::ALERT: $this->alert($message); break; - case LogLevel::CRITICAL: + case \LogLevel::CRITICAL: $this->critical($message); break; - case LogLevel::ERROR: + case \LogLevel::ERROR: $this->error($message); break; - case LogLevel::WARNING: + case \LogLevel::WARNING: $this->warning($message); break; - case LogLevel::NOTICE: + case \LogLevel::NOTICE: $this->notice($message); break; - case LogLevel::INFO: + case \LogLevel::INFO: $this->info($message); break; - case LogLevel::DEBUG: + case \LogLevel::DEBUG: $this->debug($message); break; } diff --git a/src/world/format/io/data/BedrockWorldData.php b/src/world/format/io/data/BedrockWorldData.php index cb5468a5254..bf868254771 100644 --- a/src/world/format/io/data/BedrockWorldData.php +++ b/src/world/format/io/data/BedrockWorldData.php @@ -51,12 +51,12 @@ 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 ]; diff --git a/tests/phpunit/block/regenerate_consistency_check.php b/tests/phpunit/block/regenerate_consistency_check.php index ac8a1ad9dea..b4b3875c680 100644 --- a/tests/phpunit/block/regenerate_consistency_check.php +++ b/tests/phpunit/block/regenerate_consistency_check.php @@ -30,7 +30,7 @@ /* This script needs to be re-run after any intentional blockfactory change (adding or removing a block state). */ -$factory = new \pocketmine\block\RuntimeBlockStateRegistry(); +$factory = new RuntimeBlockStateRegistry(); $remaps = []; $new = []; foreach(RuntimeBlockStateRegistry::getInstance()->getAllKnownStates() as $index => $block){ @@ -44,7 +44,7 @@ if(file_exists($oldTablePath)){ $oldTable = json_decode(file_get_contents($oldTablePath), true); if(!is_array($oldTable)){ - throw new \pocketmine\utils\AssumptionFailedError("Old table should be array{knownStates: array, stateDataBits: int}"); + throw new AssumptionFailedError("Old table should be array{knownStates: array, stateDataBits: int}"); } $old = []; /** diff --git a/tools/convert-world.php b/tools/convert-world.php index 75483c6af37..d4d15ce57b6 100644 --- a/tools/convert-world.php +++ b/tools/convert-world.php @@ -21,10 +21,29 @@ declare(strict_types=1); +namespace pocketmine\tools\convert_world; + use pocketmine\world\format\io\FormatConverter; use pocketmine\world\format\io\WorldProviderManager; use pocketmine\world\format\io\WorldProviderManagerEntry; use pocketmine\world\format\io\WritableWorldProviderManagerEntry; +use function array_filter; +use function array_key_exists; +use function array_keys; +use function array_map; +use function array_shift; +use function count; +use function dirname; +use function fwrite; +use function getopt; +use function implode; +use function is_dir; +use function is_string; +use function is_writable; +use function mkdir; +use function realpath; +use const PHP_EOL; +use const STDERR; require_once dirname(__DIR__) . '/vendor/autoload.php'; @@ -76,5 +95,5 @@ $oldProviderClass = array_shift($oldProviderClasses); $oldProvider = $oldProviderClass->fromPath($inputPath, new \PrefixedLogger(\GlobalLogger::get(), "Old World Provider")); -$converter = new FormatConverter($oldProvider, $writableFormats[$args["format"]], $backupPath, GlobalLogger::get()); +$converter = new FormatConverter($oldProvider, $writableFormats[$args["format"]], $backupPath, \GlobalLogger::get()); $converter->execute();